diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 2e5167ac8ff5..64d71bd273a6 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -9,42 +9,24 @@ */ #define PY_SSIZE_T_CLEAN #include -#include -#include -#include - -#include // agg:int8u #ifdef _WIN32 #include +#define PSAPI_VERSION 1 +#include // Must be linked with 'psapi' library +#define dlsym GetProcAddress +#else +#include #endif // Include our own excerpts from the Tcl / Tk headers #include "_tkmini.h" - #include "py_converters.h" -#if defined(_MSC_VER) -# define IMG_FORMAT "%d %d %Iu" -#else -# define IMG_FORMAT "%d %d %zu" -#endif -#define BBOX_FORMAT "%f %f %f %f" - -typedef struct -{ - PyObject_HEAD - Tcl_Interp *interp; -} TkappObject; - // Global vars for Tcl / Tk functions. We load these symbols from the tkinter // extension module or loaded Tcl / Tk libraries at run-time. -static Tcl_CreateCommand_t TCL_CREATE_COMMAND; -static Tcl_AppendResult_t TCL_APPEND_RESULT; -static Tk_MainWindow_t TK_MAIN_WINDOW; static Tk_FindPhoto_t TK_FIND_PHOTO; static Tk_PhotoPutBlock_NoComposite_t TK_PHOTO_PUT_BLOCK_NO_COMPOSITE; -static Tk_PhotoBlank_t TK_PHOTO_BLANK; static PyObject *mpl_tk_blit(PyObject *self, PyObject *args) { @@ -118,7 +100,6 @@ Win32_SetForegroundWindow(PyObject *module, PyObject *args) #endif static PyMethodDef functions[] = { - /* Tkinter interface stuff */ { "blit", (PyCFunction)mpl_tk_blit, METH_VARARGS }, #ifdef _WIN32 { "Win32_GetForegroundWindow", (PyCFunction)Win32_GetForegroundWindow, METH_VARARGS }, @@ -128,6 +109,19 @@ static PyMethodDef functions[] = { }; // Functions to fill global TCL / Tk function pointers by dynamic loading + +template +int load_tk(T lib) +{ + // Try to fill Tk global vars with function pointers. Return the number of + // functions found. + return + !!(TK_FIND_PHOTO = + (Tk_FindPhoto_t)dlsym(lib, "Tk_FindPhoto")) + + !!(TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = + (Tk_PhotoPutBlock_NoComposite_t)dlsym(lib, "Tk_PhotoPutBlock_NoComposite")); +} + #ifdef _WIN32 /* @@ -137,102 +131,24 @@ static PyMethodDef functions[] = { * Python, we scan all modules in the running process for the TCL and Tk * function names. */ -#define PSAPI_VERSION 1 -#include -// Must be linked with 'psapi' library - -FARPROC _dfunc(HMODULE lib_handle, const char *func_name) -{ - // Load function `func_name` from `lib_handle`. - // Set Python exception if we can't find `func_name` in `lib_handle`. - // Returns function pointer or NULL if not present. - - char message[100]; - - FARPROC func = GetProcAddress(lib_handle, func_name); - if (func == NULL) { - sprintf(message, "Cannot load function %s", func_name); - PyErr_SetString(PyExc_RuntimeError, message); - } - return func; -} - -int get_tcl(HMODULE hMod) -{ - // Try to fill TCL global vars with function pointers. Return 0 for no - // functions found, 1 for all functions found, -1 for some but not all - // functions found. - TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) - GetProcAddress(hMod, "Tcl_CreateCommand"); - if (TCL_CREATE_COMMAND == NULL) { // Maybe not TCL module - return 0; - } - TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(hMod, "Tcl_AppendResult"); - return (TCL_APPEND_RESULT == NULL) ? -1 : 1; -} - -int get_tk(HMODULE hMod) -{ - // Try to fill Tk global vars with function pointers. Return 0 for no - // functions found, 1 for all functions found, -1 for some but not all - // functions found. - TK_MAIN_WINDOW = (Tk_MainWindow_t) - GetProcAddress(hMod, "Tk_MainWindow"); - if (TK_MAIN_WINDOW == NULL) { // Maybe not Tk module - return 0; - } - return // -1 if any remaining symbols are NULL - ((TK_FIND_PHOTO = (Tk_FindPhoto_t) - _dfunc(hMod, "Tk_FindPhoto")) == NULL) || - ((TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = (Tk_PhotoPutBlock_NoComposite_t) - _dfunc(hMod, "Tk_PhotoPutBlock_NoComposite")) == NULL) || - ((TK_PHOTO_BLANK = (Tk_PhotoBlank_t) - _dfunc(hMod, "Tk_PhotoBlank")) == NULL) - ? -1 : 1; -} void load_tkinter_funcs(void) { // Load TCL and Tk functions by searching all modules in current process. - // Sets an error on failure. - HMODULE hMods[1024]; HANDLE hProcess; DWORD cbNeeded; unsigned int i; - int found_tcl = 0; - int found_tk = 0; - // Returns pseudo-handle that does not need to be closed hProcess = GetCurrentProcess(); - // Iterate through modules in this process looking for TCL / Tk names if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { - if (!found_tcl) { - found_tcl = get_tcl(hMods[i]); - if (found_tcl == -1) { - return; - } - } - if (!found_tk) { - found_tk = get_tk(hMods[i]); - if (found_tk == -1) { - return; - } - } - if (found_tcl && found_tk) { + if (load_tk(hMods[i])) { return; } } } - - if (found_tcl == 0) { - PyErr_SetString(PyExc_RuntimeError, "Could not find TCL routines"); - } else { - PyErr_SetString(PyExc_RuntimeError, "Could not find Tk routines"); - } - return; } #else // not Windows @@ -243,54 +159,16 @@ void load_tkinter_funcs(void) * tkinter dynamic library (module). */ -#include - -void *_dfunc(void *lib_handle, const char *func_name) -{ - // Load function `func_name` from `lib_handle`. - // Set Python exception if we can't find `func_name` in `lib_handle`. - // Returns function pointer or NULL if not present. - - void* func; - // Reset errors. - dlerror(); - func = dlsym(lib_handle, func_name); - if (func == NULL) { - PyErr_SetString(PyExc_RuntimeError, dlerror()); - } - return func; -} - -int _func_loader(void *lib) -{ - // Fill global function pointers from dynamic lib. - // Return 1 if any pointer is NULL, 0 otherwise. - return - ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) - _dfunc(lib, "Tcl_CreateCommand")) == NULL) || - ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) - _dfunc(lib, "Tcl_AppendResult")) == NULL) || - ((TK_MAIN_WINDOW = (Tk_MainWindow_t) - _dfunc(lib, "Tk_MainWindow")) == NULL) || - ((TK_FIND_PHOTO = (Tk_FindPhoto_t) - _dfunc(lib, "Tk_FindPhoto")) == NULL) || - ((TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = (Tk_PhotoPutBlock_NoComposite_t) - _dfunc(lib, "Tk_PhotoPutBlock_NoComposite")) == NULL) || - ((TK_PHOTO_BLANK = (Tk_PhotoBlank_t) - _dfunc(lib, "Tk_PhotoBlank")) == NULL); -} - void load_tkinter_funcs(void) { // Load tkinter global funcs from tkinter compiled module. - // Sets an error on failure. void *main_program, *tkinter_lib; PyObject *module = NULL, *py_path = NULL, *py_path_b = NULL; char *path; // Try loading from the main program namespace first. main_program = dlopen(NULL, RTLD_LAZY); - if (_func_loader(main_program) == 0) { + if (load_tk(main_program)) { goto exit; } // Clear exception triggered when we didn't find symbols above. @@ -313,7 +191,7 @@ void load_tkinter_funcs(void) PyErr_SetString(PyExc_RuntimeError, dlerror()); goto exit; } - _func_loader(tkinter_lib); + load_tk(tkinter_lib); // dlclose is safe because tkinter has been imported. dlclose(tkinter_lib); goto exit; @@ -331,5 +209,14 @@ static PyModuleDef _tkagg_module = { PyMODINIT_FUNC PyInit__tkagg(void) { load_tkinter_funcs(); - return PyErr_Occurred() ? NULL : PyModule_Create(&_tkagg_module); + if (PyErr_Occurred()) { + return NULL; + } else if (!TK_FIND_PHOTO) { + PyErr_SetString(PyExc_RuntimeError, "Failed to load Tk_FindPhoto"); + return NULL; + } else if (!TK_PHOTO_PUT_BLOCK_NO_COMPOSITE) { + PyErr_SetString(PyExc_RuntimeError, "Failed to load Tk_PhotoPutBlock_NoComposite"); + return NULL; + } + return PyModule_Create(&_tkagg_module); } diff --git a/src/_tkmini.h b/src/_tkmini.h index 9b730b6c8c1f..082a9f82eeb5 100644 --- a/src/_tkmini.h +++ b/src/_tkmini.h @@ -66,34 +66,13 @@ extern "C" { #endif -/* Tcl header excerpts */ -#define TCL_OK 0 -#define TCL_ERROR 1 - /* * Users of versions of Tcl >= 8.6 encouraged to tread Tcl_Interp as an opaque * pointer. The following definition results when TCL_NO_DEPRECATED defined. */ typedef struct Tcl_Interp Tcl_Interp; -typedef struct Tcl_Command_ *Tcl_Command; -typedef void *ClientData; - -typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp - *interp, int argc, const char *argv[]); -typedef void (Tcl_CmdDeleteProc) (ClientData clientData); - -/* Typedefs derived from function signatures in Tcl header */ -/* Tcl_CreateCommand */ -typedef Tcl_Command (*Tcl_CreateCommand_t)(Tcl_Interp *interp, - const char *cmdName, Tcl_CmdProc *proc, - ClientData clientData, - Tcl_CmdDeleteProc *deleteProc); -/* Tcl_AppendResult */ -typedef void (*Tcl_AppendResult_t) (Tcl_Interp *interp, ...); - /* Tk header excerpts */ -typedef struct Tk_Window_ *Tk_Window; typedef void *Tk_PhotoHandle; @@ -108,20 +87,13 @@ typedef struct Tk_PhotoImageBlock } Tk_PhotoImageBlock; /* Typedefs derived from function signatures in Tk header */ -/* Tk_MainWindow */ -typedef Tk_Window (*Tk_MainWindow_t) (Tcl_Interp *interp); +/* Tk_FindPhoto typedef */ typedef Tk_PhotoHandle (*Tk_FindPhoto_t) (Tcl_Interp *interp, const char *imageName); /* Tk_PhotoPutBLock_NoComposite typedef */ typedef void (*Tk_PhotoPutBlock_NoComposite_t) (Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr, int x, int y, int width, int height); -/* Tk_PhotoBlank */ -typedef void (*Tk_PhotoBlank_t) (Tk_PhotoHandle handle); - -/* - * end block for C++ - */ #ifdef __cplusplus }