diff options
author | Johan Dahlin <johan@gnome.org> | 2008-07-20 10:43:41 +0000 |
---|---|---|
committer | Johan Dahlin <johan@src.gnome.org> | 2008-07-20 10:43:41 +0000 |
commit | 6628e24baebc6dd40f9e76d10391ea5c06d3398a (patch) | |
tree | 68b587325b10d5616381c508609702027db8ba74 /glib | |
parent | af2dfa166520a243ea05ff7d4bd5a1fa103d8e0b (diff) | |
download | pygobject-6628e24baebc6dd40f9e76d10391ea5c06d3398a.tar.gz |
Add glib bindings, currently not installed or used. Add some internal API
2008-07-20 Johan Dahlin <johan@gnome.org>
* Makefile.am:
* configure.ac:
* glib/Makefile.am:
* glib/__init__.py:
* glib/glibmodule.c (pyg_destroy_notify), (get_handler_priority),
(pyg_handler_marshal), (pyg_idle_add), (pyg_timeout_add),
(pyg_timeout_add_seconds), (iowatch_marshal), (pyg_io_add_watch),
(pyg_source_remove), (pyg_main_context_default),
(child_watch_func), (child_watch_dnotify), (pyg_child_watch_add),
(pyg_markup_escape_text), (pyg_get_current_time), (pyg_main_depth),
(pyg_filename_display_name), (pyg_filename_display_basename),
(pyg_filename_from_utf8), (pyg_get_application_name),
(pyg_set_application_name), (pyg_get_prgname), (pyg_set_prgname),
(pyg_register_api), (pyg_register_error),
(pyg_register_version_tuples), (init_glib):
* glib/pyglib-private.h:
* glib/pyglib.c (pyglib_init), (pyglib_init_internal),
(pyglib_gil_state_ensure), (pyglib_gil_state_release),
(pyglib_enable_threads), (pyglib_gil_state_ensure_py23),
(pyglib_gil_state_release_py23), (pyglib_error_check):
* glib/pyglib.h:
* glib/pygspawn.c (pyg_pid_close), (pyg_pid_free),
(pyg_pid_tp_init), (pyg_pid_new), (_pyg_spawn_async_callback),
(pyglib_spawn_async), (pyg_spawn_register_types):
* glib/pygspawn.h:
Add glib bindings, currently not installed or used.
Add some internal API and move over a couple of functions
from the gobject module. Still very much a work in progress.
svn path=/trunk/; revision=839
Diffstat (limited to 'glib')
-rw-r--r-- | glib/Makefile.am | 33 | ||||
-rw-r--r-- | glib/__init__.py | 33 | ||||
-rw-r--r-- | glib/glibmodule.c | 678 | ||||
-rw-r--r-- | glib/pyglib-private.h | 49 | ||||
-rw-r--r-- | glib/pyglib.c | 180 | ||||
-rw-r--r-- | glib/pyglib.h | 40 | ||||
-rw-r--r-- | glib/pygspawn.c | 297 | ||||
-rw-r--r-- | glib/pygspawn.h | 32 |
8 files changed, 1342 insertions, 0 deletions
diff --git a/glib/Makefile.am b/glib/Makefile.am new file mode 100644 index 00000000..7e575805 --- /dev/null +++ b/glib/Makefile.am @@ -0,0 +1,33 @@ +AUTOMAKE_OPTIONS = 1.7 +PLATFORM_VERSION = 2.0 +INCLUDES = $(PYTHON_INCLUDES) $(GLIB_CFLAGS) -DPY_SSIZE_T_CLEAN + +# Workaround for automake so we can build shared library which are not +# going to be installed +noinstshared_LTLIBRARIES = libpyglib.la _glib.la +noinstshareddir = /tmp +install-noinstsharedLTLIBRARIES: # prevent it from being installed + +common_ldflags = -module -avoid-version +if PLATFORM_WIN32 +common_ldflags += -no-undefined +endif + +libpyglib_la_CFLAGS = $(GLIB_CFLAGS) +libpyglib_la_LIBADD = $(GLIB_LIBS) $(FFI_LIBS) +libpyglib_la_SOURCES = \ + pyglib.c \ + pyglib.h \ + pyglib-private.h + +_glib_la_CFLAGS = $(GLIB_CFLAGS) +_glib_la_LDFLAGS = $(common_ldflags) -export-symbols-regex init_glib +_glib_la_LIBADD = $(GLIB_LIBS) libpyglib.la +_glib_la_SOURCES = \ + glibmodule.c \ + pygspawn.c \ + pygspawn.h + +if PLATFORM_WIN32 +_glib_la_CFLAGS += -DPLATFORM_WIN32 +endif diff --git a/glib/__init__.py b/glib/__init__.py new file mode 100644 index 00000000..9730ea7b --- /dev/null +++ b/glib/__init__.py @@ -0,0 +1,33 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# pygobject - Python bindings for the GObject library +# Copyright (C) 2006-2008 Johan Dahlin +# +# glib/__init__.py: initialisation file for glib module +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +# this can go when things are a little further along +try: + import ltihooks + ltihooks # pyflakes + del ltihooks +except ImportError: + pass + +from _glib import * +_PyGLib_API = _glib._PyGLib_API + +del _glib diff --git a/glib/glibmodule.c b/glib/glibmodule.c new file mode 100644 index 00000000..4e01f588 --- /dev/null +++ b/glib/glibmodule.c @@ -0,0 +1,678 @@ +/* -*- Mode: C; c-set-style: python; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * glibmodule.c: wrapper for the glib library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Python.h> +#include <glib.h> +#include "pyglib.h" + +#include "pygspawn.h" +#include "pyglib-private.h" + +#define PYGLIB_MAJOR_VERSION PYGOBJECT_MAJOR_VERSION +#define PYGLIB_MINOR_VERSION PYGOBJECT_MINOR_VERSION +#define PYGLIB_MICRO_VERSION PYGOBJECT_MICRO_VERSION + +/** + * pyg_destroy_notify: + * @user_data: a PyObject pointer. + * + * A function that can be used as a GDestroyNotify callback that will + * call Py_DECREF on the data. + */ +void +pyg_destroy_notify(gpointer user_data) +{ + PyObject *obj = (PyObject *)user_data; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + Py_DECREF(obj); + pyglib_gil_state_release(state); +} + + + +/* ---------------- glib module functions -------------------- */ + +static gint +get_handler_priority(gint *priority, PyObject *kwargs) +{ + Py_ssize_t len, pos; + PyObject *key, *val; + + /* no keyword args? leave as default */ + if (kwargs == NULL) return 0; + + len = PyDict_Size(kwargs); + if (len == 0) return 0; + + if (len != 1) { + PyErr_SetString(PyExc_TypeError, + "expecting at most one keyword argument"); + return -1; + } + pos = 0; + PyDict_Next(kwargs, &pos, &key, &val); + if (!PyString_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "keyword argument name is not a string"); + return -1; + } + + if (strcmp(PyString_AsString(key), "priority") != 0) { + PyErr_SetString(PyExc_TypeError, + "only 'priority' keyword argument accepted"); + return -1; + } + + *priority = PyInt_AsLong(val); + if (PyErr_Occurred()) { + PyErr_Clear(); + PyErr_SetString(PyExc_ValueError, "could not get priority value"); + return -1; + } + return 0; +} + +gboolean +pyg_handler_marshal(gpointer user_data) +{ + PyObject *tuple, *ret; + gboolean res; + PyGILState_STATE state; + + g_return_val_if_fail(user_data != NULL, FALSE); + + state = pyglib_gil_state_ensure(); + + tuple = (PyObject *)user_data; + ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0), + PyTuple_GetItem(tuple, 1)); + if (!ret) { + PyErr_Print(); + res = FALSE; + } else { + res = PyObject_IsTrue(ret); + Py_DECREF(ret); + } + + pyglib_gil_state_release(state); + + return res; +} + +static PyObject * +pyg_idle_add(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *first, *callback, *cbargs = NULL, *data; + gint len, priority = G_PRIORITY_DEFAULT_IDLE; + guint handler_id; + + len = PyTuple_Size(args); + if (len < 1) { + PyErr_SetString(PyExc_TypeError, + "idle_add requires at least 1 argument"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 1); + if (!PyArg_ParseTuple(first, "O:idle_add", &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "first argument not callable"); + return NULL; + } + if (get_handler_priority(&priority, kwargs) < 0) + return NULL; + + cbargs = PySequence_GetSlice(args, 1, len); + if (cbargs == NULL) + return NULL; + + data = Py_BuildValue("(ON)", callback, cbargs); + if (data == NULL) + return NULL; + handler_id = g_idle_add_full(priority, pyg_handler_marshal, data, + pyg_destroy_notify); + return PyInt_FromLong(handler_id); +} + + +static PyObject * +pyg_timeout_add(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *first, *callback, *cbargs = NULL, *data; + gint len, priority = G_PRIORITY_DEFAULT; + guint interval, handler_id; + + len = PyTuple_Size(args); + if (len < 2) { + PyErr_SetString(PyExc_TypeError, + "timeout_add requires at least 2 args"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 2); + if (!PyArg_ParseTuple(first, "IO:timeout_add", &interval, &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument not callable"); + return NULL; + } + if (get_handler_priority(&priority, kwargs) < 0) + return NULL; + + cbargs = PySequence_GetSlice(args, 2, len); + if (cbargs == NULL) + return NULL; + + data = Py_BuildValue("(ON)", callback, cbargs); + if (data == NULL) + return NULL; + handler_id = g_timeout_add_full(priority, interval, + pyg_handler_marshal, data, + pyg_destroy_notify); + return PyInt_FromLong(handler_id); +} + +static PyObject * +pyg_timeout_add_seconds(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *first, *callback, *cbargs = NULL, *data; + gint len, priority = G_PRIORITY_DEFAULT; + guint interval, handler_id; + + len = PyTuple_Size(args); + if (len < 2) { + PyErr_SetString(PyExc_TypeError, + "timeout_add_seconds requires at least 2 args"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 2); + if (!PyArg_ParseTuple(first, "IO:timeout_add_seconds", &interval, &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument not callable"); + return NULL; + } + if (get_handler_priority(&priority, kwargs) < 0) + return NULL; + + cbargs = PySequence_GetSlice(args, 2, len); + if (cbargs == NULL) + return NULL; + + data = Py_BuildValue("(ON)", callback, cbargs); + if (data == NULL) + return NULL; + handler_id = g_timeout_add_seconds_full(priority, interval, + pyg_handler_marshal, data, + pyg_destroy_notify); + return PyInt_FromLong(handler_id); +} + +static gboolean +iowatch_marshal(GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + PyGILState_STATE state; + PyObject *tuple, *func, *firstargs, *args, *ret; + gboolean res; + + g_return_val_if_fail(user_data != NULL, FALSE); + + state = pyglib_gil_state_ensure(); + + tuple = (PyObject *)user_data; + func = PyTuple_GetItem(tuple, 0); + + /* arg vector is (fd, condtion, *args) */ + firstargs = Py_BuildValue("(Oi)", PyTuple_GetItem(tuple, 1), condition); + args = PySequence_Concat(firstargs, PyTuple_GetItem(tuple, 2)); + Py_DECREF(firstargs); + + ret = PyObject_CallObject(func, args); + Py_DECREF(args); + if (!ret) { + PyErr_Print(); + res = FALSE; + } else { + if (ret == Py_None) { + if (PyErr_Warn(PyExc_Warning, "glib.io_add_watch callback returned None;" + " should return True/False")) { + PyErr_Print(); + } + } + res = PyObject_IsTrue(ret); + Py_DECREF(ret); + } + + pyglib_gil_state_release(state); + + return res; +} + +static PyObject * +pyg_io_add_watch(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *first, *pyfd, *callback, *cbargs = NULL, *data; + gint fd, priority = G_PRIORITY_DEFAULT, condition; + Py_ssize_t len; + GIOChannel *iochannel; + guint handler_id; + + len = PyTuple_Size(args); + if (len < 3) { + PyErr_SetString(PyExc_TypeError, + "io_add_watch requires at least 3 args"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 3); + if (!PyArg_ParseTuple(first, "OiO:io_add_watch", &pyfd, &condition, + &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + fd = PyObject_AsFileDescriptor(pyfd); + if (fd < 0) { + return NULL; + } + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "third argument not callable"); + return NULL; + } + if (get_handler_priority(&priority, kwargs) < 0) + return NULL; + + cbargs = PySequence_GetSlice(args, 3, len); + if (cbargs == NULL) + return NULL; + data = Py_BuildValue("(OON)", callback, pyfd, cbargs); + if (data == NULL) + return NULL; + iochannel = g_io_channel_unix_new(fd); + handler_id = g_io_add_watch_full(iochannel, priority, condition, + iowatch_marshal, data, + (GDestroyNotify)pyg_destroy_notify); + g_io_channel_unref(iochannel); + + return PyInt_FromLong(handler_id); +} + +static PyObject * +pyg_source_remove(PyObject *self, PyObject *args) +{ + guint tag; + + if (!PyArg_ParseTuple(args, "i:source_remove", &tag)) + return NULL; + + return PyBool_FromLong(g_source_remove(tag)); +} + +static PyObject * +pyg_main_context_default(PyObject *unused) +{ +#ifdef FIXME + return pyg_main_context_new(g_main_context_default()); +#endif + return NULL; +} + +struct _PyGChildData { + PyObject *func; + PyObject *data; +}; + +static void +child_watch_func(GPid pid, gint status, gpointer data) +{ + struct _PyGChildData *child_data = (struct _PyGChildData *) data; + PyObject *retval; + PyGILState_STATE gil; + + gil = pyglib_gil_state_ensure(); + if (child_data->data) + retval = PyObject_CallFunction(child_data->func, "iiO", pid, status, + child_data->data); + else + retval = PyObject_CallFunction(child_data->func, "ii", pid, status); + + if (retval) + Py_DECREF(retval); + else + PyErr_Print(); + + pyglib_gil_state_release(gil); +} + +static void +child_watch_dnotify(gpointer data) +{ + struct _PyGChildData *child_data = (struct _PyGChildData *) data; + Py_DECREF(child_data->func); + Py_XDECREF(child_data->data); + g_free(child_data); +} + + +static PyObject * +pyg_child_watch_add(PyObject *unused, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "pid", "function", "data", "priority", NULL }; + guint id; + gint priority = G_PRIORITY_DEFAULT; + int pid; + PyObject *func, *user_data = NULL; + struct _PyGChildData *child_data; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "iO|Oi:glib.child_watch_add", kwlist, + &pid, &func, &user_data, &priority)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "glib.child_watch_add: second argument must be callable"); + return NULL; + } + + child_data = g_new(struct _PyGChildData, 1); + child_data->func = func; + child_data->data = user_data; + Py_INCREF(child_data->func); + if (child_data->data) + Py_INCREF(child_data->data); + id = g_child_watch_add_full(priority, pid, child_watch_func, + child_data, child_watch_dnotify); + return PyInt_FromLong(id); +} + +static PyObject * +pyg_markup_escape_text(PyObject *unused, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "text", NULL }; + char *text_in, *text_out; + Py_ssize_t text_size; + PyObject *retval; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s#:glib.markup_escape_text", kwlist, + &text_in, &text_size)) + return NULL; + + text_out = g_markup_escape_text(text_in, text_size); + retval = PyString_FromString(text_out); + g_free(text_out); + return retval; +} + +static PyObject * +pyg_get_current_time(PyObject *unused) +{ + GTimeVal timeval; + double ret; + + g_get_current_time(&timeval); + ret = (double)timeval.tv_sec + (double)timeval.tv_usec * 0.000001; + return PyFloat_FromDouble(ret); +} + +static PyObject * +pyg_main_depth(PyObject *unused) +{ + return PyInt_FromLong(g_main_depth()); +} + +static PyObject * +pyg_filename_display_name(PyObject *self, PyObject *args) +{ + PyObject *py_display_name; + char *filename, *display_name; + + if (!PyArg_ParseTuple(args, "s:glib.filename_display_name", + &filename)) + return NULL; + + display_name = g_filename_display_name(filename); + py_display_name = PyUnicode_DecodeUTF8(display_name, strlen(display_name), NULL); + g_free(display_name); + return py_display_name; +} + +static PyObject * +pyg_filename_display_basename(PyObject *self, PyObject *args) +{ + PyObject *py_display_basename; + char *filename, *display_basename; + + if (!PyArg_ParseTuple(args, "s:glib.filename_display_basename", + &filename)) + return NULL; + + display_basename = g_filename_display_basename(filename); + py_display_basename = PyUnicode_DecodeUTF8(display_basename, strlen(display_basename), NULL); + g_free(display_basename); + return py_display_basename; +} + +static PyObject * +pyg_filename_from_utf8(PyObject *self, PyObject *args) +{ + char *filename, *utf8string; + Py_ssize_t utf8string_len; + gsize bytes_written; + GError *error = NULL; + PyObject *py_filename; + + if (!PyArg_ParseTuple(args, "s#:glib.filename_from_utf8", + &utf8string, &utf8string_len)) + return NULL; + + filename = g_filename_from_utf8(utf8string, utf8string_len, NULL, &bytes_written, &error); + if (pyglib_error_check(&error)) { + g_free(filename); + return NULL; + } + py_filename = PyString_FromStringAndSize(filename, bytes_written); + g_free(filename); + return py_filename; +} + + +PyObject* +pyg_get_application_name(PyObject *self) +{ + const char *name; + + name = g_get_application_name(); + if (!name) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(name); +} + +PyObject* +pyg_set_application_name(PyObject *self, PyObject *args) +{ + char *s; + + if (!PyArg_ParseTuple(args, "s:glib.set_application_name", &s)) + return NULL; + g_set_application_name(s); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* +pyg_get_prgname(PyObject *self) +{ + char *name; + + name = g_get_prgname(); + if (!name) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(name); +} + +PyObject* +pyg_set_prgname(PyObject *self, PyObject *args) +{ + char *s; + + if (!PyArg_ParseTuple(args, "s:glib.set_prgname", &s)) + return NULL; + g_set_prgname(s); + Py_INCREF(Py_None); + return Py_None; +} + + +static PyMethodDef pyglib_functions[] = { + { "spawn_async", + (PyCFunction)pyglib_spawn_async, METH_VARARGS|METH_KEYWORDS }, + + { "idle_add", + (PyCFunction)pyg_idle_add, METH_VARARGS|METH_KEYWORDS }, + { "timeout_add", + (PyCFunction)pyg_timeout_add, METH_VARARGS|METH_KEYWORDS }, + { "timeout_add_seconds", + (PyCFunction)pyg_timeout_add_seconds, METH_VARARGS|METH_KEYWORDS }, + { "io_add_watch", + (PyCFunction)pyg_io_add_watch, METH_VARARGS|METH_KEYWORDS }, + { "source_remove", + pyg_source_remove, METH_VARARGS }, + { "child_watch_add", + (PyCFunction)pyg_child_watch_add, METH_VARARGS|METH_KEYWORDS }, + { "markup_escape_text", + (PyCFunction)pyg_markup_escape_text, METH_VARARGS|METH_KEYWORDS }, + { "get_current_time", + (PyCFunction)pyg_get_current_time, METH_NOARGS }, + { "filename_display_name", + (PyCFunction)pyg_filename_display_name, METH_VARARGS }, + { "filename_display_basename", + (PyCFunction)pyg_filename_display_basename, METH_VARARGS }, + { "filename_from_utf8", + (PyCFunction)pyg_filename_from_utf8, METH_VARARGS }, + { "get_application_name", + (PyCFunction)pyg_get_application_name, METH_NOARGS }, + { "set_application_name", + (PyCFunction)pyg_set_application_name, METH_VARARGS }, + { "get_prgname", + (PyCFunction)pyg_get_prgname, METH_NOARGS }, + { "set_prgname", + (PyCFunction)pyg_set_prgname, METH_VARARGS }, + { "main_depth", + (PyCFunction)pyg_main_depth, METH_NOARGS }, + { "main_context_default", + (PyCFunction)pyg_main_context_default, METH_NOARGS }, + + { NULL, NULL, 0 } +}; + +/* ----------------- glib module initialisation -------------- */ + +struct _PyGLib_Functions pyglib_api_functions = { + FALSE, /* threads_enabled */ + NULL /* gerror_exception */ +}; + +static void +pyg_register_api(PyObject *d) +{ + PyObject *o; + + /* for addon libraries ... */ + PyDict_SetItemString(d, "_PyGLib_API", + o=PyCObject_FromVoidPtr(&pyglib_api_functions,NULL)); + Py_DECREF(o); + + pyglib_init_internal(o); +} + +static void +pyg_register_error(PyObject *d) +{ + PyObject *dict; + PyObject *gerror_class; + dict = PyDict_New(); + /* This is a hack to work around the deprecation warning of + * BaseException.message in Python 2.6+. + * GError has also an "message" attribute. + */ + PyDict_SetItemString(dict, "message", Py_None); + gerror_class = PyErr_NewException("glib.GError", PyExc_RuntimeError, dict); + Py_DECREF(dict); + + PyDict_SetItemString(d, "GError", gerror_class); + pyglib_api_functions.gerror_exception = gerror_class; +} + +static void +pyg_register_version_tuples(PyObject *d) +{ + PyObject *o; + + /* glib version */ + o = Py_BuildValue("(iii)", glib_major_version, glib_minor_version, + glib_micro_version); + PyDict_SetItemString(d, "glib_version", o); + Py_DECREF(o); + + /* pyglib version */ + o = Py_BuildValue("(iii)", + PYGLIB_MAJOR_VERSION, + PYGLIB_MINOR_VERSION, + PYGLIB_MICRO_VERSION); + PyDict_SetItemString(d, "pyglib_version", o); + Py_DECREF(o); +} + +DL_EXPORT(void) +init_glib(void) +{ + PyObject *m, *d; + + m = Py_InitModule("glib._glib", pyglib_functions); + d = PyModule_GetDict(m); + + pyg_register_api(d); + pyg_register_error(d); + pyg_register_version_tuples(d); + pyg_spawn_register_types(d); +} diff --git a/glib/pyglib-private.h b/glib/pyglib-private.h new file mode 100644 index 00000000..fa8c6dd5 --- /dev/null +++ b/glib/pyglib-private.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYGLIB_PRIVATE_H__ +#define __PYGLIB_PRIVATE_H__ + +#include <Python.h> +#include <glib.h> + +G_BEGIN_DECLS + +struct _PyGLib_Functions { + gboolean threads_enabled; + PyObject *gerror_exception; +}; + +#define PYGLIB_REGISTER_TYPE(d, type, name) \ + type.ob_type = &PyType_Type; \ + if (!type.tp_alloc) \ + type.tp_alloc = PyType_GenericAlloc; \ + if (!type.tp_new) \ + type.tp_new = PyType_GenericNew; \ + if (PyType_Ready(&type)) \ + return; \ + PyDict_SetItemString(d, name, (PyObject *)&type); + +G_END_DECLS + +#endif /* __PYGLIB_PRIVATE_H__ */ + + diff --git a/glib/pyglib.c b/glib/pyglib.c new file mode 100644 index 00000000..bdc3d673 --- /dev/null +++ b/glib/pyglib.c @@ -0,0 +1,180 @@ +/* -*- Mode: C; c-set-style: python; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Python.h> +#include <pythread.h> +#include "pyglib.h" +#include "pyglib-private.h" + +static struct _PyGLib_Functions *_PyGLib_API; +static int pyglib_thread_state_tls_key; + +void +pyglib_init(void) +{ + PyObject *glib, *cobject; + + glib = PyImport_ImportModule("glib"); + if (!glib) { + if (PyErr_Occurred()) { + PyObject *type, *value, *traceback; + PyObject *py_orig_exc; + PyErr_Fetch(&type, &value, &traceback); + py_orig_exc = PyObject_Repr(value); + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + PyErr_Format(PyExc_ImportError, + "could not import glib (error was: %s)", + PyString_AsString(py_orig_exc)); + Py_DECREF(py_orig_exc); + } else + PyErr_SetString(PyExc_ImportError, + "could not import glib (no error given)"); + } + + cobject = PyObject_GetAttrString(glib, "_PyGLib_API"); + if (cobject && PyCObject_Check(cobject)) + _PyGLib_API = (struct _PyGLib_Functions *) PyCObject_AsVoidPtr(cobject); + else { + PyErr_SetString(PyExc_ImportError, + "could not import glib (could not find _PyGLib_API object)"); + Py_DECREF(glib); + } +} + +void +pyglib_init_internal(PyObject *api) +{ + _PyGLib_API = (struct _PyGLib_Functions *) PyCObject_AsVoidPtr(api); +} + +PyGILState_STATE +pyglib_gil_state_ensure(void) +{ + if (!_PyGLib_API->threads_enabled) + return PyGILState_LOCKED; + + return PyGILState_Ensure(); +} + +void +pyglib_gil_state_release(PyGILState_STATE state) +{ + if (!_PyGLib_API->threads_enabled) + return; + + PyGILState_Release(state); +} + +#ifdef DISABLE_THREADING +gboolean +pyglib_enable_threads(void) +{ + PyErr_SetString(PyExc_RuntimeError, + "pyglib threading disabled at compile time"); + return FALSE; +} +#else +gboolean +pyglib_enable_threads(void) +{ + if (_PyGLib_API->threads_enabled) + return TRUE; + + PyEval_InitThreads(); + if (!g_threads_got_initialized) + g_thread_init(NULL); + + _PyGLib_API->threads_enabled = TRUE; + pyglib_thread_state_tls_key = PyThread_create_key(); + + return TRUE; +} +#endif + +int +pyglib_gil_state_ensure_py23 (void) +{ + return PyGILState_Ensure(); +} + +void +pyglib_gil_state_release_py23 (int flag) +{ + PyGILState_Release(flag); +} + + +/** + * pyglib_error_check: + * @error: a pointer to the GError. + * + * Checks to see if the GError has been set. If the error has been + * set, then the glib.GError Python exception will be raised, and + * the GError cleared. + * + * Returns: True if an error was set. + */ +gboolean +pyglib_error_check(GError **error) +{ + PyGILState_STATE state; + PyObject *exc_instance; + PyObject *d; + + g_return_val_if_fail(error != NULL, FALSE); + + if (*error == NULL) + return FALSE; + + state = pyglib_gil_state_ensure(); + + exc_instance = PyObject_CallFunction(_PyGLib_API->gerror_exception, "z", + (*error)->message); + PyObject_SetAttrString(exc_instance, "domain", + d=PyString_FromString(g_quark_to_string((*error)->domain))); + Py_DECREF(d); + + PyObject_SetAttrString(exc_instance, "code", + d=PyInt_FromLong((*error)->code)); + Py_DECREF(d); + + if ((*error)->message) { + PyObject_SetAttrString(exc_instance, "message", + d=PyString_FromString((*error)->message)); + Py_DECREF(d); + } else { + PyObject_SetAttrString(exc_instance, "message", Py_None); + } + + PyErr_SetObject(_PyGLib_API->gerror_exception, exc_instance); + Py_DECREF(exc_instance); + g_clear_error(error); + + pyglib_gil_state_release(state); + + return TRUE; +} diff --git a/glib/pyglib.h b/glib/pyglib.h new file mode 100644 index 00000000..578aaa75 --- /dev/null +++ b/glib/pyglib.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYGLIB_H__ +#define __PYGLIB_H__ + +#include <Python.h> + +#include <glib.h> + +G_BEGIN_DECLS + +void pyglib_init(void); +void pyglib_init_internal(PyObject *api); +PyGILState_STATE pyglib_gil_state_ensure(void); +void pyglib_gil_state_release(PyGILState_STATE state); +gboolean pyglib_error_check(GError **error); + +G_END_DECLS + +#endif /* __PYGLIB_H__ */ + diff --git a/glib/pygspawn.c b/glib/pygspawn.c new file mode 100644 index 00000000..08c40aa6 --- /dev/null +++ b/glib/pygspawn.c @@ -0,0 +1,297 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * pygspawn.c: wrapper for the glib library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include <Python.h> +#include <glib/gspawn.h> + +#include "pyglib.h" +#include "pyglib-private.h" + +struct _PyGChildSetupData { + PyObject *func; + PyObject *data; +}; + +static PyObject * +pyg_pid_close(PyIntObject *self, PyObject *args, PyObject *kwargs) +{ + g_spawn_close_pid((GPid) self->ob_ival); + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef pyg_pid_methods[] = { + { "close", (PyCFunction)pyg_pid_close, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +static void +pyg_pid_free(PyIntObject *gpid) +{ + g_spawn_close_pid((GPid) gpid->ob_ival); + PyInt_Type.tp_free((void *) gpid); +} + +static int +pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyErr_SetString(PyExc_TypeError, "glib.Pid cannot be manually instantiated"); + return -1; +} + +static PyTypeObject PyGPid_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "glib.Pid", + sizeof(PyIntObject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + pyg_pid_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + pyg_pid_tp_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + (freefunc)pyg_pid_free, /* tp_free */ + 0, /* tp_is_gc */ +}; + +PyObject * +pyg_pid_new(GPid pid) +{ + PyIntObject *pygpid; + pygpid = PyObject_NEW(PyIntObject, &PyGPid_Type); + + pygpid->ob_ival = pid; + return (PyObject *) pygpid; +} + +static void +_pyg_spawn_async_callback(gpointer user_data) +{ + struct _PyGChildSetupData *data; + PyObject *retval; + PyGILState_STATE gil; + + data = (struct _PyGChildSetupData *) user_data; + gil = pyglib_gil_state_ensure(); + if (data->data) + retval = PyObject_CallFunction(data->func, "O", data->data); + else + retval = PyObject_CallFunction(data->func, NULL); + if (retval) + Py_DECREF(retval); + else + PyErr_Print(); + Py_DECREF(data->func); + Py_XDECREF(data->data); + g_free(data); + pyglib_gil_state_release(gil); +} + +PyObject * +pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "argv", "envp", "working_directory", "flags", + "child_setup", "user_data", "standard_input", + "standard_output", "standard_error", NULL }; + PyObject *pyargv, *pyenvp = NULL; + char **argv, **envp = NULL; + PyObject *func = Py_None, *user_data = NULL; + char *working_directory = NULL; + int flags = 0, _stdin = -1, _stdout = -1, _stderr = -1; + PyObject *pystdin = NULL, *pystdout = NULL, *pystderr = NULL; + gint *standard_input, *standard_output, *standard_error; + struct _PyGChildSetupData *callback_data = NULL; + GError *error = NULL; + GPid child_pid = -1; + Py_ssize_t len, i; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:glib.spawn_async", + kwlist, + &pyargv, &pyenvp, &working_directory, &flags, + &func, &user_data, + &pystdin, &pystdout, &pystderr)) + return NULL; + + if (pystdin && PyObject_IsTrue(pystdin)) + standard_input = &_stdin; + else + standard_input = NULL; + + if (pystdout && PyObject_IsTrue(pystdout)) + standard_output = &_stdout; + else + standard_output = NULL; + + if (pystderr && PyObject_IsTrue(pystderr)) + standard_error = &_stderr; + else + standard_error = NULL; + + /* parse argv */ + if (!PySequence_Check(pyargv)) { + PyErr_SetString(PyExc_TypeError, + "glib.spawn_async: " + "first argument must be a sequence of strings"); + return NULL; + } + len = PySequence_Length(pyargv); + argv = g_new0(char *, len + 1); + for (i = 0; i < len; ++i) { + PyObject *tmp = PySequence_ITEM(pyargv, i); + if (!PyString_Check(tmp)) { + PyErr_SetString(PyExc_TypeError, + "glib.spawn_async: " + "first argument must be a sequence of strings"); + g_free(argv); + Py_XDECREF(tmp); + return NULL; + } + argv[i] = PyString_AsString(tmp); + Py_DECREF(tmp); + } + + /* parse envp */ + if (pyenvp) { + if (!PySequence_Check(pyenvp)) { + PyErr_SetString(PyExc_TypeError, + "glib.spawn_async: " + "second argument must be a sequence of strings"); + g_free(argv); + return NULL; + } + len = PySequence_Length(pyenvp); + envp = g_new0(char *, len + 1); + for (i = 0; i < len; ++i) { + PyObject *tmp = PySequence_ITEM(pyenvp, i); + if (!PyString_Check(tmp)) { + PyErr_SetString(PyExc_TypeError, + "glib.spawn_async: " + "second argument must be a sequence of strings"); + g_free(envp); + Py_XDECREF(tmp); + g_free(argv); + return NULL; + } + envp[i] = PyString_AsString(tmp); + Py_DECREF(tmp); + } + } + + if (func != Py_None) { + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "child_setup parameter must be callable or None"); + g_free(argv); + if (envp) + g_free(envp); + return NULL; + } + callback_data = g_new(struct _PyGChildSetupData, 1); + callback_data->func = func; + callback_data->data = user_data; + Py_INCREF(callback_data->func); + if (callback_data->data) + Py_INCREF(callback_data->data); + } + + if (!g_spawn_async_with_pipes(working_directory, argv, envp, flags, + (func != Py_None ? _pyg_spawn_async_callback : NULL), + callback_data, &child_pid, + standard_input, + standard_output, + standard_error, + &error)) + + + { + g_free(argv); + if (envp) g_free(envp); + if (callback_data) { + Py_DECREF(callback_data->func); + Py_XDECREF(callback_data->data); + g_free(callback_data); + } + pyglib_error_check(&error); + return NULL; + } + g_free(argv); + if (envp) g_free(envp); + + if (standard_input) + pystdin = PyInt_FromLong(*standard_input); + else { + Py_INCREF(Py_None); + pystdin = Py_None; + } + + if (standard_output) + pystdout = PyInt_FromLong(*standard_output); + else { + Py_INCREF(Py_None); + pystdout = Py_None; + } + + if (standard_error) + pystderr = PyInt_FromLong(*standard_error); + else { + Py_INCREF(Py_None); + pystderr = Py_None; + } + + return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr); +} + +void +pyg_spawn_register_types(PyObject *d) +{ + PyGPid_Type.tp_base = &PyInt_Type; + PYGLIB_REGISTER_TYPE(d, PyGPid_Type, "Pid"); +} diff --git a/glib/pygspawn.h b/glib/pygspawn.h new file mode 100644 index 00000000..e283b858 --- /dev/null +++ b/glib/pygspawn.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pyglib - Python bindings for GLib toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef __PYG_PID_H__ +#define __PYG_PID_H__ + +PyObject * pyg_pid_new(GPid pid); +void pyg_spawn_register_types(PyObject *d); + +PyObject * pyglib_spawn_async(PyObject *self, PyObject *args, PyObject *kwargs); + + +#endif /* __PYG_PID_H__ */ + |