Skip to content

Commit 6b57a35

Browse files
committed
gh-150836: Mount embedded Tk ZIP in _tkinter on Windows
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.
1 parent c2ca772 commit 6b57a35

4 files changed

Lines changed: 43 additions & 3 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make installed tkinter work with Tcl/Tk 9 builds that embed the Tk script library in the Tk DLL on Windows.

Modules/_tkinter.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ Copyright (C) 1994 Steen Lumholt.
5353
# include <tk.h>
5454
#endif
5555

56+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
57+
# include <tkPlatDecls.h>
58+
#endif
59+
5660
#include "tkinter.h"
5761

5862
#if TK_HEX_VERSION < 0x0805020c
@@ -175,6 +179,39 @@ _get_tcl_lib_path(void)
175179
}
176180
#endif /* MS_WINDOWS */
177181

182+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
183+
static void
184+
mount_tk_dll_zip(void)
185+
{
186+
HINSTANCE tk_module = Tk_GetHINSTANCE();
187+
wchar_t tk_path[MAX_PATH];
188+
DWORD path_len = GetModuleFileNameW(tk_module, tk_path, MAX_PATH);
189+
190+
if (path_len == 0 || path_len >= MAX_PATH) {
191+
return;
192+
}
193+
194+
Tcl_DString utf8_path;
195+
196+
Tcl_DStringInit(&utf8_path);
197+
Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path);
198+
(void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path),
199+
"//zipfs:/lib/tk", NULL);
200+
Tcl_DStringFree(&utf8_path);
201+
}
202+
#endif
203+
204+
int
205+
Tkinter_TkInit(Tcl_Interp *interp)
206+
{
207+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
208+
/* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary
209+
does not search. Mount the DLL using Zipfs if possible. */
210+
mount_tk_dll_zip();
211+
#endif
212+
return Tk_Init(interp);
213+
}
214+
178215
/* The threading situation is complicated. Tcl is not thread-safe, except
179216
when configured with --enable-threads.
180217
@@ -544,7 +581,7 @@ Tcl_AppInit(Tcl_Interp *interp)
544581
return TCL_OK;
545582
}
546583

547-
if (Tk_Init(interp) == TCL_ERROR) {
584+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
548585
PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
549586
return TCL_ERROR;
550587
}
@@ -2988,7 +3025,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
29883025
return NULL;
29893026
}
29903027
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
2991-
if (Tk_Init(interp) == TCL_ERROR) {
3028+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
29923029
Tkinter_Error(self);
29933030
return NULL;
29943031
}

Modules/tkappinit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Tcl_AppInit(Tcl_Interp *interp)
3737
return TCL_OK;
3838
}
3939

40-
if (Tk_Init(interp) == TCL_ERROR) {
40+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
4141
return TCL_ERROR;
4242
}
4343

Modules/tkinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616
(TK_RELEASE_LEVEL << 8) | \
1717
(TK_RELEASE_SERIAL << 0))
1818

19+
int Tkinter_TkInit(Tcl_Interp *interp);
20+
1921
#endif /* !TKINTER_H */

0 commit comments

Comments
 (0)