]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-150836: Mount embedded Tk ZIP in _tkinter on Windows (GH-151562)
authorJonathan J. Helmus <jjhelmus@gmail.com>
Fri, 19 Jun 2026 14:23:01 +0000 (09:23 -0500)
committerGitHub <noreply@github.com>
Fri, 19 Jun 2026 14:23:01 +0000 (14:23 +0000)
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.

Misc/NEWS.d/next/Windows/2026-06-04-18-53-18.gh-issue-150836.Wci7bZ.rst [new file with mode: 0644]
Modules/_tkinter.c
Modules/tkappinit.c
Modules/tkinter.h

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 (file)
index 0000000..6497b79
--- /dev/null
@@ -0,0 +1 @@
+Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows.
index 6eca98a3c8033fa8ef1e4ed87206fc560319f93a..1deff4ed44684cdaf04457f8b1f2424f1b8bf578 100644 (file)
@@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt.
 #  include <tk.h>
 #endif
 
+#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
+#  include <tkPlatDecls.h>
+#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;
         }
index 4c4081e43a8e3dd4167320451a4717015740a406..1075ccf24d448772363b8337370e162249765e94 100644 (file)
@@ -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;
     }
 
index 40281c2176033183f62a19841b066d19ef45ea04..b73e99b28a40212581de51c58743d3fcb4c36285 100644 (file)
@@ -16,4 +16,6 @@
                         (TK_RELEASE_LEVEL << 8) | \
                         (TK_RELEASE_SERIAL << 0))
 
+int Tkinter_TkInit(Tcl_Interp *interp);
+
 #endif /* !TKINTER_H */