summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Henstridge <james@daa.com.au>1999-07-31 15:17:13 +0000
committerJames Henstridge <jamesh@src.gnome.org>1999-07-31 15:17:13 +0000
commitb353b664618a8e4a31453a22f680e18de7d36c77 (patch)
treeb77c3f4a1bde2665d75170af819e9e8089d1f9bb
parent88b29cb44e8e5ca3ec2e7ae774166ebc43de82be (diff)
downloadpygtk-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--ChangeLog15
-rw-r--r--GdkImlib.py14
-rw-r--r--configure.in6
-rw-r--r--examples/glade/test2.glade2
-rw-r--r--gdkimlibmodule.c74
-rw-r--r--gtk.py2
-rw-r--r--gtkmodule.c79
7 files changed, 162 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index a27c59f7..4f1bb974 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
diff --git a/gtk.py b/gtk.py
index ab155ad3..3bd2530a 100644
--- a/gtk.py
+++ b/gtk.py
@@ -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);
}