summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--macosx/tkMacOSXHLEvents.c7
-rw-r--r--macosx/tkMacOSXInit.c81
-rw-r--r--macosx/tkMacOSXPort.h8
-rw-r--r--unix/tkAppInit.c8
4 files changed, 100 insertions, 4 deletions
diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c
index f1489dd..f405a53 100644
--- a/macosx/tkMacOSXHLEvents.c
+++ b/macosx/tkMacOSXHLEvents.c
@@ -596,9 +596,14 @@ ReallyKillMe(
{
Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp;
int quit = Tcl_FindCommand(interp, "::tk::mac::Quit", NULL, 0)!=NULL;
- int code = Tcl_EvalEx(interp, quit ? "::tk::mac::Quit" : "exit", -1, TCL_EVAL_GLOBAL);
+ if (!quit) {
+ Tcl_Exit(0);
+ }
+
+ int code = Tcl_EvalEx(interp, "::tk::mac::Quit", -1, TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
+
/*
* Should be never reached...
*/
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index d49422b..ca3dec4 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -113,6 +113,7 @@ static int TkMacOSXGetAppPathCmd(ClientData cd, Tcl_Interp *ip,
/*
* Initialize event processing.
*/
+
TkMacOSXInitAppleEvents(_eventInterp);
/*
@@ -271,6 +272,65 @@ static int TkMacOSXGetAppPathCmd(ClientData cd, Tcl_Interp *ip,
*/
/*
+ * Helper function which closes the shared NSFontPanel and NSColorPanel.
+ */
+
+static void closePanels(
+ void)
+{
+ if ([NSFontPanel sharedFontPanelExists]) {
+ [[NSFontPanel sharedFontPanel] orderOut:nil];
+ }
+ if ([NSColorPanel sharedColorPanelExists]) {
+ [[NSColorPanel sharedColorPanel] orderOut:nil];
+ }
+}
+
+/*
+ * This custom exit procedure is called by Tcl_Exit in place of the exit
+ * function from the C runtime. It calls the terminate method of the
+ * NSApplication class (superTerminate for a TKApplication). The purpose of
+ * doing this is to ensure that the NSFontPanel and the NSColorPanel are closed
+ * before the process exits, and that the application state is recorded
+ * correctly for all termination scenarios.
+ *
+ * TkpWantsExitProc tells Tcl_AppInit whether to install our custom exit proc,
+ * which terminates the process by calling [NSApplication terminate]. This
+ * does not work correctly if the process is part of an exec pipeline, so it is
+ * only done if the process was launched by the launcher or if both stdin and
+ * stdout are ttys. To disable using the custom exit proc altogether, undefine
+ * USE_CUSTOM_EXIT_PROC.
+ */
+
+#if defined(USE_CUSTOM_EXIT_PROC)
+static Bool doCleanupFromExit = NO;
+
+int TkpWantsExitProc(void) {
+ return doCleanupFromExit == YES;
+}
+
+TCL_NORETURN void TkpExitProc(
+ void *clientdata)
+{
+ Bool doCleanup = doCleanupFromExit;
+ if (doCleanupFromExit) {
+ doCleanupFromExit = NO; /* prevent possible recursive call. */
+ closePanels();
+ }
+
+ /*
+ * Tcl_Exit does not call Tcl_Finalize if there is an exit proc installed.
+ */
+
+ Tcl_Finalize();
+ if (doCleanup == YES) {
+ [(TKApplication *)NSApp superTerminate:nil]; /* Should not return. */
+ }
+ exit((long)clientdata); /* Convince the compiler that we don't return. */
+}
+#endif
+
+/*
* This signal handler is installed for the SIGINT, SIGHUP and SIGTERM signals
* so that normal finalization occurs when a Tk app is killed by one of these
* signals (e.g when ^C is pressed while running Wish in the shell). It calls
@@ -281,6 +341,8 @@ static int TkMacOSXGetAppPathCmd(ClientData cd, Tcl_Interp *ip,
*/
static void TkMacOSXSignalHandler(TCL_UNUSED(int)) {
+ (void)signal;
+
Tcl_Exit(1);
}
@@ -298,7 +360,6 @@ TkpInit(
if (!initialized) {
struct stat st;
Bool shouldOpenConsole = NO;
- Bool isLaunched = NO;
Bool stdinIsNullish = (!isatty(0) &&
(fstat(0, &st) || (S_ISCHR(st.st_mode) && st.st_blocks == 0)));
@@ -398,7 +459,11 @@ TkpInit(
Tcl_SetVar2(interp, "tcl_interactive", NULL, "1",
TCL_GLOBAL_ONLY);
}
- isLaunched = YES;
+
+#if defined(USE_CUSTOM_EXIT_PROC)
+ doCleanupFromExit = YES;
+#endif
+
shouldOpenConsole = YES;
}
if (shouldOpenConsole) {
@@ -421,7 +486,9 @@ TkpInit(
FILE *null = fopen("/dev/null", "w");
dup2(fileno(null), STDOUT_FILENO);
dup2(fileno(null), STDERR_FILENO);
- isLaunched = YES;
+#if defined(USE_CUSTOM_EXIT_PROC)
+ doCleanupFromExit = YES;
+#endif
}
/*
@@ -458,6 +525,14 @@ TkpInit(
}
}
+# if defined(USE_CUSTOM_EXIT_PROC)
+
+ if ((isatty(0) && isatty(1))) {
+ doCleanupFromExit = YES;
+ }
+
+# endif
+
/*
* Install a signal handler for SIGINT, SIGHUP and SIGTERM which uses
* Tcl_Exit instead of exit so that normal cleanup takes place if a TK
diff --git a/macosx/tkMacOSXPort.h b/macosx/tkMacOSXPort.h
index 61c0d0d..d875873 100644
--- a/macosx/tkMacOSXPort.h
+++ b/macosx/tkMacOSXPort.h
@@ -157,4 +157,12 @@ MODULE_SCOPE void TkMacOSXHandleMapOrUnmap(Tk_Window tkwin, XEvent *event);
#define TkpHandleMapOrUnmap(tkwin, event) TkMacOSXHandleMapOrUnmap(tkwin, event)
+/*
+ * Used by tkAppInit
+ */
+
+#define USE_CUSTOM_EXIT_PROC
+EXTERN int TkpWantsExitProc(void);
+EXTERN TCL_NORETURN void TkpExitProc(void *);
+
#endif /* _TKMACPORT */
diff --git a/unix/tkAppInit.c b/unix/tkAppInit.c
index 9e6c112..db44bb7 100644
--- a/unix/tkAppInit.c
+++ b/unix/tkAppInit.c
@@ -15,6 +15,7 @@
#undef BUILD_tk
#undef STATIC_BUILD
#include "tk.h"
+#include "tkPort.h"
#ifdef TK_TEST
#ifdef __cplusplus
@@ -120,6 +121,13 @@ Tcl_AppInit(
}
Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit);
+#if defined(USE_CUSTOM_EXIT_PROC)
+ if (TkpWantsExitProc()) {
+ /* The cast below avoids warnings from old gcc compilers. */
+ Tcl_SetExitProc((void *)TkpExitProc);
+ }
+#endif
+
#ifdef TK_TEST
if (Tktest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;