From: Jonathan J. Helmus Date: Fri, 19 Jun 2026 14:23:01 +0000 (-0500) Subject: gh-150836: Mount embedded Tk ZIP in _tkinter on Windows (GH-151562) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c4eb3adbb42d781e2ad35bee5621f1c621c6767b;p=thirdparty%2FPython%2Fcpython.git gh-150836: Mount embedded Tk ZIP in _tkinter on Windows (GH-151562) Tcl/Tk 9 may embed the Tk script library in the Tk DLL on Windows. This embedded library is not found by Tcl by default. Mount the loaded Tk DLL as a zipfs archive before calling Tk_Init(), so Tk can find its embedded tk_library using its existing library discovery logic. Preserve Tk_Init()'s normal path if the library is not embedded. --- diff --git a/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst new file mode 100644 index 000000000000..6497b7927db7 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst @@ -0,0 +1 @@ +Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 6eca98a3c803..1deff4ed4468 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt. # include #endif +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 +# include +#endif + #include "tkinter.h" #if TK_HEX_VERSION < 0x0805020c @@ -175,6 +179,57 @@ _get_tcl_lib_path(void) } #endif /* MS_WINDOWS */ +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 +static void +mount_tk_dll_zip(void) +{ + HINSTANCE tk_module = Tk_GetHINSTANCE(); + wchar_t *tk_path = NULL; + DWORD path_len = 0; + for (DWORD buffer_len = 256; + tk_path == NULL && buffer_len < (1024 * 1024); + buffer_len *= 2) + { + tk_path = (wchar_t *)PyMem_RawMalloc( + buffer_len * sizeof(*tk_path)); + if (tk_path != NULL) { + path_len = GetModuleFileNameW(tk_module, tk_path, buffer_len); + if (path_len == buffer_len) { + PyMem_RawFree(tk_path); + tk_path = NULL; + } + } + } + + if (tk_path == NULL || path_len == 0) { + PyMem_RawFree(tk_path); + return; + } + + Tcl_DString utf8_path; + + Tcl_DStringInit(&utf8_path); + Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path); + /* Failure is harmless if the DLL has no embedded ZIP or if another + interpreter has already mounted it. */ + (void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path), + "//zipfs:/lib/tk", NULL); + Tcl_DStringFree(&utf8_path); + PyMem_RawFree(tk_path); +} +#endif + +int +Tkinter_TkInit(Tcl_Interp *interp) +{ +#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9 + /* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary + does not search. Mount the DLL using Zipfs if possible. */ + mount_tk_dll_zip(); +#endif + return Tk_Init(interp); +} + /* The threading situation is complicated. Tcl is not thread-safe, except when configured with --enable-threads. @@ -544,7 +599,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); return TCL_ERROR; } @@ -2988,7 +3043,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) return NULL; } if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { Tkinter_Error(self); return NULL; } diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c index 4c4081e43a8e..1075ccf24d44 100644 --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -37,7 +37,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } - if (Tk_Init(interp) == TCL_ERROR) { + if (Tkinter_TkInit(interp) == TCL_ERROR) { return TCL_ERROR; } diff --git a/Modules/tkinter.h b/Modules/tkinter.h index 40281c217603..b73e99b28a40 100644 --- a/Modules/tkinter.h +++ b/Modules/tkinter.h @@ -16,4 +16,6 @@ (TK_RELEASE_LEVEL << 8) | \ (TK_RELEASE_SERIAL << 0)) +int Tkinter_TkInit(Tcl_Interp *interp); + #endif /* !TKINTER_H */