summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--changes10
-rw-r--r--generic/tkEntry.c129
-rw-r--r--generic/tkTextDisp.c27
-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
-rw-r--r--tests/entry.test27
-rw-r--r--tests/spinbox.test26
-rw-r--r--tests/textDisp.test11
19 files changed, 403 insertions, 194 deletions
diff --git a/changes b/changes
index de882b2..37cf0bd 100644
--- a/changes
+++ b/changes
@@ -7047,6 +7047,14 @@ Tk Cocoa 2.0: App Store enabled (walzer,culler,desmera,owen,nyberg,reincke)
2015-11-29 (bug)[1997299] [text] tag borderwidth leak (vogel)
+2015-12-12 (bug)[1739605] [text see] misbehavior (danckaert)
+
+2015-12-13 (bug)[ff8a1e] Never-mapped [text] performance (danckaert)
+
+2015-12-19 (bug)[1700065] Report errors from -textvariable write trace (vogel)
+
+2015-12-19 (bug)[793909] -textvariable handle undefined namespace (vogel)
+
Tk Cocoa 2.0: More drawing internals refinements (culler,walzer)
---- Released 8.5.19, December 1, 2015 --- http://core.tcl.tk/tk/ for details
+--- Released 8.5.19, January 31, 2016 --- http://core.tcl.tk/tk/ for details
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index f6ff9b9..338652b 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -391,7 +391,7 @@ static const char *selElementNames[] = {
static int ConfigureEntry(Tcl_Interp *interp, Entry *entryPtr,
int objc, Tcl_Obj *const objv[], int flags);
-static void DeleteChars(Entry *entryPtr, int index, int count);
+static int DeleteChars(Entry *entryPtr, int index, int count);
static void DestroyEntry(char *memPtr);
static void DisplayEntry(ClientData clientData);
static void EntryBlinkProc(ClientData clientData);
@@ -417,7 +417,7 @@ static int EntryValidateChange(Entry *entryPtr, char *change,
static void ExpandPercents(Entry *entryPtr, const char *before,
const char *change, const char *newStr, int index,
int type, Tcl_DString *dsPtr);
-static void EntryValueChanged(Entry *entryPtr,
+static int EntryValueChanged(Entry *entryPtr,
const char *newValue);
static void EntryVisibleRange(Entry *entryPtr,
double *firstPtr, double *lastPtr);
@@ -427,7 +427,7 @@ static int EntryWidgetObjCmd(ClientData clientData,
static void EntryWorldChanged(ClientData instanceData);
static int GetEntryIndex(Tcl_Interp *interp, Entry *entryPtr,
char *string, int *indexPtr);
-static void InsertChars(Entry *entryPtr, int index, char *string);
+static int InsertChars(Entry *entryPtr, int index, char *string);
/*
* These forward declarations are the spinbox specific ones:
@@ -663,7 +663,7 @@ EntryWidgetObjCmd(
break;
case COMMAND_DELETE: {
- int first, last;
+ int first, last, code;
if ((objc < 3) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
@@ -680,7 +680,10 @@ EntryWidgetObjCmd(
goto error;
}
if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
- DeleteChars(entryPtr, first, last - first);
+ code = DeleteChars(entryPtr, first, last - first);
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -721,7 +724,7 @@ EntryWidgetObjCmd(
}
case COMMAND_INSERT: {
- int index;
+ int index, code;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "index text");
@@ -732,7 +735,10 @@ EntryWidgetObjCmd(
goto error;
}
if (entryPtr->state == STATE_NORMAL) {
- InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ code = InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -1096,6 +1102,7 @@ ConfigureEntry(
int valuesChanged = 0; /* lint initialization */
double oldFrom = 0.0; /* lint initialization */
double oldTo = 0.0; /* lint initialization */
+ int code;
/*
* Eliminate any existing trace on a variable monitored by the entry.
@@ -1298,6 +1305,17 @@ ConfigureEntry(
value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
if (value == NULL) {
+
+ /*
+ * Since any trace on the textvariable was eliminated above,
+ * the only possible reason for EntryValueChanged to return
+ * an error is that the textvariable lives in a namespace
+ * that does not (yet) exist. Indeed, namespaces are not
+ * automatically created as needed. Don't trap this error
+ * here, better do it below when attempting to trace the
+ * variable.
+ */
+
EntryValueChanged(entryPtr, NULL);
} else {
EntrySetValue(entryPtr, value);
@@ -1316,7 +1334,13 @@ ConfigureEntry(
*/
Tcl_ListObjIndex(interp, sbPtr->listObj, 0, &objPtr);
- EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
+
+ /*
+ * No check for error return here as well, because any possible
+ * error will be trapped below when attempting tracing.
+ */
+
+ EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
} else if ((sbPtr->valueStr == NULL)
&& !DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)
&& (!DOUBLES_EQ(sbPtr->fromValue, oldFrom)
@@ -1341,6 +1365,12 @@ ConfigureEntry(
}
}
sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
+
+ /*
+ * No check for error return here as well, because any possible
+ * error will be trapped below when attempting tracing.
+ */
+
EntryValueChanged(entryPtr, sbPtr->formatBuf);
}
}
@@ -1352,10 +1382,13 @@ ConfigureEntry(
if ((entryPtr->textVarName != NULL)
&& !(entryPtr->flags & ENTRY_VAR_TRACED)) {
- Tcl_TraceVar(interp, entryPtr->textVarName,
+ code = Tcl_TraceVar(interp, entryPtr->textVarName,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, (ClientData) entryPtr);
- entryPtr->flags |= ENTRY_VAR_TRACED;
+ if (code != TCL_OK) {
+ return TCL_ERROR;
+ }
+ entryPtr->flags |= ENTRY_VAR_TRACED;
}
EntryWorldChanged((ClientData) entryPtr);
@@ -1990,7 +2023,8 @@ EntryComputeGeometry(
* Add new characters to an entry widget.
*
* Results:
- * None.
+ * A standard Tcl result. If an error occurred then an error message is
+ * left in the interp's result.
*
* Side effects:
* New information gets added to entryPtr; it will be redisplayed soon,
@@ -1999,7 +2033,7 @@ EntryComputeGeometry(
*----------------------------------------------------------------------
*/
-static void
+static int
InsertChars(
Entry *entryPtr, /* Entry that is to get the new elements. */
int index, /* Add the new elements before this character
@@ -2017,7 +2051,7 @@ InsertChars(
byteIndex = Tcl_UtfAtIndex(string, index) - string;
byteCount = strlen(value);
if (byteCount == 0) {
- return;
+ return TCL_OK;
}
newByteCount = entryPtr->numBytes + byteCount + 1;
@@ -2031,7 +2065,7 @@ InsertChars(
EntryValidateChange(entryPtr, value, newStr, index,
VALIDATE_INSERT) != TCL_OK) {
ckfree(newStr);
- return;
+ return TCL_OK;
}
ckfree((char *)string);
@@ -2079,7 +2113,7 @@ InsertChars(
if (entryPtr->insertPos >= index) {
entryPtr->insertPos += charsAdded;
}
- EntryValueChanged(entryPtr, NULL);
+ return EntryValueChanged(entryPtr, NULL);
}
/*
@@ -2090,7 +2124,8 @@ InsertChars(
* Remove one or more characters from an entry widget.
*
* Results:
- * None.
+ * A standard Tcl result. If an error occurred then an error message is
+ * left in the interp's result.
*
* Side effects:
* Memory gets freed, the entry gets modified and (eventually)
@@ -2099,7 +2134,7 @@ InsertChars(
*----------------------------------------------------------------------
*/
-static void
+static int
DeleteChars(
Entry *entryPtr, /* Entry widget to modify. */
int index, /* Index of first character to delete. */
@@ -2113,7 +2148,7 @@ DeleteChars(
count = entryPtr->numChars - index;
}
if (count <= 0) {
- return;
+ return TCL_OK;
}
string = entryPtr->string;
@@ -2135,7 +2170,7 @@ DeleteChars(
VALIDATE_DELETE) != TCL_OK) {
ckfree(newStr);
ckfree(toDelete);
- return;
+ return TCL_OK;
}
ckfree(toDelete);
@@ -2194,7 +2229,7 @@ DeleteChars(
entryPtr->insertPos = index;
}
}
- EntryValueChanged(entryPtr, NULL);
+ return EntryValueChanged(entryPtr, NULL);
}
/*
@@ -2207,7 +2242,8 @@ DeleteChars(
* is one, and does other bookkeeping such as arranging for redisplay.
*
* Results:
- * None.
+ * A standard Tcl result. If an error occurred then an error message is
+ * left in the interp's result.
*
* Side effects:
* None.
@@ -2215,7 +2251,7 @@ DeleteChars(
*----------------------------------------------------------------------
*/
-static void
+static int
EntryValueChanged(
Entry *entryPtr, /* Entry whose value just changed. */
const char *newValue) /* If this value is not NULL, we first force
@@ -2229,7 +2265,7 @@ EntryValueChanged(
newValue = NULL;
} else {
newValue = Tcl_SetVar(entryPtr->interp, entryPtr->textVarName,
- entryPtr->string, TCL_GLOBAL_ONLY);
+ entryPtr->string, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG);
}
if ((newValue != NULL) && (strcmp(newValue, entryPtr->string) != 0)) {
@@ -2251,6 +2287,19 @@ EntryValueChanged(
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
}
+
+ /*
+ * An error may have happened when setting the textvariable in case there
+ * is a trace on that variable and the trace proc triggered an error.
+ * Another possibility is that the textvariable is in a namespace that
+ * does not (yet) exist.
+ * Signal this error.
+ */
+
+ if ((entryPtr->textVarName != NULL) && (newValue == NULL)) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
}
/*
@@ -3703,7 +3752,7 @@ SpinboxWidgetObjCmd(
break;
case SB_CMD_DELETE: {
- int first, last;
+ int first, last, code;
if ((objc < 3) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
@@ -3722,7 +3771,10 @@ SpinboxWidgetObjCmd(
}
}
if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
- DeleteChars(entryPtr, first, last - first);
+ code = DeleteChars(entryPtr, first, last - first);
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -3782,7 +3834,7 @@ SpinboxWidgetObjCmd(
}
case SB_CMD_INSERT: {
- int index;
+ int index, code;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "index text");
@@ -3793,7 +3845,10 @@ SpinboxWidgetObjCmd(
goto error;
}
if (entryPtr->state == STATE_NORMAL) {
- InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ code = InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -4001,16 +4056,22 @@ SpinboxWidgetObjCmd(
break;
}
- case SB_CMD_SET:
+ case SB_CMD_SET: {
+ int code = TCL_OK;
+
if (objc > 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?string?");
goto error;
}
if (objc == 3) {
- EntryValueChanged(entryPtr, Tcl_GetString(objv[2]));
+ code = EntryValueChanged(entryPtr, Tcl_GetString(objv[2]));
+ if (code != TCL_OK) {
+ goto error;
+ }
}
Tcl_SetStringObj(Tcl_GetObjResult(interp), entryPtr->string, -1);
break;
+ }
case SB_CMD_VALIDATE: {
int code;
@@ -4151,7 +4212,7 @@ GetSpinboxElement(
* TCL_OK.
*
* Side effects:
- * An background error condition may arise when invoking the callback.
+ * A background error condition may arise when invoking the callback.
* The widget value may change.
*
*--------------------------------------------------------------
@@ -4182,6 +4243,7 @@ SpinboxInvoke(
return TCL_OK;
}
+ code = TCL_OK;
if (fabs(sbPtr->increment) > MIN_DBL_VAL) {
if (sbPtr->listObj != NULL) {
Tcl_Obj *objPtr;
@@ -4227,7 +4289,7 @@ SpinboxInvoke(
}
}
Tcl_ListObjIndex(interp, sbPtr->listObj, sbPtr->eIndex, &objPtr);
- EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
+ code = EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
} else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) {
double dvalue;
@@ -4274,9 +4336,12 @@ SpinboxInvoke(
}
}
sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
- EntryValueChanged(entryPtr, sbPtr->formatBuf);
+ code = EntryValueChanged(entryPtr, sbPtr->formatBuf);
}
}
+ if (code != TCL_OK) {
+ return TCL_ERROR;
+ }
if (sbPtr->command != NULL) {
Tcl_DStringInit(&script);
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index cfe6e7a..ef8d6f4 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -658,17 +658,8 @@ TkTextCreateDInfo(
dInfoPtr->metricEpoch = -1;
dInfoPtr->metricIndex.textPtr = NULL;
dInfoPtr->metricIndex.linePtr = NULL;
-
- /*
- * Add a refCount for each of the idle call-backs.
- */
-
- textPtr->refCount++;
- dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(0,
- AsyncUpdateLineMetrics, (ClientData) textPtr);
- textPtr->refCount++;
- dInfoPtr->scrollbarTimer = Tcl_CreateTimerHandler(200,
- AsyncUpdateYScrollbar, (ClientData) textPtr);
+ dInfoPtr->lineUpdateTimer = NULL;
+ dInfoPtr->scrollbarTimer = NULL;
textPtr->dInfoPtr = dInfoPtr;
}
@@ -2912,9 +2903,10 @@ AsyncUpdateLineMetrics(
dInfoPtr->lineUpdateTimer = NULL;
- if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
+ if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)
+ || !Tk_IsMapped(textPtr->tkwin)) {
/*
- * The widget has been deleted. Don't do anything.
+ * The widget has been deleted, or is not mapped. Don't do anything.
*/
if (--textPtr->refCount == 0) {
@@ -5237,6 +5229,15 @@ TkTextSetYView(
}
/*
+ * If the window height is smaller than the line height, prefer to make
+ * the top of the line visible.
+ */
+
+ if (dInfoPtr->maxY - dInfoPtr->y < lineHeight) {
+ bottomY = lineHeight;
+ }
+
+ /*
* Our job now is to arrange the display so that indexPtr appears as low
* on the screen as possible but with its bottom no lower than bottomY.
* BottomY is the bottom of the window if the desired line is just below
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));
diff --git a/tests/entry.test b/tests/entry.test
index 27acfc1..da3637d 100644
--- a/tests/entry.test
+++ b/tests/entry.test
@@ -1621,13 +1621,32 @@ test entry-22.1 {lost namespaced textvar} {
namespace eval test { variable foo {a b} }
entry .e -textvariable ::test::foo
namespace delete test
- .e insert end "more stuff"
- .e delete 5 end
- catch {set ::test::foo} result
- list [.e get] [.e cget -textvar] $result
+ catch {.e insert end "more stuff"} result1
+ catch {.e delete 5 end} result2
+ catch {set ::test::foo} result3
+ list [.e get] [.e cget -textvar] $result1 $result2 $result3
} [list "a bmo" ::test::foo \
+ {can't set "::test::foo": parent namespace doesn't exist} \
+ {can't set "::test::foo": parent namespace doesn't exist} \
{can't read "::test::foo": no such variable}]
+test entry-23.1 {error in trace proc attached to the textvariable} {
+ destroy .e
+ trace variable myvar w traceit
+ proc traceit args {error "Intentional error here!"}
+ entry .e -textvariable myvar
+ catch {.e insert end mystring} result1
+ catch {.e delete 0} result2
+ list $result1 $result2
+} [list {can't set "myvar": Intentional error here!} \
+ {can't set "myvar": Intentional error here!}]
+
+test entry-24.1 {textvariable lives in a non-existing namespace} {
+ destroy .e
+ catch {entry .e -textvariable thisnsdoesntexist::myvar} result1
+ set result1
+} {can't trace "thisnsdoesntexist::myvar": parent namespace doesn't exist}
+
destroy .e
# XXX Still need to write tests for EntryBlinkProc, EntryFocusProc,
diff --git a/tests/spinbox.test b/tests/spinbox.test
index 430e176..68c6fae 100644
--- a/tests/spinbox.test
+++ b/tests/spinbox.test
@@ -1568,9 +1568,9 @@ test spinbox-22.3 {spinbox config, -from changes SF bug 559078} {
set val
} {6}
-test entry-23.1 {selection present while disabled, bug 637828} {
+test spinbox-23.1 {selection present while disabled, bug 637828} {
destroy .e
- entry .e
+ spinbox .e
.e insert end 0123456789
.e select from 3
.e select to 6
@@ -1583,6 +1583,28 @@ test entry-23.1 {selection present while disabled, bug 637828} {
} {1 1 345}
destroy .e
+
+test spinbox-24.1 {error in trace proc attached to the textvariable} {
+ destroy .s
+ trace variable myvar w traceit
+ proc traceit args {error "Intentional error here!"}
+ spinbox .s -textvariable myvar -from 1 -to 10
+ catch {.s set mystring} result1
+ catch {.s insert 0 mystring} result2
+ catch {.s delete 0} result3
+ catch {.s invoke buttonup} result4
+ list $result1 $result2 $result3 $result4
+} [list {can't set "myvar": Intentional error here!} \
+ {can't set "myvar": Intentional error here!} \
+ {can't set "myvar": Intentional error here!} \
+ {can't set "myvar": Intentional error here!}]
+
+test spinbox-25.1 {textvariable lives in a non-existing namespace} {
+ destroy .s
+ catch {spinbox .s -textvariable thisnsdoesntexist::myvar} result1
+ set result1
+} {can't trace "thisnsdoesntexist::myvar": parent namespace doesn't exist}
+
catch {unset ::e ::vVals}
##
diff --git a/tests/textDisp.test b/tests/textDisp.test
index 5508d7c..038eccd 100644
--- a/tests/textDisp.test
+++ b/tests/textDisp.test
@@ -1574,6 +1574,17 @@ test textDisp-11.20 {TkTextSetYView, see in elided lines} {
# this shall not crash (null chunkPtr in TkTextSeeCmd is tested)
.top.t see 3.0
} {}
+test textDisp-11.21 {TkTextSetYView, window height smaller than the line height} {
+ .top.t delete 1.0 end
+ for {set i 1} {$i <= 10} {incr i} {
+ .top.t insert end "Line $i\n"
+ }
+ set lineheight [font metrics [.top.t cget -font] -linespace]
+ wm geometry .top 200x[expr {$lineheight / 2}]
+ update
+ .top.t see 1.0
+ .top.t index @0,[expr {$lineheight - 2}]
+} {1.0}
.t configure -wrap word
.t delete 50.0 51.0