diff options
author | James Henstridge <james@daa.com.au> | 1999-07-31 15:17:13 +0000 |
---|---|---|
committer | James Henstridge <jamesh@src.gnome.org> | 1999-07-31 15:17:13 +0000 |
commit | b353b664618a8e4a31453a22f680e18de7d36c77 (patch) | |
tree | b77c3f4a1bde2665d75170af819e9e8089d1f9bb | |
parent | 88b29cb44e8e5ca3ec2e7ae774166ebc43de82be (diff) | |
download | pygtk-b353b664618a8e4a31453a22f680e18de7d36c77.tar.gz |
put in Paul Fisher's enhancements to the threading code. It should now
1999-07-31 James Henstridge <james@daa.com.au>
* gtkmodule.c: put in Paul Fisher's enhancements to the threading
code. It should now work better with multiple threads calling
GTK+ routines (remember to use threads_enter/threads_leave), and
doesn't reintroduce the global interpreter lock problems that
Duncan's original code worked around.
* configure.in: added a check for the numpy header.
* GdkImlib.py: added wrappers for the numpy routines.
* gdkimlibmodule.c: added Travis Oliphant's Numeric python stuff to
the imlib module.
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | GdkImlib.py | 14 | ||||
-rw-r--r-- | configure.in | 6 | ||||
-rw-r--r-- | examples/glade/test2.glade | 2 | ||||
-rw-r--r-- | gdkimlibmodule.c | 74 | ||||
-rw-r--r-- | gtk.py | 2 | ||||
-rw-r--r-- | gtkmodule.c | 79 |
7 files changed, 162 insertions, 30 deletions
@@ -1,3 +1,18 @@ +1999-07-31 James Henstridge <james@daa.com.au> + + * gtkmodule.c: put in Paul Fisher's enhancements to the threading + code. It should now work better with multiple threads calling + GTK+ routines (remember to use threads_enter/threads_leave), and + doesn't reintroduce the global interpreter lock problems that + Duncan's original code worked around. + + * configure.in: added a check for the numpy header. + + * GdkImlib.py: added wrappers for the numpy routines. + + * gdkimlibmodule.c: added Travis Oliphant's Numeric python stuff to + the imlib module. + 1999-07-20 Matt Wilson <msw@redhat.com> * gtk.py (gdk_flush): new wrapper diff --git a/GdkImlib.py b/GdkImlib.py index 53aff37e..213928f9 100644 --- a/GdkImlib.py +++ b/GdkImlib.py @@ -118,12 +118,26 @@ class Image: _gdkimlib.gdk_imlib_make_pixmap(self._im)) def get_pixmap(self): return _gdkimlib.gdk_imlib_get_pixmap(self._im) + if hasattr(_gdkimlib, 'gdk_imlib_image_get_array'): + def get_array(self): + return _gdkimlib.gdk_imlib_image_get_array(self._im) def create_image_from_data(data, alpha, width, height): # alpha can be None return Image(_obj=_gdkimlib.gdk_imlib_create_image_from_data( data, alpha, width, height)) +if hasattr(_gdkimlib, 'gdk_imlib_create_image_from_array'): + def create_image_from_array(data, alpha=None): + if alpha: + return Image(_obj= + _gdkimlib.gdk_imlib_create_image_from_array( + data, alpha)) + else: + return Image(_obj= + _gdkimlib.gdk_imlib_create_image_from_array( + data)) + def create_image_from_drawable(drawable, mask, x, y, width, height): return Image(_obj=_gdkimlib.gdk_imlib_create_image_from_drawable( drawable, mask, x, y, width, height)) diff --git a/configure.in b/configure.in index 1a682112..c1fa1ed5 100644 --- a/configure.in +++ b/configure.in @@ -16,6 +16,12 @@ AM_CONDITIONAL(BUILD_IMLIB, $build_imlib) AM_PATH_GTKGL(build_gtkgl=true, build_gtkgl=false) AM_CONDITIONAL(BUILD_GTKGL, $build_gtkgl) +dnl checks to see if Numeric Python is installed. +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +AC_CHECK_HEADER(arrayobject.h, AC_DEFINE(HAVE_NUMPY)) +CPPFLAGS="$save_CPPFLAGS" + AC_OUTPUT(Makefile generate/Makefile pyglade/Makefile) diff --git a/examples/glade/test2.glade b/examples/glade/test2.glade index d128d2cf..384d5d9c 100644 --- a/examples/glade/test2.glade +++ b/examples/glade/test2.glade @@ -4,7 +4,7 @@ <style> <style_name>Hello</style_name> <style_font>-adobe-helvetica-bold-r-normal-*-*-180-*-*-p-*-iso8859-1</style_font> - <fg:NORMAL>0,0,255</fg:NORMAL> + <fg-NORMAL>0,0,255</fg-NORMAL> </style> <widget> diff --git a/gdkimlibmodule.c b/gdkimlibmodule.c index 68ab8546..74544cf1 100644 --- a/gdkimlibmodule.c +++ b/gdkimlibmodule.c @@ -22,6 +22,10 @@ #include <gtk/gtk.h> #include <gdk_imlib.h> +#ifdef HAVE_NUMPY +#include <arrayobject.h> +#endif + #include "pygtk.h" #define _INSIDE_PYGDKIMLIB_ @@ -718,6 +722,68 @@ static PyObject *_wrap_gdk_imlib_pop_visual(PyObject *self, PyObject *args) { return Py_None; } +#ifdef HAVE_NUMPY +static PyObject *_wrap_gdk_imlib_create_image_from_array(PyObject *self, PyObject *args) { + PyArrayObject *ap_data, *ap_alpha=NULL; + unsigned char *data, *alpha = NULL; + int w, h; + if (!PyArg_ParseTuple(args, "O!|O!:gdk_imlib_create_image_from_array", + &PyArray_Type, &ap_data, &PyArray_Type, &ap_alpha)) + return NULL; + if (!PyArray_ISCONTIGUOUS(ap_data) || + ap_data->descr->type_num != PyArray_UBYTE || + ap_data->nd != 3 || + ap_data->dimensions[2] != 3) { + PyErr_SetString(PyExc_TypeError, + "image array must be MxNx3 contiguous unsigned byte array"); + return NULL; + } + data = (unsigned char *)ap_data->data; + h = ap_data->dimensions[0]; + w = ap_data->dimensions[1]; + + if (ap_data != NULL && (!PyArray_ISCONTIGUOUS(ap_alpha) || + ap_alpha->descr->type_num != PyArray_UBYTE || + ap_alpha->nd != 2 || + ap_alpha->dimensions[0] != h || + ap_alpha->dimensions[1] != w)) { + PyErr_SetString(PyExc_TypeError, + "alpha channel array must be 2D contiguous byte array"); + return NULL; + } + if (ap_alpha != NULL) + alpha = (unsigned char *)ap_alpha->data; + return PyGdkImlibImage_New(gdk_imlib_create_image_from_data( + data, alpha, w, h)); +} + +static PyObject *_wrap_gdk_imlib_image_get_array(PyObject *self, PyObject *args) { + PyObject *image; + GdkImlibImage *obj; + PyArrayObject *ap_data; + int dims[3] = {0, 0, 3}; + + if (!PyArg_ParseTuple(args, "O!:gdk_imlib_image_get_array", + &PyGdkImlibImage_Type, &image)) + return NULL; + obj = PyGdkImlibImage_Get(image); + dims[0] = (int)obj->rgb_width; + dims[1] = (int)obj->rgb_height; + + ap_data = (PyArrayObject *)PyArray_FromDimsAndData(3, dims, PyArray_UBYTE, + (char *)obj->rgb_data); + if (ap_data == NULL) + return NULL; + /* this is necessary if you want to manipulate the rgb data after + * destroying the image. It causes a reference imbalance, and + * I don't see when you would want to do this (you can always copy + * the array). + */ + /* Py_INCREF(image); */ + return PyArray_Return(ap_data); +} +#endif + static PyMethodDef _gdkimlibMethods[] = { { "gdk_imlib_push_visual", _wrap_gdk_imlib_push_visual, 1 }, { "gdk_imlib_pop_visual", _wrap_gdk_imlib_pop_visual, 1 }, @@ -770,6 +836,10 @@ static PyMethodDef _gdkimlibMethods[] = { { "gdk_imlib_set_render_type", _wrap_gdk_imlib_set_render_type, 1 }, { "gdk_imlib_get_render_type", _wrap_gdk_imlib_get_render_type, 1 }, { "gdk_imlib_init", _wrap_gdk_imlib_init, 1 }, +#ifdef HAVE_NUMPY + { "gdk_imlib_create_image_from_array", _wrap_gdk_imlib_create_image_from_data, 1 }, + { "gdk_imlib_image_get_array", _wrap_gdk_imlib_image_get_array, 1 }, +#endif { NULL, NULL } }; @@ -782,6 +852,10 @@ void init_gdkimlib() { m = Py_InitModule("_gdkimlib", _gdkimlibMethods); d = PyModule_GetDict(m); + +#ifdef HAVE_NUMPY + import_array(); +#endif PyDict_SetItemString(d, "GdkImlibImageType", (PyObject *)&PyGdkImlibImage_Type); @@ -596,7 +596,7 @@ class GtkToggleButton(GtkButton): _gtk.gtk_toggle_button_set_active(self._o, active) def get_active(self): return _gtk.gtk_toggle_button_get_active(self._o) - def toggled(self, obj): + def toggled(self, obj=None): _gtk.gtk_toggle_button_toggled(self._o) class GtkCheckButton(GtkToggleButton): diff --git a/gtkmodule.c b/gtkmodule.c index caef5faa..dc7c2c50 100644 --- a/gtkmodule.c +++ b/gtkmodule.c @@ -26,25 +26,58 @@ #include "pygtk.h" /* The threading hacks are based on ones supplied by Duncan Grisby - * of AT&T Labs Cambridge */ + * of AT&T Labs Cambridge. Since then they have been modified a bit. */ + +/* The threading code has been enhanced to be a little better with multiple + * threads accessing GTK+. Here are some notes on the changes by + * Paul Fisher: + * + * If threading is enabled, we create a recursive version of Python's + * global interpreter mutex using TSD. This scheme makes it possible, + * although rather hackish, for any thread to make a call into PyGTK, + * as long as the GDK lock is held (that is, Python code is wrapped + * around a threads_{enter,leave} pair). + * + * A viable alternative would be to wrap each and every GTK call, at + * the Python/C level, with Py_{BEGIN,END}_ALLOW_THREADS. However, + * given the nature of Python threading, this option is not + * particularly appealing. + */ + + #ifdef WITH_THREAD -/* this code may need to be updated if python is changed. It should work - * for python 1.4 and 1.5.x. Check ceval.h for changes. */ -static PyThreadState *_save; -static int _blockcount = 1; - -/* recusive versions of thread block and unblock routines */ -# define PyGTK_BLOCK_THREADS \ - if (_blockcount == 0) { \ - Py_BLOCK_THREADS; \ - } \ - _blockcount++; -# define PyGTK_UNBLOCK_THREADS \ - _blockcount--; \ - if (_blockcount == 0) { \ - Py_UNBLOCK_THREADS; \ - } \ - g_assert(_blockcount >= 0); +static GStaticPrivate pythreadstate_key = G_STATIC_PRIVATE_INIT; +static GStaticPrivate counter_key = G_STATIC_PRIVATE_INIT; + +/* The global Python lock will be grabbed by Python when entering a + * Python/C function; thus, the initial lock count will always be one. + */ +# define INITIAL_LOCK_COUNT 1 +# define PyGTK_BLOCK_THREADS \ + { \ + gint counter = GPOINTER_TO_INT(g_static_private_get(&counter_key)); \ + if (counter == -INITIAL_LOCK_COUNT) { \ + PyThreadState *_save; \ + _save = g_static_private_get(&pythreadstate_key); \ + Py_BLOCK_THREADS; \ + } \ + counter++; \ + g_static_private_set(&counter_key, GINT_TO_POINTER(counter), NULL); \ + } + +# define PyGTK_UNBLOCK_THREADS \ + { \ + gint counter = GPOINTER_TO_INT(g_static_private_get(&counter_key)); \ + counter--; \ + if (counter == -INITIAL_LOCK_COUNT) { \ + PyThreadState *_save; \ + Py_UNBLOCK_THREADS; \ + g_static_private_set(&pythreadstate_key, _save, NULL); \ + } \ + g_static_private_set(&counter_key, GINT_TO_POINTER(counter), NULL); \ + } + + #else /* !WITH_THREADS */ # define PyGTK_BLOCK_THREADS # define PyGTK_UNBLOCK_THREADS @@ -3165,10 +3198,6 @@ static PyObject *_wrap_gtk_main(PyObject *self, PyObject *args) { PyGTK_UNBLOCK_THREADS gtk_main(); PyGTK_BLOCK_THREADS -#ifdef WITH_THREAD - g_assert(_blockcount == 1); - _blockcount = 1; -#endif if (PyErr_Occurred()) return NULL; @@ -3184,10 +3213,6 @@ static PyObject *_wrap_gtk_main_iteration(PyObject *self, PyObject *args) { PyGTK_UNBLOCK_THREADS ret = gtk_main_iteration_do(block); PyGTK_BLOCK_THREADS -#ifdef WITH_THREAD - g_assert(_blockcount == 1); - _blockcount = 1; -#endif return PyInt_FromLong(ret); } @@ -3195,9 +3220,7 @@ static PyObject *_wrap_gtk_events_pending(PyObject *self, PyObject *args) { int ret; if (!PyArg_ParseTuple(args, ":gtk_events_pending")) return NULL; - PyGTK_UNBLOCK_THREADS ret = gtk_events_pending(); - PyGTK_BLOCK_THREADS return PyInt_FromLong(ret); } |