Skip to content

Commit d73c6f8

Browse files
jjhelmuszware
authored andcommitted
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.
1 parent 08407ea commit d73c6f8

4 files changed

Lines changed: 61 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: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ Copyright (C) 1994 Steen Lumholt.
5454
# include <tk.h>
5555
#endif
5656

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

5963
#if TK_HEX_VERSION < 0x0805020c
@@ -199,6 +203,57 @@ _get_tcl_lib_path(void)
199203
}
200204
#endif /* MS_WINDOWS */
201205

206+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
207+
static void
208+
mount_tk_dll_zip(void)
209+
{
210+
HINSTANCE tk_module = Tk_GetHINSTANCE();
211+
wchar_t *tk_path = NULL;
212+
DWORD path_len = 0;
213+
for (DWORD buffer_len = 256;
214+
tk_path == NULL && buffer_len < (1024 * 1024);
215+
buffer_len *= 2)
216+
{
217+
tk_path = (wchar_t *)PyMem_RawMalloc(
218+
buffer_len * sizeof(*tk_path));
219+
if (tk_path != NULL) {
220+
path_len = GetModuleFileNameW(tk_module, tk_path, buffer_len);
221+
if (path_len == buffer_len) {
222+
PyMem_RawFree(tk_path);
223+
tk_path = NULL;
224+
}
225+
}
226+
}
227+
228+
if (tk_path == NULL || path_len == 0) {
229+
PyMem_RawFree(tk_path);
230+
return;
231+
}
232+
233+
Tcl_DString utf8_path;
234+
235+
Tcl_DStringInit(&utf8_path);
236+
Tcl_WCharToUtfDString(tk_path, path_len, &utf8_path);
237+
/* Failure is harmless if the DLL has no embedded ZIP or if another
238+
interpreter has already mounted it. */
239+
(void) TclZipfs_Mount(NULL, Tcl_DStringValue(&utf8_path),
240+
"//zipfs:/lib/tk", NULL);
241+
Tcl_DStringFree(&utf8_path);
242+
PyMem_RawFree(tk_path);
243+
}
244+
#endif
245+
246+
int
247+
Tkinter_TkInit(Tcl_Interp *interp)
248+
{
249+
#if defined(MS_WINDOWS) && TK_MAJOR_VERSION >= 9
250+
/* Tcl/Tk 9 may embed the tk_library in the Tk DLL which tcl_findLibrary
251+
does not search. Mount the DLL using Zipfs if possible. */
252+
mount_tk_dll_zip();
253+
#endif
254+
return Tk_Init(interp);
255+
}
256+
202257
/* The threading situation is complicated. Tcl is not thread-safe, except
203258
when configured with --enable-threads.
204259
@@ -569,7 +624,7 @@ Tcl_AppInit(Tcl_Interp *interp)
569624
return TCL_OK;
570625
}
571626

572-
if (Tk_Init(interp) == TCL_ERROR) {
627+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
573628
PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
574629
return TCL_ERROR;
575630
}
@@ -3010,7 +3065,7 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
30103065
return NULL;
30113066
}
30123067
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
3013-
if (Tk_Init(interp) == TCL_ERROR) {
3068+
if (Tkinter_TkInit(interp) == TCL_ERROR) {
30143069
Tkinter_Error(self);
30153070
return NULL;
30163071
}

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)