-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
COMPAT: use tkagg backend on PyPy #9356
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
Changes from 4 commits
b4e2b8a
68492fb
8e80a20
512e4d8
4c5dfaa
c2a7143
09576fa
596345e
1712678
b40923d
43d9754
270f05d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,16 +13,15 @@ | |
#include <cstdio> | ||
#include <sstream> | ||
|
||
#include "py_converters.h" | ||
|
||
// Include our own excerpts from the Tcl / Tk headers | ||
#include "_tkmini.h" | ||
|
||
#if defined(_MSC_VER) | ||
# define SIZE_T_FORMAT "%Iu" | ||
# define IMG_FORMAT "%Iu %d %d" | ||
#else | ||
# define SIZE_T_FORMAT "%zu" | ||
# define IMG_FORMAT "%zu %d %d" | ||
#endif | ||
# define BBOX_FORMAT "%f %f %f %f" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extra space? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed in cc7b73e |
||
|
||
typedef struct | ||
{ | ||
|
@@ -44,16 +43,15 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int | |
{ | ||
Tk_PhotoHandle photo; | ||
Tk_PhotoImageBlock block; | ||
PyObject *bufferobj; | ||
|
||
// vars for blitting | ||
PyObject *bboxo; | ||
|
||
size_t aggl, bboxl; | ||
size_t pdata; | ||
int wdata, hdata; | ||
float x1, x2, y1, y2; | ||
bool has_bbox; | ||
uint8_t *destbuffer; | ||
uint8_t *destbuffer, *buffer; | ||
int destx, desty, destwidth, destheight, deststride; | ||
//unsigned long tmp_ptr; | ||
|
||
long mode; | ||
long nval; | ||
|
@@ -73,24 +71,14 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int | |
TCL_APPEND_RESULT(interp, "destination photo must exist", (char *)NULL); | ||
return TCL_ERROR; | ||
} | ||
/* get array (or object that can be converted to array) pointer */ | ||
if (sscanf(argv[2], SIZE_T_FORMAT, &aggl) != 1) { | ||
TCL_APPEND_RESULT(interp, "error casting pointer", (char *)NULL); | ||
return TCL_ERROR; | ||
} | ||
bufferobj = (PyObject *)aggl; | ||
|
||
numpy::array_view<uint8_t, 3> buffer; | ||
try { | ||
buffer = numpy::array_view<uint8_t, 3>(bufferobj); | ||
} catch (...) { | ||
TCL_APPEND_RESULT(interp, "buffer is of wrong type", (char *)NULL); | ||
PyErr_Clear(); | ||
/* get buffer from str which is "ptr height width" */ | ||
if (sscanf(argv[2], IMG_FORMAT, &pdata, &hdata, &wdata) != 3) { | ||
TCL_APPEND_RESULT(interp, | ||
"error reading data, expected ptr height width", | ||
(char *)NULL); | ||
return TCL_ERROR; | ||
} | ||
int srcheight = buffer.dim(0); | ||
|
||
/* XXX insert aggRenderer type check */ | ||
buffer = (uint8_t*)pdata; | ||
|
||
/* get array mode (0=mono, 1=rgb, 2=rgba) */ | ||
mode = atol(argv[3]); | ||
|
@@ -100,39 +88,33 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int | |
} | ||
|
||
/* check for bbox/blitting */ | ||
if (sscanf(argv[4], SIZE_T_FORMAT, &bboxl) != 1) { | ||
TCL_APPEND_RESULT(interp, "error casting pointer", (char *)NULL); | ||
return TCL_ERROR; | ||
} | ||
bboxo = (PyObject *)bboxl; | ||
|
||
if (bboxo != NULL && bboxo != Py_None) { | ||
agg::rect_d rect; | ||
if (!convert_rect(bboxo, &rect)) { | ||
return TCL_ERROR; | ||
} | ||
|
||
if (sscanf(argv[4], BBOX_FORMAT, &x1, &x2, &y1, &y2) == 4) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should probably error out cleanly if an invalid string is passed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yesish, these are basically "private" functions parsing a call from python, but I will add more checking code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated in cc7b73e |
||
has_bbox = true; | ||
} | ||
else { | ||
has_bbox = false; | ||
} | ||
|
||
destx = (int)rect.x1; | ||
desty = srcheight - (int)rect.y2; | ||
destwidth = (int)(rect.x2 - rect.x1); | ||
destheight = (int)(rect.y2 - rect.y1); | ||
if (has_bbox) { | ||
int srcstride = wdata * 4; | ||
destx = x1; | ||
desty = hdata - y2; | ||
destwidth = x2 - x1; | ||
destheight = y2 - y1; | ||
deststride = 4 * destwidth; | ||
|
||
10000 destbuffer = new agg::int8u[deststride * destheight]; | ||
destbuffer = new uint8_t[deststride * destheight]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason for the change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. now it no longer uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why change away from the agg types here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously there was a conversion from a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am concerned about the corner case where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder what different types you think these can be. |
||
if (destbuffer == NULL) { | ||
TCL_APPEND_RESULT(interp, "could not allocate memory", (char *)NULL); | ||
return TCL_ERROR; | ||
} | ||
|
||
for (int i = 0; i < destheight; ++i) { | ||
memcpy(destbuffer + (deststride * i), | ||
&buffer(i + desty, destx, 0), | ||
&buffer[(i + desty) * srcstride + (destx * 4)], | ||
deststride); | ||
} | ||
} else { | ||
has_bbox = false; | ||
destbuffer = NULL; | ||
destx = desty = destwidth = destheight = deststride = 0; | ||
} | ||
|
@@ -168,10 +150,10 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int | |
delete[] destbuffer; | ||
|
||
} else { | ||
block.width = buffer.dim(1); | ||
block.height = buffer.dim(0); | ||
block.width = wdata; | ||
block.height = hdata; | ||
block.pitch = (int)block.width * nval; | ||
block.pixelPtr = buffer.data(); | ||
block.pixelPtr = buffer; | ||
|
||
/* Clear current contents */ | ||
TK_PHOTO_BLANK(photo); | ||
|
@@ -199,7 +181,7 @@ static PyObject *_tkinit(PyObject *self, PyObject *args) | |
} else { | ||
/* Do it the hard way. This will break if the TkappObject | ||
layout changes */ | ||
app = (TkappObject *)PyLong_AsVoidPtr(arg); | ||
app = (TkappObject *)arg; | ||
interp = app->interp; | ||
} | ||
|
||
|
@@ -338,7 +320,7 @@ int load_tkinter_funcs(void) | |
* tkinter uses these symbols, and the symbols are therefore visible in the | ||
* tkinter dynamic library (module). | ||
*/ | ||
#if PY3K | ||
#if PY_MAJOR_VERSION >= 3 | ||
#define TKINTER_PKG "tkinter" | ||
#define TKINTER_MOD "_tkinter" | ||
// From module __file__ attribute to char *string for dlopen. | ||
|
@@ -432,13 +414,31 @@ int load_tkinter_funcs(void) | |
} | ||
tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); | ||
if (tkinter_lib == NULL) { | ||
PyErr_SetString(PyExc_RuntimeError, | ||
"Cannot dlopen tkinter module file"); | ||
goto exit; | ||
/* Perhaps it is a cffi module, like in PyPy? */ | ||
pString = PyObject_GetAttrString(pSubmodule, "tklib_cffi"); | ||
if (pString == NULL) { | ||
goto fail; | ||
} | ||
pString = PyObject_GetAttrString(pString, "__file__"); | ||
if (pString == NULL) { | ||
goto fail; | ||
} | ||
tkinter_libname = fname2char(pString); | ||
if (tkinter_libname == NULL) { | ||
goto fail; | ||
} | ||
tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); | ||
} | ||
if (tkinter_lib == NULL) { | ||
goto fail; | ||
} | ||
ret = _func_loader(tkinter_lib); | ||
// dlclose probably safe because tkinter has been imported. | ||
dlclose(tkinter_lib); | ||
goto exit; | ||
fail: | ||
PyErr_SetString(PyExc_RuntimeError, | ||
"Cannot dlopen tkinter module file"); | ||
exit: | ||
Py_XDECREF(pModule); | ||
Py_XDECREF(pSubmodule); | ||
|
@@ -447,7 +447,7 @@ int load_tkinter_funcs(void) | |
} | ||
#endif // end not Windows | ||
|
||
#if PY3K | ||
#if PY_MAJOR_VERSION >= 3 | ||
static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, | ||
NULL, NULL, NULL, NULL }; | ||
|
||
|
@@ -457,15 +457,11 @@ PyMODINIT_FUNC PyInit__tkagg(void) | |
|
||
m = PyModule_Create(&_tkagg_module); | ||
|
||
import_array(); | ||
|
||
return (load_tkinter_funcs() == 0) ? m : NULL; | ||
} | ||
#else | ||
PyMODINIT_FUNC init_tkagg(void) | ||
{ | ||
import_array(); | ||
|
||
Py_InitModule("_tkagg", functions); | ||
|
||
load_tkinter_funcs(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interpaddr was added in 1998(! python/cpython@9d1b7ae) so I cannot actually imagine a case where this is triggered today (but that can go to another PR of course)