Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Simplify tk loader. #15607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 31 additions & 144 deletions src/_tkagg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,24 @@
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <cstdlib>
#include <cstdio>
#include <sstream>

#include <agg_basics.h> // agg:int8u

#ifdef _WIN32
#include <windows.h>
#define PSAPI_VERSION 1
#include <psapi.h> // Must be linked with 'psapi' library
#define dlsym GetProcAddress
#else
#include <dlfcn.h>
#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)
{
Expand Down Expand Up @@ -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 },
Expand All @@ -128,6 +109,19 @@ static PyMethodDef functions[] = {
};

// Functions to fill global TCL / Tk function pointers by dynamic loading

template <class T>
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

/*
Expand All @@ -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 <psapi.h>
// 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
Expand All @@ -243,54 +159,16 @@ void load_tkinter_funcs(void)
* tkinter dynamic library (module).
*/

#include <dlfcn.h>

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.
Expand All @@ -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;
Expand All @@ -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);
}
30 changes: 1 addition & 29 deletions src/_tkmini.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
}
Expand Down