| Adapted from https://core.tcl-lang.org/tk/info/b1876b9ebc4b | |
| Index: generic/tkInt.h | |
| ================================================================== | |
| --- a/generic/tkInt.h.orig | |
| +++ b/generic/tkInt.h | |
| @@ -1094,10 +1094,11 @@ | |
| /* | |
| * Themed widget set init function: | |
| */ | |
| MODULE_SCOPE int Ttk_Init(Tcl_Interp *interp); | |
| +MODULE_SCOPE void Ttk_TkDestroyedHandler(Tcl_Interp *interp); | |
| /* | |
| * Internal functions shared among Tk modules but not exported to the outside | |
| * world: | |
| */ | |
| Index: generic/tkWindow.c | |
| ================================================================== | |
| --- a/generic/tkWindow.c.orig | |
| +++ b/generic/tkWindow.c | |
| @@ -1619,10 +1619,11 @@ | |
| TkBindFree(winPtr->mainPtr); | |
| TkDeleteAllImages(winPtr->mainPtr); | |
| TkFontPkgFree(winPtr->mainPtr); | |
| TkFocusFree(winPtr->mainPtr); | |
| TkStylePkgFree(winPtr->mainPtr); | |
| + Ttk_TkDestroyedHandler(winPtr->mainPtr->interp); | |
| /* | |
| * When embedding Tk into other applications, make sure that all | |
| * destroy events reach the server. Otherwise the embedding | |
| * application may also attempt to destroy the windows, resulting | |
| Index: generic/ttk/ttkTheme.c | |
| ================================================================== | |
| --- a/generic/ttk/ttkTheme.c.orig | |
| +++ b/generic/ttk/ttkTheme.c | |
| @@ -415,17 +415,10 @@ | |
| StylePackageData *pkgPtr = (StylePackageData *)clientData; | |
| Tcl_HashSearch search; | |
| Tcl_HashEntry *entryPtr; | |
| Cleanup *cleanup; | |
| - /* | |
| - * Cancel any pending ThemeChanged calls: | |
| - */ | |
| - if (pkgPtr->themeChangePending) { | |
| - Tcl_CancelIdleCall(ThemeChangedProc, pkgPtr); | |
| - } | |
| - | |
| /* | |
| * Free themes. | |
| */ | |
| entryPtr = Tcl_FirstHashEntry(&pkgPtr->themeTable, &search); | |
| while (entryPtr != NULL) { | |
| @@ -528,10 +521,29 @@ | |
| if (!pkgPtr->themeChangePending) { | |
| Tcl_DoWhenIdle(ThemeChangedProc, pkgPtr); | |
| pkgPtr->themeChangePending = 1; | |
| } | |
| } | |
| + | |
| +/* Ttk_TkDestroyedHandler -- | |
| + * See bug [310c74ecf440]: idle calls to ThemeChangedProc() | |
| + * need to be canceled when Tk is destroyed, since the interp | |
| + * may still be active afterward; canceling them from | |
| + * Ttk_StylePkgFree() would be too late. | |
| + */ | |
| +void Ttk_TkDestroyedHandler( | |
| + Tcl_Interp* interp) | |
| +{ | |
| + StylePackageData* pkgPtr = GetStylePackageData(interp); | |
| + | |
| + /* | |
| + * Cancel any pending ThemeChanged calls: | |
| + */ | |
| + if (pkgPtr->themeChangePending) { | |
| + Tcl_CancelIdleCall(ThemeChangedProc, pkgPtr); | |
| + } | |
| +} | |
| /* | |
| * Ttk_CreateTheme -- | |
| * Create a new theme and register it in the global theme table. | |
| * | |