summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorKevin Walzer <kw@codebykevin.com>2015-03-21 01:22:30 (GMT)
committerKevin Walzer <kw@codebykevin.com>2015-03-21 01:22:30 (GMT)
commitb3dcb261f002c340fd3037dcecbfca516491f552 (patch)
treeaa5390457f8371d6bf3eb56d179db157eaecc722 /macosx
parent80d69b8384abe214b34c64d36568b48adaa8c5db (diff)
downloadtk-b3dcb261f002c340fd3037dcecbfca516491f552.zip
tk-b3dcb261f002c340fd3037dcecbfca516491f552.tar.gz
tk-b3dcb261f002c340fd3037dcecbfca516491f552.tar.bz2
Cleanup and simplification of memory management in event loop; now works more smoothly; thanks to Marc Culler for patches
Diffstat (limited to 'macosx')
-rw-r--r--macosx/tkMacOSXMenu.c9
-rw-r--r--macosx/tkMacOSXNotify.c117
-rw-r--r--macosx/tkMacOSXSubwindows.c6
-rw-r--r--macosx/tkMacOSXWindowEvent.c35
-rw-r--r--macosx/tkMacOSXWm.c14
5 files changed, 104 insertions, 77 deletions
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c
index 9f14f47..0cc874c 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 ab68931..905ada5 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -18,9 +18,9 @@
#include <pthread.h>
#import <objc/objc-auto.h>
+/* 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
@@ -48,42 +49,30 @@ 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
@@ -161,7 +150,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);
@@ -194,7 +184,8 @@ TkMacOSXNotifyExitHandler(
TSD_INIT();
Tcl_DeleteEventSource(TkMacOSXEventsSetupProc,
- TkMacOSXEventsCheckProc, GetMainEventQueue());
+ TkMacOSXEventsCheckProc,
+ GetMainEventQueue());
tsdPtr->initialized = 0;
}
@@ -203,16 +194,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.
*
*----------------------------------------------------------------------
*/
@@ -225,19 +219,13 @@ TkMacOSXEventsSetupProc(
if (flags & TCL_WINDOW_EVENTS &&
![[NSRunLoop currentRunLoop] currentMode]) {
static const 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);
}
}
@@ -248,17 +236,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,
@@ -267,31 +256,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];
- }
- if (!currentEvent) {
- break;
+ break; /* No more events. */
}
- [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
@@ -300,14 +281,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 ee9167b..869f717 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 241da83..2e7c041 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -794,7 +794,6 @@ Tk_MacOSXIsAppInFront(void)
@implementation TKContentView
@end
-
/*Restrict event processing to Expose events.*/
static Tk_RestrictAction
ExposeRestrictProc(
@@ -842,9 +841,37 @@ ExposeRestrictProc(
CFRelease(drawShape);
}
+-(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
@@ -852,13 +879,11 @@ ExposeRestrictProc(
HIRect bounds = NSRectToCGRect([self bounds]);
HIShapeRef shape = HIShapeCreateWithRect(&bounds);
[self generateExposeEvents: shape];
-
}
/*Core function of this class, generates expose events for redrawing.*/
- (void) generateExposeEvents: (HIMutableShapeRef) shape
{
-
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
unsigned long serial;
CGRect updateBounds;
@@ -867,7 +892,6 @@ ExposeRestrictProc(
return;
}
-
HIShapeGetBounds(shape, &updateBounds);
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
if (GenerateUpdates(shape, &updateBounds, winPtr) &&
@@ -895,7 +919,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 ffb3c34..8866118 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -21,6 +21,8 @@
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
+#define DEBUG_ZOMBIES 0
+
/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_WINDOWS
@@ -350,6 +352,17 @@ static void RemapWindows(TkWindow *winPtr,
kHelpWindowClass || winPtr->wmInfoPtr->attributes &
kWindowNoActivatesAttribute)) ? NO : YES;
}
+
+- (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
#pragma mark -
@@ -781,7 +794,6 @@ TkWmDeadWindow(
if (parent) {
[parent removeChildWindow:window];
}
- [window setExcludedFromWindowsMenu:YES];
[window close];
TkMacOSXUnregisterMacWindow(window);
if (winPtr->window) {