From d3e8946dbb23197a2e9d7de351a7b9cd04d360b9 Mon Sep 17 00:00:00 2001 From: Simon Feltman Date: Thu, 31 Oct 2013 02:22:03 -0700 Subject: Merge gobject static code into the gi module Remove gi._gobject._gobject as a separately compiled static module and move all the files into gi._gi. Remove dead module initialization macros from "pyglib-python-compat.h" https://bugzilla.gnome.org/show_bug.cgi?id=712197 --- gi/Makefile.am | 31 +- gi/_glib/pyglib-python-compat.h | 62 +- gi/_gobject/Makefile.am | 69 +- gi/_gobject/__init__.py | 4 +- gi/_gobject/constants.py | 3 +- gi/_gobject/gobjectmodule.c | 2213 ----------------------------------- gi/_gobject/propertyhelper.py | 16 +- gi/_gobject/pygboxed.c | 235 ---- gi/_gobject/pygboxed.h | 27 - gi/_gobject/pygenum.c | 371 ------ gi/_gobject/pygenum.h | 27 - gi/_gobject/pygflags.c | 497 -------- gi/_gobject/pygflags.h | 27 - gi/_gobject/pyginterface.c | 124 -- gi/_gobject/pyginterface.h | 40 - gi/_gobject/pygobject-private.h | 204 ---- gi/_gobject/pygobject.c | 2473 --------------------------------------- gi/_gobject/pygobject.h | 636 ---------- gi/_gobject/pygparamspec.c | 418 ------- gi/_gobject/pygparamspec.h | 31 - gi/_gobject/pygpointer.c | 198 ---- gi/_gobject/pygpointer.h | 27 - gi/_gobject/pygtype.c | 1927 ------------------------------ gi/_gobject/pygtype.h | 28 - gi/_gobject/signalhelper.py | 3 +- gi/gimodule.c | 13 +- gi/gobjectmodule.c | 2213 +++++++++++++++++++++++++++++++++++ gi/module.py | 4 +- gi/pygboxed.c | 235 ++++ gi/pygboxed.h | 27 + gi/pygenum.c | 371 ++++++ gi/pygenum.h | 27 + gi/pygflags.c | 497 ++++++++ gi/pygflags.h | 27 + gi/pygi-argument.c | 3 +- gi/pygi-boxed.c | 2 +- gi/pygi-ccallback.c | 2 +- gi/pygi-foreign.c | 2 +- gi/pygi-info.c | 2 +- gi/pygi-marshal-to-py.c | 3 +- gi/pygi-private.h | 2 +- gi/pygi-source.c | 3 +- gi/pygi-struct.c | 2 +- gi/pygi.h | 3 +- gi/pyginterface.c | 124 ++ gi/pyginterface.h | 40 + gi/pygobject-private.h | 205 ++++ gi/pygobject.c | 2473 +++++++++++++++++++++++++++++++++++++++ gi/pygobject.h | 636 ++++++++++ gi/pygparamspec.c | 418 +++++++ gi/pygparamspec.h | 33 + gi/pygpointer.c | 198 ++++ gi/pygpointer.h | 27 + gi/pygtype.c | 1927 ++++++++++++++++++++++++++++++ gi/pygtype.h | 28 + gi/types.py | 3 +- tests/Makefile.am | 2 +- 57 files changed, 9594 insertions(+), 9649 deletions(-) delete mode 100644 gi/_gobject/gobjectmodule.c delete mode 100644 gi/_gobject/pygboxed.c delete mode 100644 gi/_gobject/pygboxed.h delete mode 100644 gi/_gobject/pygenum.c delete mode 100644 gi/_gobject/pygenum.h delete mode 100644 gi/_gobject/pygflags.c delete mode 100644 gi/_gobject/pygflags.h delete mode 100644 gi/_gobject/pyginterface.c delete mode 100644 gi/_gobject/pyginterface.h delete mode 100644 gi/_gobject/pygobject-private.h delete mode 100644 gi/_gobject/pygobject.c delete mode 100644 gi/_gobject/pygobject.h delete mode 100644 gi/_gobject/pygparamspec.c delete mode 100644 gi/_gobject/pygparamspec.h delete mode 100644 gi/_gobject/pygpointer.c delete mode 100644 gi/_gobject/pygpointer.h delete mode 100644 gi/_gobject/pygtype.c delete mode 100644 gi/_gobject/pygtype.h create mode 100644 gi/gobjectmodule.c create mode 100644 gi/pygboxed.c create mode 100644 gi/pygboxed.h create mode 100644 gi/pygenum.c create mode 100644 gi/pygenum.h create mode 100644 gi/pygflags.c create mode 100644 gi/pygflags.h create mode 100644 gi/pyginterface.c create mode 100644 gi/pyginterface.h create mode 100644 gi/pygobject-private.h create mode 100644 gi/pygobject.c create mode 100644 gi/pygobject.h create mode 100644 gi/pygparamspec.c create mode 100644 gi/pygparamspec.h create mode 100644 gi/pygpointer.c create mode 100644 gi/pygpointer.h create mode 100644 gi/pygtype.c create mode 100644 gi/pygtype.h diff --git a/gi/Makefile.am b/gi/Makefile.am index aa91a464..e4b18196 100644 --- a/gi/Makefile.am +++ b/gi/Makefile.am @@ -24,11 +24,32 @@ extension_ldflags += \ -no-undefined endif +pkgincludedir = $(includedir)/pygobject-$(PLATFORM_VERSION) +pkginclude_HEADERS = pygobject.h + pygidir = $(pyexecdir)/gi pygi_LTLIBRARIES = _gi.la _gi_la_SOURCES = \ + gobjectmodule.c \ + pygboxed.c \ + pygboxed.h \ + pygenum.c \ + pygenum.h \ + pygflags.c \ + pygflags.h \ + pyginterface.c \ + pyginterface.h \ + pygobject.c \ + pygobject.h \ + pygobject-private.h \ + pygparamspec.c \ + pygparamspec.h \ + pygpointer.c \ + pygpointer.h \ + pygtype.c \ + pygtype.h \ pygi-repository.c \ pygi-repository.h \ pygi-info.c \ @@ -69,13 +90,16 @@ _gi_la_SOURCES = \ pygi-marshal-cleanup.c \ pygi-marshal-cleanup.h _gi_la_CFLAGS = \ + $(extension_cppflags) \ + -I$(top_srcdir)/gi/_glib \ + $(GLIB_CFLAGS) \ $(GI_CFLAGS) _gi_la_CPPFLAGS = \ $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi/_gobject + -I$(top_srcdir)/gi/_glib _gi_la_LIBADD = \ $(extension_libadd) \ + $(GLIB_LIBS) \ $(GI_LIBS) \ $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la _gi_la_LDFLAGS = \ @@ -93,8 +117,7 @@ _gi_cairo_la_CFLAGS = \ $(PYCAIRO_CFLAGS) _gi_cairo_la_CPPFLAGS = \ $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi/_gobject + -I$(top_srcdir)/gi/_glib _gi_cairo_la_LIBADD = \ $(extension_libadd) \ $(GI_LIBS) \ diff --git a/gi/_glib/pyglib-python-compat.h b/gi/_glib/pyglib-python-compat.h index 844bc55b..5365b208 100644 --- a/gi/_glib/pyglib-python-compat.h +++ b/gi/_glib/pyglib-python-compat.h @@ -29,46 +29,6 @@ # define PYGLIB_CPointer_Import(module, symbol) \ PyCapsule_Import(##module##.##symbol##, FALSE) -#if PY_VERSION_HEX < 0x03000000 - -#define PYGLIB_INIT_FUNCTION(modname, fullpkgname, functions) \ -static int _pyglib_init_##modname(PyObject *module); \ -void init##modname(void) \ -{ \ - PyObject *module = Py_InitModule(fullpkgname, functions); \ - _pyglib_init_##modname(module); \ -} \ -static int _pyglib_init_##modname(PyObject *module) - -#else - -#define PYGLIB_INIT_FUNCTION(modname, fullpkgname, functions) \ -static struct PyModuleDef _##modname##module = { \ - PyModuleDef_HEAD_INIT, \ - fullpkgname, \ - NULL, \ - -1, \ - functions, \ - NULL, \ - NULL, \ - NULL, \ - NULL \ -}; \ -static int _pyglib_init_##modname(PyObject *module); \ -PyObject *PyInit_##modname(void) \ -{ \ - PyObject *module = PyModule_Create(&_##modname##module); \ - if (module == NULL) \ - return NULL; \ - if (_pyglib_init_##modname(module) != 0 ) {\ - Py_DECREF(module); \ - return NULL; \ - } \ - return module; \ -} \ -static int _pyglib_init_##modname(PyObject *module) - -#endif /* Compilation on Python 2.x */ #if PY_VERSION_HEX < 0x03000000 @@ -121,12 +81,18 @@ static int _pyglib_init_##modname(PyObject *module) #endif #define PYGLIB_MODULE_START(symbol, modname) \ -DL_EXPORT(void) init##symbol(void); \ -DL_EXPORT(void) init##symbol(void) \ +PyObject * pyglib_##symbol##_module_create(void); \ +DL_EXPORT(void) init##symbol(void); \ +DL_EXPORT(void) init##symbol(void) { \ + pyglib_##symbol##_module_create(); \ +}; \ +PyObject * pyglib_##symbol##_module_create(void) \ { \ PyObject *module; \ module = Py_InitModule(modname, symbol##_functions); -#define PYGLIB_MODULE_END } + +#define PYGLIB_MODULE_END return module; } + #define PYGLIB_DEFINE_TYPE(typename, symbol, csymbol) \ PyTypeObject symbol = { \ PyObject_HEAD_INIT(NULL) \ @@ -135,6 +101,7 @@ PyTypeObject symbol = { \ sizeof(csymbol), \ 0, \ }; + #define PYGLIB_REGISTER_TYPE(d, type, name) \ if (!type.tp_alloc) \ type.tp_alloc = PyType_GenericAlloc; \ @@ -160,18 +127,25 @@ PyTypeObject symbol = { \ NULL, \ NULL \ }; \ +PyObject * pyglib_##symbol##_module_create(void); \ PyMODINIT_FUNC PyInit_##symbol(void); \ -PyMODINIT_FUNC PyInit_##symbol(void) \ +PyMODINIT_FUNC PyInit_##symbol(void) { \ + return pyglib_##symbol##_module_create(); \ +}; \ +PyObject * pyglib_##symbol##_module_create(void) \ { \ PyObject *module; \ module = PyModule_Create(&_##symbol##module); + #define PYGLIB_MODULE_END return module; } + #define PYGLIB_DEFINE_TYPE(typename, symbol, csymbol) \ PyTypeObject symbol = { \ PyVarObject_HEAD_INIT(NULL, 0) \ typename, \ sizeof(csymbol) \ }; + #define PYGLIB_REGISTER_TYPE(d, type, name) \ if (!type.tp_alloc) \ type.tp_alloc = PyType_GenericAlloc; \ diff --git a/gi/_gobject/Makefile.am b/gi/_gobject/Makefile.am index 5059ea75..b128acc1 100644 --- a/gi/_gobject/Makefile.am +++ b/gi/_gobject/Makefile.am @@ -1,29 +1,6 @@ AUTOMAKE_OPTIONS = 1.7 PLATFORM_VERSION = 3.0 -pkgincludedir = $(includedir)/pygobject-$(PLATFORM_VERSION) -pkginclude_HEADERS = pygobject.h - -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -extension_ldflags = \ - -module \ - -avoid-version \ - -shrext $(PYTHON_SO) - -if OS_WIN32 -# Windows requires Python modules to be explicitly linked to libpython. -# Extension modules are shared libaries (.dll), but need to be -# called .pyd for Python to load it as an extension module. -extension_libadd = \ - $(PYTHON_LIBS) - -extension_ldflags += \ - -no-undefined -endif - pygobjectdir = $(pyexecdir)/gi/_gobject pygobject_PYTHON = \ @@ -32,44 +9,6 @@ pygobject_PYTHON = \ propertyhelper.py \ signalhelper.py -pygobject_LTLIBRARIES = _gobject.la - -_gobject_la_SOURCES = \ - gobjectmodule.c \ - pygboxed.c \ - pygboxed.h \ - pygenum.c \ - pygenum.h \ - pygflags.c \ - pygflags.h \ - pyginterface.c \ - pyginterface.h \ - pygobject.c \ - pygobject.h \ - pygobject-private.h \ - pygparamspec.c \ - pygparamspec.h \ - pygpointer.c \ - pygpointer.h \ - pygtype.c \ - pygtype.h -_gobject_la_CFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi \ - $(GLIB_CFLAGS) \ - $(GI_CFLAGS) -_gi_la_CPPFLAGS = \ - $(extension_cppflags) -_gobject_la_LIBADD = \ - $(extension_libadd) \ - $(GLIB_LIBS) \ - $(GI_LIBS) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la -_gobject_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "_gobject|PyInit__gobject" - # if we build in a separate tree, we need to symlink the *.py files from the # source tree; Python does not accept the extensions and modules in different # paths @@ -79,9 +18,5 @@ build_pylinks: done -all: $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -check-local: $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -clean-local: - rm -f $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) -%$(PYTHON_SO): %.la - $(LN_S) -f .libs/$@ $@ +all: build_pylinks +check-local: build_pylinks diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py index d3ea0e0b..0bd57425 100644 --- a/gi/_gobject/__init__.py +++ b/gi/_gobject/__init__.py @@ -27,7 +27,9 @@ import sys if 'gobject' in sys.modules: raise ImportError('When using gi.repository you must not import static modules like "gobject". Please change all occurrences of "import gobject" to "from gi.repository import GObject".') -from . import _gobject +import gi._gi +_gobject = gi._gi._gobject + from . import propertyhelper from . import signalhelper diff --git a/gi/_gobject/constants.py b/gi/_gobject/constants.py index 9565a662..5bb8665c 100644 --- a/gi/_gobject/constants.py +++ b/gi/_gobject/constants.py @@ -19,7 +19,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 # USA -from . import _gobject +import gi._gi +_gobject = gi._gi._gobject TYPE_INVALID = _gobject.TYPE_INVALID TYPE_NONE = _gobject.type_from_name('void') diff --git a/gi/_gobject/gobjectmodule.c b/gi/_gobject/gobjectmodule.c deleted file mode 100644 index e982107a..00000000 --- a/gi/_gobject/gobjectmodule.c +++ /dev/null @@ -1,2213 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * gobjectmodule.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include "pygobject-private.h" -#include "pygboxed.h" -#include "pygenum.h" -#include "pygflags.h" -#include "pyginterface.h" -#include "pygparamspec.h" -#include "pygpointer.h" -#include "pygtype.h" - -static GHashTable *log_handlers = NULL; -static gboolean log_handlers_disabled = FALSE; - -static void pyg_flags_add_constants(PyObject *module, GType flags_type, - const gchar *strip_prefix); - - -/* -------------- GDK threading hooks ---------------------------- */ - -/** - * pyg_set_thread_block_funcs: - * Deprecated, only available for ABI compatibility. - */ -static void -_pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func, - PyGThreadBlockFunc unblock_threads_func) -{ - PyGILState_STATE state = pyglib_gil_state_ensure (); - PyErr_Warn (PyExc_DeprecationWarning, - "Using pyg_set_thread_block_funcs is not longer needed. " - "PyGObject always uses Py_BLOCK/UNBLOCK_THREADS."); - pyglib_gil_state_release (state); -} - -/** - * 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); -} - - -/* ---------------- gobject module functions -------------------- */ - -static PyObject * -pyg_type_name (PyObject *self, PyObject *args) -{ - PyObject *gtype; - GType type; - const gchar *name; - -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "gobject.type_name is deprecated; " - "use GType.name instead")) - return NULL; -#endif - - if (!PyArg_ParseTuple(args, "O:gobject.type_name", >ype)) - return NULL; - if ((type = pyg_type_from_object(gtype)) == 0) - return NULL; - name = g_type_name(type); - if (name) - return PYGLIB_PyUnicode_FromString(name); - PyErr_SetString(PyExc_RuntimeError, "unknown typecode"); - return NULL; -} - -static PyObject * -pyg_type_from_name (PyObject *self, PyObject *args) -{ - const gchar *name; - GType type; - PyObject *repr = NULL; -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "gobject.type_from_name is deprecated; " - "use GType.from_name instead")) - return NULL; -#endif - if (!PyArg_ParseTuple(args, "s:gobject.type_from_name", &name)) - return NULL; - type = g_type_from_name(name); - if (type != 0) - return pyg_type_wrapper_new(type); - repr = PyObject_Repr((PyObject*)self); - PyErr_Format(PyExc_RuntimeError, "%s: unknown type name: %s", - PYGLIB_PyUnicode_AsString(repr), - name); - Py_DECREF(repr); - return NULL; -} - -static PyObject * -pyg_type_is_a (PyObject *self, PyObject *args) -{ - PyObject *gtype, *gparent; - GType type, parent; -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "gobject.type_is_a is deprecated; " - "use GType.is_a instead")) - return NULL; -#endif - if (!PyArg_ParseTuple(args, "OO:gobject.type_is_a", >ype, &gparent)) - return NULL; - if ((type = pyg_type_from_object(gtype)) == 0) - return NULL; - if ((parent = pyg_type_from_object(gparent)) == 0) - return NULL; - return PyBool_FromLong(g_type_is_a(type, parent)); -} - -static void -pyg_object_set_property (GObject *object, guint property_id, - const GValue *value, GParamSpec *pspec) -{ - PyObject *object_wrapper, *retval; - PyObject *py_pspec, *py_value; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - - object_wrapper = pygobject_new(object); - - if (object_wrapper == NULL) { - pyglib_gil_state_release(state); - return; - } - - py_pspec = pyg_param_spec_new(pspec); - py_value = pyg_value_as_pyobject (value, TRUE); - - retval = PyObject_CallMethod(object_wrapper, "do_set_property", - "OO", py_pspec, py_value); - if (retval) { - Py_DECREF(retval); - } else { - PyErr_Print(); - } - - Py_DECREF(object_wrapper); - Py_DECREF(py_pspec); - Py_DECREF(py_value); - - pyglib_gil_state_release(state); -} - -static void -pyg_object_get_property (GObject *object, guint property_id, - GValue *value, GParamSpec *pspec) -{ - PyObject *object_wrapper, *retval; - PyObject *py_pspec; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - - object_wrapper = pygobject_new(object); - - if (object_wrapper == NULL) { - pyglib_gil_state_release(state); - return; - } - - py_pspec = pyg_param_spec_new(pspec); - retval = PyObject_CallMethod(object_wrapper, "do_get_property", - "O", py_pspec); - if (retval == NULL || pyg_value_from_pyobject(value, retval) < 0) { - PyErr_Print(); - } - Py_DECREF(object_wrapper); - Py_DECREF(py_pspec); - Py_XDECREF(retval); - - pyglib_gil_state_release(state); -} - -typedef struct _PyGSignalAccumulatorData { - PyObject *callable; - PyObject *user_data; -} PyGSignalAccumulatorData; - -static gboolean -_pyg_signal_accumulator(GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer _data) -{ - PyObject *py_ihint, *py_return_accu, *py_handler_return, *py_detail; - PyObject *py_retval; - gboolean retval = FALSE; - PyGSignalAccumulatorData *data = _data; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - if (ihint->detail) - py_detail = PYGLIB_PyUnicode_FromString(g_quark_to_string(ihint->detail)); - else { - Py_INCREF(Py_None); - py_detail = Py_None; - } - - py_ihint = Py_BuildValue("lNi", (long int) ihint->signal_id, - py_detail, ihint->run_type); - py_handler_return = pyg_value_as_pyobject(handler_return, TRUE); - py_return_accu = pyg_value_as_pyobject(return_accu, FALSE); - if (data->user_data) - py_retval = PyObject_CallFunction(data->callable, "NNNO", py_ihint, - py_return_accu, py_handler_return, - data->user_data); - else - py_retval = PyObject_CallFunction(data->callable, "NNN", py_ihint, - py_return_accu, py_handler_return); - if (!py_retval) - PyErr_Print(); - else { - if (!PyTuple_Check(py_retval) || PyTuple_Size(py_retval) != 2) { - PyErr_SetString(PyExc_TypeError, "accumulator function must return" - " a (bool, object) tuple"); - PyErr_Print(); - } else { - retval = PyObject_IsTrue(PyTuple_GET_ITEM(py_retval, 0)); - if (pyg_value_from_pyobject(return_accu, PyTuple_GET_ITEM(py_retval, 1))) { - PyErr_Print(); - } - } - Py_DECREF(py_retval); - } - pyglib_gil_state_release(state); - return retval; -} - -static gboolean -create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) -{ - GSignalFlags signal_flags; - PyObject *py_return_type, *py_param_types; - GType return_type; - guint n_params, i; - GType *param_types; - guint signal_id; - GSignalAccumulator accumulator = NULL; - PyGSignalAccumulatorData *accum_data = NULL; - PyObject *py_accum = NULL, *py_accum_data = NULL; - - if (!PyArg_ParseTuple(tuple, "iOO|OO", &signal_flags, &py_return_type, - &py_param_types, &py_accum, &py_accum_data)) - { - gchar buf[128]; - - PyErr_Clear(); - g_snprintf(buf, sizeof(buf), - "value for __gsignals__['%s'] not in correct format", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - - if (py_accum && py_accum != Py_None && !PyCallable_Check(py_accum)) - { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "accumulator for __gsignals__['%s'] must be callable", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - - return_type = pyg_type_from_object(py_return_type); - if (!return_type) - return FALSE; - if (!PySequence_Check(py_param_types)) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "third element of __gsignals__['%s'] tuple must be a sequence", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - n_params = PySequence_Length(py_param_types); - param_types = g_new(GType, n_params); - for (i = 0; i < n_params; i++) { - PyObject *item = PySequence_GetItem(py_param_types, i); - - param_types[i] = pyg_type_from_object(item); - if (param_types[i] == 0) { - Py_DECREF(item); - g_free(param_types); - return FALSE; - } - Py_DECREF(item); - } - - if (py_accum != NULL && py_accum != Py_None) { - accum_data = g_new(PyGSignalAccumulatorData, 1); - accum_data->callable = py_accum; - Py_INCREF(py_accum); - accum_data->user_data = py_accum_data; - Py_XINCREF(py_accum_data); - accumulator = _pyg_signal_accumulator; - } - - signal_id = g_signal_newv(signal_name, instance_type, signal_flags, - pyg_signal_class_closure_get(), - accumulator, accum_data, - gi_cclosure_marshal_generic, - return_type, n_params, param_types); - g_free(param_types); - - if (signal_id == 0) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), "could not create signal for %s", - signal_name); - PyErr_SetString(PyExc_RuntimeError, buf); - return FALSE; - } - return TRUE; -} - -static gboolean -override_signal(GType instance_type, const gchar *signal_name) -{ - guint signal_id; - - signal_id = g_signal_lookup(signal_name, instance_type); - if (!signal_id) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), "could not look up %s", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - g_signal_override_class_closure(signal_id, instance_type, - pyg_signal_class_closure_get()); - return TRUE; -} - -static PyObject * -add_signals (GObjectClass *klass, PyObject *signals) -{ - gboolean ret = TRUE; - Py_ssize_t pos = 0; - PyObject *key, *value, *overridden_signals = NULL; - GType instance_type = G_OBJECT_CLASS_TYPE (klass); - - overridden_signals = PyDict_New(); - while (PyDict_Next(signals, &pos, &key, &value)) { - const gchar *signal_name; - gchar *signal_name_canon, *c; - - if (!PYGLIB_PyUnicode_Check(key)) { - PyErr_SetString(PyExc_TypeError, - "__gsignals__ keys must be strings"); - ret = FALSE; - break; - } - signal_name = PYGLIB_PyUnicode_AsString (key); - - if (value == Py_None || - (PYGLIB_PyUnicode_Check(value) && - !strcmp(PYGLIB_PyUnicode_AsString(value), "override"))) - { - /* canonicalize signal name, replacing '-' with '_' */ - signal_name_canon = g_strdup(signal_name); - for (c = signal_name_canon; *c; ++c) - if (*c == '-') - *c = '_'; - if (PyDict_SetItemString(overridden_signals, - signal_name_canon, key)) { - g_free(signal_name_canon); - ret = FALSE; - break; - } - g_free(signal_name_canon); - - ret = override_signal(instance_type, signal_name); - } else { - ret = create_signal(instance_type, signal_name, value); - } - - if (!ret) - break; - } - if (ret) - return overridden_signals; - else { - Py_XDECREF(overridden_signals); - return NULL; - } -} - -static GParamSpec * -create_property (const gchar *prop_name, - GType prop_type, - const gchar *nick, - const gchar *blurb, - PyObject *args, - GParamFlags flags) -{ - GParamSpec *pspec = NULL; - - switch (G_TYPE_FUNDAMENTAL(prop_type)) { - case G_TYPE_CHAR: - { - gchar minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_char (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_UCHAR: - { - gchar minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_uchar (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_BOOLEAN: - { - gboolean default_value; - - if (!PyArg_ParseTuple(args, "i", &default_value)) - return NULL; - pspec = g_param_spec_boolean (prop_name, nick, blurb, - default_value, flags); - } - break; - case G_TYPE_INT: - { - gint minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "iii", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_int (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_UINT: - { - guint minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "III", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_uint (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_LONG: - { - glong minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "lll", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_long (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_ULONG: - { - gulong minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "kkk", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_ulong (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_INT64: - { - gint64 minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "LLL", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_int64 (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_UINT64: - { - guint64 minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "KKK", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_uint64 (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_ENUM: - { - gint default_value; - PyObject *pydefault; - - if (!PyArg_ParseTuple(args, "O", &pydefault)) - return NULL; - - if (pyg_enum_get_value(prop_type, pydefault, - (gint *)&default_value)) - return NULL; - - pspec = g_param_spec_enum (prop_name, nick, blurb, - prop_type, default_value, flags); - } - break; - case G_TYPE_FLAGS: - { - guint default_value; - PyObject *pydefault; - - if (!PyArg_ParseTuple(args, "O", &pydefault)) - return NULL; - - if (pyg_flags_get_value(prop_type, pydefault, - &default_value)) - return NULL; - - pspec = g_param_spec_flags (prop_name, nick, blurb, - prop_type, default_value, flags); - } - break; - case G_TYPE_FLOAT: - { - gfloat minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "fff", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_float (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_DOUBLE: - { - gdouble minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "ddd", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_double (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_STRING: - { - const gchar *default_value; - - if (!PyArg_ParseTuple(args, "z", &default_value)) - return NULL; - pspec = g_param_spec_string (prop_name, nick, blurb, - default_value, flags); - } - break; - case G_TYPE_PARAM: - if (!PyArg_ParseTuple(args, "")) - return NULL; - pspec = g_param_spec_param (prop_name, nick, blurb, prop_type, flags); - break; - case G_TYPE_BOXED: - if (!PyArg_ParseTuple(args, "")) - return NULL; - pspec = g_param_spec_boxed (prop_name, nick, blurb, prop_type, flags); - break; - case G_TYPE_POINTER: - if (!PyArg_ParseTuple(args, "")) - return NULL; - if (prop_type == G_TYPE_GTYPE) - pspec = g_param_spec_gtype (prop_name, nick, blurb, G_TYPE_NONE, flags); - else - pspec = g_param_spec_pointer (prop_name, nick, blurb, flags); - break; - case G_TYPE_OBJECT: - case G_TYPE_INTERFACE: - if (!PyArg_ParseTuple(args, "")) - return NULL; - pspec = g_param_spec_object (prop_name, nick, blurb, prop_type, flags); - break; - case G_TYPE_VARIANT: - { - PyObject *pydefault; - GVariant *default_value = NULL; - - if (!PyArg_ParseTuple(args, "O", &pydefault)) - return NULL; - if (pydefault != Py_None) - default_value = pyg_boxed_get (pydefault, GVariant); - pspec = g_param_spec_variant (prop_name, nick, blurb, G_VARIANT_TYPE_ANY, default_value, flags); - } - break; - default: - /* unhandled pspec type ... */ - break; - } - - if (!pspec) { - char buf[128]; - - g_snprintf(buf, sizeof(buf), "could not create param spec for type %s", - g_type_name(prop_type)); - PyErr_SetString(PyExc_TypeError, buf); - return NULL; - } - - return pspec; -} - -static GParamSpec * -pyg_param_spec_from_object (PyObject *tuple) -{ - gint val_length; - const gchar *prop_name; - GType prop_type; - const gchar *nick, *blurb; - PyObject *slice, *item, *py_prop_type; - GParamSpec *pspec; - - val_length = PyTuple_Size(tuple); - if (val_length < 4) { - PyErr_SetString(PyExc_TypeError, - "paramspec tuples must be at least 4 elements long"); - return NULL; - } - - slice = PySequence_GetSlice(tuple, 0, 4); - if (!slice) { - return NULL; - } - - if (!PyArg_ParseTuple(slice, "sOzz", &prop_name, &py_prop_type, &nick, &blurb)) { - Py_DECREF(slice); - return NULL; - } - - Py_DECREF(slice); - - prop_type = pyg_type_from_object(py_prop_type); - if (!prop_type) { - return NULL; - } - - item = PyTuple_GetItem(tuple, val_length-1); - if (!PYGLIB_PyLong_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "last element in tuple must be an int"); - return NULL; - } - - /* slice is the extra items in the tuple */ - slice = PySequence_GetSlice(tuple, 4, val_length-1); - pspec = create_property(prop_name, prop_type, - nick, blurb, slice, - PYGLIB_PyLong_AsLong(item)); - - return pspec; -} - -static gboolean -add_properties (GObjectClass *klass, PyObject *properties) -{ - gboolean ret = TRUE; - Py_ssize_t pos = 0; - PyObject *key, *value; - - while (PyDict_Next(properties, &pos, &key, &value)) { - const gchar *prop_name; - GType prop_type; - const gchar *nick, *blurb; - GParamFlags flags; - gint val_length; - PyObject *slice, *item, *py_prop_type; - GParamSpec *pspec; - - /* values are of format (type,nick,blurb, type_specific_args, flags) */ - - if (!PYGLIB_PyUnicode_Check(key)) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ keys must be strings"); - ret = FALSE; - break; - } - prop_name = PYGLIB_PyUnicode_AsString (key); - - if (!PyTuple_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ values must be tuples"); - ret = FALSE; - break; - } - val_length = PyTuple_Size(value); - if (val_length < 4) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ values must be at least 4 elements long"); - ret = FALSE; - break; - } - - slice = PySequence_GetSlice(value, 0, 3); - if (!slice) { - ret = FALSE; - break; - } - if (!PyArg_ParseTuple(slice, "Ozz", &py_prop_type, &nick, &blurb)) { - Py_DECREF(slice); - ret = FALSE; - break; - } - Py_DECREF(slice); - prop_type = pyg_type_from_object(py_prop_type); - if (!prop_type) { - ret = FALSE; - break; - } - item = PyTuple_GetItem(value, val_length-1); - if (!PYGLIB_PyLong_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "last element in __gproperties__ value tuple must be an int"); - ret = FALSE; - break; - } - flags = PYGLIB_PyLong_AsLong(item); - - /* slice is the extra items in the tuple */ - slice = PySequence_GetSlice(value, 3, val_length-1); - pspec = create_property(prop_name, prop_type, nick, blurb, - slice, flags); - Py_DECREF(slice); - - if (pspec) { - g_object_class_install_property(klass, 1, pspec); - } else { - PyObject *type, *value, *traceback; - ret = FALSE; - PyErr_Fetch(&type, &value, &traceback); - if (PYGLIB_PyUnicode_Check(value)) { - char msg[256]; - g_snprintf(msg, 256, - "%s (while registering property '%s' for GType '%s')", - PYGLIB_PyUnicode_AsString(value), - prop_name, G_OBJECT_CLASS_NAME(klass)); - Py_DECREF(value); - value = PYGLIB_PyUnicode_FromString(msg); - } - PyErr_Restore(type, value, traceback); - break; - } - } - - return ret; -} - -static void -pyg_object_class_init(GObjectClass *class, PyObject *py_class) -{ - PyObject *gproperties, *gsignals, *overridden_signals; - PyObject *class_dict = ((PyTypeObject*) py_class)->tp_dict; - - class->set_property = pyg_object_set_property; - class->get_property = pyg_object_get_property; - - /* install signals */ - /* we look this up in the instance dictionary, so we don't - * accidentally get a parent type's __gsignals__ attribute. */ - gsignals = PyDict_GetItemString(class_dict, "__gsignals__"); - if (gsignals) { - if (!PyDict_Check(gsignals)) { - PyErr_SetString(PyExc_TypeError, - "__gsignals__ attribute not a dict!"); - return; - } - if (!(overridden_signals = add_signals(class, gsignals))) { - return; - } - if (PyDict_SetItemString(class_dict, "__gsignals__", - overridden_signals)) { - return; - } - Py_DECREF(overridden_signals); - - PyDict_DelItemString(class_dict, "__gsignals__"); - } else { - PyErr_Clear(); - } - - /* install properties */ - /* we look this up in the instance dictionary, so we don't - * accidentally get a parent type's __gproperties__ attribute. */ - gproperties = PyDict_GetItemString(class_dict, "__gproperties__"); - if (gproperties) { - if (!PyDict_Check(gproperties)) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ attribute not a dict!"); - return; - } - if (!add_properties(class, gproperties)) { - return; - } - PyDict_DelItemString(class_dict, "__gproperties__"); - /* Borrowed reference. Py_DECREF(gproperties); */ - } else { - PyErr_Clear(); - } -} - -static void -pyg_register_class_init(GType gtype, PyGClassInitFunc class_init) -{ - GSList *list; - - list = g_type_get_qdata(gtype, pygobject_class_init_key); - list = g_slist_prepend(list, class_init); - g_type_set_qdata(gtype, pygobject_class_init_key, list); -} - -static int -pyg_run_class_init(GType gtype, gpointer gclass, PyTypeObject *pyclass) -{ - GSList *list; - PyGClassInitFunc class_init; - GType parent_type; - int rv; - - parent_type = g_type_parent(gtype); - if (parent_type) { - rv = pyg_run_class_init(parent_type, gclass, pyclass); - if (rv) - return rv; - } - - list = g_type_get_qdata(gtype, pygobject_class_init_key); - for (; list; list = list->next) { - class_init = list->data; - rv = class_init(gclass, pyclass); - if (rv) - return rv; - } - - return 0; -} - -static PyObject * -_wrap_pyg_type_register(PyObject *self, PyObject *args) -{ - PyTypeObject *class; - char *type_name = NULL; - - if (!PyArg_ParseTuple(args, "O!|z:gobject.type_register", - &PyType_Type, &class, &type_name)) - return NULL; - if (!PyType_IsSubtype(class, &PyGObject_Type)) { - PyErr_SetString(PyExc_TypeError, - "argument must be a GObject subclass"); - return NULL; - } - - /* Check if type already registered */ - if (pyg_type_from_object((PyObject *) class) == - pyg_type_from_object((PyObject *) class->tp_base)) - { - if (pyg_type_register(class, type_name)) - return NULL; - } - - Py_INCREF(class); - return (PyObject *) class; -} - -static char * -get_type_name_for_class(PyTypeObject *class) -{ - gint i, name_serial; - char name_serial_str[16]; - PyObject *module; - char *type_name = NULL; - - /* make name for new GType */ - name_serial = 1; - /* give up after 1000 tries, just in case.. */ - while (name_serial < 1000) - { - g_free(type_name); - snprintf(name_serial_str, 16, "-v%i", name_serial); - module = PyObject_GetAttrString((PyObject *)class, "__module__"); - if (module && PYGLIB_PyUnicode_Check(module)) { - type_name = g_strconcat(PYGLIB_PyUnicode_AsString(module), ".", - class->tp_name, - name_serial > 1 ? name_serial_str : NULL, - NULL); - Py_DECREF(module); - } else { - if (module) - Py_DECREF(module); - else - PyErr_Clear(); - type_name = g_strconcat(class->tp_name, - name_serial > 1 ? name_serial_str : NULL, - NULL); - } - /* convert '.' in type name to '+', which isn't banned (grumble) */ - for (i = 0; type_name[i] != '\0'; i++) - if (type_name[i] == '.') - type_name[i] = '+'; - if (g_type_from_name(type_name) == 0) - break; /* we now have a unique name */ - ++name_serial; - } - - return type_name; -} - - -static GPrivate pygobject_construction_wrapper; - -static inline void -pygobject_init_wrapper_set(PyObject *wrapper) -{ - g_private_set(&pygobject_construction_wrapper, wrapper); -} - -static inline PyObject * -pygobject_init_wrapper_get(void) -{ - return (PyObject *) g_private_get(&pygobject_construction_wrapper); -} - -int -pygobject_constructv(PyGObject *self, - guint n_parameters, - GParameter *parameters) -{ - GObject *obj; - - g_assert (self->obj == NULL); - pygobject_init_wrapper_set((PyObject *) self); - obj = g_object_newv(pyg_type_from_object((PyObject *) self), - n_parameters, parameters); - - if (g_object_is_floating (obj)) - self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING; - pygobject_sink (obj); - - pygobject_init_wrapper_set(NULL); - self->obj = obj; - pygobject_register_wrapper((PyObject *) self); - - return 0; -} - -static void -pygobject__g_instance_init(GTypeInstance *instance, - gpointer g_class) -{ - GObject *object = (GObject *) instance; - PyObject *wrapper, *args, *kwargs; - - wrapper = g_object_get_qdata(object, pygobject_wrapper_key); - if (wrapper == NULL) { - wrapper = pygobject_init_wrapper_get(); - if (wrapper && ((PyGObject *) wrapper)->obj == NULL) { - ((PyGObject *) wrapper)->obj = object; - pygobject_register_wrapper(wrapper); - } - } - pygobject_init_wrapper_set(NULL); - if (wrapper == NULL) { - /* this looks like a python object created through - * g_object_new -> we have no python wrapper, so create it - * now */ - PyGILState_STATE state; - state = pyglib_gil_state_ensure(); - wrapper = pygobject_new_full(object, - /*steal=*/ FALSE, - g_class); - - /* float the wrapper ref here because we are going to orphan it - * so we don't destroy the wrapper. The next call to pygobject_new_full - * will take the ref */ - pygobject_ref_float ((PyGObject *) wrapper); - args = PyTuple_New(0); - kwargs = PyDict_New(); - if (Py_TYPE(wrapper)->tp_init(wrapper, args, kwargs)) - PyErr_Print(); - - Py_DECREF(args); - Py_DECREF(kwargs); - pyglib_gil_state_release(state); - } -} - - -/* This implementation is bad, see bug 566571 for an example why. - * Instead of scanning explicitly declared bases for interfaces, we - * should automatically initialize all implemented interfaces to - * prevent bugs like that one. However, this will lead to - * performance degradation as each virtual method in derived classes - * will round-trip through do_*() stuff, *even* if it is not - * overriden. We need to teach codegen to retain parent method - * instead of setting virtual to *_proxy_do_*() if corresponding - * do_*() is not overriden. Ok, that was a messy explanation. - */ -static void -pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, - PyObject *bases, - GType *parent_interfaces, guint n_parent_interfaces) -{ - int i; - - if (!bases) { - g_warning("type has no bases"); - return; - } - - for (i = 0; i < PyTuple_GET_SIZE(bases); ++i) { - PyObject *base = PyTuple_GET_ITEM(bases, i); - GType itype; - const GInterfaceInfo *iinfo; - GInterfaceInfo iinfo_copy; - - /* 'base' can also be a PyClassObject, see bug #566571. */ - if (!PyType_Check(base)) - continue; - - if (!PyType_IsSubtype((PyTypeObject*) base, &PyGInterface_Type)) - continue; - - itype = pyg_type_from_object(base); - - /* Happens for _implementations_ of an interface. */ - if (!G_TYPE_IS_INTERFACE(itype)) - continue; - - iinfo = pyg_lookup_interface_info(itype); - if (!iinfo) { - gchar *error; - error = g_strdup_printf("Interface type %s " - "has no Python implementation support", - ((PyTypeObject *) base)->tp_name); - PyErr_Warn(PyExc_RuntimeWarning, error); - g_free(error); - continue; - } - - iinfo_copy = *iinfo; - iinfo_copy.interface_data = class; - g_type_add_interface_static(instance_type, itype, &iinfo_copy); - } -} - -int -pyg_type_register(PyTypeObject *class, const char *type_name) -{ - PyObject *gtype; - GType parent_type, instance_type; - GType *parent_interfaces; - guint n_parent_interfaces; - GTypeQuery query; - gpointer gclass; - GTypeInfo type_info = { - 0, /* class_size */ - - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - - (GClassInitFunc) pyg_object_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - - 0, /* instance_size */ - 0, /* n_preallocs */ - (GInstanceInitFunc) pygobject__g_instance_init - }; - gchar *new_type_name; - - /* find the GType of the parent */ - parent_type = pyg_type_from_object((PyObject *)class); - if (!parent_type) - return -1; - - parent_interfaces = g_type_interfaces(parent_type, &n_parent_interfaces); - - if (type_name) - /* care is taken below not to free this */ - new_type_name = (gchar *) type_name; - else - new_type_name = get_type_name_for_class(class); - - /* set class_data that will be passed to the class_init function. */ - type_info.class_data = class; - - /* fill in missing values of GTypeInfo struct */ - g_type_query(parent_type, &query); - type_info.class_size = query.class_size; - type_info.instance_size = query.instance_size; - - /* create new typecode */ - instance_type = g_type_register_static(parent_type, new_type_name, - &type_info, 0); - if (instance_type == 0) { - PyErr_Format(PyExc_RuntimeError, - "could not create new GType: %s (subclass of %s)", - new_type_name, - g_type_name(parent_type)); - - if (type_name == NULL) - g_free(new_type_name); - - return -1; - } - - if (type_name == NULL) - g_free(new_type_name); - - /* store pointer to the class with the GType */ - Py_INCREF(class); - g_type_set_qdata(instance_type, g_quark_from_string("PyGObject::class"), - class); - - /* Mark this GType as a custom python type */ - g_type_set_qdata(instance_type, pygobject_custom_key, - GINT_TO_POINTER (1)); - - /* set new value of __gtype__ on class */ - gtype = pyg_type_wrapper_new(instance_type); - PyObject_SetAttrString((PyObject *)class, "__gtype__", gtype); - Py_DECREF(gtype); - - /* if no __doc__, set it to the auto doc descriptor */ - if (PyDict_GetItemString(class->tp_dict, "__doc__") == NULL) { - PyDict_SetItemString(class->tp_dict, "__doc__", - pyg_object_descr_doc_get()); - } - - /* - * Note, all interfaces need to be registered before the first - * g_type_class_ref(), see bug #686149. - * - * See also comment above pyg_type_add_interfaces(). - */ - pyg_type_add_interfaces(class, instance_type, class->tp_bases, - parent_interfaces, n_parent_interfaces); - - - gclass = g_type_class_ref(instance_type); - if (PyErr_Occurred() != NULL) { - g_type_class_unref(gclass); - g_free(parent_interfaces); - return -1; - } - - if (pyg_run_class_init(instance_type, gclass, class)) { - g_type_class_unref(gclass); - g_free(parent_interfaces); - return -1; - } - g_type_class_unref(gclass); - g_free(parent_interfaces); - - if (PyErr_Occurred() != NULL) - return -1; - return 0; -} - -static PyObject * -pyg_signal_new(PyObject *self, PyObject *args) -{ - gchar *signal_name; - PyObject *py_type; - GSignalFlags signal_flags; - GType return_type; - PyObject *py_return_type, *py_param_types; - - GType instance_type = 0; - Py_ssize_t n_params, i; - GType *param_types; - - guint signal_id; - - if (!PyArg_ParseTuple(args, "sOiOO:gobject.signal_new", &signal_name, - &py_type, &signal_flags, &py_return_type, - &py_param_types)) - return NULL; - - instance_type = pyg_type_from_object(py_type); - if (!instance_type) - return NULL; - if (!(G_TYPE_IS_INSTANTIATABLE(instance_type) || G_TYPE_IS_INTERFACE(instance_type))) { - PyErr_SetString(PyExc_TypeError, - "argument 2 must be an object type or interface type"); - return NULL; - } - - return_type = pyg_type_from_object(py_return_type); - if (!return_type) - return NULL; - - if (!PySequence_Check(py_param_types)) { - PyErr_SetString(PyExc_TypeError, - "argument 5 must be a sequence of GType codes"); - return NULL; - } - n_params = PySequence_Length(py_param_types); - param_types = g_new(GType, n_params); - for (i = 0; i < n_params; i++) { - PyObject *item = PySequence_GetItem(py_param_types, i); - - param_types[i] = pyg_type_from_object(item); - if (param_types[i] == 0) { - PyErr_Clear(); - Py_DECREF(item); - PyErr_SetString(PyExc_TypeError, - "argument 5 must be a sequence of GType codes"); - g_free(param_types); - return NULL; - } - Py_DECREF(item); - } - - signal_id = g_signal_newv(signal_name, instance_type, signal_flags, - pyg_signal_class_closure_get(), - (GSignalAccumulator)0, NULL, - (GSignalCMarshaller)0, - return_type, n_params, param_types); - g_free(param_types); - if (signal_id != 0) - return PYGLIB_PyLong_FromLong(signal_id); - PyErr_SetString(PyExc_RuntimeError, "could not create signal"); - return NULL; -} - -static PyObject * -pyg_signal_query (PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist1[] = { "name", "type", NULL }; - static char *kwlist2[] = { "signal_id", NULL }; - PyObject *py_query, *params_list, *py_itype; - GObjectClass *class = NULL; - GType itype; - gchar *signal_name; - guint i; - GSignalQuery query; - guint id; - gpointer iface = NULL; - - if (PyArg_ParseTupleAndKeywords(args, kwargs, "sO:gobject.signal_query", - kwlist1, &signal_name, &py_itype)) { - if ((itype = pyg_type_from_object(py_itype)) == 0) - return NULL; - - if (G_TYPE_IS_INSTANTIATABLE(itype)) { - class = g_type_class_ref(itype); - if (!class) { - PyErr_SetString(PyExc_RuntimeError, - "could not get a reference to type class"); - return NULL; - } - } else if (!G_TYPE_IS_INTERFACE(itype)) { - PyErr_SetString(PyExc_TypeError, - "type must be instantiable or an interface"); - return NULL; - } else { - iface = g_type_default_interface_ref(itype); - } - id = g_signal_lookup(signal_name, itype); - } else { - PyErr_Clear(); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "i:gobject.signal_query", - kwlist2, &id)) { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, - "Usage: one of:\n" - " gobject.signal_query(name, type)\n" - " gobject.signal_query(signal_id)"); - - return NULL; - } - } - - g_signal_query(id, &query); - - if (query.signal_id == 0) { - Py_INCREF(Py_None); - py_query = Py_None; - goto done; - } - py_query = PyTuple_New(6); - if (py_query == NULL) { - goto done; - } - params_list = PyTuple_New(query.n_params); - if (params_list == NULL) { - Py_DECREF(py_query); - py_query = NULL; - goto done; - } - - PyTuple_SET_ITEM(py_query, 0, PYGLIB_PyLong_FromLong(query.signal_id)); - PyTuple_SET_ITEM(py_query, 1, PYGLIB_PyUnicode_FromString(query.signal_name)); - PyTuple_SET_ITEM(py_query, 2, pyg_type_wrapper_new(query.itype)); - PyTuple_SET_ITEM(py_query, 3, PYGLIB_PyLong_FromLong(query.signal_flags)); - PyTuple_SET_ITEM(py_query, 4, pyg_type_wrapper_new(query.return_type)); - for (i = 0; i < query.n_params; i++) { - PyTuple_SET_ITEM(params_list, i, - pyg_type_wrapper_new(query.param_types[i])); - } - PyTuple_SET_ITEM(py_query, 5, params_list); - - done: - if (class) - g_type_class_unref(class); - if (iface) - g_type_default_interface_unref(iface); - - return py_query; -} - -static PyObject * -pyg_object_class_list_properties (PyObject *self, PyObject *args) -{ - GParamSpec **specs; - PyObject *py_itype, *list; - GType itype; - GObjectClass *class = NULL; - gpointer iface = NULL; - guint nprops; - guint i; - - if (!PyArg_ParseTuple(args, "O:gobject.list_properties", - &py_itype)) - return NULL; - if ((itype = pyg_type_from_object(py_itype)) == 0) - return NULL; - - if (G_TYPE_IS_INTERFACE(itype)) { - iface = g_type_default_interface_ref(itype); - if (!iface) { - PyErr_SetString(PyExc_RuntimeError, - "could not get a reference to interface type"); - return NULL; - } - specs = g_object_interface_list_properties(iface, &nprops); - } else if (g_type_is_a(itype, G_TYPE_OBJECT)) { - class = g_type_class_ref(itype); - if (!class) { - PyErr_SetString(PyExc_RuntimeError, - "could not get a reference to type class"); - return NULL; - } - specs = g_object_class_list_properties(class, &nprops); - } else { - PyErr_SetString(PyExc_TypeError, - "type must be derived from GObject or an interface"); - return NULL; - } - - list = PyTuple_New(nprops); - if (list == NULL) { - g_free(specs); - g_type_class_unref(class); - return NULL; - } - for (i = 0; i < nprops; i++) { - PyTuple_SetItem(list, i, pyg_param_spec_new(specs[i])); - } - g_free(specs); - if (class) - g_type_class_unref(class); - else - g_type_default_interface_unref(iface); - - return list; -} - -static PyObject * -pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs) -{ - PyObject *pytype; - GType type; - GObject *obj = NULL; - GObjectClass *class; - guint n_params = 0, i; - GParameter *params = NULL; - - if (!PyArg_ParseTuple (args, "O:gobject.new", &pytype)) { - return NULL; - } - - if ((type = pyg_type_from_object (pytype)) == 0) - return NULL; - - if (G_TYPE_IS_ABSTRACT(type)) { - PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " - "(non-instantiable) type `%s'", g_type_name(type)); - return NULL; - } - - if ((class = g_type_class_ref (type)) == NULL) { - PyErr_SetString(PyExc_TypeError, - "could not get a reference to type class"); - return NULL; - } - - if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, ¶ms)) - goto cleanup; - - obj = g_object_newv(type, n_params, params); - if (!obj) - PyErr_SetString (PyExc_RuntimeError, "could not create object"); - - cleanup: - for (i = 0; i < n_params; i++) { - g_free((gchar *) params[i].name); - g_value_unset(¶ms[i].value); - } - g_free(params); - g_type_class_unref(class); - - if (obj) { - pygobject_sink (obj); - self = (PyGObject *) pygobject_new((GObject *)obj); - g_object_unref(obj); - } else - self = NULL; - - return (PyObject *) self; -} - -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 int -pygobject_gil_state_ensure (void) -{ - return pyglib_gil_state_ensure (); -} - -static void -pygobject_gil_state_release (int flag) -{ - pyglib_gil_state_release(flag); -} - -/* Only for backwards compatibility */ -static int -pygobject_enable_threads(void) -{ - return 0; -} - -static PyObject * -pyg_signal_accumulator_true_handled(PyObject *unused, PyObject *args) -{ - PyErr_SetString(PyExc_TypeError, - "signal_accumulator_true_handled can only" - " be used as accumulator argument when registering signals"); - return NULL; -} - -static gboolean -marshal_emission_hook(GSignalInvocationHint *ihint, - guint n_param_values, - const GValue *param_values, - gpointer user_data) -{ - PyGILState_STATE state; - gboolean retval = FALSE; - PyObject *func, *args; - PyObject *retobj; - PyObject *params; - guint i; - - state = pyglib_gil_state_ensure(); - - /* construct Python tuple for the parameter values */ - params = PyTuple_New(n_param_values); - - for (i = 0; i < n_param_values; i++) { - PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); - - /* error condition */ - if (!item) { - goto out; - } - PyTuple_SetItem(params, i, item); - } - - args = (PyObject *)user_data; - func = PyTuple_GetItem(args, 0); - args = PySequence_Concat(params, PyTuple_GetItem(args, 1)); - Py_DECREF(params); - - /* params passed to function may have extra arguments */ - - retobj = PyObject_CallObject(func, args); - Py_DECREF(args); - if (retobj == NULL) { - PyErr_Print(); - } - - retval = (retobj == Py_True ? TRUE : FALSE); - Py_XDECREF(retobj); -out: - pyglib_gil_state_release(state); - return retval; -} - -static PyObject * -pyg_add_emission_hook(PyGObject *self, PyObject *args) -{ - PyObject *first, *callback, *extra_args, *data, *repr; - gchar *name; - gulong hook_id; - guint sigid; - Py_ssize_t len; - GQuark detail = 0; - GType gtype; - PyObject *pygtype; - - len = PyTuple_Size(args); - if (len < 3) { - PyErr_SetString(PyExc_TypeError, - "gobject.add_emission_hook requires at least 3 arguments"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 3); - if (!PyArg_ParseTuple(first, "OsO:add_emission_hook", - &pygtype, &name, &callback)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - - if ((gtype = pyg_type_from_object(pygtype)) == 0) { - return NULL; - } - if (!PyCallable_Check(callback)) { - PyErr_SetString(PyExc_TypeError, "third argument must be callable"); - return NULL; - } - - if (!g_signal_parse_name(name, gtype, &sigid, &detail, TRUE)) { - repr = PyObject_Repr((PyObject*)self); - PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", - PYGLIB_PyUnicode_AsString(repr), - name); - Py_DECREF(repr); - return NULL; - } - extra_args = PySequence_GetSlice(args, 3, len); - if (extra_args == NULL) - return NULL; - - data = Py_BuildValue("(ON)", callback, extra_args); - if (data == NULL) - return NULL; - - hook_id = g_signal_add_emission_hook(sigid, detail, - marshal_emission_hook, - data, - (GDestroyNotify)pyg_destroy_notify); - - return PyLong_FromUnsignedLong(hook_id); -} - -static PyObject * -pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) -{ - Py_INCREF(metaclass); - PyGObject_MetaType = metaclass; - Py_INCREF(metaclass); - - Py_TYPE(&PyGObject_Type) = metaclass; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -pyg__gvalue_get(PyObject *module, PyObject *pygvalue) -{ - if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) { - PyErr_SetString (PyExc_TypeError, "Expected GValue argument."); - return NULL; - } - - return pyg_value_as_pyobject (pyg_boxed_get(pygvalue, GValue), - /*copy_boxed=*/ TRUE); -} - -static PyObject * -pyg__gvalue_set(PyObject *module, PyObject *args) -{ - PyObject *pygvalue; - PyObject *pyobject; - - if (!PyArg_ParseTuple (args, "OO:_gobject._gvalue_set", - &pygvalue, &pyobject)) - return NULL; - - if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) { - PyErr_SetString (PyExc_TypeError, "Expected GValue argument."); - return NULL; - } - - if (pyg_value_from_pyobject_with_error (pyg_boxed_get (pygvalue, GValue), - pyobject) == -1) - return NULL; - - Py_RETURN_NONE; -} - -static PyMethodDef _gobject_functions[] = { - { "type_name", pyg_type_name, METH_VARARGS }, - { "type_from_name", pyg_type_from_name, METH_VARARGS }, - { "type_is_a", pyg_type_is_a, METH_VARARGS }, - { "type_register", _wrap_pyg_type_register, METH_VARARGS }, - { "signal_new", pyg_signal_new, METH_VARARGS }, - { "signal_query", - (PyCFunction)pyg_signal_query, METH_VARARGS|METH_KEYWORDS }, - { "list_properties", - pyg_object_class_list_properties, METH_VARARGS }, - { "new", - (PyCFunction)pyg_object_new, METH_VARARGS|METH_KEYWORDS }, - { "signal_accumulator_true_handled", - (PyCFunction)pyg_signal_accumulator_true_handled, METH_VARARGS }, - { "add_emission_hook", - (PyCFunction)pyg_add_emission_hook, METH_VARARGS }, - { "_install_metaclass", - (PyCFunction)pyg__install_metaclass, METH_O }, - { "_gvalue_get", - (PyCFunction)pyg__gvalue_get, METH_O }, - { "_gvalue_set", - (PyCFunction)pyg__gvalue_set, METH_VARARGS }, - - { NULL, NULL, 0 } -}; - - -/* ----------------- Constant extraction ------------------------ */ - -/** - * pyg_constant_strip_prefix: - * @name: the constant name. - * @strip_prefix: the prefix to strip. - * - * Advances the pointer @name by strlen(@strip_prefix) characters. If - * the resulting name does not start with a letter or underscore, the - * @name pointer will be rewound. This is to ensure that the - * resulting name is a valid identifier. Hence the returned string is - * a pointer into the string @name. - * - * Returns: the stripped constant name. - */ -const gchar * -pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix) -{ - gint prefix_len; - guint i; - - prefix_len = strlen(strip_prefix); - - /* Check so name starts with strip_prefix, if it doesn't: - * return the rest of the part which doesn't match - */ - for (i = 0; i < prefix_len; i++) { - if (name[i] != strip_prefix[i] && name[i] != '_') { - return &name[i]; - } - } - - /* strip off prefix from value name, while keeping it a valid - * identifier */ - for (i = prefix_len; i >= 0; i--) { - if (g_ascii_isalpha(name[i]) || name[i] == '_') { - return &name[i]; - } - } - return name; -} - -/** - * pyg_enum_add_constants: - * @module: a Python module - * @enum_type: the GType of the enumeration. - * @strip_prefix: the prefix to strip from the constant names. - * - * Adds constants to the given Python module for each value name of - * the enumeration. A prefix will be stripped from each enum name. - */ -static void -pyg_enum_add_constants(PyObject *module, GType enum_type, - const gchar *strip_prefix) -{ - GEnumClass *eclass; - guint i; - - if (!G_TYPE_IS_ENUM(enum_type)) { - if (G_TYPE_IS_FLAGS(enum_type)) /* See bug #136204 */ - pyg_flags_add_constants(module, enum_type, strip_prefix); - else - g_warning("`%s' is not an enum type", g_type_name(enum_type)); - return; - } - g_return_if_fail (strip_prefix != NULL); - - eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); - - for (i = 0; i < eclass->n_values; i++) { - const gchar *name = eclass->values[i].value_name; - gint value = eclass->values[i].value; - - PyModule_AddIntConstant(module, - (char*) pyg_constant_strip_prefix(name, strip_prefix), - (long) value); - } - - g_type_class_unref(eclass); -} - -/** - * pyg_flags_add_constants: - * @module: a Python module - * @flags_type: the GType of the flags type. - * @strip_prefix: the prefix to strip from the constant names. - * - * Adds constants to the given Python module for each value name of - * the flags set. A prefix will be stripped from each flag name. - */ -static void -pyg_flags_add_constants(PyObject *module, GType flags_type, - const gchar *strip_prefix) -{ - GFlagsClass *fclass; - guint i; - - if (!G_TYPE_IS_FLAGS(flags_type)) { - if (G_TYPE_IS_ENUM(flags_type)) /* See bug #136204 */ - pyg_enum_add_constants(module, flags_type, strip_prefix); - else - g_warning("`%s' is not an flags type", g_type_name(flags_type)); - return; - } - g_return_if_fail (strip_prefix != NULL); - - fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type)); - - for (i = 0; i < fclass->n_values; i++) { - const gchar *name = fclass->values[i].value_name; - guint value = fclass->values[i].value; - - PyModule_AddIntConstant(module, - (char*) pyg_constant_strip_prefix(name, strip_prefix), - (long) value); - } - - g_type_class_unref(fclass); -} - -/** - * pyg_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 gobject.GError Python exception will be raised, and - * the GError cleared. - * - * Returns: True if an error was set. - * - * Deprecated: Since 2.16, use pyglib_error_check instead. - */ -gboolean -pyg_error_check(GError **error) -{ -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "pyg_error_check is deprecated, use " - "pyglib_error_check instead")) - return NULL; -#endif - return pyglib_error_check(error); -} - -/** - * pyg_gerror_exception_check: - * @error: a standard GLib GError ** output parameter - * - * Checks to see if a GError exception has been raised, and if so - * translates the python exception to a standard GLib GError. If the - * raised exception is not a GError then PyErr_Print() is called. - * - * Returns: 0 if no exception has been raised, -1 if it is a - * valid gobject.GError, -2 otherwise. - * - * Deprecated: Since 2.16, use pyglib_gerror_exception_check instead. - */ -gboolean -pyg_gerror_exception_check(GError **error) -{ -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "pyg_gerror_exception_check is deprecated, use " - "pyglib_gerror_exception_check instead")) - return NULL; -#endif - return pyglib_gerror_exception_check(error); -} - -/** - * pyg_parse_constructor_args: helper function for PyGObject constructors - * @obj_type: GType of the GObject, for parameter introspection - * @arg_names: %NULL-terminated array of constructor argument names - * @prop_names: %NULL-terminated array of property names, with direct - * correspondence to @arg_names - * @params: GParameter array where parameters will be placed; length - * of this array must be at least equal to the number of - * arguments/properties - * @nparams: output parameter to contain actual number of arguments found - * @py_args: array of PyObject* containing the actual constructor arguments - * - * Parses an array of PyObject's and creates a GParameter array - * - * Return value: %TRUE if all is successful, otherwise %FALSE and - * python exception set. - **/ -static gboolean -pyg_parse_constructor_args(GType obj_type, - char **arg_names, - char **prop_names, - GParameter *params, - guint *nparams, - PyObject **py_args) -{ - guint arg_i, param_i; - GObjectClass *oclass; - - oclass = g_type_class_ref(obj_type); - g_return_val_if_fail(oclass, FALSE); - - for (param_i = arg_i = 0; arg_names[arg_i]; ++arg_i) { - GParamSpec *spec; - if (!py_args[arg_i]) - continue; - spec = g_object_class_find_property(oclass, prop_names[arg_i]); - params[param_i].name = prop_names[arg_i]; - g_value_init(¶ms[param_i].value, spec->value_type); - if (pyg_value_from_pyobject(¶ms[param_i].value, py_args[arg_i]) == -1) { - int i; - PyErr_Format(PyExc_TypeError, "could not convert parameter '%s' of type '%s'", - arg_names[arg_i], g_type_name(spec->value_type)); - g_type_class_unref(oclass); - for (i = 0; i < param_i; ++i) - g_value_unset(¶ms[i].value); - return FALSE; - } - ++param_i; - } - g_type_class_unref(oclass); - *nparams = param_i; - return TRUE; -} - -PyObject * -pyg_integer_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - gboolean t; - - switch (op) { - case Py_EQ: t = PYGLIB_PyLong_AS_LONG(v) == PYGLIB_PyLong_AS_LONG(w); break; - case Py_NE: t = PYGLIB_PyLong_AS_LONG(v) != PYGLIB_PyLong_AS_LONG(w); break; - case Py_LE: t = PYGLIB_PyLong_AS_LONG(v) <= PYGLIB_PyLong_AS_LONG(w); break; - case Py_GE: t = PYGLIB_PyLong_AS_LONG(v) >= PYGLIB_PyLong_AS_LONG(w); break; - case Py_LT: t = PYGLIB_PyLong_AS_LONG(v) < PYGLIB_PyLong_AS_LONG(w); break; - case Py_GT: t = PYGLIB_PyLong_AS_LONG(v) > PYGLIB_PyLong_AS_LONG(w); break; - default: g_assert_not_reached(); - } - - result = t ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - -static void -_log_func(const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data) -{ - if (G_LIKELY(Py_IsInitialized())) - { - PyGILState_STATE state; - PyObject* warning = user_data; - - state = pyglib_gil_state_ensure(); - PyErr_Warn(warning, (char *) message); - pyglib_gil_state_release(state); - } else - g_log_default_handler(log_domain, log_level, message, user_data); -} - -static void -add_warning_redirection(const char *domain, - PyObject *warning) -{ - g_return_if_fail(domain != NULL); - g_return_if_fail(warning != NULL); - - if (!log_handlers_disabled) - { - guint handler; - gpointer old_handler; - - if (!log_handlers) - log_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - - if ((old_handler = g_hash_table_lookup(log_handlers, domain))) - g_log_remove_handler(domain, GPOINTER_TO_UINT(old_handler)); - - handler = g_log_set_handler(domain, G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING, - _log_func, warning); - g_hash_table_insert(log_handlers, g_strdup(domain), GUINT_TO_POINTER(handler)); - } -} - -static void -remove_handler(gpointer domain, - gpointer handler, - gpointer unused) -{ - g_log_remove_handler(domain, GPOINTER_TO_UINT(handler)); -} - -static void -disable_warning_redirections(void) -{ - log_handlers_disabled = TRUE; - - if (log_handlers) - { - g_hash_table_foreach(log_handlers, remove_handler, NULL); - g_hash_table_destroy(log_handlers); - log_handlers = NULL; - } -} - -/* ----------------- gobject module initialisation -------------- */ - -struct _PyGObject_Functions pygobject_api_functions = { - pygobject_register_class, - pygobject_register_wrapper, - pygobject_lookup_class, - pygobject_new, - - pyg_closure_new, - pygobject_watch_closure, - pyg_destroy_notify, - - pyg_type_from_object, - pyg_type_wrapper_new, - pyg_enum_get_value, - pyg_flags_get_value, - pyg_register_gtype_custom, - pyg_value_from_pyobject, - pyg_value_as_pyobject, - - pyg_register_interface, - - &PyGBoxed_Type, - pyg_register_boxed, - pyg_boxed_new, - - &PyGPointer_Type, - pyg_register_pointer, - pyg_pointer_new, - - pyg_enum_add_constants, - pyg_flags_add_constants, - - pyg_constant_strip_prefix, - - pyg_error_check, - - _pyg_set_thread_block_funcs, - (PyGThreadBlockFunc)0, /* block_threads */ - (PyGThreadBlockFunc)0, /* unblock_threads */ - - &PyGParamSpec_Type, - pyg_param_spec_new, - pyg_param_spec_from_object, - - pyg_pyobj_to_unichar_conv, - pyg_parse_constructor_args, - pyg_param_gvalue_as_pyobject, - pyg_param_gvalue_from_pyobject, - - &PyGEnum_Type, - pyg_enum_add, - pyg_enum_from_gtype, - - &PyGFlags_Type, - pyg_flags_add, - pyg_flags_from_gtype, - - /* threads_enabled */ -#ifdef DISABLE_THREADING - FALSE, -#else - TRUE, -#endif - - pygobject_enable_threads, - pygobject_gil_state_ensure, - pygobject_gil_state_release, - pyg_register_class_init, - pyg_register_interface_info, - - pyg_closure_set_exception_handler, - - add_warning_redirection, - disable_warning_redirections, - - NULL, /* previously type_register_custom */ - - pyg_gerror_exception_check, - - pyglib_option_group_new, - pyg_type_from_object_strict, - - pygobject_new_full, - &PyGObject_Type, - - pyg_value_from_pyobject_with_error -}; - -/* for addon libraries ... */ -static void -pygobject_register_api(PyObject *d) -{ - PyObject *api; - - api = PYGLIB_CPointer_WrapPointer(&pygobject_api_functions, "gobject._PyGObject_API"); - PyDict_SetItemString(d, "_PyGObject_API", api); - Py_DECREF(api); -} - -/* some constants */ -static void -pygobject_register_constants(PyObject *m) -{ - /* PyFloat_ return a new ref, and add object takes the ref */ - PyModule_AddObject(m, "G_MINFLOAT", PyFloat_FromDouble(G_MINFLOAT)); - PyModule_AddObject(m, "G_MAXFLOAT", PyFloat_FromDouble(G_MAXFLOAT)); - PyModule_AddObject(m, "G_MINDOUBLE", PyFloat_FromDouble(G_MINDOUBLE)); - PyModule_AddObject(m, "G_MAXDOUBLE", PyFloat_FromDouble(G_MAXDOUBLE)); - PyModule_AddIntConstant(m, "G_MINSHORT", G_MINSHORT); - PyModule_AddIntConstant(m, "G_MAXSHORT", G_MAXSHORT); - PyModule_AddIntConstant(m, "G_MAXUSHORT", G_MAXUSHORT); - PyModule_AddIntConstant(m, "G_MININT", G_MININT); - PyModule_AddIntConstant(m, "G_MAXINT", G_MAXINT); - PyModule_AddObject(m, "G_MAXUINT", PyLong_FromUnsignedLong(G_MAXUINT)); - PyModule_AddObject(m, "G_MINLONG", PyLong_FromLong(G_MINLONG)); - PyModule_AddObject(m, "G_MAXLONG", PyLong_FromLong(G_MAXLONG)); - PyModule_AddObject(m, "G_MAXULONG", PyLong_FromUnsignedLong(G_MAXULONG)); - PyModule_AddObject(m, "G_MAXSIZE", PyLong_FromSize_t(G_MAXSIZE)); - PyModule_AddObject(m, "G_MAXSSIZE", PyLong_FromSsize_t(G_MAXSSIZE)); - PyModule_AddObject(m, "G_MINSSIZE", PyLong_FromSsize_t(G_MINSSIZE)); - PyModule_AddObject(m, "G_MINOFFSET", PyLong_FromLongLong(G_MINOFFSET)); - PyModule_AddObject(m, "G_MAXOFFSET", PyLong_FromLongLong(G_MAXOFFSET)); - - PyModule_AddIntConstant(m, "SIGNAL_RUN_FIRST", G_SIGNAL_RUN_FIRST); - PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE); - - /* The rest of the types are set in __init__.py */ - PyModule_AddObject(m, "TYPE_INVALID", pyg_type_wrapper_new(G_TYPE_INVALID)); - PyModule_AddObject(m, "TYPE_GSTRING", pyg_type_wrapper_new(G_TYPE_GSTRING)); -} - -/* features */ -static void -pygobject_register_features(PyObject *d) -{ - PyObject *features; - - features = PyDict_New(); - PyDict_SetItemString(features, "generic-c-marshaller", Py_True); - PyDict_SetItemString(d, "features", features); - Py_DECREF(features); -} - -static void -pygobject_register_version_tuples(PyObject *d) -{ - PyObject *tuple; - - /* pygobject version */ - tuple = Py_BuildValue ("(iii)", - PYGOBJECT_MAJOR_VERSION, - PYGOBJECT_MINOR_VERSION, - PYGOBJECT_MICRO_VERSION); - PyDict_SetItemString(d, "pygobject_version", tuple); -} - -static void -pygobject_register_warnings(PyObject *d) -{ - PyObject *warning; - - warning = PyErr_NewException("gobject.Warning", PyExc_Warning, NULL); - PyDict_SetItemString(d, "Warning", warning); - add_warning_redirection("GLib", warning); - add_warning_redirection("GLib-GObject", warning); - add_warning_redirection("GThread", warning); -} - - -PYGLIB_MODULE_START(_gobject, "_gobject") -{ - PyObject *d; - - pyglib_init(); - - d = PyModule_GetDict(module); - pygobject_register_api(d); - pygobject_register_constants(module); - pygobject_register_features(d); - pygobject_register_version_tuples(d); - pygobject_register_warnings(d); - pygobject_type_register_types(d); - pygobject_object_register_types(d); - pygobject_interface_register_types(d); - pygobject_paramspec_register_types(d); - pygobject_boxed_register_types(d); - pygobject_pointer_register_types(d); - pygobject_enum_register_types(d); - pygobject_flags_register_types(d); -} -PYGLIB_MODULE_END diff --git a/gi/_gobject/propertyhelper.py b/gi/_gobject/propertyhelper.py index c9400df0..0ee0d373 100644 --- a/gi/_gobject/propertyhelper.py +++ b/gi/_gobject/propertyhelper.py @@ -21,7 +21,8 @@ import sys -from . import _gobject +import gi._gi +_gobject = gi._gi._gobject from .constants import \ TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, \ @@ -30,10 +31,15 @@ from .constants import \ TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, \ TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \ TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV, TYPE_VARIANT -from ._gobject import \ - G_MAXFLOAT, G_MAXDOUBLE, \ - G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, \ - G_MAXULONG + +G_MAXFLOAT = _gobject.G_MAXFLOAT +G_MAXDOUBLE = _gobject.G_MAXDOUBLE +G_MININT = _gobject.G_MININT +G_MAXINT = _gobject.G_MAXINT +G_MAXUINT = _gobject.G_MAXUINT +G_MINLONG = _gobject.G_MINLONG +G_MAXLONG = _gobject.G_MAXLONG +G_MAXULONG = _gobject.G_MAXULONG if sys.version_info >= (3, 0): _basestring = str diff --git a/gi/_gobject/pygboxed.c b/gi/_gobject/pygboxed.c deleted file mode 100644 index 541e77b1..00000000 --- a/gi/_gobject/pygboxed.c +++ /dev/null @@ -1,235 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * pygboxed.c: wrapper for GBoxed - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "pygobject-private.h" -#include "pygboxed.h" - -#include "pygi.h" - -GQuark pygboxed_type_key; -GQuark pygboxed_marshal_key; - -PYGLIB_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed); - -static void -pyg_boxed_dealloc(PyGBoxed *self) -{ - if (self->free_on_dealloc && self->boxed) { - PyGILState_STATE state = pyglib_gil_state_ensure(); - g_boxed_free(self->gtype, self->boxed); - pyglib_gil_state_release(state); - } - - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject* -pyg_boxed_richcompare(PyObject *self, PyObject *other, int op) -{ - if (Py_TYPE(self) == Py_TYPE(other) && - PyObject_IsInstance(self, (PyObject*)&PyGBoxed_Type)) - return _pyglib_generic_ptr_richcompare(((PyGBoxed*)self)->boxed, - ((PyGBoxed*)other)->boxed, - op); - else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - - -static long -pyg_boxed_hash(PyGBoxed *self) -{ - return (long)self->boxed; -} - -static PyObject * -pyg_boxed_repr(PyGBoxed *self) -{ - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), - (long)self->boxed); - return PYGLIB_PyUnicode_FromString(buf); -} - -static int -pyg_boxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) -{ - gchar buf[512]; - - if (!PyArg_ParseTuple(args, ":GBoxed.__init__")) - return -1; - - self->boxed = NULL; - self->gtype = 0; - self->free_on_dealloc = FALSE; - - g_snprintf(buf, sizeof(buf), "%s can not be constructed", - Py_TYPE(self)->tp_name); - PyErr_SetString(PyExc_NotImplementedError, buf); - return -1; -} - -static void -pyg_boxed_free(PyObject *op) -{ - PyObject_FREE(op); -} - -static PyObject * -pyg_boxed_copy(PyGBoxed *self) -{ - return pyg_boxed_new (self->gtype, self->boxed, TRUE, TRUE); -} - - - -static PyMethodDef pygboxed_methods[] = { - { "copy", (PyCFunction) pyg_boxed_copy, METH_NOARGS }, - { NULL, NULL, 0 } -}; - - -/** - * pyg_register_boxed: - * @dict: the module dictionary to store the wrapper class. - * @class_name: the Python name for the wrapper class. - * @boxed_type: the GType of the boxed type being wrapped. - * @type: the wrapper class. - * - * Registers a wrapper for a boxed type. The wrapper class will be a - * subclass of gobject.GBoxed, and a reference to the wrapper class - * will be stored in the provided module dictionary. - */ -void -pyg_register_boxed(PyObject *dict, const gchar *class_name, - GType boxed_type, PyTypeObject *type) -{ - PyObject *o; - - g_return_if_fail(dict != NULL); - g_return_if_fail(class_name != NULL); - g_return_if_fail(boxed_type != 0); - - if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_boxed_dealloc; - - Py_TYPE(type) = &PyType_Type; - type->tp_base = &PyGBoxed_Type; - - if (PyType_Ready(type) < 0) { - g_warning("could not get type `%s' ready", type->tp_name); - return; - } - - PyDict_SetItemString(type->tp_dict, "__gtype__", - o=pyg_type_wrapper_new(boxed_type)); - Py_DECREF(o); - - g_type_set_qdata(boxed_type, pygboxed_type_key, type); - - PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); -} - -/** - * pyg_boxed_new: - * @boxed_type: the GType of the boxed value. - * @boxed: the boxed value. - * @copy_boxed: whether the new boxed wrapper should hold a copy of the value. - * @own_ref: whether the boxed wrapper should own the boxed value. - * - * Creates a wrapper for a boxed value. If @copy_boxed is set to - * True, the wrapper will hold a copy of the value, instead of the - * value itself. If @own_ref is True, then the value held by the - * wrapper will be freed when the wrapper is deallocated. If - * @copy_boxed is True, then @own_ref must also be True. - * - * Returns: the boxed wrapper. - */ -PyObject * -pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, - gboolean own_ref) -{ - PyGILState_STATE state; - PyGBoxed *self; - PyTypeObject *tp; - - g_return_val_if_fail(boxed_type != 0, NULL); - g_return_val_if_fail(!copy_boxed || (copy_boxed && own_ref), NULL); - - state = pyglib_gil_state_ensure(); - - if (!boxed) { - Py_INCREF(Py_None); - pyglib_gil_state_release(state); - return Py_None; - } - - tp = g_type_get_qdata(boxed_type, pygboxed_type_key); - - if (!tp) - tp = (PyTypeObject *)pygi_type_import_by_g_type(boxed_type); - - if (!tp) - tp = (PyTypeObject *)&PyGBoxed_Type; /* fallback */ - - self = (PyGBoxed *)tp->tp_alloc(tp, 0); - - if (self == NULL) { - pyglib_gil_state_release(state); - return NULL; - } - - if (copy_boxed) - boxed = g_boxed_copy(boxed_type, boxed); - self->boxed = boxed; - self->gtype = boxed_type; - self->free_on_dealloc = own_ref; - - pyglib_gil_state_release(state); - - return (PyObject *)self; -} - -void -pygobject_boxed_register_types(PyObject *d) -{ - pygboxed_type_key = g_quark_from_static_string("PyGBoxed::class"); - pygboxed_marshal_key = g_quark_from_static_string("PyGBoxed::marshal"); - - PyGBoxed_Type.tp_dealloc = (destructor)pyg_boxed_dealloc; - PyGBoxed_Type.tp_richcompare = pyg_boxed_richcompare; - PyGBoxed_Type.tp_repr = (reprfunc)pyg_boxed_repr; - PyGBoxed_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyGBoxed_Type.tp_methods = pygboxed_methods; - PyGBoxed_Type.tp_init = (initproc)pyg_boxed_init; - PyGBoxed_Type.tp_free = (freefunc)pyg_boxed_free; - PyGBoxed_Type.tp_hash = (hashfunc)pyg_boxed_hash; - - PYGOBJECT_REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED); -} diff --git a/gi/_gobject/pygboxed.h b/gi/_gobject/pygboxed.h deleted file mode 100644 index 8433b9de..00000000 --- a/gi/_gobject/pygboxed.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_BOXED_H__ -#define __PYGOBJECT_BOXED_H__ - -void pygobject_boxed_register_types(PyObject *d); - -#endif /* __PYGOBJECT_BOXED_H__ */ diff --git a/gi/_gobject/pygenum.c b/gi/_gobject/pygenum.c deleted file mode 100644 index 89e3a066..00000000 --- a/gi/_gobject/pygenum.c +++ /dev/null @@ -1,371 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * Copyright (C) 2004 Johan Dahlin - * - * pygenum.c: GEnum wrapper - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "pygobject-private.h" -#include "pygi.h" - -#include "pygenum.h" - -GQuark pygenum_class_key; - -PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum); - -static PyObject * -pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval) -{ - PyObject *args, *item; - args = Py_BuildValue("(O)", intval); - item = (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL); - Py_DECREF(args); - if (!item) - return NULL; - ((PyGEnum*)item)->gtype = gtype; - - return item; -} - -static PyObject * -pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) -{ - static char warning[256]; - - if (!PYGLIB_PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) { - g_snprintf(warning, sizeof(warning), "comparing different enum types: %s and %s", - g_type_name(self->gtype), g_type_name(((PyGEnum*)other)->gtype)); - if (PyErr_Warn(PyExc_Warning, warning)) - return NULL; - } - - return pyg_integer_richcompare((PyObject *)self, other, op); -} - -static PyObject * -pyg_enum_repr(PyGEnum *self) -{ - GEnumClass *enum_class; - const char *value; - guint index; - static char tmp[256]; - long l; - - enum_class = g_type_class_ref(self->gtype); - g_assert(G_IS_ENUM_CLASS(enum_class)); - - l = PYGLIB_PyLong_AS_LONG(self); - for (index = 0; index < enum_class->n_values; index++) - if (l == enum_class->values[index].value) - break; - - value = enum_class->values[index].value_name; - if (value) - sprintf(tmp, "", value, g_type_name(self->gtype)); - else - sprintf(tmp, "", PYGLIB_PyLong_AS_LONG(self), g_type_name(self->gtype)); - - g_type_class_unref(enum_class); - - return PYGLIB_PyUnicode_FromString(tmp); -} - -static PyObject * -pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "value", NULL }; - long value; - PyObject *pytc, *values, *ret, *intvalue; - GType gtype; - GEnumClass *eclass; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value)) - return NULL; - - pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); - if (!pytc) - return NULL; - - if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { - Py_DECREF(pytc); - PyErr_SetString(PyExc_TypeError, - "__gtype__ attribute not a typecode"); - return NULL; - } - - gtype = pyg_type_from_object(pytc); - Py_DECREF(pytc); - - eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); - - /* A check that 0 < value < eclass->n_values was here but got - * removed: enumeration values do not need to be consequitive, - * e.g. GtkPathPriorityType values are not. - */ - - values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); - if (!values) { - g_type_class_unref(eclass); - return NULL; - } - - /* Note that size of __enum_values__ dictionary can easily be less - * than 'n_values'. This happens if some values of the enum are - * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH. - * Johan said that "In retrospect, using a dictionary to store the - * values might not have been that good", but we need to keep - * backward compatibility. - */ - if (!PyDict_Check(values) || PyDict_Size(values) > eclass->n_values) { - PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed"); - Py_DECREF(values); - g_type_class_unref(eclass); - return NULL; - } - - g_type_class_unref(eclass); - - intvalue = PYGLIB_PyLong_FromLong(value); - ret = PyDict_GetItem(values, intvalue); - Py_DECREF(intvalue); - Py_DECREF(values); - if (ret) - Py_INCREF(ret); - else - PyErr_Format(PyExc_ValueError, "invalid enum value: %ld", value); - - return ret; -} - -PyObject* -pyg_enum_from_gtype (GType gtype, int value) -{ - PyObject *pyclass, *values, *retval, *intvalue; - - g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); - - /* Get a wrapper class by: - * 1. check for one attached to the gtype - * 2. lookup one in a typelib - * 3. creating a new one - */ - pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); - if (!pyclass) - pyclass = pygi_type_import_by_g_type(gtype); - if (!pyclass) - pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype); - if (!pyclass) - return PYGLIB_PyLong_FromLong(value); - - values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, - "__enum_values__"); - intvalue = PYGLIB_PyLong_FromLong(value); - retval = PyDict_GetItem(values, intvalue); - if (retval) { - Py_INCREF(retval); - } - else { - PyErr_Clear(); - retval = pyg_enum_val_new(pyclass, gtype, intvalue); - } - Py_DECREF(intvalue); - - return retval; -} - -/* - * pyg_enum_add - * Dynamically create a class derived from PyGEnum based on the given GType. - */ -PyObject * -pyg_enum_add (PyObject * module, - const char * typename, - const char * strip_prefix, - GType gtype) -{ - PyGILState_STATE state; - PyObject *instance_dict, *stub, *values, *o; - GEnumClass *eclass; - int i; - - g_return_val_if_fail(typename != NULL, NULL); - if (!g_type_is_a (gtype, G_TYPE_ENUM)) { - PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'", - g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype))); - return NULL; - } - - state = pyglib_gil_state_ensure(); - - /* Create a new type derived from GEnum. This is the same as: - * >>> stub = type(typename, (GEnum,), {}) - */ - instance_dict = PyDict_New(); - stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", - typename, (PyObject *)&PyGEnum_Type, - instance_dict); - Py_DECREF(instance_dict); - if (!stub) { - PyErr_SetString(PyExc_RuntimeError, "can't create const"); - pyglib_gil_state_release(state); - return NULL; - } - - ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; - ((PyTypeObject *)stub)->tp_new = pyg_enum_new; - - if (module) - PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, - "__module__", - PYGLIB_PyUnicode_FromString(PyModule_GetName(module))); - - g_type_set_qdata(gtype, pygenum_class_key, stub); - - o = pyg_type_wrapper_new(gtype); - PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); - Py_DECREF(o); - - if (module) { - /* Add it to the module name space */ - PyModule_AddObject(module, (char*)typename, stub); - Py_INCREF(stub); - } - - /* Register enum values */ - eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); - - values = PyDict_New(); - for (i = 0; i < eclass->n_values; i++) { - PyObject *item, *intval; - - intval = PYGLIB_PyLong_FromLong(eclass->values[i].value); - item = pyg_enum_val_new(stub, gtype, intval); - PyDict_SetItem(values, intval, item); - Py_DECREF(intval); - - if (module) { - char *prefix; - - prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); - PyModule_AddObject(module, prefix, item); - g_free(prefix); - - Py_INCREF(item); - } - } - - PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, - "__enum_values__", values); - Py_DECREF(values); - - g_type_class_unref(eclass); - - pyglib_gil_state_release(state); - return stub; -} - -static PyObject * -pyg_enum_reduce(PyObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, ":GEnum.__reduce__")) - return NULL; - - return Py_BuildValue("(O(i)O)", Py_TYPE(self), PYGLIB_PyLong_AsLong(self), - PyObject_GetAttrString(self, "__dict__")); -} - -static PyObject * -pyg_enum_get_value_name(PyGEnum *self, void *closure) -{ - GEnumClass *enum_class; - GEnumValue *enum_value; - PyObject *retval; - - enum_class = g_type_class_ref(self->gtype); - g_assert(G_IS_ENUM_CLASS(enum_class)); - - enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self)); - - retval = PYGLIB_PyUnicode_FromString(enum_value->value_name); - g_type_class_unref(enum_class); - - return retval; -} - -static PyObject * -pyg_enum_get_value_nick(PyGEnum *self, void *closure) -{ - GEnumClass *enum_class; - GEnumValue *enum_value; - PyObject *retval; - - enum_class = g_type_class_ref(self->gtype); - g_assert(G_IS_ENUM_CLASS(enum_class)); - - enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self)); - - retval = PYGLIB_PyUnicode_FromString(enum_value->value_nick); - g_type_class_unref(enum_class); - - return retval; -} - - -static PyMethodDef pyg_enum_methods[] = { - { "__reduce__", (PyCFunction)pyg_enum_reduce, METH_VARARGS }, - { NULL, NULL, 0 } -}; - -static PyGetSetDef pyg_enum_getsets[] = { - { "value_name", (getter)pyg_enum_get_value_name, (setter)0 }, - { "value_nick", (getter)pyg_enum_get_value_nick, (setter)0 }, - { NULL, 0, 0 } -}; - -void -pygobject_enum_register_types(PyObject *d) -{ - pygenum_class_key = g_quark_from_static_string("PyGEnum::class"); - - PyGEnum_Type.tp_base = &PYGLIB_PyLong_Type; -#if PY_VERSION_HEX < 0x03000000 - PyGEnum_Type.tp_new = pyg_enum_new; -#else - PyGEnum_Type.tp_new = PyLong_Type.tp_new; - PyGEnum_Type.tp_hash = PyLong_Type.tp_hash; -#endif - PyGEnum_Type.tp_repr = (reprfunc)pyg_enum_repr; - PyGEnum_Type.tp_str = (reprfunc)pyg_enum_repr; - PyGEnum_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyGEnum_Type.tp_richcompare = (richcmpfunc)pyg_enum_richcompare; - PyGEnum_Type.tp_methods = pyg_enum_methods; - PyGEnum_Type.tp_getset = pyg_enum_getsets; - PYGOBJECT_REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM); -} diff --git a/gi/_gobject/pygenum.h b/gi/_gobject/pygenum.h deleted file mode 100644 index 05588312..00000000 --- a/gi/_gobject/pygenum.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_ENUM_H__ -#define __PYGOBJECT_ENUM_H__ - -void pygobject_enum_register_types(PyObject *d); - -#endif /* __PYGOBJECT_ENUM_H__ */ diff --git a/gi/_gobject/pygflags.c b/gi/_gobject/pygflags.c deleted file mode 100644 index bdeaae74..00000000 --- a/gi/_gobject/pygflags.c +++ /dev/null @@ -1,497 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * Copyright (C) 2004 Johan Dahlin - * - * pygflags.c: GFlags wrapper - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "pygobject-private.h" -#include "pygflags.h" - -#include "pygi.h" - -GQuark pygflags_class_key; - -PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags); - -static PyObject * -pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval) -{ - PyObject *args, *item; - args = Py_BuildValue("(O)", intval); - g_assert(PyObject_IsSubclass(subclass, (PyObject*) &PyGFlags_Type)); - item = PYGLIB_PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL); - Py_DECREF(args); - if (!item) - return NULL; - ((PyGFlags*)item)->gtype = gtype; - - return item; -} - -static PyObject * -pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op) -{ - static char warning[256]; - - if (!PYGLIB_PyLong_Check(other)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (PyObject_TypeCheck(other, &PyGFlags_Type) && ((PyGFlags*)other)->gtype != self->gtype) { - g_snprintf(warning, sizeof(warning), "comparing different flags types: %s and %s", - g_type_name(self->gtype), g_type_name(((PyGFlags*)other)->gtype)); - if (PyErr_Warn(PyExc_Warning, warning)) - return NULL; - } - - return pyg_integer_richcompare((PyObject *)self, other, op); -} - -static char * -generate_repr(GType gtype, guint value) -{ - GFlagsClass *flags_class; - char *retval = NULL, *tmp; - int i; - - flags_class = g_type_class_ref(gtype); - g_assert(G_IS_FLAGS_CLASS(flags_class)); - - for (i = 0; i < flags_class->n_values; i++) { - /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values, - * we're just ignore them for now otherwise they'll always show up - */ - if (flags_class->values[i].value == 0) - continue; - - if ((value & flags_class->values[i].value) == flags_class->values[i].value) { - if (retval) { - tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name); - g_free(retval); - retval = tmp; - } else { - retval = g_strdup_printf("%s", flags_class->values[i].value_name); - } - } - } - - g_type_class_unref(flags_class); - - return retval; -} - -static PyObject * -pyg_flags_repr(PyGFlags *self) -{ - char *tmp, *retval; - PyObject *pyretval; - - tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self)); - - if (tmp) - retval = g_strdup_printf("", tmp, - g_type_name(self->gtype)); - else - retval = g_strdup_printf("", PYGLIB_PyLong_AsUnsignedLong(self), - g_type_name(self->gtype)); - g_free(tmp); - - pyretval = PYGLIB_PyUnicode_FromString(retval); - g_free(retval); - - return pyretval; -} - -static PyObject * -pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "value", NULL }; - gulong value; - PyObject *pytc, *values, *ret, *pyint; - GType gtype; - GFlagsClass *eclass; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", kwlist, &value)) - return NULL; - - pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); - if (!pytc) - return NULL; - - if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { - Py_DECREF(pytc); - PyErr_SetString(PyExc_TypeError, - "__gtype__ attribute not a typecode"); - return NULL; - } - - gtype = pyg_type_from_object(pytc); - Py_DECREF(pytc); - - eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); - - values = PyObject_GetAttrString((PyObject *)type, "__flags_values__"); - if (!values) { - g_type_class_unref(eclass); - return NULL; - } - - if (!PyDict_Check(values)) { - PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed"); - Py_DECREF(values); - g_type_class_unref(eclass); - return NULL; - } - - g_type_class_unref(eclass); - - pyint = PYGLIB_PyLong_FromUnsignedLong(value); - ret = PyDict_GetItem(values, pyint); - if (!ret) { - PyErr_Clear(); - - ret = pyg_flags_val_new((PyObject *)type, gtype, pyint); - g_assert(ret != NULL); - } else { - Py_INCREF(ret); - } - - Py_DECREF(pyint); - Py_DECREF(values); - - return ret; -} - -PyObject* -pyg_flags_from_gtype (GType gtype, guint value) -{ - PyObject *pyclass, *values, *retval, *pyint; - - if (PyErr_Occurred()) - return PYGLIB_PyLong_FromUnsignedLong(0); - - g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); - - /* Get a wrapper class by: - * 1. check for one attached to the gtype - * 2. lookup one in a typelib - * 3. creating a new one - */ - pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key); - if (!pyclass) - pyclass = pygi_type_import_by_g_type(gtype); - if (!pyclass) - pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype); - if (!pyclass) - return PYGLIB_PyLong_FromUnsignedLong(value); - - values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, - "__flags_values__"); - pyint = PYGLIB_PyLong_FromUnsignedLong(value); - retval = PyDict_GetItem(values, pyint); - if (!retval) { - PyErr_Clear(); - - retval = pyg_flags_val_new(pyclass, gtype, pyint); - g_assert(retval != NULL); - } else { - Py_INCREF(retval); - } - Py_DECREF(pyint); - - return retval; -} - -/* - * pyg_flags_add - * Dynamically create a class derived from PyGFlags based on the given GType. - */ -PyObject * -pyg_flags_add (PyObject * module, - const char * typename, - const char * strip_prefix, - GType gtype) -{ - PyGILState_STATE state; - PyObject *instance_dict, *stub, *values, *o; - GFlagsClass *eclass; - int i; - - g_return_val_if_fail(typename != NULL, NULL); - if (!g_type_is_a(gtype, G_TYPE_FLAGS)) { - g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'", - g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype))); - return NULL; - } - - state = pyglib_gil_state_ensure(); - - /* Create a new type derived from GFlags. This is the same as: - * >>> stub = type(typename, (GFlags,), {}) - */ - instance_dict = PyDict_New(); - stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", - typename, (PyObject *)&PyGFlags_Type, - instance_dict); - Py_DECREF(instance_dict); - if (!stub) { - PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype"); - pyglib_gil_state_release(state); - return NULL; - } - - ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; - ((PyTypeObject *)stub)->tp_new = pyg_flags_new; - - if (module) { - PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, - "__module__", - PYGLIB_PyUnicode_FromString(PyModule_GetName(module))); - - /* Add it to the module name space */ - PyModule_AddObject(module, (char*)typename, stub); - Py_INCREF(stub); - } - g_type_set_qdata(gtype, pygflags_class_key, stub); - - o = pyg_type_wrapper_new(gtype); - PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); - Py_DECREF(o); - - /* Register flag values */ - eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); - - values = PyDict_New(); - for (i = 0; i < eclass->n_values; i++) { - PyObject *item, *intval; - - intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value); - g_assert(PyErr_Occurred() == NULL); - item = pyg_flags_val_new(stub, gtype, intval); - PyDict_SetItem(values, intval, item); - Py_DECREF(intval); - - if (module) { - char *prefix; - - prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); - Py_INCREF(item); - PyModule_AddObject(module, prefix, item); - g_free(prefix); - } - Py_DECREF(item); - } - - PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, - "__flags_values__", values); - Py_DECREF(values); - - g_type_class_unref(eclass); - - pyglib_gil_state_release(state); - - return stub; -} - -static PyObject * -pyg_flags_and(PyGFlags *a, PyGFlags *b) -{ - if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) - return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a, - (PyObject*)b); - - return pyg_flags_from_gtype(a->gtype, - PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b)); -} - -static PyObject * -pyg_flags_or(PyGFlags *a, PyGFlags *b) -{ - if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) - return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a, - (PyObject*)b); - - return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b)); -} - -static PyObject * -pyg_flags_xor(PyGFlags *a, PyGFlags *b) -{ - if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) - return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a, - (PyObject*)b); - - return pyg_flags_from_gtype(a->gtype, - PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b)); - -} - -static PyObject * -pyg_flags_warn (PyObject *self, PyObject *args) -{ - if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type")) - return NULL; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -pyg_flags_get_first_value_name(PyGFlags *self, void *closure) -{ - GFlagsClass *flags_class; - GFlagsValue *flags_value; - PyObject *retval; - - flags_class = g_type_class_ref(self->gtype); - g_assert(G_IS_FLAGS_CLASS(flags_class)); - flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self)); - if (flags_value) - retval = PYGLIB_PyUnicode_FromString(flags_value->value_name); - else { - retval = Py_None; - Py_INCREF(Py_None); - } - g_type_class_unref(flags_class); - - return retval; -} - -static PyObject * -pyg_flags_get_first_value_nick(PyGFlags *self, void *closure) -{ - GFlagsClass *flags_class; - GFlagsValue *flags_value; - PyObject *retval; - - flags_class = g_type_class_ref(self->gtype); - g_assert(G_IS_FLAGS_CLASS(flags_class)); - - flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self)); - if (flags_value) - retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick); - else { - retval = Py_None; - Py_INCREF(Py_None); - } - g_type_class_unref(flags_class); - - return retval; -} - -static PyObject * -pyg_flags_get_value_names(PyGFlags *self, void *closure) -{ - GFlagsClass *flags_class; - PyObject *retval; - int i; - - flags_class = g_type_class_ref(self->gtype); - g_assert(G_IS_FLAGS_CLASS(flags_class)); - - retval = PyList_New(0); - for (i = 0; i < flags_class->n_values; i++) - if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) - PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_name)); - - g_type_class_unref(flags_class); - - return retval; -} - -static PyObject * -pyg_flags_get_value_nicks(PyGFlags *self, void *closure) -{ - GFlagsClass *flags_class; - PyObject *retval; - int i; - - flags_class = g_type_class_ref(self->gtype); - g_assert(G_IS_FLAGS_CLASS(flags_class)); - - retval = PyList_New(0); - for (i = 0; i < flags_class->n_values; i++) - if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) { - PyObject *py_nick = PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick); - PyList_Append(retval, py_nick); - Py_DECREF (py_nick); - } - - g_type_class_unref(flags_class); - - return retval; -} - -static PyGetSetDef pyg_flags_getsets[] = { - { "first_value_name", (getter)pyg_flags_get_first_value_name, (setter)0 }, - { "first_value_nick", (getter)pyg_flags_get_first_value_nick, (setter)0 }, - { "value_names", (getter)pyg_flags_get_value_names, (setter)0 }, - { "value_nicks", (getter)pyg_flags_get_value_nicks, (setter)0 }, - { NULL, 0, 0 } -}; - -static PyNumberMethods pyg_flags_as_number = { - (binaryfunc)pyg_flags_warn, /* nb_add */ - (binaryfunc)pyg_flags_warn, /* nb_subtract */ - (binaryfunc)pyg_flags_warn, /* nb_multiply */ - (binaryfunc)pyg_flags_warn, /* nb_divide */ - (binaryfunc)pyg_flags_warn, /* nb_remainder */ -#if PY_VERSION_HEX < 0x03000000 - (binaryfunc)pyg_flags_warn, /* nb_divmod */ -#endif - (ternaryfunc)pyg_flags_warn, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - 0, /* nb_nonzero */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ - (binaryfunc)pyg_flags_and, /* nb_and */ - (binaryfunc)pyg_flags_xor, /* nb_xor */ - (binaryfunc)pyg_flags_or, /* nb_or */ -}; - -void -pygobject_flags_register_types(PyObject *d) -{ - pygflags_class_key = g_quark_from_static_string("PyGFlags::class"); - - PyGFlags_Type.tp_base = &PYGLIB_PyLong_Type; -#if PY_VERSION_HEX < 0x03000000 - PyGFlags_Type.tp_new = pyg_flags_new; -#else - PyGFlags_Type.tp_new = PyLong_Type.tp_new; - PyGFlags_Type.tp_hash = PyLong_Type.tp_hash; -#endif - PyGFlags_Type.tp_repr = (reprfunc)pyg_flags_repr; - PyGFlags_Type.tp_as_number = &pyg_flags_as_number; - PyGFlags_Type.tp_str = (reprfunc)pyg_flags_repr; - PyGFlags_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyGFlags_Type.tp_richcompare = (richcmpfunc)pyg_flags_richcompare; - PyGFlags_Type.tp_getset = pyg_flags_getsets; - PYGOBJECT_REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS); -} diff --git a/gi/_gobject/pygflags.h b/gi/_gobject/pygflags.h deleted file mode 100644 index e93265cd..00000000 --- a/gi/_gobject/pygflags.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_FLAGS_H__ -#define __PYGOBJECT_FLAGS_H__ - -void pygobject_flags_register_types(PyObject *d); - -#endif /* __PYGOBJECT_FLAGS_H__ */ diff --git a/gi/_gobject/pyginterface.c b/gi/_gobject/pyginterface.c deleted file mode 100644 index eb76ba08..00000000 --- a/gi/_gobject/pyginterface.c +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "pyglib.h" -#include "pygobject-private.h" - -#include "pyginterface.h" - -GQuark pyginterface_type_key; -GQuark pyginterface_info_key; - -PYGLIB_DEFINE_TYPE("gobject.GInterface", PyGInterface_Type, PyObject) - -static int -pyg_interface_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - gchar buf[512]; - - if (!PyArg_ParseTuple(args, ":GInterface.__init__")) - return -1; - - g_snprintf(buf, sizeof(buf), "%s can not be constructed", - Py_TYPE(self)->tp_name); - PyErr_SetString(PyExc_NotImplementedError, buf); - return -1; -} - -static void -pyg_interface_free(PyObject *op) -{ - PyObject_FREE(op); -} - -/** - * pyg_register_interface: - * @dict: a module dictionary. - * @class_name: the class name for the wrapper class. - * @gtype: the GType of the interface. - * @type: the wrapper class for the interface. - * - * Registers a Python class as the wrapper for a GInterface. As a - * convenience it will also place a reference to the wrapper class in - * the provided module dictionary. - */ -void -pyg_register_interface(PyObject *dict, const gchar *class_name, - GType gtype, PyTypeObject *type) -{ - PyObject *o; - - Py_TYPE(type) = &PyType_Type; - type->tp_base = &PyGInterface_Type; - - if (PyType_Ready(type) < 0) { - g_warning("could not ready `%s'", type->tp_name); - return; - } - - if (gtype) { - o = pyg_type_wrapper_new(gtype); - PyDict_SetItemString(type->tp_dict, "__gtype__", o); - Py_DECREF(o); - } - - g_type_set_qdata(gtype, pyginterface_type_key, type); - - PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); - -} - -void -pyg_register_interface_info(GType gtype, const GInterfaceInfo *info) -{ - g_type_set_qdata(gtype, pyginterface_info_key, (gpointer) info); -} - -const GInterfaceInfo * -pyg_lookup_interface_info(GType gtype) -{ - return g_type_get_qdata(gtype, pyginterface_info_key); -} - -void -pygobject_interface_register_types(PyObject *d) -{ - pyginterface_type_key = g_quark_from_static_string("PyGInterface::type"); - pyginterface_info_key = g_quark_from_static_string("PyGInterface::info"); - - PyGInterface_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyGInterface_Type.tp_init = (initproc)pyg_interface_init; - PyGInterface_Type.tp_free = (freefunc)pyg_interface_free; - - PYGOBJECT_REGISTER_GTYPE(d, PyGInterface_Type, "GInterface", G_TYPE_INTERFACE) - - PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", - pyg_object_descr_doc_get()); - PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", - pyg_object_descr_doc_get()); - -} diff --git a/gi/_gobject/pyginterface.h b/gi/_gobject/pyginterface.h deleted file mode 100644 index 0f390c28..00000000 --- a/gi/_gobject/pyginterface.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_INTERFACE_H__ -#define __PYGOBJECT_INTERFACE_H__ - -extern GQuark pyginterface_type_key; -extern GQuark pyginterface_info_key; - -extern PyTypeObject PyGInterface_Type; - -void pyg_register_interface(PyObject *dict, - const gchar *class_name, - GType gtype, - PyTypeObject *type); -const GInterfaceInfo * pyg_lookup_interface_info(GType gtype); -void pyg_register_interface_info(GType gtype, const - GInterfaceInfo *info); -void pygobject_interface_register_types(PyObject *d); - -#endif /* __PYGOBJECT_INTERFACE_H__ */ diff --git a/gi/_gobject/pygobject-private.h b/gi/_gobject/pygobject-private.h deleted file mode 100644 index 294b0f65..00000000 --- a/gi/_gobject/pygobject-private.h +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef _PYGOBJECT_PRIVATE_H_ -#define _PYGOBJECT_PRIVATE_H_ - -#ifdef _PYGOBJECT_H_ -# error "include pygobject.h or pygobject-private.h, but not both" -#endif - -#define _INSIDE_PYGOBJECT_ -#include "pygobject.h" - -#include "pyglib-python-compat.h" - -#define PYGOBJECT_REGISTER_GTYPE(d, type, name, gtype) \ - { \ - PyObject *o; \ - PYGLIB_REGISTER_TYPE(d, type, name); \ - PyDict_SetItemString(type.tp_dict, "__gtype__", \ - o=pyg_type_wrapper_new(gtype)); \ - Py_DECREF(o); \ -} - -/* from gobjectmodule.c */ -extern struct _PyGObject_Functions pygobject_api_functions; - - -#ifndef Py_CLEAR /* since Python 2.4 */ -# define Py_CLEAR(op) \ - do { \ - if (op) { \ - PyObject *tmp = (PyObject *)(op); \ - (op) = NULL; \ - Py_DECREF(tmp); \ - } \ - } while (0) -#endif - -extern GType PY_TYPE_OBJECT; - -extern GQuark pygboxed_type_key; -extern GQuark pygboxed_marshal_key; -extern GQuark pygenum_class_key; -extern GQuark pygflags_class_key; -extern GQuark pyginterface_type_key; -extern GQuark pyginterface_info_key; -extern GQuark pygobject_class_init_key; -extern GQuark pygobject_class_key; -extern GQuark pygobject_wrapper_key; -extern GQuark pygpointer_class_key; -extern GQuark pygobject_has_updated_constructor_key; -extern GQuark pygobject_instance_data_key; -extern GQuark pygobject_custom_key; - -void pygobject_data_free (PyGObjectData *data); -void pyg_destroy_notify (gpointer user_data); -gboolean pyg_handler_marshal (gpointer user_data); -gboolean pyg_error_check (GError **error); -int pygobject_constructv (PyGObject *self, - guint n_parameters, - GParameter *parameters); - -PyObject *pyg_integer_richcompare(PyObject *v, - PyObject *w, - int op); - -gboolean pyg_gerror_exception_check(GError **error); - -void pygobject_ref_float(PyGObject *self); -void pygobject_ref_sink(PyGObject *self); - -/* from pygtype.h */ -extern PyTypeObject PyGTypeWrapper_Type; - -PyObject *pyg_type_wrapper_new (GType type); -GType pyg_type_from_object_strict (PyObject *obj, gboolean strict); -GType pyg_type_from_object (PyObject *obj); - -gint pyg_enum_get_value (GType enum_type, PyObject *obj, gint *val); -gint pyg_flags_get_value (GType flag_type, PyObject *obj, guint *val); -int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr); - -typedef PyObject *(* fromvaluefunc)(const GValue *value); -typedef int (*tovaluefunc)(GValue *value, PyObject *obj); - -void pyg_register_gtype_custom(GType gtype, - fromvaluefunc from_func, - tovaluefunc to_func); -int pyg_value_from_pyobject(GValue *value, PyObject *obj); -int pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj); -PyObject *pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed); -int pyg_param_gvalue_from_pyobject(GValue* value, - PyObject* py_obj, - const GParamSpec* pspec); -PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue, - gboolean copy_boxed, - const GParamSpec* pspec); - -GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data); -void pyg_closure_set_exception_handler(GClosure *closure, - PyClosureExceptionHandler handler); -GClosure *pyg_signal_class_closure_get(void); -GClosure *gclosure_from_pyfunc(PyGObject *object, PyObject *func); - -PyObject *pyg_object_descr_doc_get(void); -void pygobject_object_register_types(PyObject *d); - -extern PyTypeObject *PyGObject_MetaType; - -/* from pygobject.h */ -extern PyTypeObject PyGObject_Type; -extern PyTypeObject PyGProps_Type; -extern PyTypeObject PyGPropsDescr_Type; -extern PyTypeObject PyGPropsIter_Type; - - /* Data that belongs to the GObject instance, not the Python wrapper */ -struct _PyGObjectData { - PyTypeObject *type; /* wrapper type for this instance */ - GSList *closures; -}; - -void pygobject_register_class (PyObject *dict, - const gchar *type_name, - GType gtype, PyTypeObject *type, - PyObject *bases); -void pygobject_register_wrapper (PyObject *self); -PyObject * pygobject_new (GObject *obj); -PyObject * pygobject_new_full (GObject *obj, gboolean steal, gpointer g_class); -void pygobject_sink (GObject *obj); -PyTypeObject *pygobject_lookup_class (GType gtype); -void pygobject_watch_closure (PyObject *self, GClosure *closure); -int pyg_type_register (PyTypeObject *class, - const gchar *type_name); - -/* from pygboxed.c */ -extern PyTypeObject PyGBoxed_Type; - -void pyg_register_boxed (PyObject *dict, const gchar *class_name, - GType boxed_type, PyTypeObject *type); -PyObject * pyg_boxed_new (GType boxed_type, gpointer boxed, - gboolean copy_boxed, gboolean own_ref); - -extern PyTypeObject PyGPointer_Type; - -void pyg_register_pointer (PyObject *dict, const gchar *class_name, - GType pointer_type, PyTypeObject *type); -PyObject * pyg_pointer_new (GType pointer_type, gpointer pointer); - -const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix); - -/* pygflags */ -typedef struct { - PYGLIB_PyLongObject parent; - int zero_pad; /* must always be 0 */ - GType gtype; -} PyGFlags; - -extern PyTypeObject PyGFlags_Type; - -#define PyGFlags_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGFlags_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_FLAGS)) - -extern PyObject * pyg_flags_add (PyObject * module, - const char * type_name, - const char * strip_prefix, - GType gtype); -extern PyObject * pyg_flags_from_gtype (GType gtype, - guint value); - -/* pygenum */ -#define PyGEnum_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGEnum_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM)) - -typedef struct { - PYGLIB_PyLongObject parent; - int zero_pad; /* must always be 0 */ - GType gtype; -} PyGEnum; - -extern PyTypeObject PyGEnum_Type; - -extern PyObject * pyg_enum_add (PyObject * module, - const char * type_name, - const char * strip_prefix, - GType gtype); -extern PyObject * pyg_enum_from_gtype (GType gtype, - int value); - -/* pygtype.c */ -extern gboolean pyg_gtype_is_custom (GType gtype); - -/* pygobject.c */ -extern PyTypeObject PyGObjectWeakRef_Type; - -static inline PyGObjectData * -pyg_object_peek_inst_data(GObject *obj) -{ - return ((PyGObjectData *) - g_object_get_qdata(obj, pygobject_instance_data_key)); -} - -gboolean pygobject_prepare_construct_properties (GObjectClass *class, - PyObject *kwargs, - guint *n_params, - GParameter **params); - - -#endif diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c deleted file mode 100644 index 129f29ab..00000000 --- a/gi/_gobject/pygobject.c +++ /dev/null @@ -1,2473 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * pygobject.c: wrapper for the GObject type. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "pygobject-private.h" -#include "pyginterface.h" -#include "pygparamspec.h" - -#include "pygi.h" - - -static void pygobject_dealloc(PyGObject *self); -static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg); -static int pygobject_clear(PyGObject *self); -static PyObject * pyg_type_get_bases(GType gtype); -static inline int pygobject_clear(PyGObject *self); -static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data); -static inline PyGObjectData * pyg_object_peek_inst_data(GObject *obj); -static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, - gboolean check_for_present); -static void pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, - gboolean check_for_present); -GType PY_TYPE_OBJECT = 0; -GQuark pygobject_custom_key; -GQuark pygobject_class_key; -GQuark pygobject_class_init_key; -GQuark pygobject_wrapper_key; -GQuark pygobject_has_updated_constructor_key; -GQuark pygobject_instance_data_key; - -/* Copied from glib. gobject uses hyphens in property names, but in Python - * we can only represent hyphens as underscores. Convert underscores to - * hyphens for glib compatibility. */ -static void -canonicalize_key (gchar *key) -{ - gchar *p; - - for (p = key; *p != 0; p++) - { - gchar c = *p; - - if (c != '-' && - (c < '0' || c > '9') && - (c < 'A' || c > 'Z') && - (c < 'a' || c > 'z')) - *p = '-'; - } -} - -/* -------------- class <-> wrapper manipulation --------------- */ - -void -pygobject_data_free(PyGObjectData *data) -{ - /* This function may be called after the python interpreter has already - * been shut down. If this happens, we cannot do any python calls, so just - * free the memory. */ - PyGILState_STATE state; - PyThreadState *_save = NULL; - - GSList *closures, *tmp; - - if (Py_IsInitialized()) { - state = pyglib_gil_state_ensure(); - Py_DECREF(data->type); - /* We cannot use Py_BEGIN_ALLOW_THREADS here because this is inside - * a branch. */ - Py_UNBLOCK_THREADS; /* Modifies _save */ - } - - tmp = closures = data->closures; -#ifndef NDEBUG - data->closures = NULL; - data->type = NULL; -#endif - while (tmp) { - GClosure *closure = tmp->data; - - /* we get next item first, because the current link gets - * invalidated by pygobject_unwatch_closure */ - tmp = tmp->next; - g_closure_invalidate(closure); - } - - if (data->closures != NULL) - g_warning("invalidated all closures, but data->closures != NULL !"); - - g_free(data); - - if (Py_IsInitialized()) { - Py_BLOCK_THREADS; /* Restores _save */ - pyglib_gil_state_release(state); - } -} - -static inline PyGObjectData * -pygobject_data_new(void) -{ - PyGObjectData *data; - data = g_new0(PyGObjectData, 1); - return data; -} - -static inline PyGObjectData * -pygobject_get_inst_data(PyGObject *self) -{ - PyGObjectData *inst_data; - - if (G_UNLIKELY(!self->obj)) - return NULL; - inst_data = g_object_get_qdata(self->obj, pygobject_instance_data_key); - if (inst_data == NULL) - { - inst_data = pygobject_data_new(); - - inst_data->type = Py_TYPE(self); - Py_INCREF((PyObject *) inst_data->type); - - g_object_set_qdata_full(self->obj, pygobject_instance_data_key, - inst_data, (GDestroyNotify) pygobject_data_free); - } - return inst_data; -} - - -PyTypeObject *PyGObject_MetaType = NULL; - -/** - * pygobject_sink: - * @obj: a GObject - * - * As Python handles reference counting for us, the "floating - * reference" code in GTK is not all that useful. In fact, it can - * cause leaks. This function should be called to remove the floating - * references on objects on construction. - **/ -void -pygobject_sink(GObject *obj) -{ - /* The default behaviour for GInitiallyUnowned subclasses is to call ref_sink(). - * - if the object is new and owned by someone else, its ref has been sunk and - * we need to keep the one from that someone and add our own "fresh ref" - * - if the object is not and owned by nobody, its ref is floating and we need - * to transform it into a regular ref. - */ - if (G_IS_INITIALLY_UNOWNED(obj)) { - g_object_ref_sink(obj); - } -} - -typedef struct { - PyObject_HEAD - GParamSpec **props; - guint n_props; - guint index; -} PyGPropsIter; - -PYGLIB_DEFINE_TYPE("gi._gobject.GPropsIter", PyGPropsIter_Type, PyGPropsIter); - -static void -pyg_props_iter_dealloc(PyGPropsIter *self) -{ - g_free(self->props); - PyObject_Del((PyObject*) self); -} - -static PyObject* -pygobject_props_iter_next(PyGPropsIter *iter) -{ - if (iter->index < iter->n_props) - return pyg_param_spec_new(iter->props[iter->index++]); - else { - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } -} - -typedef struct { - PyObject_HEAD - /* a reference to the object containing the properties */ - PyGObject *pygobject; - GType gtype; -} PyGProps; - -static void -PyGProps_dealloc(PyGProps* self) -{ - PyGObject *tmp; - - PyObject_GC_UnTrack((PyObject*)self); - - tmp = self->pygobject; - self->pygobject = NULL; - Py_XDECREF(tmp); - - PyObject_GC_Del((PyObject*)self); -} - -static PyObject* -build_parameter_list(GObjectClass *class) -{ - GParamSpec **props; - guint n_props = 0, i; - PyObject *prop_str; - PyObject *props_list; - - props = g_object_class_list_properties(class, &n_props); - props_list = PyList_New(n_props); - for (i = 0; i < n_props; i++) { - char *name; - name = g_strdup(g_param_spec_get_name(props[i])); - /* hyphens cannot belong in identifiers */ - g_strdelimit(name, "-", '_'); - prop_str = PYGLIB_PyUnicode_FromString(name); - - PyList_SetItem(props_list, i, prop_str); - g_free(name); - } - - if (props) - g_free(props); - - return props_list; -} - - -static PyObject* -PyGProps_getattro(PyGProps *self, PyObject *attr) -{ - char *attr_name, *property_name; - GObjectClass *class; - GParamSpec *pspec; - GValue value = { 0, }; - PyObject *ret; - - attr_name = PYGLIB_PyUnicode_AsString(attr); - if (!attr_name) { - PyErr_Clear(); - return PyObject_GenericGetAttr((PyObject *)self, attr); - } - - class = g_type_class_ref(self->gtype); - - /* g_object_class_find_property recurses through the class hierarchy, - * so the resulting pspec tells us the owner_type that owns the property - * we're dealing with. */ - property_name = g_strdup(attr_name); - canonicalize_key(property_name); - pspec = g_object_class_find_property(class, property_name); - g_free(property_name); - g_type_class_unref(class); - - if (!pspec) { - return PyObject_GenericGetAttr((PyObject *)self, attr); - } - - if (!(pspec->flags & G_PARAM_READABLE)) { - PyErr_Format(PyExc_TypeError, - "property '%s' is not readable", attr_name); - return NULL; - } - - if (!self->pygobject) { - /* If we're doing it without an instance, return a GParamSpec */ - return pyg_param_spec_new(pspec); - } - - if (!pyg_gtype_is_custom (pspec->owner_type)) { - /* The GType is not implemented at the Python level: see if we can - * read the property value via gi. */ - ret = pygi_get_property_value (self->pygobject, pspec); - if (ret) - return ret; - } - - /* The GType is implemented in Python, or we failed to read it via gi: - * do a straightforward read. */ - Py_BEGIN_ALLOW_THREADS; - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - g_object_get_property(self->pygobject->obj, pspec->name, &value); - Py_END_ALLOW_THREADS; - - ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec); - g_value_unset(&value); - - return ret; -} - -static gboolean -set_property_from_pspec(GObject *obj, - GParamSpec *pspec, - PyObject *pvalue) -{ - GValue value = { 0, }; - - if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) { - PyErr_Format(PyExc_TypeError, - "property '%s' can only be set in constructor", - pspec->name); - return FALSE; - } - - if (!(pspec->flags & G_PARAM_WRITABLE)) { - PyErr_Format(PyExc_TypeError, - "property '%s' is not writable", pspec->name); - return FALSE; - } - - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - if (pyg_param_gvalue_from_pyobject(&value, pvalue, pspec) < 0) { - PyObject *pvalue_str = PyObject_Str(pvalue); - PyErr_Format(PyExc_TypeError, - "could not convert '%s' to type '%s' when setting property '%s.%s'", - PYGLIB_PyUnicode_AsString(pvalue_str), - g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)), - G_OBJECT_TYPE_NAME(obj), - pspec->name); - Py_DECREF(pvalue_str); - return FALSE; - } - - Py_BEGIN_ALLOW_THREADS; - g_object_set_property(obj, pspec->name, &value); - g_value_unset(&value); - Py_END_ALLOW_THREADS; - - return TRUE; -} - -PYGLIB_DEFINE_TYPE("gi._gobject.GProps", PyGProps_Type, PyGProps); - -static int -PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue) -{ - GParamSpec *pspec; - char *attr_name, *property_name; - GObject *obj; - int ret = -1; - - if (pvalue == NULL) { - PyErr_SetString(PyExc_TypeError, "properties cannot be " - "deleted"); - return -1; - } - - attr_name = PYGLIB_PyUnicode_AsString(attr); - if (!attr_name) { - PyErr_Clear(); - return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); - } - - if (!self->pygobject) { - PyErr_SetString(PyExc_TypeError, - "cannot set GOject properties without an instance"); - return -1; - } - - obj = self->pygobject->obj; - - property_name = g_strdup(attr_name); - canonicalize_key(property_name); - - /* g_object_class_find_property recurses through the class hierarchy, - * so the resulting pspec tells us the owner_type that owns the property - * we're dealing with. */ - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), - property_name); - g_free(property_name); - if (!pspec) { - return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); - } - if (!pyg_gtype_is_custom (pspec->owner_type)) { - /* This GType is not implemented in Python: see if we can set the - * property via gi. */ - ret = pygi_set_property_value (self->pygobject, pspec, pvalue); - if (ret == 0) - return 0; - else if (ret == -1 && PyErr_Occurred()) - return -1; - } - - /* This GType is implemented in Python, or we failed to set it via gi: - * do a straightforward set. */ - if (!set_property_from_pspec(obj, pspec, pvalue)) - return -1; - - return 0; -} - -static int -pygobject_props_traverse(PyGProps *self, visitproc visit, void *arg) -{ - if (self->pygobject && visit((PyObject *) self->pygobject, arg) < 0) - return -1; - return 0; -} - -static PyObject* -pygobject_props_get_iter(PyGProps *self) -{ - PyGPropsIter *iter; - GObjectClass *class; - - iter = PyObject_NEW(PyGPropsIter, &PyGPropsIter_Type); - class = g_type_class_ref(self->gtype); - iter->props = g_object_class_list_properties(class, &iter->n_props); - iter->index = 0; - g_type_class_unref(class); - return (PyObject *) iter; -} - -static PyObject* -pygobject_props_dir(PyGProps *self) -{ - PyObject *ret; - GObjectClass *class; - - class = g_type_class_ref (self->gtype); - ret = build_parameter_list (class); - g_type_class_unref (class); - - return ret; -} - -static PyMethodDef pygobject_props_methods[] = { - { "__dir__", (PyCFunction)pygobject_props_dir, METH_NOARGS}, - { NULL, NULL, 0} -}; - - -static Py_ssize_t -PyGProps_length(PyGProps *self) -{ - GObjectClass *class; - GParamSpec **props; - guint n_props; - - class = g_type_class_ref(self->gtype); - props = g_object_class_list_properties(class, &n_props); - g_type_class_unref(class); - g_free(props); - - return (Py_ssize_t)n_props; -} - -static PySequenceMethods _PyGProps_as_sequence = { - (lenfunc) PyGProps_length, - 0, - 0, - 0, - 0, - 0, - 0 -}; - -PYGLIB_DEFINE_TYPE("gi._gobject.GPropsDescr", PyGPropsDescr_Type, PyObject); - -static PyObject * -pyg_props_descr_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - PyGProps *gprops; - - gprops = PyObject_GC_New(PyGProps, &PyGProps_Type); - if (obj == NULL || obj == Py_None) { - gprops->pygobject = NULL; - gprops->gtype = pyg_type_from_object(type); - } else { - if (!PyObject_IsInstance(obj, (PyObject *) &PyGObject_Type)) { - PyErr_SetString(PyExc_TypeError, "cannot use GObject property" - " descriptor on non-GObject instances"); - return NULL; - } - Py_INCREF(obj); - gprops->pygobject = (PyGObject *) obj; - gprops->gtype = pyg_type_from_object(obj); - } - return (PyObject *) gprops; -} - -/** - * pygobject_register_class: - * @dict: the module dictionary. A reference to the type will be stored here. - * @type_name: not used ? - * @gtype: the GType of the GObject subclass. - * @type: the Python type object for this wrapper. - * @static_bases: a tuple of Python type objects that are the bases of - * this type - * - * This function is used to register a Python type as the wrapper for - * a particular GObject subclass. It will also insert a reference to - * the wrapper class into the module dictionary passed as a reference, - * which simplifies initialisation. - */ -void -pygobject_register_class(PyObject *dict, const gchar *type_name, - GType gtype, PyTypeObject *type, - PyObject *static_bases) -{ - PyObject *o; - const char *class_name, *s; - PyObject *runtime_bases; - PyObject *bases_list, *bases, *mod_name; - int i; - - class_name = type->tp_name; - s = strrchr(class_name, '.'); - if (s != NULL) - class_name = s + 1; - - runtime_bases = pyg_type_get_bases(gtype); - if (static_bases) { - PyTypeObject *py_parent_type = (PyTypeObject *) PyTuple_GET_ITEM(static_bases, 0); - bases_list = PySequence_List(static_bases); - /* we start at index 1 because we want to skip the primary - * base, otherwise we might get MRO conflict */ - for (i = 1; i < PyTuple_GET_SIZE(runtime_bases); ++i) - { - PyObject *base = PyTuple_GET_ITEM(runtime_bases, i); - int contains = PySequence_Contains(bases_list, base); - if (contains < 0) - PyErr_Print(); - else if (!contains) { - if (!PySequence_Contains(py_parent_type->tp_mro, base)) { -#if 0 - g_message("Adding missing base %s to type %s", - ((PyTypeObject *)base)->tp_name, type->tp_name); -#endif - PyList_Append(bases_list, base); - } - } - } - bases = PySequence_Tuple(bases_list); - Py_DECREF(bases_list); - Py_DECREF(runtime_bases); - } else - bases = runtime_bases; - - Py_TYPE(type) = PyGObject_MetaType; - type->tp_bases = bases; - if (G_LIKELY(bases)) { - type->tp_base = (PyTypeObject *)PyTuple_GetItem(bases, 0); - Py_INCREF(type->tp_base); - } - - pygobject_inherit_slots(type, bases, TRUE); - - if (PyType_Ready(type) < 0) { - g_warning ("couldn't make the type `%s' ready", type->tp_name); - return; - } - - /* Set type.__module__ to the name of the module, - * otherwise it'll default to 'gobject', see #376099 - */ - s = strrchr(type->tp_name, '.'); - if (s != NULL) { - mod_name = PYGLIB_PyUnicode_FromStringAndSize(type->tp_name, (int)(s - type->tp_name)); - PyDict_SetItemString(type->tp_dict, "__module__", mod_name); - Py_DECREF(mod_name); - } - - if (gtype) { - o = pyg_type_wrapper_new(gtype); - PyDict_SetItemString(type->tp_dict, "__gtype__", o); - Py_DECREF(o); - - /* stash a pointer to the python class with the GType */ - Py_INCREF(type); - g_type_set_qdata(gtype, pygobject_class_key, type); - } - - /* set up __doc__ descriptor on type */ - PyDict_SetItemString(type->tp_dict, "__doc__", - pyg_object_descr_doc_get()); - - PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); -} - -static void -pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref) -{ - PyGObject *self; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - - /* Avoid thread safety problems by using qdata for wrapper retrieval - * instead of the user data argument. - * See: https://bugzilla.gnome.org/show_bug.cgi?id=709223 - */ - self = (PyGObject *)g_object_get_qdata (object, pygobject_wrapper_key); - if (self) { - if (is_last_ref) - Py_DECREF(self); - else - Py_INCREF(self); - } - - pyglib_gil_state_release(state); -} - - /* Called when the inst_dict is first created; switches the - reference counting strategy to start using toggle ref to keep the - wrapper alive while the GObject lives. In contrast, while - inst_dict was NULL the python wrapper is allowed to die at - will and is recreated on demand. */ -static inline void -pygobject_switch_to_toggle_ref(PyGObject *self) -{ - g_assert(self->obj->ref_count >= 1); - - if (self->private_flags.flags & PYGOBJECT_USING_TOGGLE_REF) - return; /* already using toggle ref */ - self->private_flags.flags |= PYGOBJECT_USING_TOGGLE_REF; - /* Note that add_toggle_ref will never immediately call back into - pyg_toggle_notify */ - Py_INCREF((PyObject *) self); - g_object_add_toggle_ref(self->obj, pyg_toggle_notify, NULL); - g_object_unref(self->obj); -} - -/* Called when an custom gobject is initalized via g_object_new instead of - its constructor. The next time the wrapper is access via - pygobject_new_full it will sink the floating reference instead of - adding a new reference and causing a leak */ - -void -pygobject_ref_float(PyGObject *self) -{ - /* should only be floated once */ - g_assert(!(self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF)); - - self->private_flags.flags |= PYGOBJECT_IS_FLOATING_REF; -} - -/* Called by gobject_new_full, if the floating flag is set remove it, otherwise - ref the pyobject */ -void -pygobject_ref_sink(PyGObject *self) -{ - if (self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF) - self->private_flags.flags &= ~PYGOBJECT_IS_FLOATING_REF; - else - Py_INCREF ( (PyObject *) self); -} - -/** - * pygobject_register_wrapper: - * @self: the wrapper instance - * - * In the constructor of PyGTK wrappers, this function should be - * called after setting the obj member. It will tie the wrapper - * instance to the GObject so that the same wrapper instance will - * always be used for this GObject instance. - */ -void -pygobject_register_wrapper(PyObject *self) -{ - PyGObject *gself; - - g_return_if_fail(self != NULL); - g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type)); - - gself = (PyGObject *)self; - - g_assert(gself->obj->ref_count >= 1); - /* save wrapper pointer so we can access it later */ - g_object_set_qdata_full(gself->obj, pygobject_wrapper_key, gself, NULL); - if (gself->inst_dict) - pygobject_switch_to_toggle_ref(gself); -} - -static PyObject * -pyg_type_get_bases(GType gtype) -{ - GType *interfaces, parent_type, interface_type; - guint n_interfaces; - PyTypeObject *py_parent_type, *py_interface_type; - PyObject *bases; - int i; - - if (G_UNLIKELY(gtype == G_TYPE_OBJECT)) - return NULL; - - /* Lookup the parent type */ - parent_type = g_type_parent(gtype); - py_parent_type = pygobject_lookup_class(parent_type); - interfaces = g_type_interfaces(gtype, &n_interfaces); - bases = PyTuple_New(n_interfaces + 1); - /* We will always put the parent at the first position in bases */ - Py_INCREF(py_parent_type); /* PyTuple_SetItem steals a reference */ - PyTuple_SetItem(bases, 0, (PyObject *) py_parent_type); - - /* And traverse interfaces */ - if (n_interfaces) { - for (i = 0; i < n_interfaces; i++) { - interface_type = interfaces[i]; - py_interface_type = pygobject_lookup_class(interface_type); - Py_INCREF(py_interface_type); /* PyTuple_SetItem steals a reference */ - PyTuple_SetItem(bases, i + 1, (PyObject *) py_interface_type); - } - } - g_free(interfaces); - return bases; -} - -/** - * pygobject_new_with_interfaces - * @gtype: the GType of the GObject subclass. - * - * Creates a new PyTypeObject from the given GType with interfaces attached in - * bases. - * - * Returns: a PyTypeObject for the new type or NULL if it couldn't be created - */ -static PyTypeObject * -pygobject_new_with_interfaces(GType gtype) -{ - PyGILState_STATE state; - PyObject *o; - PyTypeObject *type; - PyObject *dict; - PyTypeObject *py_parent_type; - PyObject *bases; - PyObject *modules, *module; - gchar *type_name, *mod_name, *gtype_name; - - state = pyglib_gil_state_ensure(); - - bases = pyg_type_get_bases(gtype); - py_parent_type = (PyTypeObject *) PyTuple_GetItem(bases, 0); - - dict = PyDict_New(); - - o = pyg_type_wrapper_new(gtype); - PyDict_SetItemString(dict, "__gtype__", o); - Py_DECREF(o); - - /* set up __doc__ descriptor on type */ - PyDict_SetItemString(dict, "__doc__", pyg_object_descr_doc_get()); - - /* generate the pygtk module name and extract the base type name */ - gtype_name = (gchar*)g_type_name(gtype); - if (g_str_has_prefix(gtype_name, "Gtk")) { - mod_name = "gtk"; - gtype_name += 3; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else if (g_str_has_prefix(gtype_name, "Gdk")) { - mod_name = "gtk.gdk"; - gtype_name += 3; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else if (g_str_has_prefix(gtype_name, "Atk")) { - mod_name = "atk"; - gtype_name += 3; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else if (g_str_has_prefix(gtype_name, "Pango")) { - mod_name = "pango"; - gtype_name += 5; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else { - mod_name = "__main__"; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } - - type = (PyTypeObject*)PyObject_CallFunction((PyObject *) Py_TYPE(py_parent_type), - "sNN", type_name, bases, dict); - g_free(type_name); - - if (type == NULL) { - PyErr_Print(); - pyglib_gil_state_release(state); - return NULL; - } - - /* Workaround python tp_(get|set)attr slot inheritance bug. - * Fixes bug #144135. */ - if (!type->tp_getattr && py_parent_type->tp_getattr) { - type->tp_getattro = NULL; - type->tp_getattr = py_parent_type->tp_getattr; - } - if (!type->tp_setattr && py_parent_type->tp_setattr) { - type->tp_setattro = NULL; - type->tp_setattr = py_parent_type->tp_setattr; - } - /* override more python stupid hacks behind our back */ - type->tp_dealloc = py_parent_type->tp_dealloc; - type->tp_alloc = py_parent_type->tp_alloc; - type->tp_free = py_parent_type->tp_free; - type->tp_traverse = py_parent_type->tp_traverse; - type->tp_clear = py_parent_type->tp_clear; - - pygobject_inherit_slots(type, bases, FALSE); - - if (PyType_Ready(type) < 0) { - g_warning ("couldn't make the type `%s' ready", type->tp_name); - pyglib_gil_state_release(state); - return NULL; - } - /* insert type name in module dict */ - modules = PyImport_GetModuleDict(); - if ((module = PyDict_GetItemString(modules, mod_name)) != NULL) { - if (PyObject_SetAttrString(module, gtype_name, (PyObject *)type) < 0) - PyErr_Clear(); - } - - /* stash a pointer to the python class with the GType */ - Py_INCREF(type); - g_type_set_qdata(gtype, pygobject_class_key, type); - - pyglib_gil_state_release(state); - - return type; -} - -/* Pick appropriate value for given slot (at slot_offset inside - * PyTypeObject structure). It must be a pointer, e.g. a pointer to a - * function. We use the following heuristic: - * - * - Scan all types listed as bases of the type. - * - If for exactly one base type slot value is non-NULL and - * different from that of 'object' and 'GObject', set current type - * slot into that value. - * - Otherwise (if there is more than one such base type or none at - * all) don't touch it and live with Python default. - * - * The intention here is to propagate slot from custom wrappers to - * wrappers created at runtime when appropriate. We prefer to be on - * the safe side, so if there is potential collision (more than one - * custom slot value), we discard custom overrides altogether. - * - * When registering type with pygobject_register_class(), i.e. a type - * that has been manually created (likely with Codegen help), - * `check_for_present' should be set to TRUE. In this case, the - * function will never overwrite any non-NULL slots already present in - * the type. If `check_for_present' is FALSE, such non-NULL slots are - * though to be set by Python interpreter and so will be overwritten - * if heuristic above says so. - */ -static void -pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present) -{ - static int slot_offsets[] = { offsetof(PyTypeObject, tp_richcompare), -#if PY_VERSION_HEX < 0x03000000 - offsetof(PyTypeObject, tp_compare), -#endif - offsetof(PyTypeObject, tp_richcompare), - offsetof(PyTypeObject, tp_hash), - offsetof(PyTypeObject, tp_iter), - offsetof(PyTypeObject, tp_repr), - offsetof(PyTypeObject, tp_str), - offsetof(PyTypeObject, tp_print) }; - int i; - - /* Happens when registering gobject.GObject itself, at least. */ - if (!bases) - return; - - for (i = 0; i < G_N_ELEMENTS(slot_offsets); ++i) - pygobject_find_slot_for(type, bases, slot_offsets[i], check_for_present); -} - -static void -pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, - gboolean check_for_present) -{ -#define TYPE_SLOT(type) (* (void **) (((char *) (type)) + slot_offset)) - - void *found_slot = NULL; - int num_bases = PyTuple_Size(bases); - int i; - - if (check_for_present && TYPE_SLOT(type) != NULL) { - /* We are requested to check if there is any custom slot value - * in this type already and there actually is. Don't - * overwrite it. - */ - return; - } - - for (i = 0; i < num_bases; ++i) { - PyTypeObject *base_type = (PyTypeObject *) PyTuple_GetItem(bases, i); - void *slot = TYPE_SLOT(base_type); - - if (slot == NULL) - continue; - if (slot == TYPE_SLOT(&PyGObject_Type) || - slot == TYPE_SLOT(&PyBaseObject_Type)) - continue; - - if (found_slot != NULL && found_slot != slot) { - /* We have a conflict: more than one base use different - * custom slots. To be on the safe side, we bail out. - */ - return; - } - - found_slot = slot; - } - - /* Only perform the final assignment if at least one base has a - * custom value. Otherwise just leave this type's slot untouched. - */ - if (found_slot != NULL) - TYPE_SLOT(type) = found_slot; - -#undef TYPE_SLOT -} - -/** - * pygobject_lookup_class: - * @gtype: the GType of the GObject subclass. - * - * This function looks up the wrapper class used to represent - * instances of a GObject represented by @gtype. If no wrapper class - * or interface has been registered for the given GType, then a new - * type will be created. - * - * Returns: The wrapper class for the GObject or NULL if the - * GType has no registered type and a new type couldn't be created - */ -PyTypeObject * -pygobject_lookup_class(GType gtype) -{ - PyTypeObject *py_type; - - if (gtype == G_TYPE_INTERFACE) - return &PyGInterface_Type; - - py_type = g_type_get_qdata(gtype, pygobject_class_key); - if (py_type == NULL) { - py_type = g_type_get_qdata(gtype, pyginterface_type_key); - - if (py_type == NULL) - py_type = (PyTypeObject *)pygi_type_import_by_g_type(gtype); - - if (py_type == NULL) { - py_type = pygobject_new_with_interfaces(gtype); - g_type_set_qdata(gtype, pyginterface_type_key, py_type); - } - } - - return py_type; -} - -/** - * pygobject_new_full: - * @obj: a GObject instance. - * @steal: whether to steal a ref from the GObject or add (sink) a new one. - * @g_class: the GObjectClass - * - * This function gets a reference to a wrapper for the given GObject - * instance. If a wrapper has already been created, a new reference - * to that wrapper will be returned. Otherwise, a wrapper instance - * will be created. - * - * Returns: a reference to the wrapper for the GObject. - */ -PyObject * -pygobject_new_full(GObject *obj, gboolean steal, gpointer g_class) -{ - PyGObject *self; - - if (obj == NULL) { - Py_RETURN_NONE; - } - - /* If the GObject already has a PyObject wrapper stashed in its qdata, re-use it. - */ - self = (PyGObject *)g_object_get_qdata(obj, pygobject_wrapper_key); - if (self != NULL) { - /* Note the use of "pygobject_ref_sink" here only deals with PyObject - * wrapper ref counts and has nothing to do with GObject. - */ - pygobject_ref_sink(self); - - /* If steal is true, we also want to decref the incoming GObjects which - * already have a Python wrapper because the wrapper is already holding a - * strong reference. - */ - if (steal) - g_object_unref (obj); - - } else { - /* create wrapper */ - PyGObjectData *inst_data = pyg_object_peek_inst_data(obj); - PyTypeObject *tp; - if (inst_data) - tp = inst_data->type; - else { - if (g_class) - tp = pygobject_lookup_class(G_OBJECT_CLASS_TYPE(g_class)); - else - tp = pygobject_lookup_class(G_OBJECT_TYPE(obj)); - } - g_assert(tp != NULL); - - /* need to bump type refcount if created with - pygobject_new_with_interfaces(). fixes bug #141042 */ - if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) - Py_INCREF(tp); - self = PyObject_GC_New(PyGObject, tp); - if (self == NULL) - return NULL; - self->inst_dict = NULL; - self->weakreflist = NULL; - self->private_flags.flags = 0; - self->obj = obj; - - /* If we are not stealing a ref or the object is floating, - * add a regular ref or sink the object. */ - if (g_object_is_floating (obj)) - self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING; - if (!steal || self->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) - g_object_ref_sink (obj); - - pygobject_register_wrapper((PyObject *)self); - PyObject_GC_Track((PyObject *)self); - } - - return (PyObject *)self; -} - - -PyObject * -pygobject_new(GObject *obj) -{ - return pygobject_new_full(obj, - /*steal=*/FALSE, - NULL); -} - -static void -pygobject_unwatch_closure(gpointer data, GClosure *closure) -{ - PyGObjectData *inst_data = data; - - inst_data->closures = g_slist_remove (inst_data->closures, closure); -} - -/** - * pygobject_watch_closure: - * @self: a GObject wrapper instance - * @closure: a GClosure to watch - * - * Adds a closure to the list of watched closures for the wrapper. - * The closure must be one returned by pyg_closure_new(). When the - * cycle GC traverses the wrapper instance, it will enumerate the - * references to Python objects stored in watched closures. If the - * cycle GC tells the wrapper to clear itself, the watched closures - * will be invalidated. - */ -void -pygobject_watch_closure(PyObject *self, GClosure *closure) -{ - PyGObject *gself; - PyGObjectData *data; - - g_return_if_fail(self != NULL); - g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type)); - g_return_if_fail(closure != NULL); - - gself = (PyGObject *)self; - data = pygobject_get_inst_data(gself); - g_return_if_fail(g_slist_find(data->closures, closure) == NULL); - data->closures = g_slist_prepend(data->closures, closure); - g_closure_add_invalidate_notifier(closure, data, pygobject_unwatch_closure); -} - - -/* -------------- PyGObject behaviour ----------------- */ - -PYGLIB_DEFINE_TYPE("gi._gobject.GObject", PyGObject_Type, PyGObject); - -static void -pygobject_dealloc(PyGObject *self) -{ - /* Untrack must be done first. This is because followup calls such as - * ClearWeakRefs could call into Python and cause new allocations to - * happen, which could in turn could trigger the garbage collector, - * which would then get confused as it is tracking this half-deallocated - * object. */ - PyObject_GC_UnTrack((PyObject *)self); - - PyObject_ClearWeakRefs((PyObject *)self); - /* this forces inst_data->type to be updated, which could prove - * important if a new wrapper has to be created and it is of a - * unregistered type */ - pygobject_get_inst_data(self); - pygobject_clear(self); - /* the following causes problems with subclassed types */ - /* Py_TYPE(self)->tp_free((PyObject *)self); */ - PyObject_GC_Del(self); -} - -static PyObject* -pygobject_richcompare(PyObject *self, PyObject *other, int op) -{ - int isinst; - - isinst = PyObject_IsInstance(self, (PyObject*)&PyGObject_Type); - if (isinst == -1) - return NULL; - if (!isinst) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - isinst = PyObject_IsInstance(other, (PyObject*)&PyGObject_Type); - if (isinst == -1) - return NULL; - if (!isinst) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - return _pyglib_generic_ptr_richcompare(((PyGObject*)self)->obj, - ((PyGObject*)other)->obj, - op); -} - -static long -pygobject_hash(PyGObject *self) -{ - return (long)self->obj; -} - -static PyObject * -pygobject_repr(PyGObject *self) -{ - gchar buf[256]; - - g_snprintf(buf, sizeof(buf), - "<%s object at 0x%lx (%s at 0x%lx)>", - Py_TYPE(self)->tp_name, - (long)self, - self->obj ? G_OBJECT_TYPE_NAME(self->obj) : "uninitialized", - (long)self->obj); - return PYGLIB_PyUnicode_FromString(buf); -} - - -static int -pygobject_traverse(PyGObject *self, visitproc visit, void *arg) -{ - int ret = 0; - GSList *tmp; - PyGObjectData *data = pygobject_get_inst_data(self); - - if (self->inst_dict) ret = visit(self->inst_dict, arg); - if (ret != 0) return ret; - - if (data) { - - for (tmp = data->closures; tmp != NULL; tmp = tmp->next) { - PyGClosure *closure = tmp->data; - - if (closure->callback) ret = visit(closure->callback, arg); - if (ret != 0) return ret; - - if (closure->extra_args) ret = visit(closure->extra_args, arg); - if (ret != 0) return ret; - - if (closure->swap_data) ret = visit(closure->swap_data, arg); - if (ret != 0) return ret; - } - } - return ret; -} - -static inline int -pygobject_clear(PyGObject *self) -{ - if (self->obj) { - g_object_set_qdata_full(self->obj, pygobject_wrapper_key, NULL, NULL); - if (self->inst_dict) { - g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, NULL); - self->private_flags.flags &= ~PYGOBJECT_USING_TOGGLE_REF; - } else { - Py_BEGIN_ALLOW_THREADS; - g_object_unref(self->obj); - Py_END_ALLOW_THREADS; - } - self->obj = NULL; - } - Py_CLEAR(self->inst_dict); - return 0; -} - -static void -pygobject_free(PyObject *op) -{ - PyObject_GC_Del(op); -} - -gboolean -pygobject_prepare_construct_properties(GObjectClass *class, PyObject *kwargs, - guint *n_params, GParameter **params) -{ - *n_params = 0; - *params = NULL; - - if (kwargs) { - Py_ssize_t pos = 0; - PyObject *key; - PyObject *value; - - *params = g_new0(GParameter, PyDict_Size(kwargs)); - while (PyDict_Next(kwargs, &pos, &key, &value)) { - GParamSpec *pspec; - GParameter *param = &(*params)[*n_params]; - const gchar *key_str = PYGLIB_PyUnicode_AsString(key); - - pspec = g_object_class_find_property(class, key_str); - if (!pspec) { - PyErr_Format(PyExc_TypeError, - "gobject `%s' doesn't support property `%s'", - G_OBJECT_CLASS_NAME(class), key_str); - return FALSE; - } - g_value_init(¶m->value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - if (pyg_param_gvalue_from_pyobject(¶m->value, value, pspec) < 0) { - PyErr_Format(PyExc_TypeError, - "could not convert value for property `%s' from %s to %s", - key_str, Py_TYPE(value)->tp_name, - g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); - return FALSE; - } - param->name = g_strdup(key_str); - ++(*n_params); - } - } - return TRUE; -} - -/* ---------------- PyGObject methods ----------------- */ - -static int -pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) -{ - GType object_type; - guint n_params = 0, i; - GParameter *params = NULL; - GObjectClass *class; - - /* Only do GObject creation and property setting if the GObject hasn't - * already been created. The case where self->obj already exists can occur - * when C constructors are called directly (Gtk.Button.new_with_label) - * and we are simply wrapping the result with a PyGObject. - * In these cases we want to ignore any keyword arguments passed along - * to __init__ and simply return. - * - * See: https://bugzilla.gnome.org/show_bug.cgi?id=705810 - */ - if (self->obj != NULL) - return 0; - - if (!PyArg_ParseTuple(args, ":GObject.__init__", NULL)) - return -1; - - object_type = pyg_type_from_object((PyObject *)self); - if (!object_type) - return -1; - - if (G_TYPE_IS_ABSTRACT(object_type)) { - PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " - "(non-instantiable) type `%s'", g_type_name(object_type)); - return -1; - } - - if ((class = g_type_class_ref (object_type)) == NULL) { - PyErr_SetString(PyExc_TypeError, - "could not get a reference to type class"); - return -1; - } - - if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, ¶ms)) - goto cleanup; - - if (pygobject_constructv(self, n_params, params)) - PyErr_SetString(PyExc_RuntimeError, "could not create object"); - - cleanup: - for (i = 0; i < n_params; i++) { - g_free((gchar *) params[i].name); - g_value_unset(¶ms[i].value); - } - g_free(params); - g_type_class_unref(class); - - return (self->obj) ? 0 : -1; -} - -#define CHECK_GOBJECT(self) \ - if (!G_IS_OBJECT(self->obj)) { \ - PyErr_Format(PyExc_TypeError, \ - "object at %p of type %s is not initialized", \ - self, Py_TYPE(self)->tp_name); \ - return NULL; \ - } - -static PyObject * -pygobject_get_property(PyGObject *self, PyObject *args) -{ - gchar *param_name; - GParamSpec *pspec; - GValue value = { 0, }; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "s:GObject.get_property", ¶m_name)) - return NULL; - - CHECK_GOBJECT(self); - - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), - param_name); - if (!pspec) { - PyErr_Format(PyExc_TypeError, - "object of type `%s' does not have property `%s'", - g_type_name(G_OBJECT_TYPE(self->obj)), param_name); - return NULL; - } - if (!(pspec->flags & G_PARAM_READABLE)) { - PyErr_Format(PyExc_TypeError, "property %s is not readable", - param_name); - return NULL; - } - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - Py_BEGIN_ALLOW_THREADS; - g_object_get_property(self->obj, param_name, &value); - Py_END_ALLOW_THREADS; - - ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec); - g_value_unset(&value); - return ret; -} - -static PyObject * -pygobject_get_properties(PyGObject *self, PyObject *args) -{ - GObjectClass *class; - int len, i; - PyObject *tuple; - - if ((len = PyTuple_Size(args)) < 1) { - PyErr_SetString(PyExc_TypeError, "requires at least one argument"); - return NULL; - } - - tuple = PyTuple_New(len); - class = G_OBJECT_GET_CLASS(self->obj); - for (i = 0; i < len; i++) { - PyObject *py_property = PyTuple_GetItem(args, i); - gchar *property_name; - GParamSpec *pspec; - GValue value = { 0 }; - PyObject *item; - - if (!PYGLIB_PyUnicode_Check(py_property)) { - PyErr_SetString(PyExc_TypeError, - "Expected string argument for property."); - return NULL; - } - - property_name = PYGLIB_PyUnicode_AsString(py_property); - - pspec = g_object_class_find_property(class, - property_name); - if (!pspec) { - PyErr_Format(PyExc_TypeError, - "object of type `%s' does not have property `%s'", - g_type_name(G_OBJECT_TYPE(self->obj)), property_name); - return NULL; - } - if (!(pspec->flags & G_PARAM_READABLE)) { - PyErr_Format(PyExc_TypeError, "property %s is not readable", - property_name); - return NULL; - } - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - - Py_BEGIN_ALLOW_THREADS; - g_object_get_property(self->obj, property_name, &value); - Py_END_ALLOW_THREADS; - - item = pyg_value_as_pyobject(&value, TRUE); - PyTuple_SetItem(tuple, i, item); - - g_value_unset(&value); - } - - return tuple; -} - -static PyObject * -pygobject_set_property(PyGObject *self, PyObject *args) -{ - gchar *param_name; - GParamSpec *pspec; - PyObject *pvalue; - int ret = -1; - - if (!PyArg_ParseTuple(args, "sO:GObject.set_property", ¶m_name, - &pvalue)) - return NULL; - - CHECK_GOBJECT(self); - - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), - param_name); - if (!pspec) { - PyErr_Format(PyExc_TypeError, - "object of type `%s' does not have property `%s'", - g_type_name(G_OBJECT_TYPE(self->obj)), param_name); - return NULL; - } - - ret = pygi_set_property_value (self, pspec, pvalue); - if (ret == 0) - goto done; - else if (PyErr_Occurred()) - return NULL; - - if (!set_property_from_pspec(self->obj, pspec, pvalue)) - return NULL; - -done: - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * -pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs) -{ - GObjectClass *class; - Py_ssize_t pos; - PyObject *value; - PyObject *key; - PyObject *result = NULL; - - CHECK_GOBJECT(self); - - class = G_OBJECT_GET_CLASS(self->obj); - - g_object_freeze_notify (G_OBJECT(self->obj)); - pos = 0; - - while (kwargs && PyDict_Next (kwargs, &pos, &key, &value)) { - gchar *key_str = PYGLIB_PyUnicode_AsString(key); - GParamSpec *pspec; - int ret = -1; - - pspec = g_object_class_find_property(class, key_str); - if (!pspec) { - gchar buf[512]; - - g_snprintf(buf, sizeof(buf), - "object `%s' doesn't support property `%s'", - g_type_name(G_OBJECT_TYPE(self->obj)), key_str); - PyErr_SetString(PyExc_TypeError, buf); - goto exit; - } - - ret = pygi_set_property_value (self, pspec, value); - if (ret != 0) { - /* Non-zero return code means that either an error occured ...*/ - if (PyErr_Occurred()) - goto exit; - - /* ... or the property couldn't be found , so let's try the default - * call. */ - if (!set_property_from_pspec(G_OBJECT(self->obj), pspec, value)) - goto exit; - } - } - - result = Py_None; - - exit: - g_object_thaw_notify (G_OBJECT(self->obj)); - Py_XINCREF(result); - return result; -} - -/* custom closure for gobject bindings */ -static void -pygbinding_closure_invalidate(gpointer data, GClosure *closure) -{ - PyGClosure *pc = (PyGClosure *)closure; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - Py_XDECREF(pc->callback); - Py_XDECREF(pc->extra_args); - pyglib_gil_state_release(state); - - pc->callback = NULL; - pc->extra_args = NULL; -} - -static void -pygbinding_marshal (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - PyGILState_STATE state; - PyGClosure *pc = (PyGClosure *)closure; - PyObject *params, *ret; - GValue *out_value; - - state = pyglib_gil_state_ensure(); - - /* construct Python tuple for the parameter values */ - params = PyTuple_New(2); - PyTuple_SetItem (params, 0, pyg_value_as_pyobject(¶m_values[0], FALSE)); - PyTuple_SetItem (params, 1, pyg_value_as_pyobject(¶m_values[1], FALSE)); - - /* params passed to function may have extra arguments */ - if (pc->extra_args) { - PyObject *tuple = params; - params = PySequence_Concat(tuple, pc->extra_args); - Py_DECREF(tuple); - } - ret = PyObject_CallObject(pc->callback, params); - if (!ret) { - PyErr_Print (); - goto out; - } else if (ret == Py_None) { - g_value_set_boolean (return_value, FALSE); - goto out; - } - - out_value = g_value_get_boxed (¶m_values[2]); - if (pyg_value_from_pyobject (out_value, ret) != 0) { - PyErr_SetString (PyExc_ValueError, "can't convert value"); - PyErr_Print (); - g_value_set_boolean (return_value, FALSE); - } else { - g_value_set_boolean (return_value, TRUE); - } - - Py_DECREF(ret); - -out: - Py_DECREF(params); - pyglib_gil_state_release(state); -} - -static GClosure * -pygbinding_closure_new (PyObject *callback, PyObject *extra_args) -{ - GClosure *closure; - - g_return_val_if_fail(callback != NULL, NULL); - closure = g_closure_new_simple(sizeof(PyGClosure), NULL); - g_closure_add_invalidate_notifier(closure, NULL, pygbinding_closure_invalidate); - g_closure_set_marshal(closure, pygbinding_marshal); - Py_INCREF(callback); - ((PyGClosure *)closure)->callback = callback; - if (extra_args && extra_args != Py_None) { - Py_INCREF(extra_args); - if (!PyTuple_Check(extra_args)) { - PyObject *tmp = PyTuple_New(1); - PyTuple_SetItem(tmp, 0, extra_args); - extra_args = tmp; - } - ((PyGClosure *)closure)->extra_args = extra_args; - } - return closure; -} - -static PyObject * -pygobject_bind_property(PyGObject *self, PyObject *args) -{ - gchar *source_name, *target_name; - gchar *source_canon, *target_canon; - PyObject *target, *source_repr, *target_repr; - PyObject *transform_to, *transform_from, *user_data = NULL; - GBinding *binding; - GBindingFlags flags = G_BINDING_DEFAULT; - GClosure *to_closure = NULL, *from_closure = NULL; - - transform_from = NULL; - transform_to = NULL; - - if (!PyArg_ParseTuple(args, "sOs|iOOO:GObject.bind_property", - &source_name, &target, &target_name, &flags, - &transform_to, &transform_from, &user_data)) - return NULL; - - CHECK_GOBJECT(self); - if (!PyObject_TypeCheck(target, &PyGObject_Type)) { - PyErr_SetString(PyExc_TypeError, "Second argument must be a GObject"); - return NULL; - } - - if (transform_to && transform_to != Py_None) { - if (!PyCallable_Check (transform_to)) { - PyErr_SetString (PyExc_TypeError, - "transform_to must be callable or None"); - return NULL; - } - to_closure = pygbinding_closure_new (transform_to, user_data); - } - - if (transform_from && transform_from != Py_None) { - if (!PyCallable_Check (transform_from)) { - PyErr_SetString (PyExc_TypeError, - "transform_from must be callable or None"); - return NULL; - } - from_closure = pygbinding_closure_new (transform_from, user_data); - } - - /* Canonicalize underscores to hyphens. Note the results must be freed. */ - source_canon = g_strdelimit(g_strdup(source_name), "_", '-'); - target_canon = g_strdelimit(g_strdup(target_name), "_", '-'); - - binding = g_object_bind_property_with_closures (G_OBJECT(self->obj), source_canon, - pygobject_get(target), target_canon, - flags, to_closure, from_closure); - g_free(source_canon); - g_free(target_canon); - source_canon = target_canon = NULL; - - if (binding == NULL) { - source_repr = PyObject_Repr((PyObject*)self); - target_repr = PyObject_Repr(target); - PyErr_Format(PyExc_TypeError, "Cannot create binding from %s.%s to %s.%s", - PYGLIB_PyUnicode_AsString(source_repr), source_name, - PYGLIB_PyUnicode_AsString(target_repr), target_name); - Py_DECREF(source_repr); - Py_DECREF(target_repr); - return NULL; - } - - return pygobject_new (G_OBJECT (binding)); -} - -static PyObject * -connect_helper(PyGObject *self, gchar *name, PyObject *callback, PyObject *extra_args, PyObject *object, gboolean after) -{ - guint sigid; - GQuark detail = 0; - GClosure *closure = NULL; - gulong handlerid; - GSignalQuery query_info; - - if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj), - &sigid, &detail, TRUE)) { - PyObject *repr = PyObject_Repr((PyObject*)self); - PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", - PYGLIB_PyUnicode_AsString(repr), - name); - Py_DECREF(repr); - return NULL; - } - - g_signal_query (sigid, &query_info); - if (!pyg_gtype_is_custom (query_info.itype)) { - /* The signal is implemented by a non-Python class, probably - * something in the gi repository. */ - closure = pygi_signal_closure_new (self, query_info.itype, - query_info.signal_name, callback, - extra_args, object); - } - - if (!closure) { - /* The signal is either implemented at the Python level, or it comes - * from a foreign class that we don't have introspection data for. */ - closure = pyg_closure_new (callback, extra_args, object); - } - - pygobject_watch_closure((PyObject *)self, closure); - handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, - closure, after); - return PyLong_FromUnsignedLong(handlerid); -} - -static PyObject * -pygobject_connect(PyGObject *self, PyObject *args) -{ - PyObject *first, *callback, *extra_args, *ret; - gchar *name; - guint len; - - len = PyTuple_Size(args); - if (len < 2) { - PyErr_SetString(PyExc_TypeError, - "GObject.connect requires at least 2 arguments"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 2); - if (!PyArg_ParseTuple(first, "sO:GObject.connect", &name, &callback)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - if (!PyCallable_Check(callback)) { - PyErr_SetString(PyExc_TypeError, "second argument must be callable"); - return NULL; - } - - CHECK_GOBJECT(self); - - extra_args = PySequence_GetSlice(args, 2, len); - if (extra_args == NULL) - return NULL; - - ret = connect_helper(self, name, callback, extra_args, NULL, FALSE); - Py_DECREF(extra_args); - return ret; -} - -static PyObject * -pygobject_connect_after(PyGObject *self, PyObject *args) -{ - PyObject *first, *callback, *extra_args, *ret; - gchar *name; - Py_ssize_t len; - - len = PyTuple_Size(args); - if (len < 2) { - PyErr_SetString(PyExc_TypeError, - "GObject.connect_after requires at least 2 arguments"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 2); - if (!PyArg_ParseTuple(first, "sO:GObject.connect_after", - &name, &callback)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - if (!PyCallable_Check(callback)) { - PyErr_SetString(PyExc_TypeError, "second argument must be callable"); - return NULL; - } - - CHECK_GOBJECT(self); - - extra_args = PySequence_GetSlice(args, 2, len); - if (extra_args == NULL) - return NULL; - - ret = connect_helper(self, name, callback, extra_args, NULL, TRUE); - Py_DECREF(extra_args); - return ret; -} - -static PyObject * -pygobject_connect_object(PyGObject *self, PyObject *args) -{ - PyObject *first, *callback, *extra_args, *object, *ret; - gchar *name; - Py_ssize_t len; - - len = PyTuple_Size(args); - if (len < 3) { - PyErr_SetString(PyExc_TypeError, - "GObject.connect_object requires at least 3 arguments"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 3); - if (!PyArg_ParseTuple(first, "sOO:GObject.connect_object", - &name, &callback, &object)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - if (!PyCallable_Check(callback)) { - PyErr_SetString(PyExc_TypeError, "second argument must be callable"); - return NULL; - } - - CHECK_GOBJECT(self); - - extra_args = PySequence_GetSlice(args, 3, len); - if (extra_args == NULL) - return NULL; - - ret = connect_helper(self, name, callback, extra_args, object, FALSE); - Py_DECREF(extra_args); - return ret; -} - -static PyObject * -pygobject_connect_object_after(PyGObject *self, PyObject *args) -{ - PyObject *first, *callback, *extra_args, *object, *ret; - gchar *name; - Py_ssize_t len; - - len = PyTuple_Size(args); - if (len < 3) { - PyErr_SetString(PyExc_TypeError, - "GObject.connect_object_after requires at least 3 arguments"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 3); - if (!PyArg_ParseTuple(first, "sOO:GObject.connect_object_after", - &name, &callback, &object)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - if (!PyCallable_Check(callback)) { - PyErr_SetString(PyExc_TypeError, "second argument must be callable"); - return NULL; - } - - CHECK_GOBJECT(self); - - extra_args = PySequence_GetSlice(args, 3, len); - if (extra_args == NULL) - return NULL; - - ret = connect_helper(self, name, callback, extra_args, object, TRUE); - Py_DECREF(extra_args); - return ret; -} - -static PyObject * -pygobject_emit(PyGObject *self, PyObject *args) -{ - guint signal_id, i, j; - Py_ssize_t len; - GQuark detail; - PyObject *first, *py_ret, *repr = NULL; - gchar *name; - GSignalQuery query; - GValue *params, ret = { 0, }; - - len = PyTuple_Size(args); - if (len < 1) { - PyErr_SetString(PyExc_TypeError,"GObject.emit needs at least one arg"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 1); - if (!PyArg_ParseTuple(first, "s:GObject.emit", &name)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - - CHECK_GOBJECT(self); - - if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj), - &signal_id, &detail, TRUE)) { - repr = PyObject_Repr((PyObject*)self); - PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", - PYGLIB_PyUnicode_AsString(repr), - name); - Py_DECREF(repr); - return NULL; - } - g_signal_query(signal_id, &query); - if (len != query.n_params + 1) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "%d parameters needed for signal %s; %ld given", - query.n_params, name, (long int) (len - 1)); - PyErr_SetString(PyExc_TypeError, buf); - return NULL; - } - - params = g_new0(GValue, query.n_params + 1); - g_value_init(¶ms[0], G_OBJECT_TYPE(self->obj)); - g_value_set_object(¶ms[0], G_OBJECT(self->obj)); - - for (i = 0; i < query.n_params; i++) - g_value_init(¶ms[i + 1], - query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); - for (i = 0; i < query.n_params; i++) { - PyObject *item = PyTuple_GetItem(args, i+1); - - if (pyg_value_from_pyobject(¶ms[i+1], item) < 0) { - gchar buf[128]; - g_snprintf(buf, sizeof(buf), - "could not convert type %s to %s required for parameter %d", - Py_TYPE(item)->tp_name, - G_VALUE_TYPE_NAME(¶ms[i+1]), i); - PyErr_SetString(PyExc_TypeError, buf); - - for (j = 0; j <= i; j++) - g_value_unset(¶ms[j]); - - g_free(params); - return NULL; - } - } - - if (query.return_type != G_TYPE_NONE) - g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); - - g_signal_emitv(params, signal_id, detail, &ret); - - for (i = 0; i < query.n_params + 1; i++) - g_value_unset(¶ms[i]); - - g_free(params); - if ((query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE) != G_TYPE_NONE) { - py_ret = pyg_value_as_pyobject(&ret, TRUE); - g_value_unset(&ret); - } else { - Py_INCREF(Py_None); - py_ret = Py_None; - } - - return py_ret; -} - -static PyObject * -pygobject_chain_from_overridden(PyGObject *self, PyObject *args) -{ - GSignalInvocationHint *ihint; - guint signal_id, i; - Py_ssize_t len; - PyObject *py_ret; - const gchar *name; - GSignalQuery query; - GValue *params, ret = { 0, }; - - CHECK_GOBJECT(self); - - ihint = g_signal_get_invocation_hint(self->obj); - if (!ihint) { - PyErr_SetString(PyExc_TypeError, "could not find signal invocation " - "information for this object."); - return NULL; - } - - signal_id = ihint->signal_id; - name = g_signal_name(signal_id); - - len = PyTuple_Size(args); - if (signal_id == 0) { - PyErr_SetString(PyExc_TypeError, "unknown signal name"); - return NULL; - } - g_signal_query(signal_id, &query); - if (len != query.n_params) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "%d parameters needed for signal %s; %ld given", - query.n_params, name, (long int) len); - PyErr_SetString(PyExc_TypeError, buf); - return NULL; - } - params = g_new0(GValue, query.n_params + 1); - g_value_init(¶ms[0], G_OBJECT_TYPE(self->obj)); - g_value_set_object(¶ms[0], G_OBJECT(self->obj)); - - for (i = 0; i < query.n_params; i++) - g_value_init(¶ms[i + 1], - query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); - for (i = 0; i < query.n_params; i++) { - PyObject *item = PyTuple_GetItem(args, i); - - if (pyg_boxed_check(item, (query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE))) { - g_value_set_static_boxed(¶ms[i+1], pyg_boxed_get(item, void)); - } - else if (pyg_value_from_pyobject(¶ms[i+1], item) < 0) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "could not convert type %s to %s required for parameter %d", - Py_TYPE(item)->tp_name, - g_type_name(G_VALUE_TYPE(¶ms[i+1])), i); - PyErr_SetString(PyExc_TypeError, buf); - for (i = 0; i < query.n_params + 1; i++) - g_value_unset(¶ms[i]); - g_free(params); - return NULL; - } - } - if (query.return_type != G_TYPE_NONE) - g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); - g_signal_chain_from_overridden(params, &ret); - for (i = 0; i < query.n_params + 1; i++) - g_value_unset(¶ms[i]); - g_free(params); - if (query.return_type != G_TYPE_NONE) { - py_ret = pyg_value_as_pyobject(&ret, TRUE); - g_value_unset(&ret); - } else { - Py_INCREF(Py_None); - py_ret = Py_None; - } - return py_ret; -} - - -static PyObject * -pygobject_weak_ref(PyGObject *self, PyObject *args) -{ - int len; - PyObject *callback = NULL, *user_data = NULL; - PyObject *retval; - - CHECK_GOBJECT(self); - - if ((len = PySequence_Length(args)) >= 1) { - callback = PySequence_ITEM(args, 0); - user_data = PySequence_GetSlice(args, 1, len); - } - retval = pygobject_weak_ref_new(self->obj, callback, user_data); - Py_XDECREF(callback); - Py_XDECREF(user_data); - return retval; -} - - -static PyObject * -pygobject_copy(PyGObject *self) -{ - PyErr_SetString(PyExc_TypeError, - "GObject descendants' instances are non-copyable"); - return NULL; -} - -static PyObject * -pygobject_deepcopy(PyGObject *self, PyObject *args) -{ - PyErr_SetString(PyExc_TypeError, - "GObject descendants' instances are non-copyable"); - return NULL; -} - - -static PyObject * -pygobject_disconnect_by_func(PyGObject *self, PyObject *args) -{ - PyObject *pyfunc = NULL, *repr = NULL; - GClosure *closure = NULL; - guint retval; - - CHECK_GOBJECT(self); - - if (!PyArg_ParseTuple(args, "O:GObject.disconnect_by_func", &pyfunc)) - return NULL; - - if (!PyCallable_Check(pyfunc)) { - PyErr_SetString(PyExc_TypeError, "first argument must be callable"); - return NULL; - } - - closure = gclosure_from_pyfunc(self, pyfunc); - if (!closure) { - repr = PyObject_Repr((PyObject*)pyfunc); - PyErr_Format(PyExc_TypeError, "nothing connected to %s", - PYGLIB_PyUnicode_AsString(repr)); - Py_DECREF(repr); - return NULL; - } - - retval = g_signal_handlers_disconnect_matched(self->obj, - G_SIGNAL_MATCH_CLOSURE, - 0, 0, - closure, - NULL, NULL); - return PYGLIB_PyLong_FromLong(retval); -} - -static PyObject * -pygobject_handler_block_by_func(PyGObject *self, PyObject *args) -{ - PyObject *pyfunc = NULL, *repr = NULL; - GClosure *closure = NULL; - guint retval; - - CHECK_GOBJECT(self); - - if (!PyArg_ParseTuple(args, "O:GObject.handler_block_by_func", &pyfunc)) - return NULL; - - if (!PyCallable_Check(pyfunc)) { - PyErr_SetString(PyExc_TypeError, "first argument must be callable"); - return NULL; - } - - closure = gclosure_from_pyfunc(self, pyfunc); - if (!closure) { - repr = PyObject_Repr((PyObject*)pyfunc); - PyErr_Format(PyExc_TypeError, "nothing connected to %s", - PYGLIB_PyUnicode_AsString(repr)); - Py_DECREF(repr); - return NULL; - } - - retval = g_signal_handlers_block_matched(self->obj, - G_SIGNAL_MATCH_CLOSURE, - 0, 0, - closure, - NULL, NULL); - return PYGLIB_PyLong_FromLong(retval); -} - -static PyObject * -pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args) -{ - PyObject *pyfunc = NULL, *repr = NULL; - GClosure *closure = NULL; - guint retval; - - CHECK_GOBJECT(self); - - if (!PyArg_ParseTuple(args, "O:GObject.handler_unblock_by_func", &pyfunc)) - return NULL; - - if (!PyCallable_Check(pyfunc)) { - PyErr_SetString(PyExc_TypeError, "first argument must be callable"); - return NULL; - } - - closure = gclosure_from_pyfunc(self, pyfunc); - if (!closure) { - repr = PyObject_Repr((PyObject*)pyfunc); - PyErr_Format(PyExc_TypeError, "nothing connected to %s", - PYGLIB_PyUnicode_AsString(repr)); - Py_DECREF(repr); - return NULL; - } - - retval = g_signal_handlers_unblock_matched(self->obj, - G_SIGNAL_MATCH_CLOSURE, - 0, 0, - closure, - NULL, NULL); - return PYGLIB_PyLong_FromLong(retval); -} - - -static PyMethodDef pygobject_methods[] = { - { "get_property", (PyCFunction)pygobject_get_property, METH_VARARGS }, - { "get_properties", (PyCFunction)pygobject_get_properties, METH_VARARGS }, - { "set_property", (PyCFunction)pygobject_set_property, METH_VARARGS }, - { "set_properties", (PyCFunction)pygobject_set_properties, METH_VARARGS|METH_KEYWORDS }, - { "bind_property", (PyCFunction)pygobject_bind_property, METH_VARARGS|METH_KEYWORDS }, - { "connect", (PyCFunction)pygobject_connect, METH_VARARGS }, - { "connect_after", (PyCFunction)pygobject_connect_after, METH_VARARGS }, - { "connect_object", (PyCFunction)pygobject_connect_object, METH_VARARGS }, - { "connect_object_after", (PyCFunction)pygobject_connect_object_after, METH_VARARGS }, - { "disconnect_by_func", (PyCFunction)pygobject_disconnect_by_func, METH_VARARGS }, - { "handler_block_by_func", (PyCFunction)pygobject_handler_block_by_func, METH_VARARGS }, - { "handler_unblock_by_func", (PyCFunction)pygobject_handler_unblock_by_func, METH_VARARGS }, - { "emit", (PyCFunction)pygobject_emit, METH_VARARGS }, - { "chain", (PyCFunction)pygobject_chain_from_overridden,METH_VARARGS }, - { "weak_ref", (PyCFunction)pygobject_weak_ref, METH_VARARGS }, - { "__copy__", (PyCFunction)pygobject_copy, METH_NOARGS }, - { "__deepcopy__", (PyCFunction)pygobject_deepcopy, METH_VARARGS }, - { NULL, NULL, 0 } -}; - - -static PyObject * -pygobject_get_dict(PyGObject *self, void *closure) -{ - if (self->inst_dict == NULL) { - self->inst_dict = PyDict_New(); - if (self->inst_dict == NULL) - return NULL; - if (G_LIKELY(self->obj)) - pygobject_switch_to_toggle_ref(self); - } - Py_INCREF(self->inst_dict); - return self->inst_dict; -} - -static PyObject * -pygobject_get_refcount(PyGObject *self, void *closure) -{ - if (self->obj == NULL) { - PyErr_Format(PyExc_TypeError, "GObject instance is not yet created"); - return NULL; - } - return PYGLIB_PyLong_FromLong(self->obj->ref_count); -} - -static PyObject * -pygobject_get_pointer(PyGObject *self, void *closure) -{ - return PYGLIB_CPointer_WrapPointer (self->obj, NULL); -} - -static int -pygobject_setattro(PyObject *self, PyObject *name, PyObject *value) -{ - int res; - PyGObject *gself = (PyGObject *) self; - PyObject *inst_dict_before = gself->inst_dict; - /* call parent type's setattro */ - res = PyGObject_Type.tp_base->tp_setattro(self, name, value); - if (inst_dict_before == NULL && gself->inst_dict != NULL) { - if (G_LIKELY(gself->obj)) - pygobject_switch_to_toggle_ref(gself); - } - return res; -} - -static PyGetSetDef pygobject_getsets[] = { - { "__dict__", (getter)pygobject_get_dict, (setter)0 }, - { "__grefcount__", (getter)pygobject_get_refcount, (setter)0, }, - { "__gpointer__", (getter)pygobject_get_pointer, (setter)0, }, - { NULL, 0, 0 } -}; - -/* ------------------------------------ */ -/* ****** GObject weak reference ****** */ -/* ------------------------------------ */ - -typedef struct { - PyObject_HEAD - GObject *obj; - PyObject *callback; - PyObject *user_data; - gboolean have_floating_ref; -} PyGObjectWeakRef; - -PYGLIB_DEFINE_TYPE("gi._gobject.GObjectWeakRef", PyGObjectWeakRef_Type, PyGObjectWeakRef); - -static int -pygobject_weak_ref_traverse(PyGObjectWeakRef *self, visitproc visit, void *arg) -{ - if (self->callback && visit(self->callback, arg) < 0) - return -1; - if (self->user_data && visit(self->user_data, arg) < 0) - return -1; - return 0; -} - -static void -pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) -{ - self->obj = NULL; - if (self->callback) { - PyObject *retval; - PyGILState_STATE state = pyglib_gil_state_ensure(); - retval = PyObject_Call(self->callback, self->user_data, NULL); - if (retval) { - if (retval != Py_None) - PyErr_Format(PyExc_TypeError, - "GObject weak notify callback returned a value" - " of type %s, should return None", - Py_TYPE(retval)->tp_name); - Py_DECREF(retval); - PyErr_Print(); - } else - PyErr_Print(); - Py_CLEAR(self->callback); - Py_CLEAR(self->user_data); - if (self->have_floating_ref) { - self->have_floating_ref = FALSE; - Py_DECREF((PyObject *) self); - } - pyglib_gil_state_release(state); - } -} - -static inline int -pygobject_weak_ref_clear(PyGObjectWeakRef *self) -{ - Py_CLEAR(self->callback); - Py_CLEAR(self->user_data); - if (self->obj) { - g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); - self->obj = NULL; - } - return 0; -} - -static void -pygobject_weak_ref_dealloc(PyGObjectWeakRef *self) -{ - PyObject_GC_UnTrack((PyObject *)self); - pygobject_weak_ref_clear(self); - PyObject_GC_Del(self); -} - -static PyObject * -pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data) -{ - PyGObjectWeakRef *self; - - self = PyObject_GC_New(PyGObjectWeakRef, &PyGObjectWeakRef_Type); - self->callback = callback; - self->user_data = user_data; - Py_XINCREF(self->callback); - Py_XINCREF(self->user_data); - self->obj = obj; - g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); - if (callback != NULL) { - /* when we have a callback, we should INCREF the weakref - * object to make it stay alive even if it goes out of scope */ - self->have_floating_ref = TRUE; - Py_INCREF((PyObject *) self); - } - return (PyObject *) self; -} - -static PyObject * -pygobject_weak_ref_unref(PyGObjectWeakRef *self, PyObject *args) -{ - if (!self->obj) { - PyErr_SetString(PyExc_ValueError, "weak ref already unreffed"); - return NULL; - } - g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); - self->obj = NULL; - if (self->have_floating_ref) { - self->have_floating_ref = FALSE; - Py_DECREF(self); - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef pygobject_weak_ref_methods[] = { - { "unref", (PyCFunction)pygobject_weak_ref_unref, METH_NOARGS}, - { NULL, NULL, 0} -}; - -static PyObject * -pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw) -{ - static char *argnames[] = {NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) - return NULL; - - if (self->obj) - return pygobject_new(self->obj); - else { - Py_INCREF(Py_None); - return Py_None; - } -} - -static gpointer -pyobject_copy(gpointer boxed) -{ - PyObject *object = boxed; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - Py_INCREF(object); - pyglib_gil_state_release(state); - return object; -} - -static void -pyobject_free(gpointer boxed) -{ - PyObject *object = boxed; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - Py_DECREF(object); - pyglib_gil_state_release(state); -} - -void -pygobject_object_register_types(PyObject *d) -{ - PyObject *o, *descr; - - pygobject_custom_key = g_quark_from_static_string("PyGObject::custom"); - pygobject_class_key = g_quark_from_static_string("PyGObject::class"); - pygobject_class_init_key = g_quark_from_static_string("PyGObject::class-init"); - pygobject_wrapper_key = g_quark_from_static_string("PyGObject::wrapper"); - pygobject_has_updated_constructor_key = - g_quark_from_static_string("PyGObject::has-updated-constructor"); - pygobject_instance_data_key = g_quark_from_static_string("PyGObject::instance-data"); - - /* GObject */ - if (!PY_TYPE_OBJECT) - PY_TYPE_OBJECT = g_boxed_type_register_static("PyObject", - pyobject_copy, - pyobject_free); - PyGObject_Type.tp_dealloc = (destructor)pygobject_dealloc; - PyGObject_Type.tp_richcompare = pygobject_richcompare; - PyGObject_Type.tp_repr = (reprfunc)pygobject_repr; - PyGObject_Type.tp_hash = (hashfunc)pygobject_hash; - PyGObject_Type.tp_setattro = (setattrofunc)pygobject_setattro; - PyGObject_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC); - PyGObject_Type.tp_traverse = (traverseproc)pygobject_traverse; - PyGObject_Type.tp_clear = (inquiry)pygobject_clear; - PyGObject_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); - PyGObject_Type.tp_methods = pygobject_methods; - PyGObject_Type.tp_getset = pygobject_getsets; - PyGObject_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); - PyGObject_Type.tp_init = (initproc)pygobject_init; - PyGObject_Type.tp_free = (freefunc)pygobject_free; - PyGObject_Type.tp_alloc = PyType_GenericAlloc; - PyGObject_Type.tp_new = PyType_GenericNew; - pygobject_register_class(d, "GObject", G_TYPE_OBJECT, - &PyGObject_Type, NULL); - PyDict_SetItemString(PyGObject_Type.tp_dict, "__gdoc__", - pyg_object_descr_doc_get()); - - /* GProps */ - PyGProps_Type.tp_dealloc = (destructor)PyGProps_dealloc; - PyGProps_Type.tp_as_sequence = (PySequenceMethods*)&_PyGProps_as_sequence; - PyGProps_Type.tp_getattro = (getattrofunc)PyGProps_getattro; - PyGProps_Type.tp_setattro = (setattrofunc)PyGProps_setattro; - PyGProps_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; - PyGProps_Type.tp_doc = "The properties of the GObject accessible as " - "Python attributes."; - PyGProps_Type.tp_traverse = (traverseproc)pygobject_props_traverse; - PyGProps_Type.tp_iter = (getiterfunc)pygobject_props_get_iter; - PyGProps_Type.tp_methods = pygobject_props_methods; - if (PyType_Ready(&PyGProps_Type) < 0) - return; - - /* GPropsDescr */ - PyGPropsDescr_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGPropsDescr_Type.tp_descr_get = pyg_props_descr_descr_get; - if (PyType_Ready(&PyGPropsDescr_Type) < 0) - return; - descr = PyObject_New(PyObject, &PyGPropsDescr_Type); - PyDict_SetItemString(PyGObject_Type.tp_dict, "props", descr); - PyDict_SetItemString(PyGObject_Type.tp_dict, "__module__", - o=PYGLIB_PyUnicode_FromString("gi._gobject._gobject")); - Py_DECREF(o); - - /* GPropsIter */ - PyGPropsIter_Type.tp_dealloc = (destructor)pyg_props_iter_dealloc; - PyGPropsIter_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGPropsIter_Type.tp_doc = "GObject properties iterator"; - PyGPropsIter_Type.tp_iternext = (iternextfunc)pygobject_props_iter_next; - if (PyType_Ready(&PyGPropsIter_Type) < 0) - return; - - PyGObjectWeakRef_Type.tp_dealloc = (destructor)pygobject_weak_ref_dealloc; - PyGObjectWeakRef_Type.tp_call = (ternaryfunc)pygobject_weak_ref_call; - PyGObjectWeakRef_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; - PyGObjectWeakRef_Type.tp_doc = "A GObject weak reference"; - PyGObjectWeakRef_Type.tp_traverse = (traverseproc)pygobject_weak_ref_traverse; - PyGObjectWeakRef_Type.tp_clear = (inquiry)pygobject_weak_ref_clear; - PyGObjectWeakRef_Type.tp_methods = pygobject_weak_ref_methods; - if (PyType_Ready(&PyGObjectWeakRef_Type) < 0) - return; - PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type); -} diff --git a/gi/_gobject/pygobject.h b/gi/_gobject/pygobject.h deleted file mode 100644 index 76b8b118..00000000 --- a/gi/_gobject/pygobject.h +++ /dev/null @@ -1,636 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- */ -#ifndef _PYGOBJECT_H_ -#define _PYGOBJECT_H_ - -#include - -#include -#include - -G_BEGIN_DECLS - -/* PyGClosure is a _private_ structure */ -typedef void (* PyClosureExceptionHandler) (GValue *ret, guint n_param_values, const GValue *params); -typedef struct _PyGClosure PyGClosure; -typedef struct _PyGObjectData PyGObjectData; - -struct _PyGClosure { - GClosure closure; - PyObject *callback; - PyObject *extra_args; /* tuple of extra args to pass to callback */ - PyObject *swap_data; /* other object for gtk_signal_connect__object */ - PyClosureExceptionHandler exception_handler; -}; - -typedef enum { - PYGOBJECT_USING_TOGGLE_REF = 1 << 0, - PYGOBJECT_IS_FLOATING_REF = 1 << 1, - PYGOBJECT_GOBJECT_WAS_FLOATING = 1 << 2, -} PyGObjectFlags; - - /* closures is just an alias for what is found in the - * PyGObjectData */ -typedef struct { - PyObject_HEAD - GObject *obj; - PyObject *inst_dict; /* the instance dictionary -- must be last */ - PyObject *weakreflist; /* list of weak references */ - - /*< private >*/ - /* using union to preserve ABI compatibility (structure size - * must not change) */ - union { - GSList *closures; /* stale field; no longer updated DO-NOT-USE! */ - PyGObjectFlags flags; - } private_flags; - -} PyGObject; - -#define pygobject_get(v) (((PyGObject *)(v))->obj) -#define pygobject_check(v,base) (PyObject_TypeCheck(v,base)) - -typedef struct { - PyObject_HEAD - gpointer boxed; - GType gtype; - gboolean free_on_dealloc; -} PyGBoxed; - -#define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) -#define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) - -typedef struct { - PyObject_HEAD - gpointer pointer; - GType gtype; -} PyGPointer; - -#define pyg_pointer_get(v,t) ((t *)((PyGPointer *)(v))->pointer) -#define pyg_pointer_check(v,typecode) (PyObject_TypeCheck(v, &PyGPointer_Type) && ((PyGPointer *)(v))->gtype == typecode) - -typedef void (*PyGFatalExceptionFunc) (void); -typedef void (*PyGThreadBlockFunc) (void); - -typedef struct { - PyObject_HEAD - GParamSpec *pspec; -} PyGParamSpec; - -#define PyGParamSpec_Get(v) (((PyGParamSpec *)v)->pspec) -#define PyGParamSpec_Check(v) (PyObject_TypeCheck(v, &PyGParamSpec_Type)) - -typedef int (*PyGClassInitFunc) (gpointer gclass, PyTypeObject *pyclass); -typedef PyTypeObject * (*PyGTypeRegistrationFunction) (const gchar *name, - gpointer data); - -struct _PyGObject_Functions { - /* - * All field names in here are considered private, - * use the macros below instead, which provides stability - */ - void (* register_class)(PyObject *dict, const gchar *class_name, - GType gtype, PyTypeObject *type, PyObject *bases); - void (* register_wrapper)(PyObject *self); - PyTypeObject *(* lookup_class)(GType type); - PyObject *(* newgobj)(GObject *obj); - - GClosure *(* closure_new)(PyObject *callback, PyObject *extra_args, - PyObject *swap_data); - void (* object_watch_closure)(PyObject *self, GClosure *closure); - GDestroyNotify destroy_notify; - - GType (* type_from_object)(PyObject *obj); - PyObject *(* type_wrapper_new)(GType type); - - gint (* enum_get_value)(GType enum_type, PyObject *obj, gint *val); - gint (* flags_get_value)(GType flag_type, PyObject *obj, guint *val); - void (* register_gtype_custom)(GType gtype, - PyObject *(* from_func)(const GValue *value), - int (* to_func)(GValue *value, PyObject *obj)); - int (* value_from_pyobject)(GValue *value, PyObject *obj); - PyObject *(* value_as_pyobject)(const GValue *value, gboolean copy_boxed); - - void (* register_interface)(PyObject *dict, const gchar *class_name, - GType gtype, PyTypeObject *type); - - PyTypeObject *boxed_type; - void (* register_boxed)(PyObject *dict, const gchar *class_name, - GType boxed_type, PyTypeObject *type); - PyObject *(* boxed_new)(GType boxed_type, gpointer boxed, - gboolean copy_boxed, gboolean own_ref); - - PyTypeObject *pointer_type; - void (* register_pointer)(PyObject *dict, const gchar *class_name, - GType pointer_type, PyTypeObject *type); - PyObject *(* pointer_new)(GType boxed_type, gpointer pointer); - - void (* enum_add_constants)(PyObject *module, GType enum_type, - const gchar *strip_prefix); - void (* flags_add_constants)(PyObject *module, GType flags_type, - const gchar *strip_prefix); - - const gchar *(* constant_strip_prefix)(const gchar *name, - const gchar *strip_prefix); - - gboolean (* error_check)(GError **error); - - /* hooks to register handlers for getting GDK threads to cooperate - * with python threading */ - void (* set_thread_block_funcs) (PyGThreadBlockFunc block_threads_func, - PyGThreadBlockFunc unblock_threads_func); - PyGThreadBlockFunc block_threads; - PyGThreadBlockFunc unblock_threads; - - PyTypeObject *paramspec_type; - PyObject *(* paramspec_new)(GParamSpec *spec); - GParamSpec *(*paramspec_get)(PyObject *tuple); - int (*pyobj_to_unichar_conv)(PyObject *pyobj, void* ptr); - gboolean (*parse_constructor_args)(GType obj_type, - char **arg_names, - char **prop_names, - GParameter *params, - guint *nparams, - PyObject **py_args); - PyObject *(* param_gvalue_as_pyobject) (const GValue* gvalue, - gboolean copy_boxed, - const GParamSpec* pspec); - int (* gvalue_from_param_pyobject) (GValue* value, - PyObject* py_obj, - const GParamSpec* pspec); - PyTypeObject *enum_type; - PyObject *(*enum_add)(PyObject *module, - const char *type_name_, - const char *strip_prefix, - GType gtype); - PyObject* (*enum_from_gtype)(GType gtype, int value); - - PyTypeObject *flags_type; - PyObject *(*flags_add)(PyObject *module, - const char *type_name_, - const char *strip_prefix, - GType gtype); - PyObject* (*flags_from_gtype)(GType gtype, guint value); - - gboolean threads_enabled; - int (*enable_threads) (void); - - int (*gil_state_ensure) (void); - void (*gil_state_release) (int flag); - - void (*register_class_init) (GType gtype, PyGClassInitFunc class_init); - void (*register_interface_info) (GType gtype, const GInterfaceInfo *info); - void (*closure_set_exception_handler) (GClosure *closure, PyClosureExceptionHandler handler); - - void (*add_warning_redirection) (const char *domain, - PyObject *warning); - void (*disable_warning_redirections) (void); - - /* type_register_custom API now removed, but leave a pointer here to not - * break ABI. */ - void *_type_register_custom; - - gboolean (*gerror_exception_check) (GError **error); - PyObject* (*option_group_new) (GOptionGroup *group); - GType (* type_from_object_strict) (PyObject *obj, gboolean strict); - - PyObject *(* newgobj_full)(GObject *obj, gboolean steal, gpointer g_class); - PyTypeObject *object_type; - int (* value_from_pyobject_with_error)(GValue *value, PyObject *obj); -}; - - -#ifdef DISABLE_THREADING -# define pyg_threads_enabled FALSE -# define pyg_gil_state_ensure() 0 -# define pyg_gil_state_release(state) -# define pyg_begin_allow_threads G_STMT_START { -# define pyg_end_allow_threads } G_STMT_END -#else -# define pyg_threads_enabled TRUE -# define pyg_gil_state_ensure PyGILState_Ensure -# define pyg_gil_state_release PyGILState_Release -# define pyg_begin_allow_threads Py_BEGIN_ALLOW_THREADS -# define pyg_end_allow_threads Py_END_ALLOW_THREADS -#endif - -/* Deprecated, only available for API compatibility. */ -#define pyg_enable_threads() -#define pyg_set_thread_block_funcs(a, b) -#define pyg_block_threads() -#define pyg_unblock_threads() - - -#ifndef _INSIDE_PYGOBJECT_ - -#if defined(NO_IMPORT) || defined(NO_IMPORT_PYGOBJECT) -extern struct _PyGObject_Functions *_PyGObject_API; -#else -struct _PyGObject_Functions *_PyGObject_API; -#endif - -#define pygobject_register_class (_PyGObject_API->register_class) -#define pygobject_register_wrapper (_PyGObject_API->register_wrapper) -#define pygobject_lookup_class (_PyGObject_API->lookup_class) -#define pygobject_new (_PyGObject_API->newgobj) -#define pygobject_new_full (_PyGObject_API->newgobj_full) -#define PyGObject_Type (*_PyGObject_API->object_type) -#define pyg_closure_new (_PyGObject_API->closure_new) -#define pygobject_watch_closure (_PyGObject_API->object_watch_closure) -#define pyg_closure_set_exception_handler (_PyGObject_API->closure_set_exception_handler) -#define pyg_destroy_notify (_PyGObject_API->destroy_notify) -#define pyg_type_from_object_strict (_PyGObject_API->type_from_object_strict) -#define pyg_type_from_object (_PyGObject_API->type_from_object) -#define pyg_type_wrapper_new (_PyGObject_API->type_wrapper_new) -#define pyg_enum_get_value (_PyGObject_API->enum_get_value) -#define pyg_flags_get_value (_PyGObject_API->flags_get_value) -#define pyg_register_gtype_custom (_PyGObject_API->register_gtype_custom) -#define pyg_value_from_pyobject (_PyGObject_API->value_from_pyobject) -#define pyg_value_from_pyobject_with_error (_PyGObject_API->value_from_pyobject_with_error) -#define pyg_value_as_pyobject (_PyGObject_API->value_as_pyobject) -#define pyg_register_interface (_PyGObject_API->register_interface) -#define PyGBoxed_Type (*_PyGObject_API->boxed_type) -#define pyg_register_boxed (_PyGObject_API->register_boxed) -#define pyg_boxed_new (_PyGObject_API->boxed_new) -#define PyGPointer_Type (*_PyGObject_API->pointer_type) -#define pyg_register_pointer (_PyGObject_API->register_pointer) -#define pyg_pointer_new (_PyGObject_API->pointer_new) -#define pyg_enum_add_constants (_PyGObject_API->enum_add_constants) -#define pyg_flags_add_constants (_PyGObject_API->flags_add_constants) -#define pyg_constant_strip_prefix (_PyGObject_API->constant_strip_prefix) -#define pyg_error_check (_PyGObject_API->error_check) -#define PyGParamSpec_Type (*_PyGObject_API->paramspec_type) -#define pyg_param_spec_new (_PyGObject_API->paramspec_new) -#define pyg_param_spec_from_object (_PyGObject_API->paramspec_get) -#define pyg_pyobj_to_unichar_conv (_PyGObject_API->pyobj_to_unichar_conv) -#define pyg_parse_constructor_args (_PyGObject_API->parse_constructor_args) -#define pyg_param_gvalue_as_pyobject (_PyGObject_API->value_as_pyobject) -#define pyg_param_gvalue_from_pyobject (_PyGObject_API->gvalue_from_param_pyobject) -#define PyGEnum_Type (*_PyGObject_API->enum_type) -#define pyg_enum_add (_PyGObject_API->enum_add) -#define pyg_enum_from_gtype (_PyGObject_API->enum_from_gtype) -#define PyGFlags_Type (*_PyGObject_API->flags_type) -#define pyg_flags_add (_PyGObject_API->flags_add) -#define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype) -#define pyg_register_class_init (_PyGObject_API->register_class_init) -#define pyg_register_interface_info (_PyGObject_API->register_interface_info) -#define pyg_add_warning_redirection (_PyGObject_API->add_warning_redirection) -#define pyg_disable_warning_redirections (_PyGObject_API->disable_warning_redirections) -#define pyg_gerror_exception_check (_PyGObject_API->gerror_exception_check) -#define pyg_option_group_new (_PyGObject_API->option_group_new) - - -/** - * pygobject_init: - * @req_major: minimum version major number, or -1 - * @req_minor: minimum version minor number, or -1 - * @req_micro: minimum version micro number, or -1 - * - * Imports and initializes the 'gobject' python module. Can - * optionally check for a required minimum version if @req_major, - * @req_minor, and @req_micro are all different from -1. - * - * Returns: a new reference to the gobject module on success, NULL in - * case of failure (and raises ImportError). - **/ -static inline PyObject * -pygobject_init(int req_major, int req_minor, int req_micro) -{ - PyObject *gobject, *cobject; - - gobject = PyImport_ImportModule("gi._gobject"); - if (!gobject) { - 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); - - -#if PY_VERSION_HEX < 0x03000000 - PyErr_Format(PyExc_ImportError, - "could not import gobject (error was: %s)", - PyString_AsString(py_orig_exc)); -#else - { - /* Can not use PyErr_Format because it doesn't have - * a format string for dealing with PyUnicode objects - * like PyUnicode_FromFormat has - */ - PyObject *errmsg = PyUnicode_FromFormat("could not import gobject (error was: %U)", - py_orig_exc); - - if (errmsg) { - PyErr_SetObject(PyExc_ImportError, - errmsg); - Py_DECREF(errmsg); - } - /* if errmsg is NULL then we might have OOM - * PyErr should already be set and trying to - * return our own error would be futile - */ - } -#endif - Py_DECREF(py_orig_exc); - } else { - PyErr_SetString(PyExc_ImportError, - "could not import gobject (no error given)"); - } - return NULL; - } - - cobject = PyObject_GetAttrString(gobject, "_PyGObject_API"); - if (cobject && PyCapsule_CheckExact(cobject)) - _PyGObject_API = (struct _PyGObject_Functions *) PyCapsule_GetPointer(cobject, "gobject._PyGObject_API"); - else { - PyErr_SetString(PyExc_ImportError, - "could not import gobject (could not find _PyGObject_API object)"); - Py_DECREF(gobject); - return NULL; - } - - if (req_major != -1) - { - int found_major, found_minor, found_micro; - PyObject *version; - - version = PyObject_GetAttrString(gobject, "pygobject_version"); - if (!version) { - PyErr_SetString(PyExc_ImportError, - "could not import gobject (version too old)"); - Py_DECREF(gobject); - return NULL; - } - if (!PyArg_ParseTuple(version, "iii", - &found_major, &found_minor, &found_micro)) { - PyErr_SetString(PyExc_ImportError, - "could not import gobject (version has invalid format)"); - Py_DECREF(version); - Py_DECREF(gobject); - return NULL; - } - Py_DECREF(version); - if (req_major != found_major || - req_minor > found_minor || - (req_minor == found_minor && req_micro > found_micro)) { - PyErr_Format(PyExc_ImportError, - "could not import gobject (version mismatch, %d.%d.%d is required, " - "found %d.%d.%d)", req_major, req_minor, req_micro, - found_major, found_minor, found_micro); - Py_DECREF(gobject); - return NULL; - } - } - return gobject; -} - -/** - * PYLIST_FROMGLIBLIST: - * @type: the type of the GLib list e.g. #GList or #GSList - * @prefix: the prefix of functions that manipulate a list of the type - * given by type. - * - * A macro that creates a type specific code block which converts a GLib - * list (#GSList or #GList) to a Python list. The first two args of the macro - * are used to specify the type and list function prefix so that the type - * specific macros can be generated. - * - * The rest of the args are for the standard args for the type specific - * macro(s) created from this macro. - */ - #define PYLIST_FROMGLIBLIST(type,prefix,py_list,list,item_convert_func,\ - list_free,list_item_free) \ -G_STMT_START \ -{ \ - gint i, len; \ - PyObject *item; \ - void (*glib_list_free)(type*) = list_free; \ - GFunc glib_list_item_free = (GFunc)list_item_free; \ - \ - len = prefix##_length(list); \ - py_list = PyList_New(len); \ - for (i = 0; i < len; i++) { \ - gpointer list_item = prefix##_nth_data(list, i); \ - \ - item = item_convert_func; \ - PyList_SetItem(py_list, i, item); \ - } \ - if (glib_list_item_free != NULL) \ - prefix##_foreach(list, glib_list_item_free, NULL); \ - if (glib_list_free != NULL) \ - glib_list_free(list); \ -} G_STMT_END - -/** - * PYLIST_FROMGLIST: - * @py_list: the name of the Python list - * - * @list: the #GList to be converted to a Python list - * - * @item_convert_func: the function that converts a list item to a Python - * object. The function must refer to the list item using "@list_item" and - * must return a #PyObject* object. An example conversion function is: - * [[ - * PyString_FromString(list_item) - * ]] - * A more elaborate function is: - * [[ - * pyg_boxed_new(GTK_TYPE_RECENT_INFO, list_item, TRUE, TRUE) - * ]] - * @list_free: the name of a function that takes a single arg (the list) and - * frees its memory. Can be NULL if the list should not be freed. An example - * is: - * [[ - * g_list_free - * ]] - * @list_item_free: the name of a #GFunc function that frees the memory used - * by the items in the list or %NULL if the list items do not have to be - * freed. A simple example is: - * [[ - * g_free - * ]] - * - * A macro that adds code that converts a #GList to a Python list. - * - */ -#define PYLIST_FROMGLIST(py_list,list,item_convert_func,list_free,\ - list_item_free) \ - PYLIST_FROMGLIBLIST(GList,g_list,py_list,list,item_convert_func,\ - list_free,list_item_free) - -/** - * PYLIST_FROMGSLIST: - * @py_list: the name of the Python list - * - * @list: the #GSList to be converted to a Python list - * - * @item_convert_func: the function that converts a list item to a Python - * object. The function must refer to the list item using "@list_item" and - * must return a #PyObject* object. An example conversion function is: - * [[ - * PyString_FromString(list_item) - * ]] - * A more elaborate function is: - * [[ - * pyg_boxed_new(GTK_TYPE_RECENT_INFO, list_item, TRUE, TRUE) - * ]] - * @list_free: the name of a function that takes a single arg (the list) and - * frees its memory. Can be %NULL if the list should not be freed. An example - * is: - * [[ - * g_list_free - * ]] - * @list_item_free: the name of a #GFunc function that frees the memory used - * by the items in the list or %NULL if the list items do not have to be - * freed. A simple example is: - * [[ - * g_free - * ]] - * - * A macro that adds code that converts a #GSList to a Python list. - * - */ -#define PYLIST_FROMGSLIST(py_list,list,item_convert_func,list_free,\ - list_item_free) \ - PYLIST_FROMGLIBLIST(GSList,g_slist,py_list,list,item_convert_func,\ - list_free,list_item_free) - -/** - * PYLIST_ASGLIBLIST - * @type: the type of the GLib list e.g. GList or GSList - * @prefix: the prefix of functions that manipulate a list of the type - * given by type e.g. g_list or g_slist - * - * A macro that creates a type specific code block to be used to convert a - * Python list to a GLib list (GList or GSList). The first two args of the - * macro are used to specify the type and list function prefix so that the - * type specific macros can be generated. - * - * The rest of the args are for the standard args for the type specific - * macro(s) created from this macro. - */ -#define PYLIST_ASGLIBLIST(type,prefix,py_list,list,check_func,\ - convert_func,child_free_func,errormsg,errorreturn) \ -G_STMT_START \ -{ \ - Py_ssize_t i, n_list; \ - GFunc glib_child_free_func = (GFunc)child_free_func; \ - \ - if (!(py_list = PySequence_Fast(py_list, ""))) { \ - errormsg; \ - return errorreturn; \ - } \ - n_list = PySequence_Fast_GET_SIZE(py_list); \ - for (i = 0; i < n_list; i++) { \ - PyObject *py_item = PySequence_Fast_GET_ITEM(py_list, i); \ - \ - if (!check_func) { \ - if (glib_child_free_func) \ - prefix##_foreach(list, glib_child_free_func, NULL); \ - prefix##_free(list); \ - Py_DECREF(py_list); \ - errormsg; \ - return errorreturn; \ - } \ - list = prefix##_prepend(list, convert_func); \ - }; \ - Py_DECREF(py_list); \ - list = prefix##_reverse(list); \ -} \ -G_STMT_END -/** - * PYLIST_ASGLIST - * @py_list: the Python list to be converted - * @list: the #GList list to be converted - * @check_func: the expression that takes a #PyObject* arg (must be named - * @py_item) and returns an int value indicating if the Python object matches - * the required list item type (0 - %False or 1 - %True). An example is: - * [[ - * (PyString_Check(py_item)||PyUnicode_Check(py_item)) - * ]] - * @convert_func: the function that takes a #PyObject* arg (must be named - * py_item) and returns a pointer to the converted list object. An example - * is: - * [[ - * pygobject_get(py_item) - * ]] - * @child_free_func: the name of a #GFunc function that frees a GLib list - * item or %NULL if the list item does not have to be freed. This function is - * used to help free the items in a partially created list if there is an - * error. An example is: - * [[ - * g_free - * ]] - * @errormsg: a function that sets up a Python error message. An example is: - * [[ - * PyErr_SetString(PyExc_TypeError, "strings must be a sequence of" "strings - * or unicode objects") - * ]] - * @errorreturn: the value to return if an error occurs, e.g.: - * [[ - * %NULL - * ]] - * - * A macro that creates code that converts a Python list to a #GList. The - * returned list must be freed using the appropriate list free function when - * it's no longer needed. If an error occurs the child_free_func is used to - * release the memory used by the list items and then the list memory is - * freed. - */ -#define PYLIST_ASGLIST(py_list,list,check_func,convert_func,child_free_func,\ - errormsg,errorreturn) \ - PYLIST_ASGLIBLIST(GList,g_list,py_list,list,check_func,convert_func,\ - child_free_func,errormsg,errorreturn) - -/** - * PYLIST_ASGSLIST - * @py_list: the Python list to be converted - * @list: the #GSList list to be converted - * @check_func: the expression that takes a #PyObject* arg (must be named - * @py_item) and returns an int value indicating if the Python object matches - * the required list item type (0 - %False or 1 - %True). An example is: - * [[ - * (PyString_Check(py_item)||PyUnicode_Check(py_item)) - * ]] - * @convert_func: the function that takes a #PyObject* arg (must be named - * py_item) and returns a pointer to the converted list object. An example - * is: - * [[ - * pygobject_get(py_item) - * ]] - * @child_free_func: the name of a #GFunc function that frees a GLib list - * item or %NULL if the list item does not have to be freed. This function is - * used to help free the items in a partially created list if there is an - * error. An example is: - * [[ - * g_free - * ]] - * @errormsg: a function that sets up a Python error message. An example is: - * [[ - * PyErr_SetString(PyExc_TypeError, "strings must be a sequence of" "strings - * or unicode objects") - * ]] - * @errorreturn: the value to return if an error occurs, e.g.: - * [[ - * %NULL - * ]] - * - * A macro that creates code that converts a Python list to a #GSList. The - * returned list must be freed using the appropriate list free function when - * it's no longer needed. If an error occurs the child_free_func is used to - * release the memory used by the list items and then the list memory is - * freed. - */ -#define PYLIST_ASGSLIST(py_list,list,check_func,convert_func,child_free_func,\ - errormsg,errorreturn) \ - PYLIST_ASGLIBLIST(GSList,g_slist,py_list,list,check_func,convert_func,\ - child_free_func,errormsg,errorreturn) - -#endif /* !_INSIDE_PYGOBJECT_ */ - -G_END_DECLS - -#endif /* !_PYGOBJECT_H_ */ diff --git a/gi/_gobject/pygparamspec.c b/gi/_gobject/pygparamspec.c deleted file mode 100644 index 938f7975..00000000 --- a/gi/_gobject/pygparamspec.c +++ /dev/null @@ -1,418 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * Copyright (C) 2004 Johan Dahlin - * - * pygenum.c: GEnum and GFlag wrappers - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "pygobject-private.h" -#include "pygparamspec.h" - -PYGLIB_DEFINE_TYPE("gobject.GParamSpec", PyGParamSpec_Type, PyGParamSpec); - -static PyObject* -pyg_param_spec_richcompare(PyObject *self, PyObject *other, int op) -{ - if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGParamSpec_Type) - return _pyglib_generic_ptr_richcompare(((PyGParamSpec*)self)->pspec, - ((PyGParamSpec*)other)->pspec, - op); - else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static long -pyg_param_spec_hash(PyGParamSpec *self) -{ - return (long)self->pspec; -} - -static PyObject * -pyg_param_spec_repr(PyGParamSpec *self) -{ - char buf[80]; - - g_snprintf(buf, sizeof(buf), "<%s '%s'>", - G_PARAM_SPEC_TYPE_NAME(self->pspec), - g_param_spec_get_name(self->pspec)); - return PYGLIB_PyUnicode_FromString(buf); -} - -static void -pyg_param_spec_dealloc(PyGParamSpec *self) -{ - g_param_spec_unref(self->pspec); - PyObject_DEL(self); -} - - -static PyObject * -pygenum_from_pspec(GParamSpec *pspec) -{ - PyObject *pyclass; - GParamSpecEnum *enum_pspec; - GType enum_type; - - enum_pspec = G_PARAM_SPEC_ENUM(pspec); - enum_type = G_ENUM_CLASS_TYPE(enum_pspec->enum_class); - pyclass = (PyObject*)g_type_get_qdata(enum_type, pygenum_class_key); - if (pyclass == NULL) { - pyclass = pyg_enum_add(NULL, g_type_name(enum_type), NULL, enum_type); - if (pyclass == NULL) - pyclass = Py_None; - } - - Py_INCREF(pyclass); - return pyclass; -} - -static PyObject * -pygflags_from_pspec(GParamSpec *pspec) -{ - PyObject *pyclass; - GParamSpecFlags *flag_pspec; - GType flag_type; - - flag_pspec = G_PARAM_SPEC_FLAGS(pspec); - flag_type = G_FLAGS_CLASS_TYPE(flag_pspec->flags_class); - pyclass = (PyObject*)g_type_get_qdata(flag_type, pygflags_class_key); - if (pyclass == NULL) { - pyclass = pyg_flags_add(NULL, g_type_name(flag_type), NULL, flag_type); - if (pyclass == NULL) - pyclass = Py_None; - } - Py_INCREF(pyclass); - return pyclass; -} - -static PyObject * -pyg_param_spec_getattr(PyGParamSpec *self, const gchar *attr) -{ - GParamSpec *pspec; - - pspec = self->pspec; - - /* common attributes */ - if (!strcmp(attr, "__gtype__")) { - return pyg_type_wrapper_new(G_PARAM_SPEC_TYPE(pspec)); - } else if (!strcmp(attr, "name")) { - return Py_BuildValue("s", g_param_spec_get_name(pspec)); - } else if (!strcmp(attr, "nick")) { - return Py_BuildValue("s", g_param_spec_get_nick(pspec)); - } else if (!strcmp(attr, "blurb") || !strcmp(attr, "__doc__")) { - return Py_BuildValue("s", g_param_spec_get_blurb(pspec)); - } else if (!strcmp(attr, "flags")) { - return PYGLIB_PyLong_FromLong(pspec->flags); - } else if (!strcmp(attr, "value_type")) { - return pyg_type_wrapper_new(pspec->value_type); - } else if (!strcmp(attr, "owner_type")) { - return pyg_type_wrapper_new(pspec->owner_type); - } - - if (G_IS_PARAM_SPEC_CHAR(pspec)) { - if (!strcmp(attr, "default_value")) { - return PYGLIB_PyUnicode_FromFormat( - "%c", G_PARAM_SPEC_CHAR(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_CHAR(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_CHAR(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { - if (!strcmp(attr, "default_value")) { - return PYGLIB_PyUnicode_FromFormat( - "%c", G_PARAM_SPEC_UCHAR(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_UCHAR(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_UCHAR(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyBool_FromLong(G_PARAM_SPEC_BOOLEAN(pspec)->default_value); - } - } else if (G_IS_PARAM_SPEC_INT(pspec)) { - if (!strcmp(attr, "default_value")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UINT(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_LONG(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_INT64(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - if (!strcmp(attr, "default_value")) { - return PYGLIB_PyUnicode_FromFormat( - "%c", G_PARAM_SPEC_UNICHAR(pspec)->default_value); - } - } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { - if (!strcmp(attr, "default_value")) { - return pyg_enum_from_gtype( - pspec->value_type, G_PARAM_SPEC_ENUM(pspec)->default_value); - } else if (!strcmp(attr, "enum_class")) { - return pygenum_from_pspec(pspec); - } - } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { - if (!strcmp(attr, "default_value")) { - return pyg_flags_from_gtype( - pspec->value_type, G_PARAM_SPEC_FLAGS(pspec)->default_value); - } else if (!strcmp(attr, "flags_class")) { - return pygflags_from_pspec(pspec); - } - } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->maximum); - } else if (!strcmp(attr, "epsilon")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->epsilon); - } - } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { - if (!strcmp(attr, "default_value")) { - return PyFloat_FromDouble( - G_PARAM_SPEC_DOUBLE(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->maximum); - } else if (!strcmp(attr, "epsilon")) { - return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->epsilon); - } - } else if (G_IS_PARAM_SPEC_STRING(pspec)) { - if (!strcmp(attr, "default_value")) { - return Py_BuildValue( - "s", G_PARAM_SPEC_STRING(pspec)->default_value); - } else if (!strcmp(attr, "cset_first")) { - return Py_BuildValue( - "s", G_PARAM_SPEC_STRING(pspec)->cset_first); - } else if (!strcmp(attr, "cset_nth")) { - return Py_BuildValue( - "s", G_PARAM_SPEC_STRING(pspec)->cset_nth); - } else if (!strcmp(attr, "substitutor")) { - return Py_BuildValue( - "c", G_PARAM_SPEC_STRING(pspec)->substitutor); - } else if (!strcmp(attr, "null_fold_if_empty")) { - return PyBool_FromLong( - G_PARAM_SPEC_STRING(pspec)->null_fold_if_empty); - } else if (!strcmp(attr, "ensure_non_null")) { - return PyBool_FromLong( - G_PARAM_SPEC_STRING(pspec)->ensure_non_null); - } - } else { - /* This is actually not what's exported by GObjects paramspecs, - * But we exported this in earlier versions, so it's better to keep it here - * compatibility. But don't return it in __dir__, to "hide" it. - */ - if (!strcmp(attr, "default_value")) { - /* XXX: Raise deprecation warning */ - Py_INCREF(Py_None); - return Py_None; - } - } - - PyErr_SetString(PyExc_AttributeError, attr); - return NULL; -} - - -static PyObject * -pyg_param_spec_dir(PyGParamSpec *self, PyObject *dummy) -{ - GParamSpec *pspec = self->pspec; - - if (G_IS_PARAM_SPEC_CHAR(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", "flags", - "maximum", "minimum", "name", "nick", - "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", - "name", "nick", "owner_type", - "value_type"); - } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { - return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "name", "nick", "owner_type", - "value_type"); - } else if (G_IS_PARAM_SPEC_INT(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_UINT(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", - "name", "nick", "owner_type", - "value_type"); - } else if (G_IS_PARAM_SPEC_LONG(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_INT64(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", - "name", "nick", "owner_type", - "value_type"); - } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "name", "nick", "owner_type", - "value_type"); - } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { - return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", "enum_class", - "flags", "name", "nick", "owner_type", - "value_type"); - } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { - return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "flags_class", "name", "nick", - "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { - return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", - "blurb", "epsilon", - "flags", "maximum", "minimum", "name", "nick", "owner_type", - "value_type", - "default_value"); - } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { - return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", "epsilon", - "flags", "maximum", "minimum", "name", "nick", - "owner_type", "value_type"); - } else if (G_IS_PARAM_SPEC_STRING(pspec)) { - return Py_BuildValue("[ssssssssssssss]", "__doc__", "__gtype__", - "blurb", "cset_first", "cset_nth", "default_value", - "ensure_non_null", "flags", "name", "nick", - "null_fold_if_empty", "owner_type", "substitutor", - "value_type"); - } else { - return Py_BuildValue("[ssssssss]", "__doc__", "__gtype__", "blurb", - "flags", "name", "nick", - "owner_type", "value_type"); - } -} - -static PyMethodDef pyg_param_spec_methods[] = { - { "__dir__", (PyCFunction)pyg_param_spec_dir, METH_NOARGS}, - { NULL, NULL, 0} -}; - -/** - * pyg_param_spec_new: - * @pspec: a GParamSpec. - * - * Creates a wrapper for a GParamSpec. - * - * Returns: the GParamSpec wrapper. - */ -PyObject * -pyg_param_spec_new(GParamSpec *pspec) -{ - PyGParamSpec *self; - - self = (PyGParamSpec *)PyObject_NEW(PyGParamSpec, - &PyGParamSpec_Type); - if (self == NULL) - return NULL; - - self->pspec = g_param_spec_ref(pspec); - return (PyObject *)self; -} - -void -pygobject_paramspec_register_types(PyObject *d) -{ - Py_TYPE(&PyGParamSpec_Type) = &PyType_Type; - PyGParamSpec_Type.tp_dealloc = (destructor)pyg_param_spec_dealloc; - PyGParamSpec_Type.tp_getattr = (getattrfunc)pyg_param_spec_getattr; - PyGParamSpec_Type.tp_richcompare = pyg_param_spec_richcompare; - PyGParamSpec_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGParamSpec_Type.tp_repr = (reprfunc)pyg_param_spec_repr; - PyGParamSpec_Type.tp_hash = (hashfunc)pyg_param_spec_hash; - PyGParamSpec_Type.tp_methods = pyg_param_spec_methods; - - - if (PyType_Ready(&PyGParamSpec_Type)) - return; - PyDict_SetItemString(d, "GParamSpec", (PyObject *)&PyGParamSpec_Type); -} diff --git a/gi/_gobject/pygparamspec.h b/gi/_gobject/pygparamspec.h deleted file mode 100644 index 64aab0ce..00000000 --- a/gi/_gobject/pygparamspec.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_PARAMSPEC_H__ -#define __PYGOBJECT_PARAMSPEC_H__ - -extern PyTypeObject PyGParamSpec_Type; -PyObject * pyg_param_spec_new (GParamSpec *pspec); - -void pygobject_paramspec_register_types(PyObject *d); - -#endif /* __PYGOBJECT_PARAMSPEC_H__ */ diff --git a/gi/_gobject/pygpointer.c b/gi/_gobject/pygpointer.c deleted file mode 100644 index 575c7511..00000000 --- a/gi/_gobject/pygpointer.c +++ /dev/null @@ -1,198 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * pygpointer.c: wrapper for GPointer - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include "pygobject-private.h" -#include "pygpointer.h" - -#include "pygi.h" - - -GQuark pygpointer_class_key; - -PYGLIB_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer); - -static void -pyg_pointer_dealloc(PyGPointer *self) -{ - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyObject* -pyg_pointer_richcompare(PyObject *self, PyObject *other, int op) -{ - if (Py_TYPE(self) == Py_TYPE(other)) - return _pyglib_generic_ptr_richcompare(((PyGPointer*)self)->pointer, - ((PyGPointer*)other)->pointer, - op); - else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static long -pyg_pointer_hash(PyGPointer *self) -{ - return (long)self->pointer; -} - -static PyObject * -pyg_pointer_repr(PyGPointer *self) -{ - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), - (long)self->pointer); - return PYGLIB_PyUnicode_FromString(buf); -} - -static int -pyg_pointer_init(PyGPointer *self, PyObject *args, PyObject *kwargs) -{ - gchar buf[512]; - - if (!PyArg_ParseTuple(args, ":GPointer.__init__")) - return -1; - - self->pointer = NULL; - self->gtype = 0; - - g_snprintf(buf, sizeof(buf), "%s can not be constructed", - Py_TYPE(self)->tp_name); - PyErr_SetString(PyExc_NotImplementedError, buf); - return -1; -} - -static void -pyg_pointer_free(PyObject *op) -{ - PyObject_FREE(op); -} - -/** - * pyg_register_pointer: - * @dict: the module dictionary to store the wrapper class. - * @class_name: the Python name for the wrapper class. - * @pointer_type: the GType of the pointer type being wrapped. - * @type: the wrapper class. - * - * Registers a wrapper for a pointer type. The wrapper class will be - * a subclass of gobject.GPointer, and a reference to the wrapper - * class will be stored in the provided module dictionary. - */ -void -pyg_register_pointer(PyObject *dict, const gchar *class_name, - GType pointer_type, PyTypeObject *type) -{ - PyObject *o; - - g_return_if_fail(dict != NULL); - g_return_if_fail(class_name != NULL); - g_return_if_fail(pointer_type != 0); - - if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_pointer_dealloc; - - Py_TYPE(type) = &PyType_Type; - type->tp_base = &PyGPointer_Type; - - if (PyType_Ready(type) < 0) { - g_warning("could not get type `%s' ready", type->tp_name); - return; - } - - PyDict_SetItemString(type->tp_dict, "__gtype__", - o=pyg_type_wrapper_new(pointer_type)); - Py_DECREF(o); - - g_type_set_qdata(pointer_type, pygpointer_class_key, type); - - PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); -} - -/** - * pyg_pointer_new: - * @pointer_type: the GType of the pointer value. - * @pointer: the pointer value. - * - * Creates a wrapper for a pointer value. Since G_TYPE_POINTER types - * don't register any information about how to copy/free them, there - * is no guarantee that the pointer will remain valid, and there is - * nothing registered to release the pointer when the pointer goes out - * of scope. This is why we don't recommend people use these types. - * - * Returns: the boxed wrapper. - */ -PyObject * -pyg_pointer_new(GType pointer_type, gpointer pointer) -{ - PyGILState_STATE state; - PyGPointer *self; - PyTypeObject *tp; - g_return_val_if_fail(pointer_type != 0, NULL); - - state = pyglib_gil_state_ensure(); - - if (!pointer) { - Py_INCREF(Py_None); - pyglib_gil_state_release(state); - return Py_None; - } - - tp = g_type_get_qdata(pointer_type, pygpointer_class_key); - - if (!tp) - tp = (PyTypeObject *)pygi_type_import_by_g_type(pointer_type); - - if (!tp) - tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */ - self = PyObject_NEW(PyGPointer, tp); - - pyglib_gil_state_release(state); - - if (self == NULL) - return NULL; - - self->pointer = pointer; - self->gtype = pointer_type; - - return (PyObject *)self; -} - -void -pygobject_pointer_register_types(PyObject *d) -{ - pygpointer_class_key = g_quark_from_static_string("PyGPointer::class"); - - PyGPointer_Type.tp_dealloc = (destructor)pyg_pointer_dealloc; - PyGPointer_Type.tp_richcompare = pyg_pointer_richcompare; - PyGPointer_Type.tp_repr = (reprfunc)pyg_pointer_repr; - PyGPointer_Type.tp_hash = (hashfunc)pyg_pointer_hash; - PyGPointer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyGPointer_Type.tp_init = (initproc)pyg_pointer_init; - PyGPointer_Type.tp_free = (freefunc)pyg_pointer_free; - PYGOBJECT_REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER); -} diff --git a/gi/_gobject/pygpointer.h b/gi/_gobject/pygpointer.h deleted file mode 100644 index f2923daa..00000000 --- a/gi/_gobject/pygpointer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_POINTER_H__ -#define __PYGOBJECT_POINTER_H__ - -void pygobject_pointer_register_types(PyObject *d); - -#endif /* __PYGOBJECT_POINTER_H__ */ diff --git a/gi/_gobject/pygtype.c b/gi/_gobject/pygtype.c deleted file mode 100644 index 9dc1153e..00000000 --- a/gi/_gobject/pygtype.c +++ /dev/null @@ -1,1927 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * pygtype.c: glue code to wrap the GType code. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include "pygobject-private.h" -#include "pygparamspec.h" -#include "pygtype.h" - -/* -------------- __gtype__ objects ---------------------------- */ - -typedef struct { - PyObject_HEAD - GType type; -} PyGTypeWrapper; - -PYGLIB_DEFINE_TYPE("gobject.GType", PyGTypeWrapper_Type, PyGTypeWrapper); - -static PyObject* -pyg_type_wrapper_richcompare(PyObject *self, PyObject *other, int op) -{ - if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGTypeWrapper_Type) - return _pyglib_generic_long_richcompare(((PyGTypeWrapper*)self)->type, - ((PyGTypeWrapper*)other)->type, - op); - else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static long -pyg_type_wrapper_hash(PyGTypeWrapper *self) -{ - return (long)self->type; -} - -static PyObject * -pyg_type_wrapper_repr(PyGTypeWrapper *self) -{ - char buf[80]; - const gchar *name = g_type_name(self->type); - - g_snprintf(buf, sizeof(buf), "", - name?name:"invalid", (unsigned long int) self->type); - return PYGLIB_PyUnicode_FromString(buf); -} - -static void -pyg_type_wrapper_dealloc(PyGTypeWrapper *self) -{ - PyObject_DEL(self); -} - -static GQuark -_pyg_type_key(GType type) { - GQuark key; - - if (g_type_is_a(type, G_TYPE_INTERFACE)) { - key = pyginterface_type_key; - } else if (g_type_is_a(type, G_TYPE_ENUM)) { - key = pygenum_class_key; - } else if (g_type_is_a(type, G_TYPE_FLAGS)) { - key = pygflags_class_key; - } else if (g_type_is_a(type, G_TYPE_POINTER)) { - key = pygpointer_class_key; - } else if (g_type_is_a(type, G_TYPE_BOXED)) { - key = pygboxed_type_key; - } else { - key = pygobject_class_key; - } - - return key; -} - -static PyObject * -_wrap_g_type_wrapper__get_pytype(PyGTypeWrapper *self, void *closure) -{ - GQuark key; - PyObject *py_type; - - key = _pyg_type_key(self->type); - - py_type = g_type_get_qdata(self->type, key); - if (!py_type) - py_type = Py_None; - - Py_INCREF(py_type); - return py_type; -} - -static int -_wrap_g_type_wrapper__set_pytype(PyGTypeWrapper *self, PyObject* value, void *closure) -{ - GQuark key; - PyObject *py_type; - - key = _pyg_type_key(self->type); - - py_type = g_type_get_qdata(self->type, key); - Py_CLEAR(py_type); - if (value == Py_None) - g_type_set_qdata(self->type, key, NULL); - else if (PyType_Check(value)) { - Py_INCREF(value); - g_type_set_qdata(self->type, key, value); - } else { - PyErr_SetString(PyExc_TypeError, "Value must be None or a type object"); - return -1; - } - - return 0; -} - -static PyObject * -_wrap_g_type_wrapper__get_name(PyGTypeWrapper *self, void *closure) -{ - const char *name = g_type_name(self->type); - return PYGLIB_PyUnicode_FromString(name ? name : "invalid"); -} - -static PyObject * -_wrap_g_type_wrapper__get_parent(PyGTypeWrapper *self, void *closure) -{ - return pyg_type_wrapper_new(g_type_parent(self->type)); -} - -static PyObject * -_wrap_g_type_wrapper__get_fundamental(PyGTypeWrapper *self, void *closure) -{ - return pyg_type_wrapper_new(g_type_fundamental(self->type)); -} - -static PyObject * -_wrap_g_type_wrapper__get_children(PyGTypeWrapper *self, void *closure) -{ - guint n_children, i; - GType *children; - PyObject *retval; - - children = g_type_children(self->type, &n_children); - - retval = PyList_New(n_children); - for (i = 0; i < n_children; i++) - PyList_SetItem(retval, i, pyg_type_wrapper_new(children[i])); - g_free(children); - - return retval; -} - -static PyObject * -_wrap_g_type_wrapper__get_interfaces(PyGTypeWrapper *self, void *closure) -{ - guint n_interfaces, i; - GType *interfaces; - PyObject *retval; - - interfaces = g_type_interfaces(self->type, &n_interfaces); - - retval = PyList_New(n_interfaces); - for (i = 0; i < n_interfaces; i++) - PyList_SetItem(retval, i, pyg_type_wrapper_new(interfaces[i])); - g_free(interfaces); - - return retval; -} - -static PyObject * -_wrap_g_type_wrapper__get_depth(PyGTypeWrapper *self, void *closure) -{ - return PYGLIB_PyLong_FromLong(g_type_depth(self->type)); -} - -static PyGetSetDef _PyGTypeWrapper_getsets[] = { - { "pytype", (getter)_wrap_g_type_wrapper__get_pytype, (setter)_wrap_g_type_wrapper__set_pytype }, - { "name", (getter)_wrap_g_type_wrapper__get_name, (setter)0 }, - { "fundamental", (getter)_wrap_g_type_wrapper__get_fundamental, (setter)0 }, - { "parent", (getter)_wrap_g_type_wrapper__get_parent, (setter)0 }, - { "children", (getter)_wrap_g_type_wrapper__get_children, (setter)0 }, - { "interfaces", (getter)_wrap_g_type_wrapper__get_interfaces, (setter)0 }, - { "depth", (getter)_wrap_g_type_wrapper__get_depth, (setter)0 }, - { NULL, (getter)0, (setter)0 } -}; - -static PyObject* -_wrap_g_type_is_interface(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_INTERFACE(self->type)); -} - -static PyObject* -_wrap_g_type_is_classed(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_CLASSED(self->type)); -} - -static PyObject* -_wrap_g_type_is_instantiatable(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_INSTANTIATABLE(self->type)); -} - -static PyObject* -_wrap_g_type_is_derivable(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_DERIVABLE(self->type)); -} - -static PyObject* -_wrap_g_type_is_deep_derivable(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_DEEP_DERIVABLE(self->type)); -} - -static PyObject* -_wrap_g_type_is_abstract(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_ABSTRACT(self->type)); -} - -static PyObject* -_wrap_g_type_is_value_abstract(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_VALUE_ABSTRACT(self->type)); -} - -static PyObject* -_wrap_g_type_is_value_type(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_VALUE_TYPE(self->type)); -} - -static PyObject* -_wrap_g_type_has_value_table(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_HAS_VALUE_TABLE(self->type)); -} - -static PyObject* -_wrap_g_type_from_name(PyGTypeWrapper *_, PyObject *args) -{ - char *type_name; - GType type; - - if (!PyArg_ParseTuple(args, "s:GType.from_name", &type_name)) - return NULL; - - type = g_type_from_name(type_name); - if (type == 0) { - PyErr_SetString(PyExc_RuntimeError, "unknown type name"); - return NULL; - } - - return pyg_type_wrapper_new(type); -} - -static PyObject* -_wrap_g_type_is_a(PyGTypeWrapper *self, PyObject *args) -{ - PyObject *gparent; - GType parent; - - if (!PyArg_ParseTuple(args, "O:GType.is_a", &gparent)) - return NULL; - else if ((parent = pyg_type_from_object(gparent)) == 0) - return NULL; - - return PyBool_FromLong(g_type_is_a(self->type, parent)); -} - -static PyMethodDef _PyGTypeWrapper_methods[] = { - { "is_interface", (PyCFunction)_wrap_g_type_is_interface, METH_NOARGS }, - { "is_classed", (PyCFunction)_wrap_g_type_is_classed, METH_NOARGS }, - { "is_instantiatable", (PyCFunction)_wrap_g_type_is_instantiatable, METH_NOARGS }, - { "is_derivable", (PyCFunction)_wrap_g_type_is_derivable, METH_NOARGS }, - { "is_deep_derivable", (PyCFunction)_wrap_g_type_is_deep_derivable, METH_NOARGS }, - { "is_abstract", (PyCFunction)_wrap_g_type_is_abstract, METH_NOARGS }, - { "is_value_abstract", (PyCFunction)_wrap_g_type_is_value_abstract, METH_NOARGS }, - { "is_value_type", (PyCFunction)_wrap_g_type_is_value_type, METH_NOARGS }, - { "has_value_table", (PyCFunction)_wrap_g_type_has_value_table, METH_NOARGS }, - { "from_name", (PyCFunction)_wrap_g_type_from_name, METH_VARARGS | METH_STATIC }, - { "is_a", (PyCFunction)_wrap_g_type_is_a, METH_VARARGS }, - { NULL, 0, 0 } -}; - -static int -pyg_type_wrapper_init(PyGTypeWrapper *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "object", NULL }; - PyObject *py_object; - GType type; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O:GType.__init__", - kwlist, &py_object)) - return -1; - - if (!(type = pyg_type_from_object(py_object))) - return -1; - - self->type = type; - - return 0; -} - -/** - * pyg_type_wrapper_new: - * type: a GType - * - * Creates a Python wrapper for a GType. - * - * Returns: the Python wrapper. - */ -PyObject * -pyg_type_wrapper_new(GType type) -{ - PyGTypeWrapper *self; - - self = (PyGTypeWrapper *)PyObject_NEW(PyGTypeWrapper, - &PyGTypeWrapper_Type); - if (self == NULL) - return NULL; - - self->type = type; - return (PyObject *)self; -} - -/** - * pyg_type_from_object_strict: - * obj: a Python object - * strict: if set to TRUE, raises an exception if it can't perform the - * conversion - * - * converts a python object to a GType. If strict is set, raises an - * exception if it can't perform the conversion, otherwise returns - * PY_TYPE_OBJECT. - * - * Returns: the corresponding GType, or 0 on error. - */ - -GType -pyg_type_from_object_strict(PyObject *obj, gboolean strict) -{ - PyObject *gtype; - GType type; - - /* NULL check */ - if (!obj) { - PyErr_SetString(PyExc_TypeError, "can't get type from NULL object"); - return 0; - } - - /* map some standard types to primitive GTypes ... */ - if (obj == Py_None) - return G_TYPE_NONE; - if (PyType_Check(obj)) { - PyTypeObject *tp = (PyTypeObject *)obj; - - if (tp == &PYGLIB_PyLong_Type) - return G_TYPE_INT; - else if (tp == &PyBool_Type) - return G_TYPE_BOOLEAN; - else if (tp == &PyLong_Type) - return G_TYPE_LONG; - else if (tp == &PyFloat_Type) - return G_TYPE_DOUBLE; - else if (tp == &PYGLIB_PyUnicode_Type) - return G_TYPE_STRING; - else if (tp == &PyBaseObject_Type) - return PY_TYPE_OBJECT; - } - - if (Py_TYPE(obj) == &PyGTypeWrapper_Type) { - return ((PyGTypeWrapper *)obj)->type; - } - - /* handle strings */ - if (PYGLIB_PyUnicode_Check(obj)) { - gchar *name = PYGLIB_PyUnicode_AsString(obj); - - type = g_type_from_name(name); - if (type != 0) { - return type; - } - } - - /* finally, look for a __gtype__ attribute on the object */ - gtype = PyObject_GetAttrString(obj, "__gtype__"); - - if (gtype) { - if (Py_TYPE(gtype) == &PyGTypeWrapper_Type) { - type = ((PyGTypeWrapper *)gtype)->type; - Py_DECREF(gtype); - return type; - } - Py_DECREF(gtype); - } - - PyErr_Clear(); - - /* Some API like those that take GValues can hold a python object as - * a pointer. This is potentially dangerous becuase everything is - * passed in as a PyObject so we can't actually type check it. Only - * fallback to PY_TYPE_OBJECT if strict checking is disabled - */ - if (!strict) - return PY_TYPE_OBJECT; - - PyErr_SetString(PyExc_TypeError, "could not get typecode from object"); - return 0; -} - -/** - * pyg_type_from_object: - * obj: a Python object - * - * converts a python object to a GType. Raises an exception if it - * can't perform the conversion. - * - * Returns: the corresponding GType, or 0 on error. - */ -GType -pyg_type_from_object(PyObject *obj) -{ - /* Legacy call always defaults to strict type checking */ - return pyg_type_from_object_strict(obj, TRUE); -} - -/* -------------- GValue marshalling ------------------ */ - -/** - * pyg_enum_get_value: - * @enum_type: the GType of the flag. - * @obj: a Python object representing the flag value - * @val: a pointer to the location to store the integer representation of the flag. - * - * Converts a Python object to the integer equivalent. The conversion - * will depend on the type of the Python object. If the object is an - * integer, it is passed through directly. If it is a string, it will - * be treated as a full or short enum name as defined in the GType. - * - * Returns: 0 on success or -1 on failure - */ -gint -pyg_enum_get_value(GType enum_type, PyObject *obj, gint *val) -{ - GEnumClass *eclass = NULL; - gint res = -1; - - g_return_val_if_fail(val != NULL, -1); - if (!obj) { - *val = 0; - res = 0; - } else if (PYGLIB_PyLong_Check(obj)) { - *val = PYGLIB_PyLong_AsLong(obj); - res = 0; - - if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { - g_warning("expected enumeration type %s, but got %s instead", - g_type_name(enum_type), - g_type_name(((PyGEnum *) obj)->gtype)); - } - /* Dumb code duplication, but probably not worth it to have yet another macro. */ - } else if (PyLong_Check(obj)) { - *val = PyLong_AsLong(obj); - res = 0; - - if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { - g_warning("expected enumeration type %s, but got %s instead", - g_type_name(enum_type), - g_type_name(((PyGEnum *) obj)->gtype)); - } - } else if (PYGLIB_PyUnicode_Check(obj)) { - GEnumValue *info; - char *str = PYGLIB_PyUnicode_AsString(obj); - - if (enum_type != G_TYPE_NONE) - eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); - else { - PyErr_SetString(PyExc_TypeError, "could not convert string to enum because there is no GType associated to look up the value"); - res = -1; - } - info = g_enum_get_value_by_name(eclass, str); - g_type_class_unref(eclass); - - if (!info) - info = g_enum_get_value_by_nick(eclass, str); - if (info) { - *val = info->value; - res = 0; - } else { - PyErr_SetString(PyExc_TypeError, "could not convert string"); - res = -1; - } - } else { - PyErr_SetString(PyExc_TypeError,"enum values must be strings or ints"); - res = -1; - } - return res; -} - -/** - * pyg_flags_get_value: - * @flag_type: the GType of the flag. - * @obj: a Python object representing the flag value - * @val: a pointer to the location to store the integer representation of the flag. - * - * Converts a Python object to the integer equivalent. The conversion - * will depend on the type of the Python object. If the object is an - * integer, it is passed through directly. If it is a string, it will - * be treated as a full or short flag name as defined in the GType. - * If it is a tuple, then the items are treated as strings and ORed - * together. - * - * Returns: 0 on success or -1 on failure - */ -gint -pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val) -{ - GFlagsClass *fclass = NULL; - gint res = -1; - - g_return_val_if_fail(val != NULL, -1); - if (!obj) { - *val = 0; - res = 0; - } else if (PYGLIB_PyLong_Check(obj)) { - *val = PYGLIB_PyLong_AsUnsignedLong(obj); - res = 0; - } else if (PyLong_Check(obj)) { - *val = PyLong_AsLongLong(obj); - res = 0; - } else if (PYGLIB_PyUnicode_Check(obj)) { - GFlagsValue *info; - char *str = PYGLIB_PyUnicode_AsString(obj); - - if (flag_type != G_TYPE_NONE) - fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); - else { - PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); - res = -1; - } - info = g_flags_get_value_by_name(fclass, str); - g_type_class_unref(fclass); - - if (!info) - info = g_flags_get_value_by_nick(fclass, str); - if (info) { - *val = info->value; - res = 0; - } else { - PyErr_SetString(PyExc_TypeError, "could not convert string"); - res = -1; - } - } else if (PyTuple_Check(obj)) { - int i, len; - - len = PyTuple_Size(obj); - *val = 0; - res = 0; - - if (flag_type != G_TYPE_NONE) - fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); - else { - PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); - res = -1; - } - - for (i = 0; i < len; i++) { - PyObject *item = PyTuple_GetItem(obj, i); - char *str = PYGLIB_PyUnicode_AsString(item); - GFlagsValue *info = g_flags_get_value_by_name(fclass, str); - - if (!info) - info = g_flags_get_value_by_nick(fclass, str); - if (info) { - *val |= info->value; - } else { - PyErr_SetString(PyExc_TypeError, "could not convert string"); - res = -1; - break; - } - } - g_type_class_unref(fclass); - } else { - PyErr_SetString(PyExc_TypeError, - "flag values must be strings, ints, longs, or tuples"); - res = -1; - } - return res; -} - -typedef struct { - fromvaluefunc fromvalue; - tovaluefunc tovalue; -} PyGTypeMarshal; -static GQuark pyg_type_marshal_key = 0; - -static PyGTypeMarshal * -pyg_type_lookup(GType type) -{ - GType ptype = type; - PyGTypeMarshal *tm = NULL; - - /* recursively lookup types */ - while (ptype) { - if ((tm = g_type_get_qdata(ptype, pyg_type_marshal_key)) != NULL) - break; - ptype = g_type_parent(ptype); - } - return tm; -} - -/** - * pyg_register_gtype_custom: - * @gtype: the GType for the new type - * @from_func: a function to convert GValues to Python objects - * @to_func: a function to convert Python objects to GValues - * - * In order to handle specific conversion of gboxed types or new - * fundamental types, you may use this function to register conversion - * handlers. - */ - -void -pyg_register_gtype_custom(GType gtype, - fromvaluefunc from_func, - tovaluefunc to_func) -{ - PyGTypeMarshal *tm; - - if (!pyg_type_marshal_key) - pyg_type_marshal_key = g_quark_from_static_string("PyGType::marshal"); - - tm = g_new(PyGTypeMarshal, 1); - tm->fromvalue = from_func; - tm->tovalue = to_func; - g_type_set_qdata(gtype, pyg_type_marshal_key, tm); -} - -static int -pyg_value_array_from_pyobject(GValue *value, - PyObject *obj, - const GParamSpecValueArray *pspec) -{ - int len; - GValueArray *value_array; - int i; - - len = PySequence_Length(obj); - if (len == -1) { - PyErr_Clear(); - return -1; - } - - if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements) - return -1; - - value_array = g_value_array_new(len); - - for (i = 0; i < len; ++i) { - PyObject *item = PySequence_GetItem(obj, i); - GType type; - GValue item_value = { 0, }; - int status; - - if (! item) { - PyErr_Clear(); - g_value_array_free(value_array); - return -1; - } - - if (pspec && pspec->element_spec) - type = G_PARAM_SPEC_VALUE_TYPE(pspec->element_spec); - else if (item == Py_None) - type = G_TYPE_POINTER; /* store None as NULL */ - else { - type = pyg_type_from_object((PyObject*)Py_TYPE(item)); - if (! type) { - PyErr_Clear(); - g_value_array_free(value_array); - Py_DECREF(item); - return -1; - } - } - - g_value_init(&item_value, type); - status = (pspec && pspec->element_spec) - ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec) - : pyg_value_from_pyobject(&item_value, item); - Py_DECREF(item); - - if (status == -1) { - g_value_array_free(value_array); - g_value_unset(&item_value); - return -1; - } - - g_value_array_append(value_array, &item_value); - g_value_unset(&item_value); - } - - g_value_take_boxed(value, value_array); - return 0; -} - -static int -pyg_array_from_pyobject(GValue *value, - PyObject *obj) -{ - int len; - GArray *array; - int i; - - len = PySequence_Length(obj); - if (len == -1) { - PyErr_Clear(); - return -1; - } - - array = g_array_new(FALSE, TRUE, sizeof(GValue)); - - for (i = 0; i < len; ++i) { - PyObject *item = PySequence_GetItem(obj, i); - GType type; - GValue item_value = { 0, }; - int status; - - if (! item) { - PyErr_Clear(); - g_array_free(array, FALSE); - return -1; - } - - if (item == Py_None) - type = G_TYPE_POINTER; /* store None as NULL */ - else { - type = pyg_type_from_object((PyObject*)Py_TYPE(item)); - if (! type) { - PyErr_Clear(); - g_array_free(array, FALSE); - Py_DECREF(item); - return -1; - } - } - - g_value_init(&item_value, type); - status = pyg_value_from_pyobject(&item_value, item); - Py_DECREF(item); - - if (status == -1) { - g_array_free(array, FALSE); - g_value_unset(&item_value); - return -1; - } - - g_array_append_val(array, item_value); - } - - g_value_take_boxed(value, array); - return 0; -} - -/** - * pyg_value_from_pyobject_with_error: - * @value: the GValue object to store the converted value in. - * @obj: the Python object to convert. - * - * This function converts a Python object and stores the result in a - * GValue. The GValue must be initialised in advance with - * g_value_init(). If the Python object can't be converted to the - * type of the GValue, then an error is returned. - * - * Returns: 0 on success, -1 on error. - */ -int -pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj) -{ - PyObject *tmp; - GType value_type = G_VALUE_TYPE(value); - - switch (G_TYPE_FUNDAMENTAL(value_type)) { - case G_TYPE_INTERFACE: - /* we only handle interface types that have a GObject prereq */ - if (g_type_is_a(value_type, G_TYPE_OBJECT)) { - if (obj == Py_None) - g_value_set_object(value, NULL); - else { - if (!PyObject_TypeCheck(obj, &PyGObject_Type)) { - PyErr_SetString(PyExc_TypeError, "GObject is required"); - return -1; - } - if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj), - value_type)) { - PyErr_SetString(PyExc_TypeError, "Invalid GObject type for assignment"); - return -1; - } - g_value_set_object(value, pygobject_get(obj)); - } - } else { - PyErr_SetString(PyExc_TypeError, "Unsupported conversion"); - return -1; - } - break; - case G_TYPE_CHAR: - if (PYGLIB_PyLong_Check(obj)) { - glong val; - val = PYGLIB_PyLong_AsLong(obj); - if (val >= -128 && val <= 127) - g_value_set_schar(value, (gchar) val); - else - return -1; - } -#if PY_VERSION_HEX < 0x03000000 - else if (PyString_Check(obj)) { - g_value_set_schar(value, PyString_AsString(obj)[0]); - } -#endif - else if (PyUnicode_Check(obj)) { - tmp = PyUnicode_AsUTF8String(obj); - g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]); - Py_DECREF(tmp); - } else { - PyErr_SetString(PyExc_TypeError, "Cannot convert to TYPE_CHAR"); - return -1; - } - - break; - case G_TYPE_UCHAR: - if (PYGLIB_PyLong_Check(obj)) { - glong val; - val = PYGLIB_PyLong_AsLong(obj); - if (val >= 0 && val <= 255) - g_value_set_uchar(value, (guchar) val); - else - return -1; -#if PY_VERSION_HEX < 0x03000000 - } else if (PyString_Check(obj)) { - g_value_set_uchar(value, PyString_AsString(obj)[0]); -#endif - } else if (PyUnicode_Check(obj)) { - tmp = PyUnicode_AsUTF8String(obj); - g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]); - Py_DECREF(tmp); - } else { - PyErr_Clear(); - return -1; - } - break; - case G_TYPE_BOOLEAN: - g_value_set_boolean(value, PyObject_IsTrue(obj)); - break; - case G_TYPE_INT: - g_value_set_int(value, PYGLIB_PyLong_AsLong(obj)); - break; - case G_TYPE_UINT: - { - if (PYGLIB_PyLong_Check(obj)) { - guint val; - - /* check that number is not negative */ - if (PyLong_AsLongLong(obj) < 0) - return -1; - - val = PyLong_AsUnsignedLong(obj); - if (val <= G_MAXUINT) - g_value_set_uint(value, val); - else - return -1; - } else { - g_value_set_uint(value, PyLong_AsUnsignedLong(obj)); - } - } - break; - case G_TYPE_LONG: - g_value_set_long(value, PYGLIB_PyLong_AsLong(obj)); - break; - case G_TYPE_ULONG: -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - long val; - - val = PYGLIB_PyLong_AsLong(obj); - if (val < 0) { - PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property"); - return -1; - } - g_value_set_ulong(value, (gulong)val); - } else -#endif - if (PyLong_Check(obj)) - g_value_set_ulong(value, PyLong_AsUnsignedLong(obj)); - else - return -1; - break; - case G_TYPE_INT64: - g_value_set_int64(value, PyLong_AsLongLong(obj)); - break; - case G_TYPE_UINT64: -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - long v = PyInt_AsLong(obj); - if (v < 0) { - PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property"); - return -1; - } - g_value_set_uint64(value, v); - } else -#endif - if (PyLong_Check(obj)) - g_value_set_uint64(value, PyLong_AsUnsignedLongLong(obj)); - else - return -1; - break; - case G_TYPE_ENUM: - { - gint val = 0; - if (pyg_enum_get_value(G_VALUE_TYPE(value), obj, &val) < 0) { - return -1; - } - g_value_set_enum(value, val); - } - break; - case G_TYPE_FLAGS: - { - guint val = 0; - if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) { - return -1; - } - g_value_set_flags(value, val); - } - break; - case G_TYPE_FLOAT: - g_value_set_float(value, PyFloat_AsDouble(obj)); - break; - case G_TYPE_DOUBLE: - g_value_set_double(value, PyFloat_AsDouble(obj)); - break; - case G_TYPE_STRING: - if (obj == Py_None) { - g_value_set_string(value, NULL); - } else { - PyObject* tmp_str = PyObject_Str(obj); - if (tmp_str == NULL) { - PyErr_Clear(); - if (PyUnicode_Check(obj)) { - tmp = PyUnicode_AsUTF8String(obj); - g_value_set_string(value, PYGLIB_PyBytes_AsString(tmp)); - Py_DECREF(tmp); - } else { - PyErr_SetString(PyExc_TypeError, "Expected string"); - return -1; - } - } else { -#if PY_VERSION_HEX < 0x03000000 - g_value_set_string(value, PyString_AsString(tmp_str)); -#else - tmp = PyUnicode_AsUTF8String(tmp_str); - g_value_set_string(value, PyBytes_AsString(tmp)); - Py_DECREF(tmp); -#endif - } - Py_XDECREF(tmp_str); - } - break; - case G_TYPE_POINTER: - if (obj == Py_None) - g_value_set_pointer(value, NULL); - else if (PyObject_TypeCheck(obj, &PyGPointer_Type) && - G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype)) - g_value_set_pointer(value, pyg_pointer_get(obj, gpointer)); - else if (PYGLIB_CPointer_Check(obj)) - g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL)); - else if (G_VALUE_HOLDS_GTYPE (value)) - g_value_set_gtype (value, pyg_type_from_object (obj)); - else { - PyErr_SetString(PyExc_TypeError, "Expected pointer"); - return -1; - } - break; - case G_TYPE_BOXED: { - PyGTypeMarshal *bm; - - if (obj == Py_None) - g_value_set_boxed(value, NULL); - else if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) - g_value_set_boxed(value, obj); - else if (PyObject_TypeCheck(obj, &PyGBoxed_Type) && - G_VALUE_HOLDS(value, ((PyGBoxed *)obj)->gtype)) - g_value_set_boxed(value, pyg_boxed_get(obj, gpointer)); - else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) { - GType type; - GValue *n_value; - - type = pyg_type_from_object((PyObject*)Py_TYPE(obj)); - if (G_UNLIKELY (! type)) { - return -1; - } - n_value = g_new0 (GValue, 1); - g_value_init (n_value, type); - g_value_take_boxed (value, n_value); - return pyg_value_from_pyobject_with_error (n_value, obj); - } - else if (PySequence_Check(obj) && - G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) - return pyg_value_array_from_pyobject(value, obj, NULL); - else if (PySequence_Check(obj) && - G_VALUE_HOLDS(value, G_TYPE_ARRAY)) - return pyg_array_from_pyobject(value, obj); - else if (PYGLIB_PyUnicode_Check(obj) && - G_VALUE_HOLDS(value, G_TYPE_GSTRING)) { - GString *string; - char *buffer; - Py_ssize_t len; - if (PYGLIB_PyUnicode_AsStringAndSize(obj, &buffer, &len)) - return -1; - string = g_string_new_len(buffer, len); - g_value_set_boxed(value, string); - g_string_free (string, TRUE); - break; - } - else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) - return bm->tovalue(value, obj); - else if (PYGLIB_CPointer_Check(obj)) - g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL)); - else { - PyErr_SetString(PyExc_TypeError, "Expected Boxed"); - return -1; - } - break; - } - case G_TYPE_PARAM: - /* we need to support both the wrapped _gobject.GParamSpec and the GI - * GObject.ParamSpec */ - if (G_IS_PARAM_SPEC (pygobject_get (obj))) - g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj))); - else if (PyGParamSpec_Check(obj)) - g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL)); - else { - PyErr_SetString(PyExc_TypeError, "Expected ParamSpec"); - return -1; - } - break; - case G_TYPE_OBJECT: - if (obj == Py_None) { - g_value_set_object(value, NULL); - } else if (PyObject_TypeCheck(obj, &PyGObject_Type) && - G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj), - G_VALUE_TYPE(value))) { - g_value_set_object(value, pygobject_get(obj)); - } else { - PyErr_SetString(PyExc_TypeError, "Expected GObject"); - return -1; - } - break; - case G_TYPE_VARIANT: - { - if (obj == Py_None) - g_value_set_variant(value, NULL); - else if (pyg_type_from_object_strict(obj, FALSE) == G_TYPE_VARIANT) - g_value_set_variant(value, pyg_boxed_get(obj, GVariant)); - else { - PyErr_SetString(PyExc_TypeError, "Expected Variant"); - return -1; - } - break; - } - default: - { - PyGTypeMarshal *bm; - if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) { - return bm->tovalue(value, obj); - } else { - PyErr_SetString(PyExc_TypeError, "Unknown value type"); - return -1; - } - break; - } - } - - /* If an error occurred, unset the GValue but don't clear the Python error. */ - if (PyErr_Occurred()) { - g_value_unset(value); - return -1; - } - - return 0; -} - -/** - * pyg_value_from_pyobject: - * @value: the GValue object to store the converted value in. - * @obj: the Python object to convert. - * - * Same basic function as pyg_value_from_pyobject_with_error but clears - * any Python errors before returning. - * - * Returns: 0 on success, -1 on error. - */ -int -pyg_value_from_pyobject(GValue *value, PyObject *obj) -{ - int res = pyg_value_from_pyobject_with_error (value, obj); - - if (PyErr_Occurred()) { - PyErr_Clear(); - return -1; - } - return res; -} - -/** - * pyg_value_as_pyobject: - * @value: the GValue object. - * @copy_boxed: true if boxed values should be copied. - * - * This function creates/returns a Python wrapper object that - * represents the GValue passed as an argument. - * - * Returns: a PyObject representing the value. - */ -PyObject * -pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed) -{ - gchar buf[128]; - - switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) { - case G_TYPE_INTERFACE: - if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT)) - return pygobject_new(g_value_get_object(value)); - else - break; - case G_TYPE_CHAR: { - gint8 val = g_value_get_schar(value); - return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1); - } - case G_TYPE_UCHAR: { - guint8 val = g_value_get_uchar(value); - return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1); - } - case G_TYPE_BOOLEAN: { - return PyBool_FromLong(g_value_get_boolean(value)); - } - case G_TYPE_INT: - return PYGLIB_PyLong_FromLong(g_value_get_int(value)); - case G_TYPE_UINT: - { - /* in Python, the Int object is backed by a long. If a - long can hold the whole value of an unsigned int, use - an Int. Otherwise, use a Long object to avoid overflow. - This matches the ULongArg behavior in codegen/argtypes.h */ -#if (G_MAXUINT <= G_MAXLONG) - return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value)); -#else - return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value)); -#endif - } - case G_TYPE_LONG: - return PYGLIB_PyLong_FromLong(g_value_get_long(value)); - case G_TYPE_ULONG: - { - gulong val = g_value_get_ulong(value); - - if (val <= G_MAXLONG) - return PYGLIB_PyLong_FromLong((glong) val); - else - return PyLong_FromUnsignedLong(val); - } - case G_TYPE_INT64: - { - gint64 val = g_value_get_int64(value); - - if (G_MINLONG <= val && val <= G_MAXLONG) - return PYGLIB_PyLong_FromLong((glong) val); - else - return PyLong_FromLongLong(val); - } - case G_TYPE_UINT64: - { - guint64 val = g_value_get_uint64(value); - - if (val <= G_MAXLONG) - return PYGLIB_PyLong_FromLong((glong) val); - else - return PyLong_FromUnsignedLongLong(val); - } - case G_TYPE_ENUM: - return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value)); - case G_TYPE_FLAGS: - return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value)); - case G_TYPE_FLOAT: - return PyFloat_FromDouble(g_value_get_float(value)); - case G_TYPE_DOUBLE: - return PyFloat_FromDouble(g_value_get_double(value)); - case G_TYPE_STRING: - { - const gchar *str = g_value_get_string(value); - - if (str) - return PYGLIB_PyUnicode_FromString(str); - Py_INCREF(Py_None); - return Py_None; - } - case G_TYPE_POINTER: - if (G_VALUE_HOLDS_GTYPE (value)) - return pyg_type_wrapper_new (g_value_get_gtype (value)); - else - return pyg_pointer_new(G_VALUE_TYPE(value), - g_value_get_pointer(value)); - case G_TYPE_BOXED: { - PyGTypeMarshal *bm; - - if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) { - PyObject *ret = (PyObject *)g_value_dup_boxed(value); - if (ret == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return ret; - } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) { - GValue *n_value = g_value_get_boxed (value); - return pyg_value_as_pyobject(n_value, copy_boxed); - } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) { - GValueArray *array = (GValueArray *) g_value_get_boxed(value); - PyObject *ret = PyList_New(array->n_values); - int i; - for (i = 0; i < array->n_values; ++i) - PyList_SET_ITEM(ret, i, pyg_value_as_pyobject - (array->values + i, copy_boxed)); - return ret; - } else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) { - GString *string = (GString *) g_value_get_boxed(value); - PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len); - return ret; - } - bm = pyg_type_lookup(G_VALUE_TYPE(value)); - if (bm) { - return bm->fromvalue(value); - } else { - if (copy_boxed) - return pyg_boxed_new(G_VALUE_TYPE(value), - g_value_get_boxed(value), TRUE, TRUE); - else - return pyg_boxed_new(G_VALUE_TYPE(value), - g_value_get_boxed(value),FALSE,FALSE); - } - } - case G_TYPE_PARAM: - return pyg_param_spec_new(g_value_get_param(value)); - case G_TYPE_OBJECT: - return pygobject_new(g_value_get_object(value)); - case G_TYPE_VARIANT: - { - GVariant *v = g_value_get_variant(value); - if (v == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE); - } - default: - { - PyGTypeMarshal *bm; - if ((bm = pyg_type_lookup(G_VALUE_TYPE(value)))) - return bm->fromvalue(value); - break; - } - } - g_snprintf(buf, sizeof(buf), "unknown type %s", - g_type_name(G_VALUE_TYPE(value))); - PyErr_SetString(PyExc_TypeError, buf); - return NULL; -} - -/* -------------- PyGClosure ----------------- */ - -static void -pyg_closure_invalidate(gpointer data, GClosure *closure) -{ - PyGClosure *pc = (PyGClosure *)closure; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - Py_XDECREF(pc->callback); - Py_XDECREF(pc->extra_args); - Py_XDECREF(pc->swap_data); - pyglib_gil_state_release(state); - - pc->callback = NULL; - pc->extra_args = NULL; - pc->swap_data = NULL; -} - -static void -pyg_closure_marshal(GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - PyGILState_STATE state; - PyGClosure *pc = (PyGClosure *)closure; - PyObject *params, *ret; - guint i; - - state = pyglib_gil_state_ensure(); - - /* construct Python tuple for the parameter values */ - params = PyTuple_New(n_param_values); - for (i = 0; i < n_param_values; i++) { - /* swap in a different initial data for connect_object() */ - if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { - g_return_if_fail(pc->swap_data != NULL); - Py_INCREF(pc->swap_data); - PyTuple_SetItem(params, 0, pc->swap_data); - } else { - PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); - - /* error condition */ - if (!item) { - goto out; - } - PyTuple_SetItem(params, i, item); - } - } - /* params passed to function may have extra arguments */ - if (pc->extra_args) { - PyObject *tuple = params; - params = PySequence_Concat(tuple, pc->extra_args); - Py_DECREF(tuple); - } - ret = PyObject_CallObject(pc->callback, params); - if (ret == NULL) { - if (pc->exception_handler) - pc->exception_handler(return_value, n_param_values, param_values); - else - PyErr_Print(); - goto out; - } - - if (G_IS_VALUE(return_value) && pyg_value_from_pyobject(return_value, ret) != 0) { - /* If we already have an exception set, use that, otherwise set a - * generic one */ - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, - "can't convert return value to desired type"); - - if (pc->exception_handler) - pc->exception_handler(return_value, n_param_values, param_values); - else - PyErr_Print(); - } - Py_DECREF(ret); - - out: - Py_DECREF(params); - pyglib_gil_state_release(state); -} - -/** - * pyg_closure_new: - * callback: a Python callable object - * extra_args: a tuple of extra arguments, or None/NULL. - * swap_data: an alternative python object to pass first. - * - * Creates a GClosure wrapping a Python callable and optionally a set - * of additional function arguments. This is needed to attach python - * handlers to signals, for instance. - * - * Returns: the new closure. - */ -GClosure * -pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data) -{ - GClosure *closure; - - g_return_val_if_fail(callback != NULL, NULL); - closure = g_closure_new_simple(sizeof(PyGClosure), NULL); - g_closure_add_invalidate_notifier(closure, NULL, pyg_closure_invalidate); - g_closure_set_marshal(closure, pyg_closure_marshal); - Py_INCREF(callback); - ((PyGClosure *)closure)->callback = callback; - if (extra_args && extra_args != Py_None) { - Py_INCREF(extra_args); - if (!PyTuple_Check(extra_args)) { - PyObject *tmp = PyTuple_New(1); - PyTuple_SetItem(tmp, 0, extra_args); - extra_args = tmp; - } - ((PyGClosure *)closure)->extra_args = extra_args; - } - if (swap_data) { - Py_INCREF(swap_data); - ((PyGClosure *)closure)->swap_data = swap_data; - closure->derivative_flag = TRUE; - } - return closure; -} - -/** - * pyg_closure_set_exception_handler: - * @closure: a closure created with pyg_closure_new() - * @handler: the handler to call when an exception occurs or NULL for none - * - * Sets the handler to call when an exception occurs during closure invocation. - * The handler is responsible for providing a proper return value to the - * closure invocation. If @handler is %NULL, the default handler will be used. - * The default handler prints the exception to stderr and doesn't touch the - * closure's return value. - */ -void -pyg_closure_set_exception_handler(GClosure *closure, - PyClosureExceptionHandler handler) -{ - PyGClosure *pygclosure; - - g_return_if_fail(closure != NULL); - - pygclosure = (PyGClosure *)closure; - pygclosure->exception_handler = handler; -} -/* -------------- PySignalClassClosure ----------------- */ -/* a closure used for the `class closure' of a signal. As this gets - * all the info from the first argument to the closure and the - * invocation hint, we can have a single closure that handles all - * class closure cases. We call a method by the name of the signal - * with "do_" prepended. - * - * We also remove the first argument from the * param list, as it is - * the instance object, which is passed * implicitly to the method - * object. */ - -static void -pyg_signal_class_closure_marshal(GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - PyGILState_STATE state; - GObject *object; - PyObject *object_wrapper; - GSignalInvocationHint *hint = (GSignalInvocationHint *)invocation_hint; - gchar *method_name, *tmp; - PyObject *method; - PyObject *params, *ret; - guint i, len; - - state = pyglib_gil_state_ensure(); - - g_return_if_fail(invocation_hint != NULL); - /* get the object passed as the first argument to the closure */ - object = g_value_get_object(¶m_values[0]); - g_return_if_fail(object != NULL && G_IS_OBJECT(object)); - - /* get the wrapper for this object */ - object_wrapper = pygobject_new(object); - g_return_if_fail(object_wrapper != NULL); - - /* construct method name for this class closure */ - method_name = g_strconcat("do_", g_signal_name(hint->signal_id), NULL); - - /* convert dashes to underscores. For some reason, g_signal_name - * seems to convert all the underscores in the signal name to - dashes??? */ - for (tmp = method_name; *tmp != '\0'; tmp++) - if (*tmp == '-') *tmp = '_'; - - method = PyObject_GetAttrString(object_wrapper, method_name); - g_free(method_name); - - if (!method) { - PyErr_Clear(); - Py_DECREF(object_wrapper); - pyglib_gil_state_release(state); - return; - } - Py_DECREF(object_wrapper); - - /* construct Python tuple for the parameter values; don't copy boxed values - initially because we'll check after the call to see if a copy is needed. */ - params = PyTuple_New(n_param_values - 1); - for (i = 1; i < n_param_values; i++) { - PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); - - /* error condition */ - if (!item) { - Py_DECREF(params); - pyglib_gil_state_release(state); - return; - } - PyTuple_SetItem(params, i - 1, item); - } - - ret = PyObject_CallObject(method, params); - - /* Copy boxed values if others ref them, this needs to be done regardless of - exception status. */ - len = PyTuple_Size(params); - for (i = 0; i < len; i++) { - PyObject *item = PyTuple_GetItem(params, i); - if (item != NULL && PyObject_TypeCheck(item, &PyGBoxed_Type) - && item->ob_refcnt != 1) { - PyGBoxed* boxed_item = (PyGBoxed*)item; - if (!boxed_item->free_on_dealloc) { - boxed_item->boxed = g_boxed_copy(boxed_item->gtype, boxed_item->boxed); - boxed_item->free_on_dealloc = TRUE; - } - } - } - - if (ret == NULL) { - PyErr_Print(); - Py_DECREF(method); - Py_DECREF(params); - pyglib_gil_state_release(state); - return; - } - Py_DECREF(method); - Py_DECREF(params); - if (G_IS_VALUE(return_value)) - pyg_value_from_pyobject(return_value, ret); - Py_DECREF(ret); - pyglib_gil_state_release(state); -} - -/** - * pyg_signal_class_closure_get: - * - * Returns the GClosure used for the class closure of signals. When - * called, it will invoke the method do_signalname (for the signal - * "signalname"). - * - * Returns: the closure. - */ -GClosure * -pyg_signal_class_closure_get(void) -{ - static GClosure *closure; - - if (closure == NULL) { - closure = g_closure_new_simple(sizeof(GClosure), NULL); - g_closure_set_marshal(closure, pyg_signal_class_closure_marshal); - - g_closure_ref(closure); - g_closure_sink(closure); - } - return closure; -} - -GClosure * -gclosure_from_pyfunc(PyGObject *object, PyObject *func) -{ - GSList *l; - PyGObjectData *inst_data; - inst_data = pyg_object_peek_inst_data(object->obj); - if (inst_data) { - for (l = inst_data->closures; l; l = l->next) { - PyGClosure *pyclosure = l->data; - int res = PyObject_RichCompareBool(pyclosure->callback, func, Py_EQ); - if (res == -1) { - PyErr_Clear(); // Is there anything else to do? - } else if (res) { - return (GClosure*)pyclosure; - } - } - } - return NULL; -} - -/* ----- __doc__ descriptor for GObject and GInterface ----- */ - -static void -object_doc_dealloc(PyObject *self) -{ - PyObject_FREE(self); -} - -/* append information about signals of a particular gtype */ -static void -add_signal_docs(GType gtype, GString *string) -{ - GTypeClass *class = NULL; - guint *signal_ids, n_ids = 0, i; - - if (G_TYPE_IS_CLASSED(gtype)) - class = g_type_class_ref(gtype); - signal_ids = g_signal_list_ids(gtype, &n_ids); - - if (n_ids > 0) { - g_string_append_printf(string, "Signals from %s:\n", - g_type_name(gtype)); - - for (i = 0; i < n_ids; i++) { - GSignalQuery query; - guint j; - - g_signal_query(signal_ids[i], &query); - - g_string_append(string, " "); - g_string_append(string, query.signal_name); - g_string_append(string, " ("); - for (j = 0; j < query.n_params; j++) { - g_string_append(string, g_type_name(query.param_types[j])); - if (j != query.n_params - 1) - g_string_append(string, ", "); - } - g_string_append(string, ")"); - if (query.return_type && query.return_type != G_TYPE_NONE) { - g_string_append(string, " -> "); - g_string_append(string, g_type_name(query.return_type)); - } - g_string_append(string, "\n"); - } - g_free(signal_ids); - g_string_append(string, "\n"); - } - if (class) - g_type_class_unref(class); -} - -static void -add_property_docs(GType gtype, GString *string) -{ - GObjectClass *class; - GParamSpec **props; - guint n_props = 0, i; - gboolean has_prop = FALSE; - G_CONST_RETURN gchar *blurb=NULL; - - class = g_type_class_ref(gtype); - props = g_object_class_list_properties(class, &n_props); - - for (i = 0; i < n_props; i++) { - if (props[i]->owner_type != gtype) - continue; /* these are from a parent type */ - - /* print out the heading first */ - if (!has_prop) { - g_string_append_printf(string, "Properties from %s:\n", - g_type_name(gtype)); - has_prop = TRUE; - } - g_string_append_printf(string, " %s -> %s: %s\n", - g_param_spec_get_name(props[i]), - g_type_name(props[i]->value_type), - g_param_spec_get_nick(props[i])); - - /* g_string_append_printf crashes on win32 if the third - argument is NULL. */ - blurb=g_param_spec_get_blurb(props[i]); - if (blurb) - g_string_append_printf(string, " %s\n",blurb); - } - g_free(props); - if (has_prop) - g_string_append(string, "\n"); - g_type_class_unref(class); -} - -static PyObject * -object_doc_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - GType gtype = 0; - GString *string; - PyObject *pystring; - - if (obj && pygobject_check(obj, &PyGObject_Type)) { - gtype = G_OBJECT_TYPE(pygobject_get(obj)); - if (!gtype) - PyErr_SetString(PyExc_RuntimeError, "could not get object type"); - } else { - gtype = pyg_type_from_object(type); - } - if (!gtype) - return NULL; - - string = g_string_new_len(NULL, 512); - - if (g_type_is_a(gtype, G_TYPE_INTERFACE)) - g_string_append_printf(string, "Interface %s\n\n", g_type_name(gtype)); - else if (g_type_is_a(gtype, G_TYPE_OBJECT)) - g_string_append_printf(string, "Object %s\n\n", g_type_name(gtype)); - else - g_string_append_printf(string, "%s\n\n", g_type_name(gtype)); - - if (((PyTypeObject *) type)->tp_doc) - g_string_append_printf(string, "%s\n\n", ((PyTypeObject *) type)->tp_doc); - - if (g_type_is_a(gtype, G_TYPE_OBJECT)) { - GType parent = G_TYPE_OBJECT; - GArray *parents = g_array_new(FALSE, FALSE, sizeof(GType)); - int iparent; - - while (parent) { - g_array_append_val(parents, parent); - parent = g_type_next_base(gtype, parent); - } - - for (iparent = parents->len - 1; iparent >= 0; --iparent) { - GType *interfaces; - guint n_interfaces, i; - - parent = g_array_index(parents, GType, iparent); - add_signal_docs(parent, string); - add_property_docs(parent, string); - - /* add docs for implemented interfaces */ - interfaces = g_type_interfaces(parent, &n_interfaces); - for (i = 0; i < n_interfaces; i++) - add_signal_docs(interfaces[i], string); - g_free(interfaces); - } - g_array_free(parents, TRUE); - } - - pystring = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len); - g_string_free(string, TRUE); - return pystring; -} - -PYGLIB_DEFINE_TYPE("gobject.GObject.__doc__", PyGObjectDoc_Type, PyObject); - -/** - * pyg_object_descr_doc_get: - * - * Returns an object intended to be the __doc__ attribute of GObject - * wrappers. When read in the context of the object it will return - * some documentation about the signals and properties of the object. - * - * Returns: the descriptor. - */ -PyObject * -pyg_object_descr_doc_get(void) -{ - static PyObject *doc_descr = NULL; - - if (!doc_descr) { - Py_TYPE(&PyGObjectDoc_Type) = &PyType_Type; - if (PyType_Ready(&PyGObjectDoc_Type)) - return NULL; - - doc_descr = PyObject_NEW(PyObject, &PyGObjectDoc_Type); - if (doc_descr == NULL) - return NULL; - } - return doc_descr; -} - - -/** - * pyg_pyobj_to_unichar_conv: - * - * Converts PyObject value to a unichar and write result to memory - * pointed to by ptr. Follows the calling convention of a ParseArgs - * converter (O& format specifier) so it may be used to convert function - * arguments. - * - * Returns: 1 if the conversion succeeds and 0 otherwise. If the conversion - * did not succeesd, a Python exception is raised - */ -int pyg_pyobj_to_unichar_conv(PyObject* py_obj, void* ptr) -{ - gunichar* u = ptr; - const Py_UNICODE* uni_buffer; - PyObject* tmp_uni = NULL; - - if (PyUnicode_Check(py_obj)) { - tmp_uni = py_obj; - Py_INCREF(tmp_uni); - } - else { - tmp_uni = PyUnicode_FromObject(py_obj); - if (tmp_uni == NULL) - goto failure; - } - - if ( PyUnicode_GetSize(tmp_uni) != 1) { - PyErr_SetString(PyExc_ValueError, "unicode character value must be 1 character uniode string"); - goto failure; - } - uni_buffer = PyUnicode_AsUnicode(tmp_uni); - if ( uni_buffer == NULL) - goto failure; - *u = uni_buffer[0]; - - Py_DECREF(tmp_uni); - return 1; - - failure: - Py_XDECREF(tmp_uni); - return 0; -} - - -int -pyg_param_gvalue_from_pyobject(GValue* value, - PyObject* py_obj, - const GParamSpec* pspec) -{ - if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - gunichar u; - - if (!pyg_pyobj_to_unichar_conv(py_obj, &u)) { - PyErr_Clear(); - return -1; - } - g_value_set_uint(value, u); - return 0; - } - else if (G_IS_PARAM_SPEC_VALUE_ARRAY(pspec)) - return pyg_value_array_from_pyobject(value, py_obj, - G_PARAM_SPEC_VALUE_ARRAY(pspec)); - else { - return pyg_value_from_pyobject(value, py_obj); - } -} - -PyObject* -pyg_param_gvalue_as_pyobject(const GValue* gvalue, - gboolean copy_boxed, - const GParamSpec* pspec) -{ - if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - gunichar u; - Py_UNICODE uni_buffer[2] = { 0, 0 }; - - u = g_value_get_uint(gvalue); - uni_buffer[0] = u; - return PyUnicode_FromUnicode(uni_buffer, 1); - } - else { - return pyg_value_as_pyobject(gvalue, copy_boxed); - } -} - -gboolean -pyg_gtype_is_custom(GType gtype) -{ - return g_type_get_qdata (gtype, pygobject_custom_key) != NULL; -} - -static PyObject * -_pyg_strv_from_gvalue(const GValue *value) -{ - gchar **argv = (gchar **) g_value_get_boxed(value); - int argc = 0, i; - PyObject *py_argv; - - if (argv) { - while (argv[argc]) - argc++; - } - py_argv = PyList_New(argc); - for (i = 0; i < argc; ++i) - PyList_SET_ITEM(py_argv, i, PYGLIB_PyUnicode_FromString(argv[i])); - return py_argv; -} - -static int -_pyg_strv_to_gvalue(GValue *value, PyObject *obj) -{ - Py_ssize_t argc, i; - gchar **argv; - - if (!(PyTuple_Check(obj) || PyList_Check(obj))) - return -1; - - argc = PySequence_Length(obj); - for (i = 0; i < argc; ++i) - if (!PYGLIB_PyUnicode_Check(PySequence_Fast_GET_ITEM(obj, i))) - return -1; - argv = g_new(gchar *, argc + 1); - for (i = 0; i < argc; ++i) - argv[i] = g_strdup(PYGLIB_PyUnicode_AsString(PySequence_Fast_GET_ITEM(obj, i))); - argv[i] = NULL; - g_value_take_boxed(value, argv); - return 0; -} - -void -pygobject_type_register_types(PyObject *d) -{ - PyGTypeWrapper_Type.tp_dealloc = (destructor)pyg_type_wrapper_dealloc; - PyGTypeWrapper_Type.tp_richcompare = pyg_type_wrapper_richcompare; - PyGTypeWrapper_Type.tp_repr = (reprfunc)pyg_type_wrapper_repr; - PyGTypeWrapper_Type.tp_hash = (hashfunc)pyg_type_wrapper_hash; - PyGTypeWrapper_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGTypeWrapper_Type.tp_methods = _PyGTypeWrapper_methods; - PyGTypeWrapper_Type.tp_getset = _PyGTypeWrapper_getsets; - PyGTypeWrapper_Type.tp_init = (initproc)pyg_type_wrapper_init; - PYGLIB_REGISTER_TYPE(d, PyGTypeWrapper_Type, "GType"); - - /* This type lazily registered in pyg_object_descr_doc_get */ - PyGObjectDoc_Type.tp_dealloc = (destructor)object_doc_dealloc; - PyGObjectDoc_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGObjectDoc_Type.tp_descr_get = (descrgetfunc)object_doc_descr_get; - - pyg_register_gtype_custom(G_TYPE_STRV, - _pyg_strv_from_gvalue, - _pyg_strv_to_gvalue); -} diff --git a/gi/_gobject/pygtype.h b/gi/_gobject/pygtype.h deleted file mode 100644 index 2f9e7add..00000000 --- a/gi/_gobject/pygtype.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_TYPE_H__ -#define __PYGOBJECT_TYPE_H__ - -void pygobject_type_register_types(PyObject *d); - -#endif /* __PYGOBJECT_TYPE_H__ */ diff --git a/gi/_gobject/signalhelper.py b/gi/_gobject/signalhelper.py index b630158b..19207cc3 100644 --- a/gi/_gobject/signalhelper.py +++ b/gi/_gobject/signalhelper.py @@ -22,7 +22,8 @@ import sys import inspect -from . import _gobject +import gi._gi +_gobject = gi._gi._gobject # Callable went away in python 3.0 and came back in 3.2. # Use versioning to figure out when to define it, otherwise we have to deal with diff --git a/gi/gimodule.c b/gi/gimodule.c index 12addbcc..0ca6d40c 100644 --- a/gi/gimodule.c +++ b/gi/gimodule.c @@ -21,11 +21,12 @@ * USA */ +#include "pygobject-private.h" +#include "pyginterface.h" #include "pygi-private.h" #include "pygi.h" #include "pyglib.h" -#include #include PyObject *PyGIDeprecationWarning; @@ -627,6 +628,7 @@ static struct PyGI_API CAPI = { PYGLIB_MODULE_START(_gi, "_gi") { PyObject *api; + PyObject *_gobject_module; /* Always enable Python threads since we cannot predict which GI repositories * might accept Python callbacks run within non-Python threads or might trigger @@ -635,13 +637,12 @@ PYGLIB_MODULE_START(_gi, "_gi") */ PyEval_InitThreads (); - if (pygobject_init (-1, -1, -1) == NULL) { - return PYGLIB_MODULE_ERROR_RETURN; - } - - if (_pygobject_import() < 0) { + _gobject_module = pyglib__gobject_module_create (); + if (_gobject_module == NULL) { return PYGLIB_MODULE_ERROR_RETURN; } + PyModule_AddObject (module, "_gobject", _gobject_module); + PyModule_AddStringConstant(module, "__package__", "gi._gi"); _pygi_repository_register_types (module); _pygi_info_register_types (module); diff --git a/gi/gobjectmodule.c b/gi/gobjectmodule.c new file mode 100644 index 00000000..e982107a --- /dev/null +++ b/gi/gobjectmodule.c @@ -0,0 +1,2213 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * gobjectmodule.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include "pygobject-private.h" +#include "pygboxed.h" +#include "pygenum.h" +#include "pygflags.h" +#include "pyginterface.h" +#include "pygparamspec.h" +#include "pygpointer.h" +#include "pygtype.h" + +static GHashTable *log_handlers = NULL; +static gboolean log_handlers_disabled = FALSE; + +static void pyg_flags_add_constants(PyObject *module, GType flags_type, + const gchar *strip_prefix); + + +/* -------------- GDK threading hooks ---------------------------- */ + +/** + * pyg_set_thread_block_funcs: + * Deprecated, only available for ABI compatibility. + */ +static void +_pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func, + PyGThreadBlockFunc unblock_threads_func) +{ + PyGILState_STATE state = pyglib_gil_state_ensure (); + PyErr_Warn (PyExc_DeprecationWarning, + "Using pyg_set_thread_block_funcs is not longer needed. " + "PyGObject always uses Py_BLOCK/UNBLOCK_THREADS."); + pyglib_gil_state_release (state); +} + +/** + * 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); +} + + +/* ---------------- gobject module functions -------------------- */ + +static PyObject * +pyg_type_name (PyObject *self, PyObject *args) +{ + PyObject *gtype; + GType type; + const gchar *name; + +#if 0 + if (PyErr_Warn(PyExc_DeprecationWarning, + "gobject.type_name is deprecated; " + "use GType.name instead")) + return NULL; +#endif + + if (!PyArg_ParseTuple(args, "O:gobject.type_name", >ype)) + return NULL; + if ((type = pyg_type_from_object(gtype)) == 0) + return NULL; + name = g_type_name(type); + if (name) + return PYGLIB_PyUnicode_FromString(name); + PyErr_SetString(PyExc_RuntimeError, "unknown typecode"); + return NULL; +} + +static PyObject * +pyg_type_from_name (PyObject *self, PyObject *args) +{ + const gchar *name; + GType type; + PyObject *repr = NULL; +#if 0 + if (PyErr_Warn(PyExc_DeprecationWarning, + "gobject.type_from_name is deprecated; " + "use GType.from_name instead")) + return NULL; +#endif + if (!PyArg_ParseTuple(args, "s:gobject.type_from_name", &name)) + return NULL; + type = g_type_from_name(name); + if (type != 0) + return pyg_type_wrapper_new(type); + repr = PyObject_Repr((PyObject*)self); + PyErr_Format(PyExc_RuntimeError, "%s: unknown type name: %s", + PYGLIB_PyUnicode_AsString(repr), + name); + Py_DECREF(repr); + return NULL; +} + +static PyObject * +pyg_type_is_a (PyObject *self, PyObject *args) +{ + PyObject *gtype, *gparent; + GType type, parent; +#if 0 + if (PyErr_Warn(PyExc_DeprecationWarning, + "gobject.type_is_a is deprecated; " + "use GType.is_a instead")) + return NULL; +#endif + if (!PyArg_ParseTuple(args, "OO:gobject.type_is_a", >ype, &gparent)) + return NULL; + if ((type = pyg_type_from_object(gtype)) == 0) + return NULL; + if ((parent = pyg_type_from_object(gparent)) == 0) + return NULL; + return PyBool_FromLong(g_type_is_a(type, parent)); +} + +static void +pyg_object_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + PyObject *object_wrapper, *retval; + PyObject *py_pspec, *py_value; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + object_wrapper = pygobject_new(object); + + if (object_wrapper == NULL) { + pyglib_gil_state_release(state); + return; + } + + py_pspec = pyg_param_spec_new(pspec); + py_value = pyg_value_as_pyobject (value, TRUE); + + retval = PyObject_CallMethod(object_wrapper, "do_set_property", + "OO", py_pspec, py_value); + if (retval) { + Py_DECREF(retval); + } else { + PyErr_Print(); + } + + Py_DECREF(object_wrapper); + Py_DECREF(py_pspec); + Py_DECREF(py_value); + + pyglib_gil_state_release(state); +} + +static void +pyg_object_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + PyObject *object_wrapper, *retval; + PyObject *py_pspec; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + object_wrapper = pygobject_new(object); + + if (object_wrapper == NULL) { + pyglib_gil_state_release(state); + return; + } + + py_pspec = pyg_param_spec_new(pspec); + retval = PyObject_CallMethod(object_wrapper, "do_get_property", + "O", py_pspec); + if (retval == NULL || pyg_value_from_pyobject(value, retval) < 0) { + PyErr_Print(); + } + Py_DECREF(object_wrapper); + Py_DECREF(py_pspec); + Py_XDECREF(retval); + + pyglib_gil_state_release(state); +} + +typedef struct _PyGSignalAccumulatorData { + PyObject *callable; + PyObject *user_data; +} PyGSignalAccumulatorData; + +static gboolean +_pyg_signal_accumulator(GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer _data) +{ + PyObject *py_ihint, *py_return_accu, *py_handler_return, *py_detail; + PyObject *py_retval; + gboolean retval = FALSE; + PyGSignalAccumulatorData *data = _data; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + if (ihint->detail) + py_detail = PYGLIB_PyUnicode_FromString(g_quark_to_string(ihint->detail)); + else { + Py_INCREF(Py_None); + py_detail = Py_None; + } + + py_ihint = Py_BuildValue("lNi", (long int) ihint->signal_id, + py_detail, ihint->run_type); + py_handler_return = pyg_value_as_pyobject(handler_return, TRUE); + py_return_accu = pyg_value_as_pyobject(return_accu, FALSE); + if (data->user_data) + py_retval = PyObject_CallFunction(data->callable, "NNNO", py_ihint, + py_return_accu, py_handler_return, + data->user_data); + else + py_retval = PyObject_CallFunction(data->callable, "NNN", py_ihint, + py_return_accu, py_handler_return); + if (!py_retval) + PyErr_Print(); + else { + if (!PyTuple_Check(py_retval) || PyTuple_Size(py_retval) != 2) { + PyErr_SetString(PyExc_TypeError, "accumulator function must return" + " a (bool, object) tuple"); + PyErr_Print(); + } else { + retval = PyObject_IsTrue(PyTuple_GET_ITEM(py_retval, 0)); + if (pyg_value_from_pyobject(return_accu, PyTuple_GET_ITEM(py_retval, 1))) { + PyErr_Print(); + } + } + Py_DECREF(py_retval); + } + pyglib_gil_state_release(state); + return retval; +} + +static gboolean +create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) +{ + GSignalFlags signal_flags; + PyObject *py_return_type, *py_param_types; + GType return_type; + guint n_params, i; + GType *param_types; + guint signal_id; + GSignalAccumulator accumulator = NULL; + PyGSignalAccumulatorData *accum_data = NULL; + PyObject *py_accum = NULL, *py_accum_data = NULL; + + if (!PyArg_ParseTuple(tuple, "iOO|OO", &signal_flags, &py_return_type, + &py_param_types, &py_accum, &py_accum_data)) + { + gchar buf[128]; + + PyErr_Clear(); + g_snprintf(buf, sizeof(buf), + "value for __gsignals__['%s'] not in correct format", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + + if (py_accum && py_accum != Py_None && !PyCallable_Check(py_accum)) + { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "accumulator for __gsignals__['%s'] must be callable", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + + return_type = pyg_type_from_object(py_return_type); + if (!return_type) + return FALSE; + if (!PySequence_Check(py_param_types)) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "third element of __gsignals__['%s'] tuple must be a sequence", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + n_params = PySequence_Length(py_param_types); + param_types = g_new(GType, n_params); + for (i = 0; i < n_params; i++) { + PyObject *item = PySequence_GetItem(py_param_types, i); + + param_types[i] = pyg_type_from_object(item); + if (param_types[i] == 0) { + Py_DECREF(item); + g_free(param_types); + return FALSE; + } + Py_DECREF(item); + } + + if (py_accum != NULL && py_accum != Py_None) { + accum_data = g_new(PyGSignalAccumulatorData, 1); + accum_data->callable = py_accum; + Py_INCREF(py_accum); + accum_data->user_data = py_accum_data; + Py_XINCREF(py_accum_data); + accumulator = _pyg_signal_accumulator; + } + + signal_id = g_signal_newv(signal_name, instance_type, signal_flags, + pyg_signal_class_closure_get(), + accumulator, accum_data, + gi_cclosure_marshal_generic, + return_type, n_params, param_types); + g_free(param_types); + + if (signal_id == 0) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "could not create signal for %s", + signal_name); + PyErr_SetString(PyExc_RuntimeError, buf); + return FALSE; + } + return TRUE; +} + +static gboolean +override_signal(GType instance_type, const gchar *signal_name) +{ + guint signal_id; + + signal_id = g_signal_lookup(signal_name, instance_type); + if (!signal_id) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "could not look up %s", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + g_signal_override_class_closure(signal_id, instance_type, + pyg_signal_class_closure_get()); + return TRUE; +} + +static PyObject * +add_signals (GObjectClass *klass, PyObject *signals) +{ + gboolean ret = TRUE; + Py_ssize_t pos = 0; + PyObject *key, *value, *overridden_signals = NULL; + GType instance_type = G_OBJECT_CLASS_TYPE (klass); + + overridden_signals = PyDict_New(); + while (PyDict_Next(signals, &pos, &key, &value)) { + const gchar *signal_name; + gchar *signal_name_canon, *c; + + if (!PYGLIB_PyUnicode_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "__gsignals__ keys must be strings"); + ret = FALSE; + break; + } + signal_name = PYGLIB_PyUnicode_AsString (key); + + if (value == Py_None || + (PYGLIB_PyUnicode_Check(value) && + !strcmp(PYGLIB_PyUnicode_AsString(value), "override"))) + { + /* canonicalize signal name, replacing '-' with '_' */ + signal_name_canon = g_strdup(signal_name); + for (c = signal_name_canon; *c; ++c) + if (*c == '-') + *c = '_'; + if (PyDict_SetItemString(overridden_signals, + signal_name_canon, key)) { + g_free(signal_name_canon); + ret = FALSE; + break; + } + g_free(signal_name_canon); + + ret = override_signal(instance_type, signal_name); + } else { + ret = create_signal(instance_type, signal_name, value); + } + + if (!ret) + break; + } + if (ret) + return overridden_signals; + else { + Py_XDECREF(overridden_signals); + return NULL; + } +} + +static GParamSpec * +create_property (const gchar *prop_name, + GType prop_type, + const gchar *nick, + const gchar *blurb, + PyObject *args, + GParamFlags flags) +{ + GParamSpec *pspec = NULL; + + switch (G_TYPE_FUNDAMENTAL(prop_type)) { + case G_TYPE_CHAR: + { + gchar minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_char (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UCHAR: + { + gchar minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_uchar (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_BOOLEAN: + { + gboolean default_value; + + if (!PyArg_ParseTuple(args, "i", &default_value)) + return NULL; + pspec = g_param_spec_boolean (prop_name, nick, blurb, + default_value, flags); + } + break; + case G_TYPE_INT: + { + gint minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "iii", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_int (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UINT: + { + guint minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "III", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_uint (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_LONG: + { + glong minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "lll", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_long (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_ULONG: + { + gulong minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "kkk", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_ulong (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_INT64: + { + gint64 minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "LLL", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_int64 (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UINT64: + { + guint64 minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "KKK", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_uint64 (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_ENUM: + { + gint default_value; + PyObject *pydefault; + + if (!PyArg_ParseTuple(args, "O", &pydefault)) + return NULL; + + if (pyg_enum_get_value(prop_type, pydefault, + (gint *)&default_value)) + return NULL; + + pspec = g_param_spec_enum (prop_name, nick, blurb, + prop_type, default_value, flags); + } + break; + case G_TYPE_FLAGS: + { + guint default_value; + PyObject *pydefault; + + if (!PyArg_ParseTuple(args, "O", &pydefault)) + return NULL; + + if (pyg_flags_get_value(prop_type, pydefault, + &default_value)) + return NULL; + + pspec = g_param_spec_flags (prop_name, nick, blurb, + prop_type, default_value, flags); + } + break; + case G_TYPE_FLOAT: + { + gfloat minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "fff", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_float (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_DOUBLE: + { + gdouble minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ddd", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_double (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_STRING: + { + const gchar *default_value; + + if (!PyArg_ParseTuple(args, "z", &default_value)) + return NULL; + pspec = g_param_spec_string (prop_name, nick, blurb, + default_value, flags); + } + break; + case G_TYPE_PARAM: + if (!PyArg_ParseTuple(args, "")) + return NULL; + pspec = g_param_spec_param (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_BOXED: + if (!PyArg_ParseTuple(args, "")) + return NULL; + pspec = g_param_spec_boxed (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_POINTER: + if (!PyArg_ParseTuple(args, "")) + return NULL; + if (prop_type == G_TYPE_GTYPE) + pspec = g_param_spec_gtype (prop_name, nick, blurb, G_TYPE_NONE, flags); + else + pspec = g_param_spec_pointer (prop_name, nick, blurb, flags); + break; + case G_TYPE_OBJECT: + case G_TYPE_INTERFACE: + if (!PyArg_ParseTuple(args, "")) + return NULL; + pspec = g_param_spec_object (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_VARIANT: + { + PyObject *pydefault; + GVariant *default_value = NULL; + + if (!PyArg_ParseTuple(args, "O", &pydefault)) + return NULL; + if (pydefault != Py_None) + default_value = pyg_boxed_get (pydefault, GVariant); + pspec = g_param_spec_variant (prop_name, nick, blurb, G_VARIANT_TYPE_ANY, default_value, flags); + } + break; + default: + /* unhandled pspec type ... */ + break; + } + + if (!pspec) { + char buf[128]; + + g_snprintf(buf, sizeof(buf), "could not create param spec for type %s", + g_type_name(prop_type)); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + + return pspec; +} + +static GParamSpec * +pyg_param_spec_from_object (PyObject *tuple) +{ + gint val_length; + const gchar *prop_name; + GType prop_type; + const gchar *nick, *blurb; + PyObject *slice, *item, *py_prop_type; + GParamSpec *pspec; + + val_length = PyTuple_Size(tuple); + if (val_length < 4) { + PyErr_SetString(PyExc_TypeError, + "paramspec tuples must be at least 4 elements long"); + return NULL; + } + + slice = PySequence_GetSlice(tuple, 0, 4); + if (!slice) { + return NULL; + } + + if (!PyArg_ParseTuple(slice, "sOzz", &prop_name, &py_prop_type, &nick, &blurb)) { + Py_DECREF(slice); + return NULL; + } + + Py_DECREF(slice); + + prop_type = pyg_type_from_object(py_prop_type); + if (!prop_type) { + return NULL; + } + + item = PyTuple_GetItem(tuple, val_length-1); + if (!PYGLIB_PyLong_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "last element in tuple must be an int"); + return NULL; + } + + /* slice is the extra items in the tuple */ + slice = PySequence_GetSlice(tuple, 4, val_length-1); + pspec = create_property(prop_name, prop_type, + nick, blurb, slice, + PYGLIB_PyLong_AsLong(item)); + + return pspec; +} + +static gboolean +add_properties (GObjectClass *klass, PyObject *properties) +{ + gboolean ret = TRUE; + Py_ssize_t pos = 0; + PyObject *key, *value; + + while (PyDict_Next(properties, &pos, &key, &value)) { + const gchar *prop_name; + GType prop_type; + const gchar *nick, *blurb; + GParamFlags flags; + gint val_length; + PyObject *slice, *item, *py_prop_type; + GParamSpec *pspec; + + /* values are of format (type,nick,blurb, type_specific_args, flags) */ + + if (!PYGLIB_PyUnicode_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ keys must be strings"); + ret = FALSE; + break; + } + prop_name = PYGLIB_PyUnicode_AsString (key); + + if (!PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ values must be tuples"); + ret = FALSE; + break; + } + val_length = PyTuple_Size(value); + if (val_length < 4) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ values must be at least 4 elements long"); + ret = FALSE; + break; + } + + slice = PySequence_GetSlice(value, 0, 3); + if (!slice) { + ret = FALSE; + break; + } + if (!PyArg_ParseTuple(slice, "Ozz", &py_prop_type, &nick, &blurb)) { + Py_DECREF(slice); + ret = FALSE; + break; + } + Py_DECREF(slice); + prop_type = pyg_type_from_object(py_prop_type); + if (!prop_type) { + ret = FALSE; + break; + } + item = PyTuple_GetItem(value, val_length-1); + if (!PYGLIB_PyLong_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "last element in __gproperties__ value tuple must be an int"); + ret = FALSE; + break; + } + flags = PYGLIB_PyLong_AsLong(item); + + /* slice is the extra items in the tuple */ + slice = PySequence_GetSlice(value, 3, val_length-1); + pspec = create_property(prop_name, prop_type, nick, blurb, + slice, flags); + Py_DECREF(slice); + + if (pspec) { + g_object_class_install_property(klass, 1, pspec); + } else { + PyObject *type, *value, *traceback; + ret = FALSE; + PyErr_Fetch(&type, &value, &traceback); + if (PYGLIB_PyUnicode_Check(value)) { + char msg[256]; + g_snprintf(msg, 256, + "%s (while registering property '%s' for GType '%s')", + PYGLIB_PyUnicode_AsString(value), + prop_name, G_OBJECT_CLASS_NAME(klass)); + Py_DECREF(value); + value = PYGLIB_PyUnicode_FromString(msg); + } + PyErr_Restore(type, value, traceback); + break; + } + } + + return ret; +} + +static void +pyg_object_class_init(GObjectClass *class, PyObject *py_class) +{ + PyObject *gproperties, *gsignals, *overridden_signals; + PyObject *class_dict = ((PyTypeObject*) py_class)->tp_dict; + + class->set_property = pyg_object_set_property; + class->get_property = pyg_object_get_property; + + /* install signals */ + /* we look this up in the instance dictionary, so we don't + * accidentally get a parent type's __gsignals__ attribute. */ + gsignals = PyDict_GetItemString(class_dict, "__gsignals__"); + if (gsignals) { + if (!PyDict_Check(gsignals)) { + PyErr_SetString(PyExc_TypeError, + "__gsignals__ attribute not a dict!"); + return; + } + if (!(overridden_signals = add_signals(class, gsignals))) { + return; + } + if (PyDict_SetItemString(class_dict, "__gsignals__", + overridden_signals)) { + return; + } + Py_DECREF(overridden_signals); + + PyDict_DelItemString(class_dict, "__gsignals__"); + } else { + PyErr_Clear(); + } + + /* install properties */ + /* we look this up in the instance dictionary, so we don't + * accidentally get a parent type's __gproperties__ attribute. */ + gproperties = PyDict_GetItemString(class_dict, "__gproperties__"); + if (gproperties) { + if (!PyDict_Check(gproperties)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ attribute not a dict!"); + return; + } + if (!add_properties(class, gproperties)) { + return; + } + PyDict_DelItemString(class_dict, "__gproperties__"); + /* Borrowed reference. Py_DECREF(gproperties); */ + } else { + PyErr_Clear(); + } +} + +static void +pyg_register_class_init(GType gtype, PyGClassInitFunc class_init) +{ + GSList *list; + + list = g_type_get_qdata(gtype, pygobject_class_init_key); + list = g_slist_prepend(list, class_init); + g_type_set_qdata(gtype, pygobject_class_init_key, list); +} + +static int +pyg_run_class_init(GType gtype, gpointer gclass, PyTypeObject *pyclass) +{ + GSList *list; + PyGClassInitFunc class_init; + GType parent_type; + int rv; + + parent_type = g_type_parent(gtype); + if (parent_type) { + rv = pyg_run_class_init(parent_type, gclass, pyclass); + if (rv) + return rv; + } + + list = g_type_get_qdata(gtype, pygobject_class_init_key); + for (; list; list = list->next) { + class_init = list->data; + rv = class_init(gclass, pyclass); + if (rv) + return rv; + } + + return 0; +} + +static PyObject * +_wrap_pyg_type_register(PyObject *self, PyObject *args) +{ + PyTypeObject *class; + char *type_name = NULL; + + if (!PyArg_ParseTuple(args, "O!|z:gobject.type_register", + &PyType_Type, &class, &type_name)) + return NULL; + if (!PyType_IsSubtype(class, &PyGObject_Type)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a GObject subclass"); + return NULL; + } + + /* Check if type already registered */ + if (pyg_type_from_object((PyObject *) class) == + pyg_type_from_object((PyObject *) class->tp_base)) + { + if (pyg_type_register(class, type_name)) + return NULL; + } + + Py_INCREF(class); + return (PyObject *) class; +} + +static char * +get_type_name_for_class(PyTypeObject *class) +{ + gint i, name_serial; + char name_serial_str[16]; + PyObject *module; + char *type_name = NULL; + + /* make name for new GType */ + name_serial = 1; + /* give up after 1000 tries, just in case.. */ + while (name_serial < 1000) + { + g_free(type_name); + snprintf(name_serial_str, 16, "-v%i", name_serial); + module = PyObject_GetAttrString((PyObject *)class, "__module__"); + if (module && PYGLIB_PyUnicode_Check(module)) { + type_name = g_strconcat(PYGLIB_PyUnicode_AsString(module), ".", + class->tp_name, + name_serial > 1 ? name_serial_str : NULL, + NULL); + Py_DECREF(module); + } else { + if (module) + Py_DECREF(module); + else + PyErr_Clear(); + type_name = g_strconcat(class->tp_name, + name_serial > 1 ? name_serial_str : NULL, + NULL); + } + /* convert '.' in type name to '+', which isn't banned (grumble) */ + for (i = 0; type_name[i] != '\0'; i++) + if (type_name[i] == '.') + type_name[i] = '+'; + if (g_type_from_name(type_name) == 0) + break; /* we now have a unique name */ + ++name_serial; + } + + return type_name; +} + + +static GPrivate pygobject_construction_wrapper; + +static inline void +pygobject_init_wrapper_set(PyObject *wrapper) +{ + g_private_set(&pygobject_construction_wrapper, wrapper); +} + +static inline PyObject * +pygobject_init_wrapper_get(void) +{ + return (PyObject *) g_private_get(&pygobject_construction_wrapper); +} + +int +pygobject_constructv(PyGObject *self, + guint n_parameters, + GParameter *parameters) +{ + GObject *obj; + + g_assert (self->obj == NULL); + pygobject_init_wrapper_set((PyObject *) self); + obj = g_object_newv(pyg_type_from_object((PyObject *) self), + n_parameters, parameters); + + if (g_object_is_floating (obj)) + self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING; + pygobject_sink (obj); + + pygobject_init_wrapper_set(NULL); + self->obj = obj; + pygobject_register_wrapper((PyObject *) self); + + return 0; +} + +static void +pygobject__g_instance_init(GTypeInstance *instance, + gpointer g_class) +{ + GObject *object = (GObject *) instance; + PyObject *wrapper, *args, *kwargs; + + wrapper = g_object_get_qdata(object, pygobject_wrapper_key); + if (wrapper == NULL) { + wrapper = pygobject_init_wrapper_get(); + if (wrapper && ((PyGObject *) wrapper)->obj == NULL) { + ((PyGObject *) wrapper)->obj = object; + pygobject_register_wrapper(wrapper); + } + } + pygobject_init_wrapper_set(NULL); + if (wrapper == NULL) { + /* this looks like a python object created through + * g_object_new -> we have no python wrapper, so create it + * now */ + PyGILState_STATE state; + state = pyglib_gil_state_ensure(); + wrapper = pygobject_new_full(object, + /*steal=*/ FALSE, + g_class); + + /* float the wrapper ref here because we are going to orphan it + * so we don't destroy the wrapper. The next call to pygobject_new_full + * will take the ref */ + pygobject_ref_float ((PyGObject *) wrapper); + args = PyTuple_New(0); + kwargs = PyDict_New(); + if (Py_TYPE(wrapper)->tp_init(wrapper, args, kwargs)) + PyErr_Print(); + + Py_DECREF(args); + Py_DECREF(kwargs); + pyglib_gil_state_release(state); + } +} + + +/* This implementation is bad, see bug 566571 for an example why. + * Instead of scanning explicitly declared bases for interfaces, we + * should automatically initialize all implemented interfaces to + * prevent bugs like that one. However, this will lead to + * performance degradation as each virtual method in derived classes + * will round-trip through do_*() stuff, *even* if it is not + * overriden. We need to teach codegen to retain parent method + * instead of setting virtual to *_proxy_do_*() if corresponding + * do_*() is not overriden. Ok, that was a messy explanation. + */ +static void +pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, + PyObject *bases, + GType *parent_interfaces, guint n_parent_interfaces) +{ + int i; + + if (!bases) { + g_warning("type has no bases"); + return; + } + + for (i = 0; i < PyTuple_GET_SIZE(bases); ++i) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + GType itype; + const GInterfaceInfo *iinfo; + GInterfaceInfo iinfo_copy; + + /* 'base' can also be a PyClassObject, see bug #566571. */ + if (!PyType_Check(base)) + continue; + + if (!PyType_IsSubtype((PyTypeObject*) base, &PyGInterface_Type)) + continue; + + itype = pyg_type_from_object(base); + + /* Happens for _implementations_ of an interface. */ + if (!G_TYPE_IS_INTERFACE(itype)) + continue; + + iinfo = pyg_lookup_interface_info(itype); + if (!iinfo) { + gchar *error; + error = g_strdup_printf("Interface type %s " + "has no Python implementation support", + ((PyTypeObject *) base)->tp_name); + PyErr_Warn(PyExc_RuntimeWarning, error); + g_free(error); + continue; + } + + iinfo_copy = *iinfo; + iinfo_copy.interface_data = class; + g_type_add_interface_static(instance_type, itype, &iinfo_copy); + } +} + +int +pyg_type_register(PyTypeObject *class, const char *type_name) +{ + PyObject *gtype; + GType parent_type, instance_type; + GType *parent_interfaces; + guint n_parent_interfaces; + GTypeQuery query; + gpointer gclass; + GTypeInfo type_info = { + 0, /* class_size */ + + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + + (GClassInitFunc) pyg_object_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + + 0, /* instance_size */ + 0, /* n_preallocs */ + (GInstanceInitFunc) pygobject__g_instance_init + }; + gchar *new_type_name; + + /* find the GType of the parent */ + parent_type = pyg_type_from_object((PyObject *)class); + if (!parent_type) + return -1; + + parent_interfaces = g_type_interfaces(parent_type, &n_parent_interfaces); + + if (type_name) + /* care is taken below not to free this */ + new_type_name = (gchar *) type_name; + else + new_type_name = get_type_name_for_class(class); + + /* set class_data that will be passed to the class_init function. */ + type_info.class_data = class; + + /* fill in missing values of GTypeInfo struct */ + g_type_query(parent_type, &query); + type_info.class_size = query.class_size; + type_info.instance_size = query.instance_size; + + /* create new typecode */ + instance_type = g_type_register_static(parent_type, new_type_name, + &type_info, 0); + if (instance_type == 0) { + PyErr_Format(PyExc_RuntimeError, + "could not create new GType: %s (subclass of %s)", + new_type_name, + g_type_name(parent_type)); + + if (type_name == NULL) + g_free(new_type_name); + + return -1; + } + + if (type_name == NULL) + g_free(new_type_name); + + /* store pointer to the class with the GType */ + Py_INCREF(class); + g_type_set_qdata(instance_type, g_quark_from_string("PyGObject::class"), + class); + + /* Mark this GType as a custom python type */ + g_type_set_qdata(instance_type, pygobject_custom_key, + GINT_TO_POINTER (1)); + + /* set new value of __gtype__ on class */ + gtype = pyg_type_wrapper_new(instance_type); + PyObject_SetAttrString((PyObject *)class, "__gtype__", gtype); + Py_DECREF(gtype); + + /* if no __doc__, set it to the auto doc descriptor */ + if (PyDict_GetItemString(class->tp_dict, "__doc__") == NULL) { + PyDict_SetItemString(class->tp_dict, "__doc__", + pyg_object_descr_doc_get()); + } + + /* + * Note, all interfaces need to be registered before the first + * g_type_class_ref(), see bug #686149. + * + * See also comment above pyg_type_add_interfaces(). + */ + pyg_type_add_interfaces(class, instance_type, class->tp_bases, + parent_interfaces, n_parent_interfaces); + + + gclass = g_type_class_ref(instance_type); + if (PyErr_Occurred() != NULL) { + g_type_class_unref(gclass); + g_free(parent_interfaces); + return -1; + } + + if (pyg_run_class_init(instance_type, gclass, class)) { + g_type_class_unref(gclass); + g_free(parent_interfaces); + return -1; + } + g_type_class_unref(gclass); + g_free(parent_interfaces); + + if (PyErr_Occurred() != NULL) + return -1; + return 0; +} + +static PyObject * +pyg_signal_new(PyObject *self, PyObject *args) +{ + gchar *signal_name; + PyObject *py_type; + GSignalFlags signal_flags; + GType return_type; + PyObject *py_return_type, *py_param_types; + + GType instance_type = 0; + Py_ssize_t n_params, i; + GType *param_types; + + guint signal_id; + + if (!PyArg_ParseTuple(args, "sOiOO:gobject.signal_new", &signal_name, + &py_type, &signal_flags, &py_return_type, + &py_param_types)) + return NULL; + + instance_type = pyg_type_from_object(py_type); + if (!instance_type) + return NULL; + if (!(G_TYPE_IS_INSTANTIATABLE(instance_type) || G_TYPE_IS_INTERFACE(instance_type))) { + PyErr_SetString(PyExc_TypeError, + "argument 2 must be an object type or interface type"); + return NULL; + } + + return_type = pyg_type_from_object(py_return_type); + if (!return_type) + return NULL; + + if (!PySequence_Check(py_param_types)) { + PyErr_SetString(PyExc_TypeError, + "argument 5 must be a sequence of GType codes"); + return NULL; + } + n_params = PySequence_Length(py_param_types); + param_types = g_new(GType, n_params); + for (i = 0; i < n_params; i++) { + PyObject *item = PySequence_GetItem(py_param_types, i); + + param_types[i] = pyg_type_from_object(item); + if (param_types[i] == 0) { + PyErr_Clear(); + Py_DECREF(item); + PyErr_SetString(PyExc_TypeError, + "argument 5 must be a sequence of GType codes"); + g_free(param_types); + return NULL; + } + Py_DECREF(item); + } + + signal_id = g_signal_newv(signal_name, instance_type, signal_flags, + pyg_signal_class_closure_get(), + (GSignalAccumulator)0, NULL, + (GSignalCMarshaller)0, + return_type, n_params, param_types); + g_free(param_types); + if (signal_id != 0) + return PYGLIB_PyLong_FromLong(signal_id); + PyErr_SetString(PyExc_RuntimeError, "could not create signal"); + return NULL; +} + +static PyObject * +pyg_signal_query (PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist1[] = { "name", "type", NULL }; + static char *kwlist2[] = { "signal_id", NULL }; + PyObject *py_query, *params_list, *py_itype; + GObjectClass *class = NULL; + GType itype; + gchar *signal_name; + guint i; + GSignalQuery query; + guint id; + gpointer iface = NULL; + + if (PyArg_ParseTupleAndKeywords(args, kwargs, "sO:gobject.signal_query", + kwlist1, &signal_name, &py_itype)) { + if ((itype = pyg_type_from_object(py_itype)) == 0) + return NULL; + + if (G_TYPE_IS_INSTANTIATABLE(itype)) { + class = g_type_class_ref(itype); + if (!class) { + PyErr_SetString(PyExc_RuntimeError, + "could not get a reference to type class"); + return NULL; + } + } else if (!G_TYPE_IS_INTERFACE(itype)) { + PyErr_SetString(PyExc_TypeError, + "type must be instantiable or an interface"); + return NULL; + } else { + iface = g_type_default_interface_ref(itype); + } + id = g_signal_lookup(signal_name, itype); + } else { + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "i:gobject.signal_query", + kwlist2, &id)) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "Usage: one of:\n" + " gobject.signal_query(name, type)\n" + " gobject.signal_query(signal_id)"); + + return NULL; + } + } + + g_signal_query(id, &query); + + if (query.signal_id == 0) { + Py_INCREF(Py_None); + py_query = Py_None; + goto done; + } + py_query = PyTuple_New(6); + if (py_query == NULL) { + goto done; + } + params_list = PyTuple_New(query.n_params); + if (params_list == NULL) { + Py_DECREF(py_query); + py_query = NULL; + goto done; + } + + PyTuple_SET_ITEM(py_query, 0, PYGLIB_PyLong_FromLong(query.signal_id)); + PyTuple_SET_ITEM(py_query, 1, PYGLIB_PyUnicode_FromString(query.signal_name)); + PyTuple_SET_ITEM(py_query, 2, pyg_type_wrapper_new(query.itype)); + PyTuple_SET_ITEM(py_query, 3, PYGLIB_PyLong_FromLong(query.signal_flags)); + PyTuple_SET_ITEM(py_query, 4, pyg_type_wrapper_new(query.return_type)); + for (i = 0; i < query.n_params; i++) { + PyTuple_SET_ITEM(params_list, i, + pyg_type_wrapper_new(query.param_types[i])); + } + PyTuple_SET_ITEM(py_query, 5, params_list); + + done: + if (class) + g_type_class_unref(class); + if (iface) + g_type_default_interface_unref(iface); + + return py_query; +} + +static PyObject * +pyg_object_class_list_properties (PyObject *self, PyObject *args) +{ + GParamSpec **specs; + PyObject *py_itype, *list; + GType itype; + GObjectClass *class = NULL; + gpointer iface = NULL; + guint nprops; + guint i; + + if (!PyArg_ParseTuple(args, "O:gobject.list_properties", + &py_itype)) + return NULL; + if ((itype = pyg_type_from_object(py_itype)) == 0) + return NULL; + + if (G_TYPE_IS_INTERFACE(itype)) { + iface = g_type_default_interface_ref(itype); + if (!iface) { + PyErr_SetString(PyExc_RuntimeError, + "could not get a reference to interface type"); + return NULL; + } + specs = g_object_interface_list_properties(iface, &nprops); + } else if (g_type_is_a(itype, G_TYPE_OBJECT)) { + class = g_type_class_ref(itype); + if (!class) { + PyErr_SetString(PyExc_RuntimeError, + "could not get a reference to type class"); + return NULL; + } + specs = g_object_class_list_properties(class, &nprops); + } else { + PyErr_SetString(PyExc_TypeError, + "type must be derived from GObject or an interface"); + return NULL; + } + + list = PyTuple_New(nprops); + if (list == NULL) { + g_free(specs); + g_type_class_unref(class); + return NULL; + } + for (i = 0; i < nprops; i++) { + PyTuple_SetItem(list, i, pyg_param_spec_new(specs[i])); + } + g_free(specs); + if (class) + g_type_class_unref(class); + else + g_type_default_interface_unref(iface); + + return list; +} + +static PyObject * +pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *pytype; + GType type; + GObject *obj = NULL; + GObjectClass *class; + guint n_params = 0, i; + GParameter *params = NULL; + + if (!PyArg_ParseTuple (args, "O:gobject.new", &pytype)) { + return NULL; + } + + if ((type = pyg_type_from_object (pytype)) == 0) + return NULL; + + if (G_TYPE_IS_ABSTRACT(type)) { + PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " + "(non-instantiable) type `%s'", g_type_name(type)); + return NULL; + } + + if ((class = g_type_class_ref (type)) == NULL) { + PyErr_SetString(PyExc_TypeError, + "could not get a reference to type class"); + return NULL; + } + + if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, ¶ms)) + goto cleanup; + + obj = g_object_newv(type, n_params, params); + if (!obj) + PyErr_SetString (PyExc_RuntimeError, "could not create object"); + + cleanup: + for (i = 0; i < n_params; i++) { + g_free((gchar *) params[i].name); + g_value_unset(¶ms[i].value); + } + g_free(params); + g_type_class_unref(class); + + if (obj) { + pygobject_sink (obj); + self = (PyGObject *) pygobject_new((GObject *)obj); + g_object_unref(obj); + } else + self = NULL; + + return (PyObject *) self; +} + +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 int +pygobject_gil_state_ensure (void) +{ + return pyglib_gil_state_ensure (); +} + +static void +pygobject_gil_state_release (int flag) +{ + pyglib_gil_state_release(flag); +} + +/* Only for backwards compatibility */ +static int +pygobject_enable_threads(void) +{ + return 0; +} + +static PyObject * +pyg_signal_accumulator_true_handled(PyObject *unused, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "signal_accumulator_true_handled can only" + " be used as accumulator argument when registering signals"); + return NULL; +} + +static gboolean +marshal_emission_hook(GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer user_data) +{ + PyGILState_STATE state; + gboolean retval = FALSE; + PyObject *func, *args; + PyObject *retobj; + PyObject *params; + guint i; + + state = pyglib_gil_state_ensure(); + + /* construct Python tuple for the parameter values */ + params = PyTuple_New(n_param_values); + + for (i = 0; i < n_param_values; i++) { + PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); + + /* error condition */ + if (!item) { + goto out; + } + PyTuple_SetItem(params, i, item); + } + + args = (PyObject *)user_data; + func = PyTuple_GetItem(args, 0); + args = PySequence_Concat(params, PyTuple_GetItem(args, 1)); + Py_DECREF(params); + + /* params passed to function may have extra arguments */ + + retobj = PyObject_CallObject(func, args); + Py_DECREF(args); + if (retobj == NULL) { + PyErr_Print(); + } + + retval = (retobj == Py_True ? TRUE : FALSE); + Py_XDECREF(retobj); +out: + pyglib_gil_state_release(state); + return retval; +} + +static PyObject * +pyg_add_emission_hook(PyGObject *self, PyObject *args) +{ + PyObject *first, *callback, *extra_args, *data, *repr; + gchar *name; + gulong hook_id; + guint sigid; + Py_ssize_t len; + GQuark detail = 0; + GType gtype; + PyObject *pygtype; + + len = PyTuple_Size(args); + if (len < 3) { + PyErr_SetString(PyExc_TypeError, + "gobject.add_emission_hook requires at least 3 arguments"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 3); + if (!PyArg_ParseTuple(first, "OsO:add_emission_hook", + &pygtype, &name, &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + + if ((gtype = pyg_type_from_object(pygtype)) == 0) { + return NULL; + } + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "third argument must be callable"); + return NULL; + } + + if (!g_signal_parse_name(name, gtype, &sigid, &detail, TRUE)) { + repr = PyObject_Repr((PyObject*)self); + PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", + PYGLIB_PyUnicode_AsString(repr), + name); + Py_DECREF(repr); + return NULL; + } + extra_args = PySequence_GetSlice(args, 3, len); + if (extra_args == NULL) + return NULL; + + data = Py_BuildValue("(ON)", callback, extra_args); + if (data == NULL) + return NULL; + + hook_id = g_signal_add_emission_hook(sigid, detail, + marshal_emission_hook, + data, + (GDestroyNotify)pyg_destroy_notify); + + return PyLong_FromUnsignedLong(hook_id); +} + +static PyObject * +pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) +{ + Py_INCREF(metaclass); + PyGObject_MetaType = metaclass; + Py_INCREF(metaclass); + + Py_TYPE(&PyGObject_Type) = metaclass; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +pyg__gvalue_get(PyObject *module, PyObject *pygvalue) +{ + if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) { + PyErr_SetString (PyExc_TypeError, "Expected GValue argument."); + return NULL; + } + + return pyg_value_as_pyobject (pyg_boxed_get(pygvalue, GValue), + /*copy_boxed=*/ TRUE); +} + +static PyObject * +pyg__gvalue_set(PyObject *module, PyObject *args) +{ + PyObject *pygvalue; + PyObject *pyobject; + + if (!PyArg_ParseTuple (args, "OO:_gobject._gvalue_set", + &pygvalue, &pyobject)) + return NULL; + + if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) { + PyErr_SetString (PyExc_TypeError, "Expected GValue argument."); + return NULL; + } + + if (pyg_value_from_pyobject_with_error (pyg_boxed_get (pygvalue, GValue), + pyobject) == -1) + return NULL; + + Py_RETURN_NONE; +} + +static PyMethodDef _gobject_functions[] = { + { "type_name", pyg_type_name, METH_VARARGS }, + { "type_from_name", pyg_type_from_name, METH_VARARGS }, + { "type_is_a", pyg_type_is_a, METH_VARARGS }, + { "type_register", _wrap_pyg_type_register, METH_VARARGS }, + { "signal_new", pyg_signal_new, METH_VARARGS }, + { "signal_query", + (PyCFunction)pyg_signal_query, METH_VARARGS|METH_KEYWORDS }, + { "list_properties", + pyg_object_class_list_properties, METH_VARARGS }, + { "new", + (PyCFunction)pyg_object_new, METH_VARARGS|METH_KEYWORDS }, + { "signal_accumulator_true_handled", + (PyCFunction)pyg_signal_accumulator_true_handled, METH_VARARGS }, + { "add_emission_hook", + (PyCFunction)pyg_add_emission_hook, METH_VARARGS }, + { "_install_metaclass", + (PyCFunction)pyg__install_metaclass, METH_O }, + { "_gvalue_get", + (PyCFunction)pyg__gvalue_get, METH_O }, + { "_gvalue_set", + (PyCFunction)pyg__gvalue_set, METH_VARARGS }, + + { NULL, NULL, 0 } +}; + + +/* ----------------- Constant extraction ------------------------ */ + +/** + * pyg_constant_strip_prefix: + * @name: the constant name. + * @strip_prefix: the prefix to strip. + * + * Advances the pointer @name by strlen(@strip_prefix) characters. If + * the resulting name does not start with a letter or underscore, the + * @name pointer will be rewound. This is to ensure that the + * resulting name is a valid identifier. Hence the returned string is + * a pointer into the string @name. + * + * Returns: the stripped constant name. + */ +const gchar * +pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix) +{ + gint prefix_len; + guint i; + + prefix_len = strlen(strip_prefix); + + /* Check so name starts with strip_prefix, if it doesn't: + * return the rest of the part which doesn't match + */ + for (i = 0; i < prefix_len; i++) { + if (name[i] != strip_prefix[i] && name[i] != '_') { + return &name[i]; + } + } + + /* strip off prefix from value name, while keeping it a valid + * identifier */ + for (i = prefix_len; i >= 0; i--) { + if (g_ascii_isalpha(name[i]) || name[i] == '_') { + return &name[i]; + } + } + return name; +} + +/** + * pyg_enum_add_constants: + * @module: a Python module + * @enum_type: the GType of the enumeration. + * @strip_prefix: the prefix to strip from the constant names. + * + * Adds constants to the given Python module for each value name of + * the enumeration. A prefix will be stripped from each enum name. + */ +static void +pyg_enum_add_constants(PyObject *module, GType enum_type, + const gchar *strip_prefix) +{ + GEnumClass *eclass; + guint i; + + if (!G_TYPE_IS_ENUM(enum_type)) { + if (G_TYPE_IS_FLAGS(enum_type)) /* See bug #136204 */ + pyg_flags_add_constants(module, enum_type, strip_prefix); + else + g_warning("`%s' is not an enum type", g_type_name(enum_type)); + return; + } + g_return_if_fail (strip_prefix != NULL); + + eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); + + for (i = 0; i < eclass->n_values; i++) { + const gchar *name = eclass->values[i].value_name; + gint value = eclass->values[i].value; + + PyModule_AddIntConstant(module, + (char*) pyg_constant_strip_prefix(name, strip_prefix), + (long) value); + } + + g_type_class_unref(eclass); +} + +/** + * pyg_flags_add_constants: + * @module: a Python module + * @flags_type: the GType of the flags type. + * @strip_prefix: the prefix to strip from the constant names. + * + * Adds constants to the given Python module for each value name of + * the flags set. A prefix will be stripped from each flag name. + */ +static void +pyg_flags_add_constants(PyObject *module, GType flags_type, + const gchar *strip_prefix) +{ + GFlagsClass *fclass; + guint i; + + if (!G_TYPE_IS_FLAGS(flags_type)) { + if (G_TYPE_IS_ENUM(flags_type)) /* See bug #136204 */ + pyg_enum_add_constants(module, flags_type, strip_prefix); + else + g_warning("`%s' is not an flags type", g_type_name(flags_type)); + return; + } + g_return_if_fail (strip_prefix != NULL); + + fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type)); + + for (i = 0; i < fclass->n_values; i++) { + const gchar *name = fclass->values[i].value_name; + guint value = fclass->values[i].value; + + PyModule_AddIntConstant(module, + (char*) pyg_constant_strip_prefix(name, strip_prefix), + (long) value); + } + + g_type_class_unref(fclass); +} + +/** + * pyg_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 gobject.GError Python exception will be raised, and + * the GError cleared. + * + * Returns: True if an error was set. + * + * Deprecated: Since 2.16, use pyglib_error_check instead. + */ +gboolean +pyg_error_check(GError **error) +{ +#if 0 + if (PyErr_Warn(PyExc_DeprecationWarning, + "pyg_error_check is deprecated, use " + "pyglib_error_check instead")) + return NULL; +#endif + return pyglib_error_check(error); +} + +/** + * pyg_gerror_exception_check: + * @error: a standard GLib GError ** output parameter + * + * Checks to see if a GError exception has been raised, and if so + * translates the python exception to a standard GLib GError. If the + * raised exception is not a GError then PyErr_Print() is called. + * + * Returns: 0 if no exception has been raised, -1 if it is a + * valid gobject.GError, -2 otherwise. + * + * Deprecated: Since 2.16, use pyglib_gerror_exception_check instead. + */ +gboolean +pyg_gerror_exception_check(GError **error) +{ +#if 0 + if (PyErr_Warn(PyExc_DeprecationWarning, + "pyg_gerror_exception_check is deprecated, use " + "pyglib_gerror_exception_check instead")) + return NULL; +#endif + return pyglib_gerror_exception_check(error); +} + +/** + * pyg_parse_constructor_args: helper function for PyGObject constructors + * @obj_type: GType of the GObject, for parameter introspection + * @arg_names: %NULL-terminated array of constructor argument names + * @prop_names: %NULL-terminated array of property names, with direct + * correspondence to @arg_names + * @params: GParameter array where parameters will be placed; length + * of this array must be at least equal to the number of + * arguments/properties + * @nparams: output parameter to contain actual number of arguments found + * @py_args: array of PyObject* containing the actual constructor arguments + * + * Parses an array of PyObject's and creates a GParameter array + * + * Return value: %TRUE if all is successful, otherwise %FALSE and + * python exception set. + **/ +static gboolean +pyg_parse_constructor_args(GType obj_type, + char **arg_names, + char **prop_names, + GParameter *params, + guint *nparams, + PyObject **py_args) +{ + guint arg_i, param_i; + GObjectClass *oclass; + + oclass = g_type_class_ref(obj_type); + g_return_val_if_fail(oclass, FALSE); + + for (param_i = arg_i = 0; arg_names[arg_i]; ++arg_i) { + GParamSpec *spec; + if (!py_args[arg_i]) + continue; + spec = g_object_class_find_property(oclass, prop_names[arg_i]); + params[param_i].name = prop_names[arg_i]; + g_value_init(¶ms[param_i].value, spec->value_type); + if (pyg_value_from_pyobject(¶ms[param_i].value, py_args[arg_i]) == -1) { + int i; + PyErr_Format(PyExc_TypeError, "could not convert parameter '%s' of type '%s'", + arg_names[arg_i], g_type_name(spec->value_type)); + g_type_class_unref(oclass); + for (i = 0; i < param_i; ++i) + g_value_unset(¶ms[i].value); + return FALSE; + } + ++param_i; + } + g_type_class_unref(oclass); + *nparams = param_i; + return TRUE; +} + +PyObject * +pyg_integer_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *result; + gboolean t; + + switch (op) { + case Py_EQ: t = PYGLIB_PyLong_AS_LONG(v) == PYGLIB_PyLong_AS_LONG(w); break; + case Py_NE: t = PYGLIB_PyLong_AS_LONG(v) != PYGLIB_PyLong_AS_LONG(w); break; + case Py_LE: t = PYGLIB_PyLong_AS_LONG(v) <= PYGLIB_PyLong_AS_LONG(w); break; + case Py_GE: t = PYGLIB_PyLong_AS_LONG(v) >= PYGLIB_PyLong_AS_LONG(w); break; + case Py_LT: t = PYGLIB_PyLong_AS_LONG(v) < PYGLIB_PyLong_AS_LONG(w); break; + case Py_GT: t = PYGLIB_PyLong_AS_LONG(v) > PYGLIB_PyLong_AS_LONG(w); break; + default: g_assert_not_reached(); + } + + result = t ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +static void +_log_func(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + if (G_LIKELY(Py_IsInitialized())) + { + PyGILState_STATE state; + PyObject* warning = user_data; + + state = pyglib_gil_state_ensure(); + PyErr_Warn(warning, (char *) message); + pyglib_gil_state_release(state); + } else + g_log_default_handler(log_domain, log_level, message, user_data); +} + +static void +add_warning_redirection(const char *domain, + PyObject *warning) +{ + g_return_if_fail(domain != NULL); + g_return_if_fail(warning != NULL); + + if (!log_handlers_disabled) + { + guint handler; + gpointer old_handler; + + if (!log_handlers) + log_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + if ((old_handler = g_hash_table_lookup(log_handlers, domain))) + g_log_remove_handler(domain, GPOINTER_TO_UINT(old_handler)); + + handler = g_log_set_handler(domain, G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING, + _log_func, warning); + g_hash_table_insert(log_handlers, g_strdup(domain), GUINT_TO_POINTER(handler)); + } +} + +static void +remove_handler(gpointer domain, + gpointer handler, + gpointer unused) +{ + g_log_remove_handler(domain, GPOINTER_TO_UINT(handler)); +} + +static void +disable_warning_redirections(void) +{ + log_handlers_disabled = TRUE; + + if (log_handlers) + { + g_hash_table_foreach(log_handlers, remove_handler, NULL); + g_hash_table_destroy(log_handlers); + log_handlers = NULL; + } +} + +/* ----------------- gobject module initialisation -------------- */ + +struct _PyGObject_Functions pygobject_api_functions = { + pygobject_register_class, + pygobject_register_wrapper, + pygobject_lookup_class, + pygobject_new, + + pyg_closure_new, + pygobject_watch_closure, + pyg_destroy_notify, + + pyg_type_from_object, + pyg_type_wrapper_new, + pyg_enum_get_value, + pyg_flags_get_value, + pyg_register_gtype_custom, + pyg_value_from_pyobject, + pyg_value_as_pyobject, + + pyg_register_interface, + + &PyGBoxed_Type, + pyg_register_boxed, + pyg_boxed_new, + + &PyGPointer_Type, + pyg_register_pointer, + pyg_pointer_new, + + pyg_enum_add_constants, + pyg_flags_add_constants, + + pyg_constant_strip_prefix, + + pyg_error_check, + + _pyg_set_thread_block_funcs, + (PyGThreadBlockFunc)0, /* block_threads */ + (PyGThreadBlockFunc)0, /* unblock_threads */ + + &PyGParamSpec_Type, + pyg_param_spec_new, + pyg_param_spec_from_object, + + pyg_pyobj_to_unichar_conv, + pyg_parse_constructor_args, + pyg_param_gvalue_as_pyobject, + pyg_param_gvalue_from_pyobject, + + &PyGEnum_Type, + pyg_enum_add, + pyg_enum_from_gtype, + + &PyGFlags_Type, + pyg_flags_add, + pyg_flags_from_gtype, + + /* threads_enabled */ +#ifdef DISABLE_THREADING + FALSE, +#else + TRUE, +#endif + + pygobject_enable_threads, + pygobject_gil_state_ensure, + pygobject_gil_state_release, + pyg_register_class_init, + pyg_register_interface_info, + + pyg_closure_set_exception_handler, + + add_warning_redirection, + disable_warning_redirections, + + NULL, /* previously type_register_custom */ + + pyg_gerror_exception_check, + + pyglib_option_group_new, + pyg_type_from_object_strict, + + pygobject_new_full, + &PyGObject_Type, + + pyg_value_from_pyobject_with_error +}; + +/* for addon libraries ... */ +static void +pygobject_register_api(PyObject *d) +{ + PyObject *api; + + api = PYGLIB_CPointer_WrapPointer(&pygobject_api_functions, "gobject._PyGObject_API"); + PyDict_SetItemString(d, "_PyGObject_API", api); + Py_DECREF(api); +} + +/* some constants */ +static void +pygobject_register_constants(PyObject *m) +{ + /* PyFloat_ return a new ref, and add object takes the ref */ + PyModule_AddObject(m, "G_MINFLOAT", PyFloat_FromDouble(G_MINFLOAT)); + PyModule_AddObject(m, "G_MAXFLOAT", PyFloat_FromDouble(G_MAXFLOAT)); + PyModule_AddObject(m, "G_MINDOUBLE", PyFloat_FromDouble(G_MINDOUBLE)); + PyModule_AddObject(m, "G_MAXDOUBLE", PyFloat_FromDouble(G_MAXDOUBLE)); + PyModule_AddIntConstant(m, "G_MINSHORT", G_MINSHORT); + PyModule_AddIntConstant(m, "G_MAXSHORT", G_MAXSHORT); + PyModule_AddIntConstant(m, "G_MAXUSHORT", G_MAXUSHORT); + PyModule_AddIntConstant(m, "G_MININT", G_MININT); + PyModule_AddIntConstant(m, "G_MAXINT", G_MAXINT); + PyModule_AddObject(m, "G_MAXUINT", PyLong_FromUnsignedLong(G_MAXUINT)); + PyModule_AddObject(m, "G_MINLONG", PyLong_FromLong(G_MINLONG)); + PyModule_AddObject(m, "G_MAXLONG", PyLong_FromLong(G_MAXLONG)); + PyModule_AddObject(m, "G_MAXULONG", PyLong_FromUnsignedLong(G_MAXULONG)); + PyModule_AddObject(m, "G_MAXSIZE", PyLong_FromSize_t(G_MAXSIZE)); + PyModule_AddObject(m, "G_MAXSSIZE", PyLong_FromSsize_t(G_MAXSSIZE)); + PyModule_AddObject(m, "G_MINSSIZE", PyLong_FromSsize_t(G_MINSSIZE)); + PyModule_AddObject(m, "G_MINOFFSET", PyLong_FromLongLong(G_MINOFFSET)); + PyModule_AddObject(m, "G_MAXOFFSET", PyLong_FromLongLong(G_MAXOFFSET)); + + PyModule_AddIntConstant(m, "SIGNAL_RUN_FIRST", G_SIGNAL_RUN_FIRST); + PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE); + + /* The rest of the types are set in __init__.py */ + PyModule_AddObject(m, "TYPE_INVALID", pyg_type_wrapper_new(G_TYPE_INVALID)); + PyModule_AddObject(m, "TYPE_GSTRING", pyg_type_wrapper_new(G_TYPE_GSTRING)); +} + +/* features */ +static void +pygobject_register_features(PyObject *d) +{ + PyObject *features; + + features = PyDict_New(); + PyDict_SetItemString(features, "generic-c-marshaller", Py_True); + PyDict_SetItemString(d, "features", features); + Py_DECREF(features); +} + +static void +pygobject_register_version_tuples(PyObject *d) +{ + PyObject *tuple; + + /* pygobject version */ + tuple = Py_BuildValue ("(iii)", + PYGOBJECT_MAJOR_VERSION, + PYGOBJECT_MINOR_VERSION, + PYGOBJECT_MICRO_VERSION); + PyDict_SetItemString(d, "pygobject_version", tuple); +} + +static void +pygobject_register_warnings(PyObject *d) +{ + PyObject *warning; + + warning = PyErr_NewException("gobject.Warning", PyExc_Warning, NULL); + PyDict_SetItemString(d, "Warning", warning); + add_warning_redirection("GLib", warning); + add_warning_redirection("GLib-GObject", warning); + add_warning_redirection("GThread", warning); +} + + +PYGLIB_MODULE_START(_gobject, "_gobject") +{ + PyObject *d; + + pyglib_init(); + + d = PyModule_GetDict(module); + pygobject_register_api(d); + pygobject_register_constants(module); + pygobject_register_features(d); + pygobject_register_version_tuples(d); + pygobject_register_warnings(d); + pygobject_type_register_types(d); + pygobject_object_register_types(d); + pygobject_interface_register_types(d); + pygobject_paramspec_register_types(d); + pygobject_boxed_register_types(d); + pygobject_pointer_register_types(d); + pygobject_enum_register_types(d); + pygobject_flags_register_types(d); +} +PYGLIB_MODULE_END diff --git a/gi/module.py b/gi/module.py index 89969267..22ae551b 100644 --- a/gi/module.py +++ b/gi/module.py @@ -59,8 +59,8 @@ from .types import \ GObjectMeta, \ StructMeta -from ._gobject._gobject import \ - GInterface +import gi._gi +GInterface = gi._gi._gobject.GInterface from ._gobject.constants import \ TYPE_NONE, \ diff --git a/gi/pygboxed.c b/gi/pygboxed.c new file mode 100644 index 00000000..541e77b1 --- /dev/null +++ b/gi/pygboxed.c @@ -0,0 +1,235 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * pygboxed.c: wrapper for GBoxed + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "pygobject-private.h" +#include "pygboxed.h" + +#include "pygi.h" + +GQuark pygboxed_type_key; +GQuark pygboxed_marshal_key; + +PYGLIB_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed); + +static void +pyg_boxed_dealloc(PyGBoxed *self) +{ + if (self->free_on_dealloc && self->boxed) { + PyGILState_STATE state = pyglib_gil_state_ensure(); + g_boxed_free(self->gtype, self->boxed); + pyglib_gil_state_release(state); + } + + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject* +pyg_boxed_richcompare(PyObject *self, PyObject *other, int op) +{ + if (Py_TYPE(self) == Py_TYPE(other) && + PyObject_IsInstance(self, (PyObject*)&PyGBoxed_Type)) + return _pyglib_generic_ptr_richcompare(((PyGBoxed*)self)->boxed, + ((PyGBoxed*)other)->boxed, + op); + else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + + +static long +pyg_boxed_hash(PyGBoxed *self) +{ + return (long)self->boxed; +} + +static PyObject * +pyg_boxed_repr(PyGBoxed *self) +{ + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), + (long)self->boxed); + return PYGLIB_PyUnicode_FromString(buf); +} + +static int +pyg_boxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) +{ + gchar buf[512]; + + if (!PyArg_ParseTuple(args, ":GBoxed.__init__")) + return -1; + + self->boxed = NULL; + self->gtype = 0; + self->free_on_dealloc = FALSE; + + g_snprintf(buf, sizeof(buf), "%s can not be constructed", + Py_TYPE(self)->tp_name); + PyErr_SetString(PyExc_NotImplementedError, buf); + return -1; +} + +static void +pyg_boxed_free(PyObject *op) +{ + PyObject_FREE(op); +} + +static PyObject * +pyg_boxed_copy(PyGBoxed *self) +{ + return pyg_boxed_new (self->gtype, self->boxed, TRUE, TRUE); +} + + + +static PyMethodDef pygboxed_methods[] = { + { "copy", (PyCFunction) pyg_boxed_copy, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/** + * pyg_register_boxed: + * @dict: the module dictionary to store the wrapper class. + * @class_name: the Python name for the wrapper class. + * @boxed_type: the GType of the boxed type being wrapped. + * @type: the wrapper class. + * + * Registers a wrapper for a boxed type. The wrapper class will be a + * subclass of gobject.GBoxed, and a reference to the wrapper class + * will be stored in the provided module dictionary. + */ +void +pyg_register_boxed(PyObject *dict, const gchar *class_name, + GType boxed_type, PyTypeObject *type) +{ + PyObject *o; + + g_return_if_fail(dict != NULL); + g_return_if_fail(class_name != NULL); + g_return_if_fail(boxed_type != 0); + + if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_boxed_dealloc; + + Py_TYPE(type) = &PyType_Type; + type->tp_base = &PyGBoxed_Type; + + if (PyType_Ready(type) < 0) { + g_warning("could not get type `%s' ready", type->tp_name); + return; + } + + PyDict_SetItemString(type->tp_dict, "__gtype__", + o=pyg_type_wrapper_new(boxed_type)); + Py_DECREF(o); + + g_type_set_qdata(boxed_type, pygboxed_type_key, type); + + PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); +} + +/** + * pyg_boxed_new: + * @boxed_type: the GType of the boxed value. + * @boxed: the boxed value. + * @copy_boxed: whether the new boxed wrapper should hold a copy of the value. + * @own_ref: whether the boxed wrapper should own the boxed value. + * + * Creates a wrapper for a boxed value. If @copy_boxed is set to + * True, the wrapper will hold a copy of the value, instead of the + * value itself. If @own_ref is True, then the value held by the + * wrapper will be freed when the wrapper is deallocated. If + * @copy_boxed is True, then @own_ref must also be True. + * + * Returns: the boxed wrapper. + */ +PyObject * +pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, + gboolean own_ref) +{ + PyGILState_STATE state; + PyGBoxed *self; + PyTypeObject *tp; + + g_return_val_if_fail(boxed_type != 0, NULL); + g_return_val_if_fail(!copy_boxed || (copy_boxed && own_ref), NULL); + + state = pyglib_gil_state_ensure(); + + if (!boxed) { + Py_INCREF(Py_None); + pyglib_gil_state_release(state); + return Py_None; + } + + tp = g_type_get_qdata(boxed_type, pygboxed_type_key); + + if (!tp) + tp = (PyTypeObject *)pygi_type_import_by_g_type(boxed_type); + + if (!tp) + tp = (PyTypeObject *)&PyGBoxed_Type; /* fallback */ + + self = (PyGBoxed *)tp->tp_alloc(tp, 0); + + if (self == NULL) { + pyglib_gil_state_release(state); + return NULL; + } + + if (copy_boxed) + boxed = g_boxed_copy(boxed_type, boxed); + self->boxed = boxed; + self->gtype = boxed_type; + self->free_on_dealloc = own_ref; + + pyglib_gil_state_release(state); + + return (PyObject *)self; +} + +void +pygobject_boxed_register_types(PyObject *d) +{ + pygboxed_type_key = g_quark_from_static_string("PyGBoxed::class"); + pygboxed_marshal_key = g_quark_from_static_string("PyGBoxed::marshal"); + + PyGBoxed_Type.tp_dealloc = (destructor)pyg_boxed_dealloc; + PyGBoxed_Type.tp_richcompare = pyg_boxed_richcompare; + PyGBoxed_Type.tp_repr = (reprfunc)pyg_boxed_repr; + PyGBoxed_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGBoxed_Type.tp_methods = pygboxed_methods; + PyGBoxed_Type.tp_init = (initproc)pyg_boxed_init; + PyGBoxed_Type.tp_free = (freefunc)pyg_boxed_free; + PyGBoxed_Type.tp_hash = (hashfunc)pyg_boxed_hash; + + PYGOBJECT_REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED); +} diff --git a/gi/pygboxed.h b/gi/pygboxed.h new file mode 100644 index 00000000..8433b9de --- /dev/null +++ b/gi/pygboxed.h @@ -0,0 +1,27 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_BOXED_H__ +#define __PYGOBJECT_BOXED_H__ + +void pygobject_boxed_register_types(PyObject *d); + +#endif /* __PYGOBJECT_BOXED_H__ */ diff --git a/gi/pygenum.c b/gi/pygenum.c new file mode 100644 index 00000000..89e3a066 --- /dev/null +++ b/gi/pygenum.c @@ -0,0 +1,371 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * pygenum.c: GEnum wrapper + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "pygobject-private.h" +#include "pygi.h" + +#include "pygenum.h" + +GQuark pygenum_class_key; + +PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum); + +static PyObject * +pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval) +{ + PyObject *args, *item; + args = Py_BuildValue("(O)", intval); + item = (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL); + Py_DECREF(args); + if (!item) + return NULL; + ((PyGEnum*)item)->gtype = gtype; + + return item; +} + +static PyObject * +pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) +{ + static char warning[256]; + + if (!PYGLIB_PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) { + g_snprintf(warning, sizeof(warning), "comparing different enum types: %s and %s", + g_type_name(self->gtype), g_type_name(((PyGEnum*)other)->gtype)); + if (PyErr_Warn(PyExc_Warning, warning)) + return NULL; + } + + return pyg_integer_richcompare((PyObject *)self, other, op); +} + +static PyObject * +pyg_enum_repr(PyGEnum *self) +{ + GEnumClass *enum_class; + const char *value; + guint index; + static char tmp[256]; + long l; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + l = PYGLIB_PyLong_AS_LONG(self); + for (index = 0; index < enum_class->n_values; index++) + if (l == enum_class->values[index].value) + break; + + value = enum_class->values[index].value_name; + if (value) + sprintf(tmp, "", value, g_type_name(self->gtype)); + else + sprintf(tmp, "", PYGLIB_PyLong_AS_LONG(self), g_type_name(self->gtype)); + + g_type_class_unref(enum_class); + + return PYGLIB_PyUnicode_FromString(tmp); +} + +static PyObject * +pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "value", NULL }; + long value; + PyObject *pytc, *values, *ret, *intvalue; + GType gtype; + GEnumClass *eclass; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value)) + return NULL; + + pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); + if (!pytc) + return NULL; + + if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { + Py_DECREF(pytc); + PyErr_SetString(PyExc_TypeError, + "__gtype__ attribute not a typecode"); + return NULL; + } + + gtype = pyg_type_from_object(pytc); + Py_DECREF(pytc); + + eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); + + /* A check that 0 < value < eclass->n_values was here but got + * removed: enumeration values do not need to be consequitive, + * e.g. GtkPathPriorityType values are not. + */ + + values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + /* Note that size of __enum_values__ dictionary can easily be less + * than 'n_values'. This happens if some values of the enum are + * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH. + * Johan said that "In retrospect, using a dictionary to store the + * values might not have been that good", but we need to keep + * backward compatibility. + */ + if (!PyDict_Check(values) || PyDict_Size(values) > eclass->n_values) { + PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed"); + Py_DECREF(values); + g_type_class_unref(eclass); + return NULL; + } + + g_type_class_unref(eclass); + + intvalue = PYGLIB_PyLong_FromLong(value); + ret = PyDict_GetItem(values, intvalue); + Py_DECREF(intvalue); + Py_DECREF(values); + if (ret) + Py_INCREF(ret); + else + PyErr_Format(PyExc_ValueError, "invalid enum value: %ld", value); + + return ret; +} + +PyObject* +pyg_enum_from_gtype (GType gtype, int value) +{ + PyObject *pyclass, *values, *retval, *intvalue; + + g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); + + /* Get a wrapper class by: + * 1. check for one attached to the gtype + * 2. lookup one in a typelib + * 3. creating a new one + */ + pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); + if (!pyclass) + pyclass = pygi_type_import_by_g_type(gtype); + if (!pyclass) + pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype); + if (!pyclass) + return PYGLIB_PyLong_FromLong(value); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__enum_values__"); + intvalue = PYGLIB_PyLong_FromLong(value); + retval = PyDict_GetItem(values, intvalue); + if (retval) { + Py_INCREF(retval); + } + else { + PyErr_Clear(); + retval = pyg_enum_val_new(pyclass, gtype, intvalue); + } + Py_DECREF(intvalue); + + return retval; +} + +/* + * pyg_enum_add + * Dynamically create a class derived from PyGEnum based on the given GType. + */ +PyObject * +pyg_enum_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype) +{ + PyGILState_STATE state; + PyObject *instance_dict, *stub, *values, *o; + GEnumClass *eclass; + int i; + + g_return_val_if_fail(typename != NULL, NULL); + if (!g_type_is_a (gtype, G_TYPE_ENUM)) { + PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'", + g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype))); + return NULL; + } + + state = pyglib_gil_state_ensure(); + + /* Create a new type derived from GEnum. This is the same as: + * >>> stub = type(typename, (GEnum,), {}) + */ + instance_dict = PyDict_New(); + stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", + typename, (PyObject *)&PyGEnum_Type, + instance_dict); + Py_DECREF(instance_dict); + if (!stub) { + PyErr_SetString(PyExc_RuntimeError, "can't create const"); + pyglib_gil_state_release(state); + return NULL; + } + + ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; + ((PyTypeObject *)stub)->tp_new = pyg_enum_new; + + if (module) + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PYGLIB_PyUnicode_FromString(PyModule_GetName(module))); + + g_type_set_qdata(gtype, pygenum_class_key, stub); + + o = pyg_type_wrapper_new(gtype); + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); + Py_DECREF(o); + + if (module) { + /* Add it to the module name space */ + PyModule_AddObject(module, (char*)typename, stub); + Py_INCREF(stub); + } + + /* Register enum values */ + eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); + + values = PyDict_New(); + for (i = 0; i < eclass->n_values; i++) { + PyObject *item, *intval; + + intval = PYGLIB_PyLong_FromLong(eclass->values[i].value); + item = pyg_enum_val_new(stub, gtype, intval); + PyDict_SetItem(values, intval, item); + Py_DECREF(intval); + + if (module) { + char *prefix; + + prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); + PyModule_AddObject(module, prefix, item); + g_free(prefix); + + Py_INCREF(item); + } + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__enum_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + pyglib_gil_state_release(state); + return stub; +} + +static PyObject * +pyg_enum_reduce(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GEnum.__reduce__")) + return NULL; + + return Py_BuildValue("(O(i)O)", Py_TYPE(self), PYGLIB_PyLong_AsLong(self), + PyObject_GetAttrString(self, "__dict__")); +} + +static PyObject * +pyg_enum_get_value_name(PyGEnum *self, void *closure) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + PyObject *retval; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self)); + + retval = PYGLIB_PyUnicode_FromString(enum_value->value_name); + g_type_class_unref(enum_class); + + return retval; +} + +static PyObject * +pyg_enum_get_value_nick(PyGEnum *self, void *closure) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + PyObject *retval; + + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); + + enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self)); + + retval = PYGLIB_PyUnicode_FromString(enum_value->value_nick); + g_type_class_unref(enum_class); + + return retval; +} + + +static PyMethodDef pyg_enum_methods[] = { + { "__reduce__", (PyCFunction)pyg_enum_reduce, METH_VARARGS }, + { NULL, NULL, 0 } +}; + +static PyGetSetDef pyg_enum_getsets[] = { + { "value_name", (getter)pyg_enum_get_value_name, (setter)0 }, + { "value_nick", (getter)pyg_enum_get_value_nick, (setter)0 }, + { NULL, 0, 0 } +}; + +void +pygobject_enum_register_types(PyObject *d) +{ + pygenum_class_key = g_quark_from_static_string("PyGEnum::class"); + + PyGEnum_Type.tp_base = &PYGLIB_PyLong_Type; +#if PY_VERSION_HEX < 0x03000000 + PyGEnum_Type.tp_new = pyg_enum_new; +#else + PyGEnum_Type.tp_new = PyLong_Type.tp_new; + PyGEnum_Type.tp_hash = PyLong_Type.tp_hash; +#endif + PyGEnum_Type.tp_repr = (reprfunc)pyg_enum_repr; + PyGEnum_Type.tp_str = (reprfunc)pyg_enum_repr; + PyGEnum_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGEnum_Type.tp_richcompare = (richcmpfunc)pyg_enum_richcompare; + PyGEnum_Type.tp_methods = pyg_enum_methods; + PyGEnum_Type.tp_getset = pyg_enum_getsets; + PYGOBJECT_REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM); +} diff --git a/gi/pygenum.h b/gi/pygenum.h new file mode 100644 index 00000000..05588312 --- /dev/null +++ b/gi/pygenum.h @@ -0,0 +1,27 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_ENUM_H__ +#define __PYGOBJECT_ENUM_H__ + +void pygobject_enum_register_types(PyObject *d); + +#endif /* __PYGOBJECT_ENUM_H__ */ diff --git a/gi/pygflags.c b/gi/pygflags.c new file mode 100644 index 00000000..bdeaae74 --- /dev/null +++ b/gi/pygflags.c @@ -0,0 +1,497 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * pygflags.c: GFlags wrapper + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "pygobject-private.h" +#include "pygflags.h" + +#include "pygi.h" + +GQuark pygflags_class_key; + +PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags); + +static PyObject * +pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval) +{ + PyObject *args, *item; + args = Py_BuildValue("(O)", intval); + g_assert(PyObject_IsSubclass(subclass, (PyObject*) &PyGFlags_Type)); + item = PYGLIB_PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL); + Py_DECREF(args); + if (!item) + return NULL; + ((PyGFlags*)item)->gtype = gtype; + + return item; +} + +static PyObject * +pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op) +{ + static char warning[256]; + + if (!PYGLIB_PyLong_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (PyObject_TypeCheck(other, &PyGFlags_Type) && ((PyGFlags*)other)->gtype != self->gtype) { + g_snprintf(warning, sizeof(warning), "comparing different flags types: %s and %s", + g_type_name(self->gtype), g_type_name(((PyGFlags*)other)->gtype)); + if (PyErr_Warn(PyExc_Warning, warning)) + return NULL; + } + + return pyg_integer_richcompare((PyObject *)self, other, op); +} + +static char * +generate_repr(GType gtype, guint value) +{ + GFlagsClass *flags_class; + char *retval = NULL, *tmp; + int i; + + flags_class = g_type_class_ref(gtype); + g_assert(G_IS_FLAGS_CLASS(flags_class)); + + for (i = 0; i < flags_class->n_values; i++) { + /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values, + * we're just ignore them for now otherwise they'll always show up + */ + if (flags_class->values[i].value == 0) + continue; + + if ((value & flags_class->values[i].value) == flags_class->values[i].value) { + if (retval) { + tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name); + g_free(retval); + retval = tmp; + } else { + retval = g_strdup_printf("%s", flags_class->values[i].value_name); + } + } + } + + g_type_class_unref(flags_class); + + return retval; +} + +static PyObject * +pyg_flags_repr(PyGFlags *self) +{ + char *tmp, *retval; + PyObject *pyretval; + + tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self)); + + if (tmp) + retval = g_strdup_printf("", tmp, + g_type_name(self->gtype)); + else + retval = g_strdup_printf("", PYGLIB_PyLong_AsUnsignedLong(self), + g_type_name(self->gtype)); + g_free(tmp); + + pyretval = PYGLIB_PyUnicode_FromString(retval); + g_free(retval); + + return pyretval; +} + +static PyObject * +pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "value", NULL }; + gulong value; + PyObject *pytc, *values, *ret, *pyint; + GType gtype; + GFlagsClass *eclass; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", kwlist, &value)) + return NULL; + + pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); + if (!pytc) + return NULL; + + if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { + Py_DECREF(pytc); + PyErr_SetString(PyExc_TypeError, + "__gtype__ attribute not a typecode"); + return NULL; + } + + gtype = pyg_type_from_object(pytc); + Py_DECREF(pytc); + + eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); + + values = PyObject_GetAttrString((PyObject *)type, "__flags_values__"); + if (!values) { + g_type_class_unref(eclass); + return NULL; + } + + if (!PyDict_Check(values)) { + PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed"); + Py_DECREF(values); + g_type_class_unref(eclass); + return NULL; + } + + g_type_class_unref(eclass); + + pyint = PYGLIB_PyLong_FromUnsignedLong(value); + ret = PyDict_GetItem(values, pyint); + if (!ret) { + PyErr_Clear(); + + ret = pyg_flags_val_new((PyObject *)type, gtype, pyint); + g_assert(ret != NULL); + } else { + Py_INCREF(ret); + } + + Py_DECREF(pyint); + Py_DECREF(values); + + return ret; +} + +PyObject* +pyg_flags_from_gtype (GType gtype, guint value) +{ + PyObject *pyclass, *values, *retval, *pyint; + + if (PyErr_Occurred()) + return PYGLIB_PyLong_FromUnsignedLong(0); + + g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); + + /* Get a wrapper class by: + * 1. check for one attached to the gtype + * 2. lookup one in a typelib + * 3. creating a new one + */ + pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key); + if (!pyclass) + pyclass = pygi_type_import_by_g_type(gtype); + if (!pyclass) + pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype); + if (!pyclass) + return PYGLIB_PyLong_FromUnsignedLong(value); + + values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, + "__flags_values__"); + pyint = PYGLIB_PyLong_FromUnsignedLong(value); + retval = PyDict_GetItem(values, pyint); + if (!retval) { + PyErr_Clear(); + + retval = pyg_flags_val_new(pyclass, gtype, pyint); + g_assert(retval != NULL); + } else { + Py_INCREF(retval); + } + Py_DECREF(pyint); + + return retval; +} + +/* + * pyg_flags_add + * Dynamically create a class derived from PyGFlags based on the given GType. + */ +PyObject * +pyg_flags_add (PyObject * module, + const char * typename, + const char * strip_prefix, + GType gtype) +{ + PyGILState_STATE state; + PyObject *instance_dict, *stub, *values, *o; + GFlagsClass *eclass; + int i; + + g_return_val_if_fail(typename != NULL, NULL); + if (!g_type_is_a(gtype, G_TYPE_FLAGS)) { + g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'", + g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype))); + return NULL; + } + + state = pyglib_gil_state_ensure(); + + /* Create a new type derived from GFlags. This is the same as: + * >>> stub = type(typename, (GFlags,), {}) + */ + instance_dict = PyDict_New(); + stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", + typename, (PyObject *)&PyGFlags_Type, + instance_dict); + Py_DECREF(instance_dict); + if (!stub) { + PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype"); + pyglib_gil_state_release(state); + return NULL; + } + + ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; + ((PyTypeObject *)stub)->tp_new = pyg_flags_new; + + if (module) { + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__module__", + PYGLIB_PyUnicode_FromString(PyModule_GetName(module))); + + /* Add it to the module name space */ + PyModule_AddObject(module, (char*)typename, stub); + Py_INCREF(stub); + } + g_type_set_qdata(gtype, pygflags_class_key, stub); + + o = pyg_type_wrapper_new(gtype); + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); + Py_DECREF(o); + + /* Register flag values */ + eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); + + values = PyDict_New(); + for (i = 0; i < eclass->n_values; i++) { + PyObject *item, *intval; + + intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value); + g_assert(PyErr_Occurred() == NULL); + item = pyg_flags_val_new(stub, gtype, intval); + PyDict_SetItem(values, intval, item); + Py_DECREF(intval); + + if (module) { + char *prefix; + + prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); + Py_INCREF(item); + PyModule_AddObject(module, prefix, item); + g_free(prefix); + } + Py_DECREF(item); + } + + PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, + "__flags_values__", values); + Py_DECREF(values); + + g_type_class_unref(eclass); + + pyglib_gil_state_release(state); + + return stub; +} + +static PyObject * +pyg_flags_and(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, + PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b)); +} + +static PyObject * +pyg_flags_or(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b)); +} + +static PyObject * +pyg_flags_xor(PyGFlags *a, PyGFlags *b) +{ + if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) + return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a, + (PyObject*)b); + + return pyg_flags_from_gtype(a->gtype, + PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b)); + +} + +static PyObject * +pyg_flags_warn (PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type")) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +pyg_flags_get_first_value_name(PyGFlags *self, void *closure) +{ + GFlagsClass *flags_class; + GFlagsValue *flags_value; + PyObject *retval; + + flags_class = g_type_class_ref(self->gtype); + g_assert(G_IS_FLAGS_CLASS(flags_class)); + flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self)); + if (flags_value) + retval = PYGLIB_PyUnicode_FromString(flags_value->value_name); + else { + retval = Py_None; + Py_INCREF(Py_None); + } + g_type_class_unref(flags_class); + + return retval; +} + +static PyObject * +pyg_flags_get_first_value_nick(PyGFlags *self, void *closure) +{ + GFlagsClass *flags_class; + GFlagsValue *flags_value; + PyObject *retval; + + flags_class = g_type_class_ref(self->gtype); + g_assert(G_IS_FLAGS_CLASS(flags_class)); + + flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self)); + if (flags_value) + retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick); + else { + retval = Py_None; + Py_INCREF(Py_None); + } + g_type_class_unref(flags_class); + + return retval; +} + +static PyObject * +pyg_flags_get_value_names(PyGFlags *self, void *closure) +{ + GFlagsClass *flags_class; + PyObject *retval; + int i; + + flags_class = g_type_class_ref(self->gtype); + g_assert(G_IS_FLAGS_CLASS(flags_class)); + + retval = PyList_New(0); + for (i = 0; i < flags_class->n_values; i++) + if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) + PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_name)); + + g_type_class_unref(flags_class); + + return retval; +} + +static PyObject * +pyg_flags_get_value_nicks(PyGFlags *self, void *closure) +{ + GFlagsClass *flags_class; + PyObject *retval; + int i; + + flags_class = g_type_class_ref(self->gtype); + g_assert(G_IS_FLAGS_CLASS(flags_class)); + + retval = PyList_New(0); + for (i = 0; i < flags_class->n_values; i++) + if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) { + PyObject *py_nick = PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick); + PyList_Append(retval, py_nick); + Py_DECREF (py_nick); + } + + g_type_class_unref(flags_class); + + return retval; +} + +static PyGetSetDef pyg_flags_getsets[] = { + { "first_value_name", (getter)pyg_flags_get_first_value_name, (setter)0 }, + { "first_value_nick", (getter)pyg_flags_get_first_value_nick, (setter)0 }, + { "value_names", (getter)pyg_flags_get_value_names, (setter)0 }, + { "value_nicks", (getter)pyg_flags_get_value_nicks, (setter)0 }, + { NULL, 0, 0 } +}; + +static PyNumberMethods pyg_flags_as_number = { + (binaryfunc)pyg_flags_warn, /* nb_add */ + (binaryfunc)pyg_flags_warn, /* nb_subtract */ + (binaryfunc)pyg_flags_warn, /* nb_multiply */ + (binaryfunc)pyg_flags_warn, /* nb_divide */ + (binaryfunc)pyg_flags_warn, /* nb_remainder */ +#if PY_VERSION_HEX < 0x03000000 + (binaryfunc)pyg_flags_warn, /* nb_divmod */ +#endif + (ternaryfunc)pyg_flags_warn, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, /* nb_nonzero */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + (binaryfunc)pyg_flags_and, /* nb_and */ + (binaryfunc)pyg_flags_xor, /* nb_xor */ + (binaryfunc)pyg_flags_or, /* nb_or */ +}; + +void +pygobject_flags_register_types(PyObject *d) +{ + pygflags_class_key = g_quark_from_static_string("PyGFlags::class"); + + PyGFlags_Type.tp_base = &PYGLIB_PyLong_Type; +#if PY_VERSION_HEX < 0x03000000 + PyGFlags_Type.tp_new = pyg_flags_new; +#else + PyGFlags_Type.tp_new = PyLong_Type.tp_new; + PyGFlags_Type.tp_hash = PyLong_Type.tp_hash; +#endif + PyGFlags_Type.tp_repr = (reprfunc)pyg_flags_repr; + PyGFlags_Type.tp_as_number = &pyg_flags_as_number; + PyGFlags_Type.tp_str = (reprfunc)pyg_flags_repr; + PyGFlags_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGFlags_Type.tp_richcompare = (richcmpfunc)pyg_flags_richcompare; + PyGFlags_Type.tp_getset = pyg_flags_getsets; + PYGOBJECT_REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS); +} diff --git a/gi/pygflags.h b/gi/pygflags.h new file mode 100644 index 00000000..e93265cd --- /dev/null +++ b/gi/pygflags.h @@ -0,0 +1,27 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_FLAGS_H__ +#define __PYGOBJECT_FLAGS_H__ + +void pygobject_flags_register_types(PyObject *d); + +#endif /* __PYGOBJECT_FLAGS_H__ */ diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c index 63788922..67367a02 100644 --- a/gi/pygi-argument.c +++ b/gi/pygi-argument.c @@ -22,12 +22,12 @@ */ #include "pygi-private.h" +#include "pygobject-private.h" #include #include #include -#include #include #include @@ -1981,6 +1981,5 @@ void _pygi_argument_init (void) { PyDateTime_IMPORT; - _pygobject_import(); } diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c index ea798ff6..a9b39c14 100644 --- a/gi/pygi-boxed.c +++ b/gi/pygi-boxed.c @@ -22,8 +22,8 @@ */ #include "pygi-private.h" +#include "pygobject-private.h" -#include #include #include diff --git a/gi/pygi-ccallback.c b/gi/pygi-ccallback.c index 82777fb7..7a35e609 100644 --- a/gi/pygi-ccallback.c +++ b/gi/pygi-ccallback.c @@ -22,8 +22,8 @@ */ #include "pygi-private.h" +#include "pygobject-private.h" -#include #include #include diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c index 75373992..c046d0fa 100644 --- a/gi/pygi-foreign.c +++ b/gi/pygi-foreign.c @@ -26,7 +26,7 @@ # include #endif -#include "pygobject.h" +#include "pygobject-private.h" #include "pygi-foreign.h" #include diff --git a/gi/pygi-info.c b/gi/pygi-info.c index af893ec6..d0d21582 100644 --- a/gi/pygi-info.c +++ b/gi/pygi-info.c @@ -24,8 +24,8 @@ #include "pygi-private.h" #include "pygi-cache.h" +#include "pygobject-private.h" -#include #include diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c index 2c7a8de2..9427754a 100644 --- a/gi/pygi-marshal-to-py.c +++ b/gi/pygi-marshal-to-py.c @@ -22,12 +22,13 @@ */ #include "pygi-private.h" +#include "pygobject-private.h" +#include "pygparamspec.h" #include #include #include -#include #include #include "pygi-cache.h" diff --git a/gi/pygi-private.h b/gi/pygi-private.h index 97eced59..af12f1ca 100644 --- a/gi/pygi-private.h +++ b/gi/pygi-private.h @@ -16,7 +16,7 @@ #include "pygi.h" -#include "pygobject-external.h" +#include "pygobject-private.h" #include "pygi-repository.h" #include "pygi-info.h" diff --git a/gi/pygi-source.c b/gi/pygi-source.c index 66bbc3c2..d2f39c6f 100644 --- a/gi/pygi-source.c +++ b/gi/pygi-source.c @@ -23,8 +23,7 @@ * IN THE SOFTWARE. */ -#define NO_IMPORT -#include "pygobject.h" +#include "pygobject-private.h" #include "pygi-private.h" #include "pyglib.h" diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c index 296c47c0..40bfb6da 100644 --- a/gi/pygi-struct.c +++ b/gi/pygi-struct.c @@ -22,8 +22,8 @@ */ #include "pygi-private.h" +#include "pygobject-private.h" -#include #include #include diff --git a/gi/pygi.h b/gi/pygi.h index dcd91b3d..3a1591f8 100644 --- a/gi/pygi.h +++ b/gi/pygi.h @@ -26,8 +26,7 @@ # include #endif -#define NO_IMPORT_PYGOBJECT -#include +#include #include #include "pygi-cache.h" diff --git a/gi/pyginterface.c b/gi/pyginterface.c new file mode 100644 index 00000000..eb76ba08 --- /dev/null +++ b/gi/pyginterface.c @@ -0,0 +1,124 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "pyglib.h" +#include "pygobject-private.h" + +#include "pyginterface.h" + +GQuark pyginterface_type_key; +GQuark pyginterface_info_key; + +PYGLIB_DEFINE_TYPE("gobject.GInterface", PyGInterface_Type, PyObject) + +static int +pyg_interface_init(PyObject *self, PyObject *args, PyObject *kwargs) +{ + gchar buf[512]; + + if (!PyArg_ParseTuple(args, ":GInterface.__init__")) + return -1; + + g_snprintf(buf, sizeof(buf), "%s can not be constructed", + Py_TYPE(self)->tp_name); + PyErr_SetString(PyExc_NotImplementedError, buf); + return -1; +} + +static void +pyg_interface_free(PyObject *op) +{ + PyObject_FREE(op); +} + +/** + * pyg_register_interface: + * @dict: a module dictionary. + * @class_name: the class name for the wrapper class. + * @gtype: the GType of the interface. + * @type: the wrapper class for the interface. + * + * Registers a Python class as the wrapper for a GInterface. As a + * convenience it will also place a reference to the wrapper class in + * the provided module dictionary. + */ +void +pyg_register_interface(PyObject *dict, const gchar *class_name, + GType gtype, PyTypeObject *type) +{ + PyObject *o; + + Py_TYPE(type) = &PyType_Type; + type->tp_base = &PyGInterface_Type; + + if (PyType_Ready(type) < 0) { + g_warning("could not ready `%s'", type->tp_name); + return; + } + + if (gtype) { + o = pyg_type_wrapper_new(gtype); + PyDict_SetItemString(type->tp_dict, "__gtype__", o); + Py_DECREF(o); + } + + g_type_set_qdata(gtype, pyginterface_type_key, type); + + PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); + +} + +void +pyg_register_interface_info(GType gtype, const GInterfaceInfo *info) +{ + g_type_set_qdata(gtype, pyginterface_info_key, (gpointer) info); +} + +const GInterfaceInfo * +pyg_lookup_interface_info(GType gtype) +{ + return g_type_get_qdata(gtype, pyginterface_info_key); +} + +void +pygobject_interface_register_types(PyObject *d) +{ + pyginterface_type_key = g_quark_from_static_string("PyGInterface::type"); + pyginterface_info_key = g_quark_from_static_string("PyGInterface::info"); + + PyGInterface_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGInterface_Type.tp_init = (initproc)pyg_interface_init; + PyGInterface_Type.tp_free = (freefunc)pyg_interface_free; + + PYGOBJECT_REGISTER_GTYPE(d, PyGInterface_Type, "GInterface", G_TYPE_INTERFACE) + + PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", + pyg_object_descr_doc_get()); + PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", + pyg_object_descr_doc_get()); + +} diff --git a/gi/pyginterface.h b/gi/pyginterface.h new file mode 100644 index 00000000..0f390c28 --- /dev/null +++ b/gi/pyginterface.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_INTERFACE_H__ +#define __PYGOBJECT_INTERFACE_H__ + +extern GQuark pyginterface_type_key; +extern GQuark pyginterface_info_key; + +extern PyTypeObject PyGInterface_Type; + +void pyg_register_interface(PyObject *dict, + const gchar *class_name, + GType gtype, + PyTypeObject *type); +const GInterfaceInfo * pyg_lookup_interface_info(GType gtype); +void pyg_register_interface_info(GType gtype, const + GInterfaceInfo *info); +void pygobject_interface_register_types(PyObject *d); + +#endif /* __PYGOBJECT_INTERFACE_H__ */ diff --git a/gi/pygobject-private.h b/gi/pygobject-private.h new file mode 100644 index 00000000..f48d073b --- /dev/null +++ b/gi/pygobject-private.h @@ -0,0 +1,205 @@ +#ifndef _PYGOBJECT_PRIVATE_H_ +#define _PYGOBJECT_PRIVATE_H_ + +#ifdef _PYGOBJECT_H_ +# error "include pygobject.h or pygobject-private.h, but not both" +#endif + +#define _INSIDE_PYGOBJECT_ +#include "pygobject.h" + +#include "pyglib-python-compat.h" + +#define PYGOBJECT_REGISTER_GTYPE(d, type, name, gtype) \ + { \ + PyObject *o; \ + PYGLIB_REGISTER_TYPE(d, type, name); \ + PyDict_SetItemString(type.tp_dict, "__gtype__", \ + o=pyg_type_wrapper_new(gtype)); \ + Py_DECREF(o); \ +} + +/* from gobjectmodule.c */ +extern struct _PyGObject_Functions pygobject_api_functions; + + +#ifndef Py_CLEAR /* since Python 2.4 */ +# define Py_CLEAR(op) \ + do { \ + if (op) { \ + PyObject *tmp = (PyObject *)(op); \ + (op) = NULL; \ + Py_DECREF(tmp); \ + } \ + } while (0) +#endif + +extern GType PY_TYPE_OBJECT; + +extern GQuark pygboxed_type_key; +extern GQuark pygboxed_marshal_key; +extern GQuark pygenum_class_key; +extern GQuark pygflags_class_key; +extern GQuark pyginterface_type_key; +extern GQuark pyginterface_info_key; +extern GQuark pygobject_class_init_key; +extern GQuark pygobject_class_key; +extern GQuark pygobject_wrapper_key; +extern GQuark pygpointer_class_key; +extern GQuark pygobject_has_updated_constructor_key; +extern GQuark pygobject_instance_data_key; +extern GQuark pygobject_custom_key; + +void pygobject_data_free (PyGObjectData *data); +void pyg_destroy_notify (gpointer user_data); +gboolean pyg_handler_marshal (gpointer user_data); +gboolean pyg_error_check (GError **error); +int pygobject_constructv (PyGObject *self, + guint n_parameters, + GParameter *parameters); + +PyObject *pyg_integer_richcompare(PyObject *v, + PyObject *w, + int op); + +gboolean pyg_gerror_exception_check(GError **error); + +void pygobject_ref_float(PyGObject *self); +void pygobject_ref_sink(PyGObject *self); + +/* from pygtype.h */ +extern PyTypeObject PyGTypeWrapper_Type; + +PyObject *pyg_type_wrapper_new (GType type); +GType pyg_type_from_object_strict (PyObject *obj, gboolean strict); +GType pyg_type_from_object (PyObject *obj); + +gint pyg_enum_get_value (GType enum_type, PyObject *obj, gint *val); +gint pyg_flags_get_value (GType flag_type, PyObject *obj, guint *val); +int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr); + +typedef PyObject *(* fromvaluefunc)(const GValue *value); +typedef int (*tovaluefunc)(GValue *value, PyObject *obj); + +void pyg_register_gtype_custom(GType gtype, + fromvaluefunc from_func, + tovaluefunc to_func); +int pyg_value_from_pyobject(GValue *value, PyObject *obj); +int pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj); +PyObject *pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed); +int pyg_param_gvalue_from_pyobject(GValue* value, + PyObject* py_obj, + const GParamSpec* pspec); +PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue, + gboolean copy_boxed, + const GParamSpec* pspec); + +GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data); +void pyg_closure_set_exception_handler(GClosure *closure, + PyClosureExceptionHandler handler); +GClosure *pyg_signal_class_closure_get(void); +GClosure *gclosure_from_pyfunc(PyGObject *object, PyObject *func); + +PyObject *pyg_object_descr_doc_get(void); +void pygobject_object_register_types(PyObject *d); + +extern PyTypeObject *PyGObject_MetaType; + +/* from pygobject.h */ +extern PyTypeObject PyGObject_Type; +extern PyTypeObject PyGProps_Type; +extern PyTypeObject PyGPropsDescr_Type; +extern PyTypeObject PyGPropsIter_Type; + + /* Data that belongs to the GObject instance, not the Python wrapper */ +struct _PyGObjectData { + PyTypeObject *type; /* wrapper type for this instance */ + GSList *closures; +}; + +void pygobject_register_class (PyObject *dict, + const gchar *type_name, + GType gtype, PyTypeObject *type, + PyObject *bases); +void pygobject_register_wrapper (PyObject *self); +PyObject * pygobject_new (GObject *obj); +PyObject * pygobject_new_full (GObject *obj, gboolean steal, gpointer g_class); +void pygobject_sink (GObject *obj); +PyTypeObject *pygobject_lookup_class (GType gtype); +void pygobject_watch_closure (PyObject *self, GClosure *closure); +int pyg_type_register (PyTypeObject *class, + const gchar *type_name); + +/* from pygboxed.c */ +extern PyTypeObject PyGBoxed_Type; + +void pyg_register_boxed (PyObject *dict, const gchar *class_name, + GType boxed_type, PyTypeObject *type); +PyObject * pyg_boxed_new (GType boxed_type, gpointer boxed, + gboolean copy_boxed, gboolean own_ref); + +extern PyTypeObject PyGPointer_Type; + +void pyg_register_pointer (PyObject *dict, const gchar *class_name, + GType pointer_type, PyTypeObject *type); +PyObject * pyg_pointer_new (GType pointer_type, gpointer pointer); + +const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix); + +/* pygflags */ +typedef struct { + PYGLIB_PyLongObject parent; + int zero_pad; /* must always be 0 */ + GType gtype; +} PyGFlags; + +extern PyTypeObject PyGFlags_Type; + +#define PyGFlags_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGFlags_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_FLAGS)) + +extern PyObject * pyg_flags_add (PyObject * module, + const char * type_name, + const char * strip_prefix, + GType gtype); +extern PyObject * pyg_flags_from_gtype (GType gtype, + guint value); + +/* pygenum */ +#define PyGEnum_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGEnum_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM)) + +typedef struct { + PYGLIB_PyLongObject parent; + int zero_pad; /* must always be 0 */ + GType gtype; +} PyGEnum; + +extern PyTypeObject PyGEnum_Type; + +extern PyObject * pyg_enum_add (PyObject * module, + const char * type_name, + const char * strip_prefix, + GType gtype); +extern PyObject * pyg_enum_from_gtype (GType gtype, + int value); + +/* pygtype.c */ +extern gboolean pyg_gtype_is_custom (GType gtype); + +/* pygobject.c */ +extern PyTypeObject PyGObjectWeakRef_Type; + +static inline PyGObjectData * +pyg_object_peek_inst_data(GObject *obj) +{ + return ((PyGObjectData *) + g_object_get_qdata(obj, pygobject_instance_data_key)); +} + +gboolean pygobject_prepare_construct_properties (GObjectClass *class, + PyObject *kwargs, + guint *n_params, + GParameter **params); +/* Defined by PYGLIB_MODULE_START */ +extern PyObject *pyglib__gobject_module_create (void); + +#endif /*_PYGOBJECT_PRIVATE_H_*/ diff --git a/gi/pygobject.c b/gi/pygobject.c new file mode 100644 index 00000000..129f29ab --- /dev/null +++ b/gi/pygobject.c @@ -0,0 +1,2473 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * pygobject.c: wrapper for the GObject type. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "pygobject-private.h" +#include "pyginterface.h" +#include "pygparamspec.h" + +#include "pygi.h" + + +static void pygobject_dealloc(PyGObject *self); +static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg); +static int pygobject_clear(PyGObject *self); +static PyObject * pyg_type_get_bases(GType gtype); +static inline int pygobject_clear(PyGObject *self); +static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data); +static inline PyGObjectData * pyg_object_peek_inst_data(GObject *obj); +static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, + gboolean check_for_present); +static void pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, + gboolean check_for_present); +GType PY_TYPE_OBJECT = 0; +GQuark pygobject_custom_key; +GQuark pygobject_class_key; +GQuark pygobject_class_init_key; +GQuark pygobject_wrapper_key; +GQuark pygobject_has_updated_constructor_key; +GQuark pygobject_instance_data_key; + +/* Copied from glib. gobject uses hyphens in property names, but in Python + * we can only represent hyphens as underscores. Convert underscores to + * hyphens for glib compatibility. */ +static void +canonicalize_key (gchar *key) +{ + gchar *p; + + for (p = key; *p != 0; p++) + { + gchar c = *p; + + if (c != '-' && + (c < '0' || c > '9') && + (c < 'A' || c > 'Z') && + (c < 'a' || c > 'z')) + *p = '-'; + } +} + +/* -------------- class <-> wrapper manipulation --------------- */ + +void +pygobject_data_free(PyGObjectData *data) +{ + /* This function may be called after the python interpreter has already + * been shut down. If this happens, we cannot do any python calls, so just + * free the memory. */ + PyGILState_STATE state; + PyThreadState *_save = NULL; + + GSList *closures, *tmp; + + if (Py_IsInitialized()) { + state = pyglib_gil_state_ensure(); + Py_DECREF(data->type); + /* We cannot use Py_BEGIN_ALLOW_THREADS here because this is inside + * a branch. */ + Py_UNBLOCK_THREADS; /* Modifies _save */ + } + + tmp = closures = data->closures; +#ifndef NDEBUG + data->closures = NULL; + data->type = NULL; +#endif + while (tmp) { + GClosure *closure = tmp->data; + + /* we get next item first, because the current link gets + * invalidated by pygobject_unwatch_closure */ + tmp = tmp->next; + g_closure_invalidate(closure); + } + + if (data->closures != NULL) + g_warning("invalidated all closures, but data->closures != NULL !"); + + g_free(data); + + if (Py_IsInitialized()) { + Py_BLOCK_THREADS; /* Restores _save */ + pyglib_gil_state_release(state); + } +} + +static inline PyGObjectData * +pygobject_data_new(void) +{ + PyGObjectData *data; + data = g_new0(PyGObjectData, 1); + return data; +} + +static inline PyGObjectData * +pygobject_get_inst_data(PyGObject *self) +{ + PyGObjectData *inst_data; + + if (G_UNLIKELY(!self->obj)) + return NULL; + inst_data = g_object_get_qdata(self->obj, pygobject_instance_data_key); + if (inst_data == NULL) + { + inst_data = pygobject_data_new(); + + inst_data->type = Py_TYPE(self); + Py_INCREF((PyObject *) inst_data->type); + + g_object_set_qdata_full(self->obj, pygobject_instance_data_key, + inst_data, (GDestroyNotify) pygobject_data_free); + } + return inst_data; +} + + +PyTypeObject *PyGObject_MetaType = NULL; + +/** + * pygobject_sink: + * @obj: a GObject + * + * As Python handles reference counting for us, the "floating + * reference" code in GTK is not all that useful. In fact, it can + * cause leaks. This function should be called to remove the floating + * references on objects on construction. + **/ +void +pygobject_sink(GObject *obj) +{ + /* The default behaviour for GInitiallyUnowned subclasses is to call ref_sink(). + * - if the object is new and owned by someone else, its ref has been sunk and + * we need to keep the one from that someone and add our own "fresh ref" + * - if the object is not and owned by nobody, its ref is floating and we need + * to transform it into a regular ref. + */ + if (G_IS_INITIALLY_UNOWNED(obj)) { + g_object_ref_sink(obj); + } +} + +typedef struct { + PyObject_HEAD + GParamSpec **props; + guint n_props; + guint index; +} PyGPropsIter; + +PYGLIB_DEFINE_TYPE("gi._gobject.GPropsIter", PyGPropsIter_Type, PyGPropsIter); + +static void +pyg_props_iter_dealloc(PyGPropsIter *self) +{ + g_free(self->props); + PyObject_Del((PyObject*) self); +} + +static PyObject* +pygobject_props_iter_next(PyGPropsIter *iter) +{ + if (iter->index < iter->n_props) + return pyg_param_spec_new(iter->props[iter->index++]); + else { + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } +} + +typedef struct { + PyObject_HEAD + /* a reference to the object containing the properties */ + PyGObject *pygobject; + GType gtype; +} PyGProps; + +static void +PyGProps_dealloc(PyGProps* self) +{ + PyGObject *tmp; + + PyObject_GC_UnTrack((PyObject*)self); + + tmp = self->pygobject; + self->pygobject = NULL; + Py_XDECREF(tmp); + + PyObject_GC_Del((PyObject*)self); +} + +static PyObject* +build_parameter_list(GObjectClass *class) +{ + GParamSpec **props; + guint n_props = 0, i; + PyObject *prop_str; + PyObject *props_list; + + props = g_object_class_list_properties(class, &n_props); + props_list = PyList_New(n_props); + for (i = 0; i < n_props; i++) { + char *name; + name = g_strdup(g_param_spec_get_name(props[i])); + /* hyphens cannot belong in identifiers */ + g_strdelimit(name, "-", '_'); + prop_str = PYGLIB_PyUnicode_FromString(name); + + PyList_SetItem(props_list, i, prop_str); + g_free(name); + } + + if (props) + g_free(props); + + return props_list; +} + + +static PyObject* +PyGProps_getattro(PyGProps *self, PyObject *attr) +{ + char *attr_name, *property_name; + GObjectClass *class; + GParamSpec *pspec; + GValue value = { 0, }; + PyObject *ret; + + attr_name = PYGLIB_PyUnicode_AsString(attr); + if (!attr_name) { + PyErr_Clear(); + return PyObject_GenericGetAttr((PyObject *)self, attr); + } + + class = g_type_class_ref(self->gtype); + + /* g_object_class_find_property recurses through the class hierarchy, + * so the resulting pspec tells us the owner_type that owns the property + * we're dealing with. */ + property_name = g_strdup(attr_name); + canonicalize_key(property_name); + pspec = g_object_class_find_property(class, property_name); + g_free(property_name); + g_type_class_unref(class); + + if (!pspec) { + return PyObject_GenericGetAttr((PyObject *)self, attr); + } + + if (!(pspec->flags & G_PARAM_READABLE)) { + PyErr_Format(PyExc_TypeError, + "property '%s' is not readable", attr_name); + return NULL; + } + + if (!self->pygobject) { + /* If we're doing it without an instance, return a GParamSpec */ + return pyg_param_spec_new(pspec); + } + + if (!pyg_gtype_is_custom (pspec->owner_type)) { + /* The GType is not implemented at the Python level: see if we can + * read the property value via gi. */ + ret = pygi_get_property_value (self->pygobject, pspec); + if (ret) + return ret; + } + + /* The GType is implemented in Python, or we failed to read it via gi: + * do a straightforward read. */ + Py_BEGIN_ALLOW_THREADS; + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + g_object_get_property(self->pygobject->obj, pspec->name, &value); + Py_END_ALLOW_THREADS; + + ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec); + g_value_unset(&value); + + return ret; +} + +static gboolean +set_property_from_pspec(GObject *obj, + GParamSpec *pspec, + PyObject *pvalue) +{ + GValue value = { 0, }; + + if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) { + PyErr_Format(PyExc_TypeError, + "property '%s' can only be set in constructor", + pspec->name); + return FALSE; + } + + if (!(pspec->flags & G_PARAM_WRITABLE)) { + PyErr_Format(PyExc_TypeError, + "property '%s' is not writable", pspec->name); + return FALSE; + } + + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + if (pyg_param_gvalue_from_pyobject(&value, pvalue, pspec) < 0) { + PyObject *pvalue_str = PyObject_Str(pvalue); + PyErr_Format(PyExc_TypeError, + "could not convert '%s' to type '%s' when setting property '%s.%s'", + PYGLIB_PyUnicode_AsString(pvalue_str), + g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)), + G_OBJECT_TYPE_NAME(obj), + pspec->name); + Py_DECREF(pvalue_str); + return FALSE; + } + + Py_BEGIN_ALLOW_THREADS; + g_object_set_property(obj, pspec->name, &value); + g_value_unset(&value); + Py_END_ALLOW_THREADS; + + return TRUE; +} + +PYGLIB_DEFINE_TYPE("gi._gobject.GProps", PyGProps_Type, PyGProps); + +static int +PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue) +{ + GParamSpec *pspec; + char *attr_name, *property_name; + GObject *obj; + int ret = -1; + + if (pvalue == NULL) { + PyErr_SetString(PyExc_TypeError, "properties cannot be " + "deleted"); + return -1; + } + + attr_name = PYGLIB_PyUnicode_AsString(attr); + if (!attr_name) { + PyErr_Clear(); + return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); + } + + if (!self->pygobject) { + PyErr_SetString(PyExc_TypeError, + "cannot set GOject properties without an instance"); + return -1; + } + + obj = self->pygobject->obj; + + property_name = g_strdup(attr_name); + canonicalize_key(property_name); + + /* g_object_class_find_property recurses through the class hierarchy, + * so the resulting pspec tells us the owner_type that owns the property + * we're dealing with. */ + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), + property_name); + g_free(property_name); + if (!pspec) { + return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); + } + if (!pyg_gtype_is_custom (pspec->owner_type)) { + /* This GType is not implemented in Python: see if we can set the + * property via gi. */ + ret = pygi_set_property_value (self->pygobject, pspec, pvalue); + if (ret == 0) + return 0; + else if (ret == -1 && PyErr_Occurred()) + return -1; + } + + /* This GType is implemented in Python, or we failed to set it via gi: + * do a straightforward set. */ + if (!set_property_from_pspec(obj, pspec, pvalue)) + return -1; + + return 0; +} + +static int +pygobject_props_traverse(PyGProps *self, visitproc visit, void *arg) +{ + if (self->pygobject && visit((PyObject *) self->pygobject, arg) < 0) + return -1; + return 0; +} + +static PyObject* +pygobject_props_get_iter(PyGProps *self) +{ + PyGPropsIter *iter; + GObjectClass *class; + + iter = PyObject_NEW(PyGPropsIter, &PyGPropsIter_Type); + class = g_type_class_ref(self->gtype); + iter->props = g_object_class_list_properties(class, &iter->n_props); + iter->index = 0; + g_type_class_unref(class); + return (PyObject *) iter; +} + +static PyObject* +pygobject_props_dir(PyGProps *self) +{ + PyObject *ret; + GObjectClass *class; + + class = g_type_class_ref (self->gtype); + ret = build_parameter_list (class); + g_type_class_unref (class); + + return ret; +} + +static PyMethodDef pygobject_props_methods[] = { + { "__dir__", (PyCFunction)pygobject_props_dir, METH_NOARGS}, + { NULL, NULL, 0} +}; + + +static Py_ssize_t +PyGProps_length(PyGProps *self) +{ + GObjectClass *class; + GParamSpec **props; + guint n_props; + + class = g_type_class_ref(self->gtype); + props = g_object_class_list_properties(class, &n_props); + g_type_class_unref(class); + g_free(props); + + return (Py_ssize_t)n_props; +} + +static PySequenceMethods _PyGProps_as_sequence = { + (lenfunc) PyGProps_length, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +PYGLIB_DEFINE_TYPE("gi._gobject.GPropsDescr", PyGPropsDescr_Type, PyObject); + +static PyObject * +pyg_props_descr_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + PyGProps *gprops; + + gprops = PyObject_GC_New(PyGProps, &PyGProps_Type); + if (obj == NULL || obj == Py_None) { + gprops->pygobject = NULL; + gprops->gtype = pyg_type_from_object(type); + } else { + if (!PyObject_IsInstance(obj, (PyObject *) &PyGObject_Type)) { + PyErr_SetString(PyExc_TypeError, "cannot use GObject property" + " descriptor on non-GObject instances"); + return NULL; + } + Py_INCREF(obj); + gprops->pygobject = (PyGObject *) obj; + gprops->gtype = pyg_type_from_object(obj); + } + return (PyObject *) gprops; +} + +/** + * pygobject_register_class: + * @dict: the module dictionary. A reference to the type will be stored here. + * @type_name: not used ? + * @gtype: the GType of the GObject subclass. + * @type: the Python type object for this wrapper. + * @static_bases: a tuple of Python type objects that are the bases of + * this type + * + * This function is used to register a Python type as the wrapper for + * a particular GObject subclass. It will also insert a reference to + * the wrapper class into the module dictionary passed as a reference, + * which simplifies initialisation. + */ +void +pygobject_register_class(PyObject *dict, const gchar *type_name, + GType gtype, PyTypeObject *type, + PyObject *static_bases) +{ + PyObject *o; + const char *class_name, *s; + PyObject *runtime_bases; + PyObject *bases_list, *bases, *mod_name; + int i; + + class_name = type->tp_name; + s = strrchr(class_name, '.'); + if (s != NULL) + class_name = s + 1; + + runtime_bases = pyg_type_get_bases(gtype); + if (static_bases) { + PyTypeObject *py_parent_type = (PyTypeObject *) PyTuple_GET_ITEM(static_bases, 0); + bases_list = PySequence_List(static_bases); + /* we start at index 1 because we want to skip the primary + * base, otherwise we might get MRO conflict */ + for (i = 1; i < PyTuple_GET_SIZE(runtime_bases); ++i) + { + PyObject *base = PyTuple_GET_ITEM(runtime_bases, i); + int contains = PySequence_Contains(bases_list, base); + if (contains < 0) + PyErr_Print(); + else if (!contains) { + if (!PySequence_Contains(py_parent_type->tp_mro, base)) { +#if 0 + g_message("Adding missing base %s to type %s", + ((PyTypeObject *)base)->tp_name, type->tp_name); +#endif + PyList_Append(bases_list, base); + } + } + } + bases = PySequence_Tuple(bases_list); + Py_DECREF(bases_list); + Py_DECREF(runtime_bases); + } else + bases = runtime_bases; + + Py_TYPE(type) = PyGObject_MetaType; + type->tp_bases = bases; + if (G_LIKELY(bases)) { + type->tp_base = (PyTypeObject *)PyTuple_GetItem(bases, 0); + Py_INCREF(type->tp_base); + } + + pygobject_inherit_slots(type, bases, TRUE); + + if (PyType_Ready(type) < 0) { + g_warning ("couldn't make the type `%s' ready", type->tp_name); + return; + } + + /* Set type.__module__ to the name of the module, + * otherwise it'll default to 'gobject', see #376099 + */ + s = strrchr(type->tp_name, '.'); + if (s != NULL) { + mod_name = PYGLIB_PyUnicode_FromStringAndSize(type->tp_name, (int)(s - type->tp_name)); + PyDict_SetItemString(type->tp_dict, "__module__", mod_name); + Py_DECREF(mod_name); + } + + if (gtype) { + o = pyg_type_wrapper_new(gtype); + PyDict_SetItemString(type->tp_dict, "__gtype__", o); + Py_DECREF(o); + + /* stash a pointer to the python class with the GType */ + Py_INCREF(type); + g_type_set_qdata(gtype, pygobject_class_key, type); + } + + /* set up __doc__ descriptor on type */ + PyDict_SetItemString(type->tp_dict, "__doc__", + pyg_object_descr_doc_get()); + + PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); +} + +static void +pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref) +{ + PyGObject *self; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + + /* Avoid thread safety problems by using qdata for wrapper retrieval + * instead of the user data argument. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=709223 + */ + self = (PyGObject *)g_object_get_qdata (object, pygobject_wrapper_key); + if (self) { + if (is_last_ref) + Py_DECREF(self); + else + Py_INCREF(self); + } + + pyglib_gil_state_release(state); +} + + /* Called when the inst_dict is first created; switches the + reference counting strategy to start using toggle ref to keep the + wrapper alive while the GObject lives. In contrast, while + inst_dict was NULL the python wrapper is allowed to die at + will and is recreated on demand. */ +static inline void +pygobject_switch_to_toggle_ref(PyGObject *self) +{ + g_assert(self->obj->ref_count >= 1); + + if (self->private_flags.flags & PYGOBJECT_USING_TOGGLE_REF) + return; /* already using toggle ref */ + self->private_flags.flags |= PYGOBJECT_USING_TOGGLE_REF; + /* Note that add_toggle_ref will never immediately call back into + pyg_toggle_notify */ + Py_INCREF((PyObject *) self); + g_object_add_toggle_ref(self->obj, pyg_toggle_notify, NULL); + g_object_unref(self->obj); +} + +/* Called when an custom gobject is initalized via g_object_new instead of + its constructor. The next time the wrapper is access via + pygobject_new_full it will sink the floating reference instead of + adding a new reference and causing a leak */ + +void +pygobject_ref_float(PyGObject *self) +{ + /* should only be floated once */ + g_assert(!(self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF)); + + self->private_flags.flags |= PYGOBJECT_IS_FLOATING_REF; +} + +/* Called by gobject_new_full, if the floating flag is set remove it, otherwise + ref the pyobject */ +void +pygobject_ref_sink(PyGObject *self) +{ + if (self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF) + self->private_flags.flags &= ~PYGOBJECT_IS_FLOATING_REF; + else + Py_INCREF ( (PyObject *) self); +} + +/** + * pygobject_register_wrapper: + * @self: the wrapper instance + * + * In the constructor of PyGTK wrappers, this function should be + * called after setting the obj member. It will tie the wrapper + * instance to the GObject so that the same wrapper instance will + * always be used for this GObject instance. + */ +void +pygobject_register_wrapper(PyObject *self) +{ + PyGObject *gself; + + g_return_if_fail(self != NULL); + g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type)); + + gself = (PyGObject *)self; + + g_assert(gself->obj->ref_count >= 1); + /* save wrapper pointer so we can access it later */ + g_object_set_qdata_full(gself->obj, pygobject_wrapper_key, gself, NULL); + if (gself->inst_dict) + pygobject_switch_to_toggle_ref(gself); +} + +static PyObject * +pyg_type_get_bases(GType gtype) +{ + GType *interfaces, parent_type, interface_type; + guint n_interfaces; + PyTypeObject *py_parent_type, *py_interface_type; + PyObject *bases; + int i; + + if (G_UNLIKELY(gtype == G_TYPE_OBJECT)) + return NULL; + + /* Lookup the parent type */ + parent_type = g_type_parent(gtype); + py_parent_type = pygobject_lookup_class(parent_type); + interfaces = g_type_interfaces(gtype, &n_interfaces); + bases = PyTuple_New(n_interfaces + 1); + /* We will always put the parent at the first position in bases */ + Py_INCREF(py_parent_type); /* PyTuple_SetItem steals a reference */ + PyTuple_SetItem(bases, 0, (PyObject *) py_parent_type); + + /* And traverse interfaces */ + if (n_interfaces) { + for (i = 0; i < n_interfaces; i++) { + interface_type = interfaces[i]; + py_interface_type = pygobject_lookup_class(interface_type); + Py_INCREF(py_interface_type); /* PyTuple_SetItem steals a reference */ + PyTuple_SetItem(bases, i + 1, (PyObject *) py_interface_type); + } + } + g_free(interfaces); + return bases; +} + +/** + * pygobject_new_with_interfaces + * @gtype: the GType of the GObject subclass. + * + * Creates a new PyTypeObject from the given GType with interfaces attached in + * bases. + * + * Returns: a PyTypeObject for the new type or NULL if it couldn't be created + */ +static PyTypeObject * +pygobject_new_with_interfaces(GType gtype) +{ + PyGILState_STATE state; + PyObject *o; + PyTypeObject *type; + PyObject *dict; + PyTypeObject *py_parent_type; + PyObject *bases; + PyObject *modules, *module; + gchar *type_name, *mod_name, *gtype_name; + + state = pyglib_gil_state_ensure(); + + bases = pyg_type_get_bases(gtype); + py_parent_type = (PyTypeObject *) PyTuple_GetItem(bases, 0); + + dict = PyDict_New(); + + o = pyg_type_wrapper_new(gtype); + PyDict_SetItemString(dict, "__gtype__", o); + Py_DECREF(o); + + /* set up __doc__ descriptor on type */ + PyDict_SetItemString(dict, "__doc__", pyg_object_descr_doc_get()); + + /* generate the pygtk module name and extract the base type name */ + gtype_name = (gchar*)g_type_name(gtype); + if (g_str_has_prefix(gtype_name, "Gtk")) { + mod_name = "gtk"; + gtype_name += 3; + type_name = g_strconcat(mod_name, ".", gtype_name, NULL); + } else if (g_str_has_prefix(gtype_name, "Gdk")) { + mod_name = "gtk.gdk"; + gtype_name += 3; + type_name = g_strconcat(mod_name, ".", gtype_name, NULL); + } else if (g_str_has_prefix(gtype_name, "Atk")) { + mod_name = "atk"; + gtype_name += 3; + type_name = g_strconcat(mod_name, ".", gtype_name, NULL); + } else if (g_str_has_prefix(gtype_name, "Pango")) { + mod_name = "pango"; + gtype_name += 5; + type_name = g_strconcat(mod_name, ".", gtype_name, NULL); + } else { + mod_name = "__main__"; + type_name = g_strconcat(mod_name, ".", gtype_name, NULL); + } + + type = (PyTypeObject*)PyObject_CallFunction((PyObject *) Py_TYPE(py_parent_type), + "sNN", type_name, bases, dict); + g_free(type_name); + + if (type == NULL) { + PyErr_Print(); + pyglib_gil_state_release(state); + return NULL; + } + + /* Workaround python tp_(get|set)attr slot inheritance bug. + * Fixes bug #144135. */ + if (!type->tp_getattr && py_parent_type->tp_getattr) { + type->tp_getattro = NULL; + type->tp_getattr = py_parent_type->tp_getattr; + } + if (!type->tp_setattr && py_parent_type->tp_setattr) { + type->tp_setattro = NULL; + type->tp_setattr = py_parent_type->tp_setattr; + } + /* override more python stupid hacks behind our back */ + type->tp_dealloc = py_parent_type->tp_dealloc; + type->tp_alloc = py_parent_type->tp_alloc; + type->tp_free = py_parent_type->tp_free; + type->tp_traverse = py_parent_type->tp_traverse; + type->tp_clear = py_parent_type->tp_clear; + + pygobject_inherit_slots(type, bases, FALSE); + + if (PyType_Ready(type) < 0) { + g_warning ("couldn't make the type `%s' ready", type->tp_name); + pyglib_gil_state_release(state); + return NULL; + } + /* insert type name in module dict */ + modules = PyImport_GetModuleDict(); + if ((module = PyDict_GetItemString(modules, mod_name)) != NULL) { + if (PyObject_SetAttrString(module, gtype_name, (PyObject *)type) < 0) + PyErr_Clear(); + } + + /* stash a pointer to the python class with the GType */ + Py_INCREF(type); + g_type_set_qdata(gtype, pygobject_class_key, type); + + pyglib_gil_state_release(state); + + return type; +} + +/* Pick appropriate value for given slot (at slot_offset inside + * PyTypeObject structure). It must be a pointer, e.g. a pointer to a + * function. We use the following heuristic: + * + * - Scan all types listed as bases of the type. + * - If for exactly one base type slot value is non-NULL and + * different from that of 'object' and 'GObject', set current type + * slot into that value. + * - Otherwise (if there is more than one such base type or none at + * all) don't touch it and live with Python default. + * + * The intention here is to propagate slot from custom wrappers to + * wrappers created at runtime when appropriate. We prefer to be on + * the safe side, so if there is potential collision (more than one + * custom slot value), we discard custom overrides altogether. + * + * When registering type with pygobject_register_class(), i.e. a type + * that has been manually created (likely with Codegen help), + * `check_for_present' should be set to TRUE. In this case, the + * function will never overwrite any non-NULL slots already present in + * the type. If `check_for_present' is FALSE, such non-NULL slots are + * though to be set by Python interpreter and so will be overwritten + * if heuristic above says so. + */ +static void +pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present) +{ + static int slot_offsets[] = { offsetof(PyTypeObject, tp_richcompare), +#if PY_VERSION_HEX < 0x03000000 + offsetof(PyTypeObject, tp_compare), +#endif + offsetof(PyTypeObject, tp_richcompare), + offsetof(PyTypeObject, tp_hash), + offsetof(PyTypeObject, tp_iter), + offsetof(PyTypeObject, tp_repr), + offsetof(PyTypeObject, tp_str), + offsetof(PyTypeObject, tp_print) }; + int i; + + /* Happens when registering gobject.GObject itself, at least. */ + if (!bases) + return; + + for (i = 0; i < G_N_ELEMENTS(slot_offsets); ++i) + pygobject_find_slot_for(type, bases, slot_offsets[i], check_for_present); +} + +static void +pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, + gboolean check_for_present) +{ +#define TYPE_SLOT(type) (* (void **) (((char *) (type)) + slot_offset)) + + void *found_slot = NULL; + int num_bases = PyTuple_Size(bases); + int i; + + if (check_for_present && TYPE_SLOT(type) != NULL) { + /* We are requested to check if there is any custom slot value + * in this type already and there actually is. Don't + * overwrite it. + */ + return; + } + + for (i = 0; i < num_bases; ++i) { + PyTypeObject *base_type = (PyTypeObject *) PyTuple_GetItem(bases, i); + void *slot = TYPE_SLOT(base_type); + + if (slot == NULL) + continue; + if (slot == TYPE_SLOT(&PyGObject_Type) || + slot == TYPE_SLOT(&PyBaseObject_Type)) + continue; + + if (found_slot != NULL && found_slot != slot) { + /* We have a conflict: more than one base use different + * custom slots. To be on the safe side, we bail out. + */ + return; + } + + found_slot = slot; + } + + /* Only perform the final assignment if at least one base has a + * custom value. Otherwise just leave this type's slot untouched. + */ + if (found_slot != NULL) + TYPE_SLOT(type) = found_slot; + +#undef TYPE_SLOT +} + +/** + * pygobject_lookup_class: + * @gtype: the GType of the GObject subclass. + * + * This function looks up the wrapper class used to represent + * instances of a GObject represented by @gtype. If no wrapper class + * or interface has been registered for the given GType, then a new + * type will be created. + * + * Returns: The wrapper class for the GObject or NULL if the + * GType has no registered type and a new type couldn't be created + */ +PyTypeObject * +pygobject_lookup_class(GType gtype) +{ + PyTypeObject *py_type; + + if (gtype == G_TYPE_INTERFACE) + return &PyGInterface_Type; + + py_type = g_type_get_qdata(gtype, pygobject_class_key); + if (py_type == NULL) { + py_type = g_type_get_qdata(gtype, pyginterface_type_key); + + if (py_type == NULL) + py_type = (PyTypeObject *)pygi_type_import_by_g_type(gtype); + + if (py_type == NULL) { + py_type = pygobject_new_with_interfaces(gtype); + g_type_set_qdata(gtype, pyginterface_type_key, py_type); + } + } + + return py_type; +} + +/** + * pygobject_new_full: + * @obj: a GObject instance. + * @steal: whether to steal a ref from the GObject or add (sink) a new one. + * @g_class: the GObjectClass + * + * This function gets a reference to a wrapper for the given GObject + * instance. If a wrapper has already been created, a new reference + * to that wrapper will be returned. Otherwise, a wrapper instance + * will be created. + * + * Returns: a reference to the wrapper for the GObject. + */ +PyObject * +pygobject_new_full(GObject *obj, gboolean steal, gpointer g_class) +{ + PyGObject *self; + + if (obj == NULL) { + Py_RETURN_NONE; + } + + /* If the GObject already has a PyObject wrapper stashed in its qdata, re-use it. + */ + self = (PyGObject *)g_object_get_qdata(obj, pygobject_wrapper_key); + if (self != NULL) { + /* Note the use of "pygobject_ref_sink" here only deals with PyObject + * wrapper ref counts and has nothing to do with GObject. + */ + pygobject_ref_sink(self); + + /* If steal is true, we also want to decref the incoming GObjects which + * already have a Python wrapper because the wrapper is already holding a + * strong reference. + */ + if (steal) + g_object_unref (obj); + + } else { + /* create wrapper */ + PyGObjectData *inst_data = pyg_object_peek_inst_data(obj); + PyTypeObject *tp; + if (inst_data) + tp = inst_data->type; + else { + if (g_class) + tp = pygobject_lookup_class(G_OBJECT_CLASS_TYPE(g_class)); + else + tp = pygobject_lookup_class(G_OBJECT_TYPE(obj)); + } + g_assert(tp != NULL); + + /* need to bump type refcount if created with + pygobject_new_with_interfaces(). fixes bug #141042 */ + if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_INCREF(tp); + self = PyObject_GC_New(PyGObject, tp); + if (self == NULL) + return NULL; + self->inst_dict = NULL; + self->weakreflist = NULL; + self->private_flags.flags = 0; + self->obj = obj; + + /* If we are not stealing a ref or the object is floating, + * add a regular ref or sink the object. */ + if (g_object_is_floating (obj)) + self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING; + if (!steal || self->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) + g_object_ref_sink (obj); + + pygobject_register_wrapper((PyObject *)self); + PyObject_GC_Track((PyObject *)self); + } + + return (PyObject *)self; +} + + +PyObject * +pygobject_new(GObject *obj) +{ + return pygobject_new_full(obj, + /*steal=*/FALSE, + NULL); +} + +static void +pygobject_unwatch_closure(gpointer data, GClosure *closure) +{ + PyGObjectData *inst_data = data; + + inst_data->closures = g_slist_remove (inst_data->closures, closure); +} + +/** + * pygobject_watch_closure: + * @self: a GObject wrapper instance + * @closure: a GClosure to watch + * + * Adds a closure to the list of watched closures for the wrapper. + * The closure must be one returned by pyg_closure_new(). When the + * cycle GC traverses the wrapper instance, it will enumerate the + * references to Python objects stored in watched closures. If the + * cycle GC tells the wrapper to clear itself, the watched closures + * will be invalidated. + */ +void +pygobject_watch_closure(PyObject *self, GClosure *closure) +{ + PyGObject *gself; + PyGObjectData *data; + + g_return_if_fail(self != NULL); + g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type)); + g_return_if_fail(closure != NULL); + + gself = (PyGObject *)self; + data = pygobject_get_inst_data(gself); + g_return_if_fail(g_slist_find(data->closures, closure) == NULL); + data->closures = g_slist_prepend(data->closures, closure); + g_closure_add_invalidate_notifier(closure, data, pygobject_unwatch_closure); +} + + +/* -------------- PyGObject behaviour ----------------- */ + +PYGLIB_DEFINE_TYPE("gi._gobject.GObject", PyGObject_Type, PyGObject); + +static void +pygobject_dealloc(PyGObject *self) +{ + /* Untrack must be done first. This is because followup calls such as + * ClearWeakRefs could call into Python and cause new allocations to + * happen, which could in turn could trigger the garbage collector, + * which would then get confused as it is tracking this half-deallocated + * object. */ + PyObject_GC_UnTrack((PyObject *)self); + + PyObject_ClearWeakRefs((PyObject *)self); + /* this forces inst_data->type to be updated, which could prove + * important if a new wrapper has to be created and it is of a + * unregistered type */ + pygobject_get_inst_data(self); + pygobject_clear(self); + /* the following causes problems with subclassed types */ + /* Py_TYPE(self)->tp_free((PyObject *)self); */ + PyObject_GC_Del(self); +} + +static PyObject* +pygobject_richcompare(PyObject *self, PyObject *other, int op) +{ + int isinst; + + isinst = PyObject_IsInstance(self, (PyObject*)&PyGObject_Type); + if (isinst == -1) + return NULL; + if (!isinst) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + isinst = PyObject_IsInstance(other, (PyObject*)&PyGObject_Type); + if (isinst == -1) + return NULL; + if (!isinst) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + return _pyglib_generic_ptr_richcompare(((PyGObject*)self)->obj, + ((PyGObject*)other)->obj, + op); +} + +static long +pygobject_hash(PyGObject *self) +{ + return (long)self->obj; +} + +static PyObject * +pygobject_repr(PyGObject *self) +{ + gchar buf[256]; + + g_snprintf(buf, sizeof(buf), + "<%s object at 0x%lx (%s at 0x%lx)>", + Py_TYPE(self)->tp_name, + (long)self, + self->obj ? G_OBJECT_TYPE_NAME(self->obj) : "uninitialized", + (long)self->obj); + return PYGLIB_PyUnicode_FromString(buf); +} + + +static int +pygobject_traverse(PyGObject *self, visitproc visit, void *arg) +{ + int ret = 0; + GSList *tmp; + PyGObjectData *data = pygobject_get_inst_data(self); + + if (self->inst_dict) ret = visit(self->inst_dict, arg); + if (ret != 0) return ret; + + if (data) { + + for (tmp = data->closures; tmp != NULL; tmp = tmp->next) { + PyGClosure *closure = tmp->data; + + if (closure->callback) ret = visit(closure->callback, arg); + if (ret != 0) return ret; + + if (closure->extra_args) ret = visit(closure->extra_args, arg); + if (ret != 0) return ret; + + if (closure->swap_data) ret = visit(closure->swap_data, arg); + if (ret != 0) return ret; + } + } + return ret; +} + +static inline int +pygobject_clear(PyGObject *self) +{ + if (self->obj) { + g_object_set_qdata_full(self->obj, pygobject_wrapper_key, NULL, NULL); + if (self->inst_dict) { + g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, NULL); + self->private_flags.flags &= ~PYGOBJECT_USING_TOGGLE_REF; + } else { + Py_BEGIN_ALLOW_THREADS; + g_object_unref(self->obj); + Py_END_ALLOW_THREADS; + } + self->obj = NULL; + } + Py_CLEAR(self->inst_dict); + return 0; +} + +static void +pygobject_free(PyObject *op) +{ + PyObject_GC_Del(op); +} + +gboolean +pygobject_prepare_construct_properties(GObjectClass *class, PyObject *kwargs, + guint *n_params, GParameter **params) +{ + *n_params = 0; + *params = NULL; + + if (kwargs) { + Py_ssize_t pos = 0; + PyObject *key; + PyObject *value; + + *params = g_new0(GParameter, PyDict_Size(kwargs)); + while (PyDict_Next(kwargs, &pos, &key, &value)) { + GParamSpec *pspec; + GParameter *param = &(*params)[*n_params]; + const gchar *key_str = PYGLIB_PyUnicode_AsString(key); + + pspec = g_object_class_find_property(class, key_str); + if (!pspec) { + PyErr_Format(PyExc_TypeError, + "gobject `%s' doesn't support property `%s'", + G_OBJECT_CLASS_NAME(class), key_str); + return FALSE; + } + g_value_init(¶m->value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + if (pyg_param_gvalue_from_pyobject(¶m->value, value, pspec) < 0) { + PyErr_Format(PyExc_TypeError, + "could not convert value for property `%s' from %s to %s", + key_str, Py_TYPE(value)->tp_name, + g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); + return FALSE; + } + param->name = g_strdup(key_str); + ++(*n_params); + } + } + return TRUE; +} + +/* ---------------- PyGObject methods ----------------- */ + +static int +pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) +{ + GType object_type; + guint n_params = 0, i; + GParameter *params = NULL; + GObjectClass *class; + + /* Only do GObject creation and property setting if the GObject hasn't + * already been created. The case where self->obj already exists can occur + * when C constructors are called directly (Gtk.Button.new_with_label) + * and we are simply wrapping the result with a PyGObject. + * In these cases we want to ignore any keyword arguments passed along + * to __init__ and simply return. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=705810 + */ + if (self->obj != NULL) + return 0; + + if (!PyArg_ParseTuple(args, ":GObject.__init__", NULL)) + return -1; + + object_type = pyg_type_from_object((PyObject *)self); + if (!object_type) + return -1; + + if (G_TYPE_IS_ABSTRACT(object_type)) { + PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " + "(non-instantiable) type `%s'", g_type_name(object_type)); + return -1; + } + + if ((class = g_type_class_ref (object_type)) == NULL) { + PyErr_SetString(PyExc_TypeError, + "could not get a reference to type class"); + return -1; + } + + if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, ¶ms)) + goto cleanup; + + if (pygobject_constructv(self, n_params, params)) + PyErr_SetString(PyExc_RuntimeError, "could not create object"); + + cleanup: + for (i = 0; i < n_params; i++) { + g_free((gchar *) params[i].name); + g_value_unset(¶ms[i].value); + } + g_free(params); + g_type_class_unref(class); + + return (self->obj) ? 0 : -1; +} + +#define CHECK_GOBJECT(self) \ + if (!G_IS_OBJECT(self->obj)) { \ + PyErr_Format(PyExc_TypeError, \ + "object at %p of type %s is not initialized", \ + self, Py_TYPE(self)->tp_name); \ + return NULL; \ + } + +static PyObject * +pygobject_get_property(PyGObject *self, PyObject *args) +{ + gchar *param_name; + GParamSpec *pspec; + GValue value = { 0, }; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "s:GObject.get_property", ¶m_name)) + return NULL; + + CHECK_GOBJECT(self); + + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), + param_name); + if (!pspec) { + PyErr_Format(PyExc_TypeError, + "object of type `%s' does not have property `%s'", + g_type_name(G_OBJECT_TYPE(self->obj)), param_name); + return NULL; + } + if (!(pspec->flags & G_PARAM_READABLE)) { + PyErr_Format(PyExc_TypeError, "property %s is not readable", + param_name); + return NULL; + } + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + Py_BEGIN_ALLOW_THREADS; + g_object_get_property(self->obj, param_name, &value); + Py_END_ALLOW_THREADS; + + ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec); + g_value_unset(&value); + return ret; +} + +static PyObject * +pygobject_get_properties(PyGObject *self, PyObject *args) +{ + GObjectClass *class; + int len, i; + PyObject *tuple; + + if ((len = PyTuple_Size(args)) < 1) { + PyErr_SetString(PyExc_TypeError, "requires at least one argument"); + return NULL; + } + + tuple = PyTuple_New(len); + class = G_OBJECT_GET_CLASS(self->obj); + for (i = 0; i < len; i++) { + PyObject *py_property = PyTuple_GetItem(args, i); + gchar *property_name; + GParamSpec *pspec; + GValue value = { 0 }; + PyObject *item; + + if (!PYGLIB_PyUnicode_Check(py_property)) { + PyErr_SetString(PyExc_TypeError, + "Expected string argument for property."); + return NULL; + } + + property_name = PYGLIB_PyUnicode_AsString(py_property); + + pspec = g_object_class_find_property(class, + property_name); + if (!pspec) { + PyErr_Format(PyExc_TypeError, + "object of type `%s' does not have property `%s'", + g_type_name(G_OBJECT_TYPE(self->obj)), property_name); + return NULL; + } + if (!(pspec->flags & G_PARAM_READABLE)) { + PyErr_Format(PyExc_TypeError, "property %s is not readable", + property_name); + return NULL; + } + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + + Py_BEGIN_ALLOW_THREADS; + g_object_get_property(self->obj, property_name, &value); + Py_END_ALLOW_THREADS; + + item = pyg_value_as_pyobject(&value, TRUE); + PyTuple_SetItem(tuple, i, item); + + g_value_unset(&value); + } + + return tuple; +} + +static PyObject * +pygobject_set_property(PyGObject *self, PyObject *args) +{ + gchar *param_name; + GParamSpec *pspec; + PyObject *pvalue; + int ret = -1; + + if (!PyArg_ParseTuple(args, "sO:GObject.set_property", ¶m_name, + &pvalue)) + return NULL; + + CHECK_GOBJECT(self); + + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), + param_name); + if (!pspec) { + PyErr_Format(PyExc_TypeError, + "object of type `%s' does not have property `%s'", + g_type_name(G_OBJECT_TYPE(self->obj)), param_name); + return NULL; + } + + ret = pygi_set_property_value (self, pspec, pvalue); + if (ret == 0) + goto done; + else if (PyErr_Occurred()) + return NULL; + + if (!set_property_from_pspec(self->obj, pspec, pvalue)) + return NULL; + +done: + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs) +{ + GObjectClass *class; + Py_ssize_t pos; + PyObject *value; + PyObject *key; + PyObject *result = NULL; + + CHECK_GOBJECT(self); + + class = G_OBJECT_GET_CLASS(self->obj); + + g_object_freeze_notify (G_OBJECT(self->obj)); + pos = 0; + + while (kwargs && PyDict_Next (kwargs, &pos, &key, &value)) { + gchar *key_str = PYGLIB_PyUnicode_AsString(key); + GParamSpec *pspec; + int ret = -1; + + pspec = g_object_class_find_property(class, key_str); + if (!pspec) { + gchar buf[512]; + + g_snprintf(buf, sizeof(buf), + "object `%s' doesn't support property `%s'", + g_type_name(G_OBJECT_TYPE(self->obj)), key_str); + PyErr_SetString(PyExc_TypeError, buf); + goto exit; + } + + ret = pygi_set_property_value (self, pspec, value); + if (ret != 0) { + /* Non-zero return code means that either an error occured ...*/ + if (PyErr_Occurred()) + goto exit; + + /* ... or the property couldn't be found , so let's try the default + * call. */ + if (!set_property_from_pspec(G_OBJECT(self->obj), pspec, value)) + goto exit; + } + } + + result = Py_None; + + exit: + g_object_thaw_notify (G_OBJECT(self->obj)); + Py_XINCREF(result); + return result; +} + +/* custom closure for gobject bindings */ +static void +pygbinding_closure_invalidate(gpointer data, GClosure *closure) +{ + PyGClosure *pc = (PyGClosure *)closure; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + Py_XDECREF(pc->callback); + Py_XDECREF(pc->extra_args); + pyglib_gil_state_release(state); + + pc->callback = NULL; + pc->extra_args = NULL; +} + +static void +pygbinding_marshal (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + PyGILState_STATE state; + PyGClosure *pc = (PyGClosure *)closure; + PyObject *params, *ret; + GValue *out_value; + + state = pyglib_gil_state_ensure(); + + /* construct Python tuple for the parameter values */ + params = PyTuple_New(2); + PyTuple_SetItem (params, 0, pyg_value_as_pyobject(¶m_values[0], FALSE)); + PyTuple_SetItem (params, 1, pyg_value_as_pyobject(¶m_values[1], FALSE)); + + /* params passed to function may have extra arguments */ + if (pc->extra_args) { + PyObject *tuple = params; + params = PySequence_Concat(tuple, pc->extra_args); + Py_DECREF(tuple); + } + ret = PyObject_CallObject(pc->callback, params); + if (!ret) { + PyErr_Print (); + goto out; + } else if (ret == Py_None) { + g_value_set_boolean (return_value, FALSE); + goto out; + } + + out_value = g_value_get_boxed (¶m_values[2]); + if (pyg_value_from_pyobject (out_value, ret) != 0) { + PyErr_SetString (PyExc_ValueError, "can't convert value"); + PyErr_Print (); + g_value_set_boolean (return_value, FALSE); + } else { + g_value_set_boolean (return_value, TRUE); + } + + Py_DECREF(ret); + +out: + Py_DECREF(params); + pyglib_gil_state_release(state); +} + +static GClosure * +pygbinding_closure_new (PyObject *callback, PyObject *extra_args) +{ + GClosure *closure; + + g_return_val_if_fail(callback != NULL, NULL); + closure = g_closure_new_simple(sizeof(PyGClosure), NULL); + g_closure_add_invalidate_notifier(closure, NULL, pygbinding_closure_invalidate); + g_closure_set_marshal(closure, pygbinding_marshal); + Py_INCREF(callback); + ((PyGClosure *)closure)->callback = callback; + if (extra_args && extra_args != Py_None) { + Py_INCREF(extra_args); + if (!PyTuple_Check(extra_args)) { + PyObject *tmp = PyTuple_New(1); + PyTuple_SetItem(tmp, 0, extra_args); + extra_args = tmp; + } + ((PyGClosure *)closure)->extra_args = extra_args; + } + return closure; +} + +static PyObject * +pygobject_bind_property(PyGObject *self, PyObject *args) +{ + gchar *source_name, *target_name; + gchar *source_canon, *target_canon; + PyObject *target, *source_repr, *target_repr; + PyObject *transform_to, *transform_from, *user_data = NULL; + GBinding *binding; + GBindingFlags flags = G_BINDING_DEFAULT; + GClosure *to_closure = NULL, *from_closure = NULL; + + transform_from = NULL; + transform_to = NULL; + + if (!PyArg_ParseTuple(args, "sOs|iOOO:GObject.bind_property", + &source_name, &target, &target_name, &flags, + &transform_to, &transform_from, &user_data)) + return NULL; + + CHECK_GOBJECT(self); + if (!PyObject_TypeCheck(target, &PyGObject_Type)) { + PyErr_SetString(PyExc_TypeError, "Second argument must be a GObject"); + return NULL; + } + + if (transform_to && transform_to != Py_None) { + if (!PyCallable_Check (transform_to)) { + PyErr_SetString (PyExc_TypeError, + "transform_to must be callable or None"); + return NULL; + } + to_closure = pygbinding_closure_new (transform_to, user_data); + } + + if (transform_from && transform_from != Py_None) { + if (!PyCallable_Check (transform_from)) { + PyErr_SetString (PyExc_TypeError, + "transform_from must be callable or None"); + return NULL; + } + from_closure = pygbinding_closure_new (transform_from, user_data); + } + + /* Canonicalize underscores to hyphens. Note the results must be freed. */ + source_canon = g_strdelimit(g_strdup(source_name), "_", '-'); + target_canon = g_strdelimit(g_strdup(target_name), "_", '-'); + + binding = g_object_bind_property_with_closures (G_OBJECT(self->obj), source_canon, + pygobject_get(target), target_canon, + flags, to_closure, from_closure); + g_free(source_canon); + g_free(target_canon); + source_canon = target_canon = NULL; + + if (binding == NULL) { + source_repr = PyObject_Repr((PyObject*)self); + target_repr = PyObject_Repr(target); + PyErr_Format(PyExc_TypeError, "Cannot create binding from %s.%s to %s.%s", + PYGLIB_PyUnicode_AsString(source_repr), source_name, + PYGLIB_PyUnicode_AsString(target_repr), target_name); + Py_DECREF(source_repr); + Py_DECREF(target_repr); + return NULL; + } + + return pygobject_new (G_OBJECT (binding)); +} + +static PyObject * +connect_helper(PyGObject *self, gchar *name, PyObject *callback, PyObject *extra_args, PyObject *object, gboolean after) +{ + guint sigid; + GQuark detail = 0; + GClosure *closure = NULL; + gulong handlerid; + GSignalQuery query_info; + + if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj), + &sigid, &detail, TRUE)) { + PyObject *repr = PyObject_Repr((PyObject*)self); + PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", + PYGLIB_PyUnicode_AsString(repr), + name); + Py_DECREF(repr); + return NULL; + } + + g_signal_query (sigid, &query_info); + if (!pyg_gtype_is_custom (query_info.itype)) { + /* The signal is implemented by a non-Python class, probably + * something in the gi repository. */ + closure = pygi_signal_closure_new (self, query_info.itype, + query_info.signal_name, callback, + extra_args, object); + } + + if (!closure) { + /* The signal is either implemented at the Python level, or it comes + * from a foreign class that we don't have introspection data for. */ + closure = pyg_closure_new (callback, extra_args, object); + } + + pygobject_watch_closure((PyObject *)self, closure); + handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, + closure, after); + return PyLong_FromUnsignedLong(handlerid); +} + +static PyObject * +pygobject_connect(PyGObject *self, PyObject *args) +{ + PyObject *first, *callback, *extra_args, *ret; + gchar *name; + guint len; + + len = PyTuple_Size(args); + if (len < 2) { + PyErr_SetString(PyExc_TypeError, + "GObject.connect requires at least 2 arguments"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 2); + if (!PyArg_ParseTuple(first, "sO:GObject.connect", &name, &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument must be callable"); + return NULL; + } + + CHECK_GOBJECT(self); + + extra_args = PySequence_GetSlice(args, 2, len); + if (extra_args == NULL) + return NULL; + + ret = connect_helper(self, name, callback, extra_args, NULL, FALSE); + Py_DECREF(extra_args); + return ret; +} + +static PyObject * +pygobject_connect_after(PyGObject *self, PyObject *args) +{ + PyObject *first, *callback, *extra_args, *ret; + gchar *name; + Py_ssize_t len; + + len = PyTuple_Size(args); + if (len < 2) { + PyErr_SetString(PyExc_TypeError, + "GObject.connect_after requires at least 2 arguments"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 2); + if (!PyArg_ParseTuple(first, "sO:GObject.connect_after", + &name, &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument must be callable"); + return NULL; + } + + CHECK_GOBJECT(self); + + extra_args = PySequence_GetSlice(args, 2, len); + if (extra_args == NULL) + return NULL; + + ret = connect_helper(self, name, callback, extra_args, NULL, TRUE); + Py_DECREF(extra_args); + return ret; +} + +static PyObject * +pygobject_connect_object(PyGObject *self, PyObject *args) +{ + PyObject *first, *callback, *extra_args, *object, *ret; + gchar *name; + Py_ssize_t len; + + len = PyTuple_Size(args); + if (len < 3) { + PyErr_SetString(PyExc_TypeError, + "GObject.connect_object requires at least 3 arguments"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 3); + if (!PyArg_ParseTuple(first, "sOO:GObject.connect_object", + &name, &callback, &object)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument must be callable"); + return NULL; + } + + CHECK_GOBJECT(self); + + extra_args = PySequence_GetSlice(args, 3, len); + if (extra_args == NULL) + return NULL; + + ret = connect_helper(self, name, callback, extra_args, object, FALSE); + Py_DECREF(extra_args); + return ret; +} + +static PyObject * +pygobject_connect_object_after(PyGObject *self, PyObject *args) +{ + PyObject *first, *callback, *extra_args, *object, *ret; + gchar *name; + Py_ssize_t len; + + len = PyTuple_Size(args); + if (len < 3) { + PyErr_SetString(PyExc_TypeError, + "GObject.connect_object_after requires at least 3 arguments"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 3); + if (!PyArg_ParseTuple(first, "sOO:GObject.connect_object_after", + &name, &callback, &object)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "second argument must be callable"); + return NULL; + } + + CHECK_GOBJECT(self); + + extra_args = PySequence_GetSlice(args, 3, len); + if (extra_args == NULL) + return NULL; + + ret = connect_helper(self, name, callback, extra_args, object, TRUE); + Py_DECREF(extra_args); + return ret; +} + +static PyObject * +pygobject_emit(PyGObject *self, PyObject *args) +{ + guint signal_id, i, j; + Py_ssize_t len; + GQuark detail; + PyObject *first, *py_ret, *repr = NULL; + gchar *name; + GSignalQuery query; + GValue *params, ret = { 0, }; + + len = PyTuple_Size(args); + if (len < 1) { + PyErr_SetString(PyExc_TypeError,"GObject.emit needs at least one arg"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 1); + if (!PyArg_ParseTuple(first, "s:GObject.emit", &name)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + + CHECK_GOBJECT(self); + + if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj), + &signal_id, &detail, TRUE)) { + repr = PyObject_Repr((PyObject*)self); + PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", + PYGLIB_PyUnicode_AsString(repr), + name); + Py_DECREF(repr); + return NULL; + } + g_signal_query(signal_id, &query); + if (len != query.n_params + 1) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "%d parameters needed for signal %s; %ld given", + query.n_params, name, (long int) (len - 1)); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + + params = g_new0(GValue, query.n_params + 1); + g_value_init(¶ms[0], G_OBJECT_TYPE(self->obj)); + g_value_set_object(¶ms[0], G_OBJECT(self->obj)); + + for (i = 0; i < query.n_params; i++) + g_value_init(¶ms[i + 1], + query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); + for (i = 0; i < query.n_params; i++) { + PyObject *item = PyTuple_GetItem(args, i+1); + + if (pyg_value_from_pyobject(¶ms[i+1], item) < 0) { + gchar buf[128]; + g_snprintf(buf, sizeof(buf), + "could not convert type %s to %s required for parameter %d", + Py_TYPE(item)->tp_name, + G_VALUE_TYPE_NAME(¶ms[i+1]), i); + PyErr_SetString(PyExc_TypeError, buf); + + for (j = 0; j <= i; j++) + g_value_unset(¶ms[j]); + + g_free(params); + return NULL; + } + } + + if (query.return_type != G_TYPE_NONE) + g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); + + g_signal_emitv(params, signal_id, detail, &ret); + + for (i = 0; i < query.n_params + 1; i++) + g_value_unset(¶ms[i]); + + g_free(params); + if ((query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE) != G_TYPE_NONE) { + py_ret = pyg_value_as_pyobject(&ret, TRUE); + g_value_unset(&ret); + } else { + Py_INCREF(Py_None); + py_ret = Py_None; + } + + return py_ret; +} + +static PyObject * +pygobject_chain_from_overridden(PyGObject *self, PyObject *args) +{ + GSignalInvocationHint *ihint; + guint signal_id, i; + Py_ssize_t len; + PyObject *py_ret; + const gchar *name; + GSignalQuery query; + GValue *params, ret = { 0, }; + + CHECK_GOBJECT(self); + + ihint = g_signal_get_invocation_hint(self->obj); + if (!ihint) { + PyErr_SetString(PyExc_TypeError, "could not find signal invocation " + "information for this object."); + return NULL; + } + + signal_id = ihint->signal_id; + name = g_signal_name(signal_id); + + len = PyTuple_Size(args); + if (signal_id == 0) { + PyErr_SetString(PyExc_TypeError, "unknown signal name"); + return NULL; + } + g_signal_query(signal_id, &query); + if (len != query.n_params) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "%d parameters needed for signal %s; %ld given", + query.n_params, name, (long int) len); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + params = g_new0(GValue, query.n_params + 1); + g_value_init(¶ms[0], G_OBJECT_TYPE(self->obj)); + g_value_set_object(¶ms[0], G_OBJECT(self->obj)); + + for (i = 0; i < query.n_params; i++) + g_value_init(¶ms[i + 1], + query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); + for (i = 0; i < query.n_params; i++) { + PyObject *item = PyTuple_GetItem(args, i); + + if (pyg_boxed_check(item, (query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE))) { + g_value_set_static_boxed(¶ms[i+1], pyg_boxed_get(item, void)); + } + else if (pyg_value_from_pyobject(¶ms[i+1], item) < 0) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "could not convert type %s to %s required for parameter %d", + Py_TYPE(item)->tp_name, + g_type_name(G_VALUE_TYPE(¶ms[i+1])), i); + PyErr_SetString(PyExc_TypeError, buf); + for (i = 0; i < query.n_params + 1; i++) + g_value_unset(¶ms[i]); + g_free(params); + return NULL; + } + } + if (query.return_type != G_TYPE_NONE) + g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); + g_signal_chain_from_overridden(params, &ret); + for (i = 0; i < query.n_params + 1; i++) + g_value_unset(¶ms[i]); + g_free(params); + if (query.return_type != G_TYPE_NONE) { + py_ret = pyg_value_as_pyobject(&ret, TRUE); + g_value_unset(&ret); + } else { + Py_INCREF(Py_None); + py_ret = Py_None; + } + return py_ret; +} + + +static PyObject * +pygobject_weak_ref(PyGObject *self, PyObject *args) +{ + int len; + PyObject *callback = NULL, *user_data = NULL; + PyObject *retval; + + CHECK_GOBJECT(self); + + if ((len = PySequence_Length(args)) >= 1) { + callback = PySequence_ITEM(args, 0); + user_data = PySequence_GetSlice(args, 1, len); + } + retval = pygobject_weak_ref_new(self->obj, callback, user_data); + Py_XDECREF(callback); + Py_XDECREF(user_data); + return retval; +} + + +static PyObject * +pygobject_copy(PyGObject *self) +{ + PyErr_SetString(PyExc_TypeError, + "GObject descendants' instances are non-copyable"); + return NULL; +} + +static PyObject * +pygobject_deepcopy(PyGObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "GObject descendants' instances are non-copyable"); + return NULL; +} + + +static PyObject * +pygobject_disconnect_by_func(PyGObject *self, PyObject *args) +{ + PyObject *pyfunc = NULL, *repr = NULL; + GClosure *closure = NULL; + guint retval; + + CHECK_GOBJECT(self); + + if (!PyArg_ParseTuple(args, "O:GObject.disconnect_by_func", &pyfunc)) + return NULL; + + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "first argument must be callable"); + return NULL; + } + + closure = gclosure_from_pyfunc(self, pyfunc); + if (!closure) { + repr = PyObject_Repr((PyObject*)pyfunc); + PyErr_Format(PyExc_TypeError, "nothing connected to %s", + PYGLIB_PyUnicode_AsString(repr)); + Py_DECREF(repr); + return NULL; + } + + retval = g_signal_handlers_disconnect_matched(self->obj, + G_SIGNAL_MATCH_CLOSURE, + 0, 0, + closure, + NULL, NULL); + return PYGLIB_PyLong_FromLong(retval); +} + +static PyObject * +pygobject_handler_block_by_func(PyGObject *self, PyObject *args) +{ + PyObject *pyfunc = NULL, *repr = NULL; + GClosure *closure = NULL; + guint retval; + + CHECK_GOBJECT(self); + + if (!PyArg_ParseTuple(args, "O:GObject.handler_block_by_func", &pyfunc)) + return NULL; + + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "first argument must be callable"); + return NULL; + } + + closure = gclosure_from_pyfunc(self, pyfunc); + if (!closure) { + repr = PyObject_Repr((PyObject*)pyfunc); + PyErr_Format(PyExc_TypeError, "nothing connected to %s", + PYGLIB_PyUnicode_AsString(repr)); + Py_DECREF(repr); + return NULL; + } + + retval = g_signal_handlers_block_matched(self->obj, + G_SIGNAL_MATCH_CLOSURE, + 0, 0, + closure, + NULL, NULL); + return PYGLIB_PyLong_FromLong(retval); +} + +static PyObject * +pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args) +{ + PyObject *pyfunc = NULL, *repr = NULL; + GClosure *closure = NULL; + guint retval; + + CHECK_GOBJECT(self); + + if (!PyArg_ParseTuple(args, "O:GObject.handler_unblock_by_func", &pyfunc)) + return NULL; + + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "first argument must be callable"); + return NULL; + } + + closure = gclosure_from_pyfunc(self, pyfunc); + if (!closure) { + repr = PyObject_Repr((PyObject*)pyfunc); + PyErr_Format(PyExc_TypeError, "nothing connected to %s", + PYGLIB_PyUnicode_AsString(repr)); + Py_DECREF(repr); + return NULL; + } + + retval = g_signal_handlers_unblock_matched(self->obj, + G_SIGNAL_MATCH_CLOSURE, + 0, 0, + closure, + NULL, NULL); + return PYGLIB_PyLong_FromLong(retval); +} + + +static PyMethodDef pygobject_methods[] = { + { "get_property", (PyCFunction)pygobject_get_property, METH_VARARGS }, + { "get_properties", (PyCFunction)pygobject_get_properties, METH_VARARGS }, + { "set_property", (PyCFunction)pygobject_set_property, METH_VARARGS }, + { "set_properties", (PyCFunction)pygobject_set_properties, METH_VARARGS|METH_KEYWORDS }, + { "bind_property", (PyCFunction)pygobject_bind_property, METH_VARARGS|METH_KEYWORDS }, + { "connect", (PyCFunction)pygobject_connect, METH_VARARGS }, + { "connect_after", (PyCFunction)pygobject_connect_after, METH_VARARGS }, + { "connect_object", (PyCFunction)pygobject_connect_object, METH_VARARGS }, + { "connect_object_after", (PyCFunction)pygobject_connect_object_after, METH_VARARGS }, + { "disconnect_by_func", (PyCFunction)pygobject_disconnect_by_func, METH_VARARGS }, + { "handler_block_by_func", (PyCFunction)pygobject_handler_block_by_func, METH_VARARGS }, + { "handler_unblock_by_func", (PyCFunction)pygobject_handler_unblock_by_func, METH_VARARGS }, + { "emit", (PyCFunction)pygobject_emit, METH_VARARGS }, + { "chain", (PyCFunction)pygobject_chain_from_overridden,METH_VARARGS }, + { "weak_ref", (PyCFunction)pygobject_weak_ref, METH_VARARGS }, + { "__copy__", (PyCFunction)pygobject_copy, METH_NOARGS }, + { "__deepcopy__", (PyCFunction)pygobject_deepcopy, METH_VARARGS }, + { NULL, NULL, 0 } +}; + + +static PyObject * +pygobject_get_dict(PyGObject *self, void *closure) +{ + if (self->inst_dict == NULL) { + self->inst_dict = PyDict_New(); + if (self->inst_dict == NULL) + return NULL; + if (G_LIKELY(self->obj)) + pygobject_switch_to_toggle_ref(self); + } + Py_INCREF(self->inst_dict); + return self->inst_dict; +} + +static PyObject * +pygobject_get_refcount(PyGObject *self, void *closure) +{ + if (self->obj == NULL) { + PyErr_Format(PyExc_TypeError, "GObject instance is not yet created"); + return NULL; + } + return PYGLIB_PyLong_FromLong(self->obj->ref_count); +} + +static PyObject * +pygobject_get_pointer(PyGObject *self, void *closure) +{ + return PYGLIB_CPointer_WrapPointer (self->obj, NULL); +} + +static int +pygobject_setattro(PyObject *self, PyObject *name, PyObject *value) +{ + int res; + PyGObject *gself = (PyGObject *) self; + PyObject *inst_dict_before = gself->inst_dict; + /* call parent type's setattro */ + res = PyGObject_Type.tp_base->tp_setattro(self, name, value); + if (inst_dict_before == NULL && gself->inst_dict != NULL) { + if (G_LIKELY(gself->obj)) + pygobject_switch_to_toggle_ref(gself); + } + return res; +} + +static PyGetSetDef pygobject_getsets[] = { + { "__dict__", (getter)pygobject_get_dict, (setter)0 }, + { "__grefcount__", (getter)pygobject_get_refcount, (setter)0, }, + { "__gpointer__", (getter)pygobject_get_pointer, (setter)0, }, + { NULL, 0, 0 } +}; + +/* ------------------------------------ */ +/* ****** GObject weak reference ****** */ +/* ------------------------------------ */ + +typedef struct { + PyObject_HEAD + GObject *obj; + PyObject *callback; + PyObject *user_data; + gboolean have_floating_ref; +} PyGObjectWeakRef; + +PYGLIB_DEFINE_TYPE("gi._gobject.GObjectWeakRef", PyGObjectWeakRef_Type, PyGObjectWeakRef); + +static int +pygobject_weak_ref_traverse(PyGObjectWeakRef *self, visitproc visit, void *arg) +{ + if (self->callback && visit(self->callback, arg) < 0) + return -1; + if (self->user_data && visit(self->user_data, arg) < 0) + return -1; + return 0; +} + +static void +pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) +{ + self->obj = NULL; + if (self->callback) { + PyObject *retval; + PyGILState_STATE state = pyglib_gil_state_ensure(); + retval = PyObject_Call(self->callback, self->user_data, NULL); + if (retval) { + if (retval != Py_None) + PyErr_Format(PyExc_TypeError, + "GObject weak notify callback returned a value" + " of type %s, should return None", + Py_TYPE(retval)->tp_name); + Py_DECREF(retval); + PyErr_Print(); + } else + PyErr_Print(); + Py_CLEAR(self->callback); + Py_CLEAR(self->user_data); + if (self->have_floating_ref) { + self->have_floating_ref = FALSE; + Py_DECREF((PyObject *) self); + } + pyglib_gil_state_release(state); + } +} + +static inline int +pygobject_weak_ref_clear(PyGObjectWeakRef *self) +{ + Py_CLEAR(self->callback); + Py_CLEAR(self->user_data); + if (self->obj) { + g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); + self->obj = NULL; + } + return 0; +} + +static void +pygobject_weak_ref_dealloc(PyGObjectWeakRef *self) +{ + PyObject_GC_UnTrack((PyObject *)self); + pygobject_weak_ref_clear(self); + PyObject_GC_Del(self); +} + +static PyObject * +pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data) +{ + PyGObjectWeakRef *self; + + self = PyObject_GC_New(PyGObjectWeakRef, &PyGObjectWeakRef_Type); + self->callback = callback; + self->user_data = user_data; + Py_XINCREF(self->callback); + Py_XINCREF(self->user_data); + self->obj = obj; + g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); + if (callback != NULL) { + /* when we have a callback, we should INCREF the weakref + * object to make it stay alive even if it goes out of scope */ + self->have_floating_ref = TRUE; + Py_INCREF((PyObject *) self); + } + return (PyObject *) self; +} + +static PyObject * +pygobject_weak_ref_unref(PyGObjectWeakRef *self, PyObject *args) +{ + if (!self->obj) { + PyErr_SetString(PyExc_ValueError, "weak ref already unreffed"); + return NULL; + } + g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); + self->obj = NULL; + if (self->have_floating_ref) { + self->have_floating_ref = FALSE; + Py_DECREF(self); + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef pygobject_weak_ref_methods[] = { + { "unref", (PyCFunction)pygobject_weak_ref_unref, METH_NOARGS}, + { NULL, NULL, 0} +}; + +static PyObject * +pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw) +{ + static char *argnames[] = {NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) + return NULL; + + if (self->obj) + return pygobject_new(self->obj); + else { + Py_INCREF(Py_None); + return Py_None; + } +} + +static gpointer +pyobject_copy(gpointer boxed) +{ + PyObject *object = boxed; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + Py_INCREF(object); + pyglib_gil_state_release(state); + return object; +} + +static void +pyobject_free(gpointer boxed) +{ + PyObject *object = boxed; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + Py_DECREF(object); + pyglib_gil_state_release(state); +} + +void +pygobject_object_register_types(PyObject *d) +{ + PyObject *o, *descr; + + pygobject_custom_key = g_quark_from_static_string("PyGObject::custom"); + pygobject_class_key = g_quark_from_static_string("PyGObject::class"); + pygobject_class_init_key = g_quark_from_static_string("PyGObject::class-init"); + pygobject_wrapper_key = g_quark_from_static_string("PyGObject::wrapper"); + pygobject_has_updated_constructor_key = + g_quark_from_static_string("PyGObject::has-updated-constructor"); + pygobject_instance_data_key = g_quark_from_static_string("PyGObject::instance-data"); + + /* GObject */ + if (!PY_TYPE_OBJECT) + PY_TYPE_OBJECT = g_boxed_type_register_static("PyObject", + pyobject_copy, + pyobject_free); + PyGObject_Type.tp_dealloc = (destructor)pygobject_dealloc; + PyGObject_Type.tp_richcompare = pygobject_richcompare; + PyGObject_Type.tp_repr = (reprfunc)pygobject_repr; + PyGObject_Type.tp_hash = (hashfunc)pygobject_hash; + PyGObject_Type.tp_setattro = (setattrofunc)pygobject_setattro; + PyGObject_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC); + PyGObject_Type.tp_traverse = (traverseproc)pygobject_traverse; + PyGObject_Type.tp_clear = (inquiry)pygobject_clear; + PyGObject_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); + PyGObject_Type.tp_methods = pygobject_methods; + PyGObject_Type.tp_getset = pygobject_getsets; + PyGObject_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); + PyGObject_Type.tp_init = (initproc)pygobject_init; + PyGObject_Type.tp_free = (freefunc)pygobject_free; + PyGObject_Type.tp_alloc = PyType_GenericAlloc; + PyGObject_Type.tp_new = PyType_GenericNew; + pygobject_register_class(d, "GObject", G_TYPE_OBJECT, + &PyGObject_Type, NULL); + PyDict_SetItemString(PyGObject_Type.tp_dict, "__gdoc__", + pyg_object_descr_doc_get()); + + /* GProps */ + PyGProps_Type.tp_dealloc = (destructor)PyGProps_dealloc; + PyGProps_Type.tp_as_sequence = (PySequenceMethods*)&_PyGProps_as_sequence; + PyGProps_Type.tp_getattro = (getattrofunc)PyGProps_getattro; + PyGProps_Type.tp_setattro = (setattrofunc)PyGProps_setattro; + PyGProps_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; + PyGProps_Type.tp_doc = "The properties of the GObject accessible as " + "Python attributes."; + PyGProps_Type.tp_traverse = (traverseproc)pygobject_props_traverse; + PyGProps_Type.tp_iter = (getiterfunc)pygobject_props_get_iter; + PyGProps_Type.tp_methods = pygobject_props_methods; + if (PyType_Ready(&PyGProps_Type) < 0) + return; + + /* GPropsDescr */ + PyGPropsDescr_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGPropsDescr_Type.tp_descr_get = pyg_props_descr_descr_get; + if (PyType_Ready(&PyGPropsDescr_Type) < 0) + return; + descr = PyObject_New(PyObject, &PyGPropsDescr_Type); + PyDict_SetItemString(PyGObject_Type.tp_dict, "props", descr); + PyDict_SetItemString(PyGObject_Type.tp_dict, "__module__", + o=PYGLIB_PyUnicode_FromString("gi._gobject._gobject")); + Py_DECREF(o); + + /* GPropsIter */ + PyGPropsIter_Type.tp_dealloc = (destructor)pyg_props_iter_dealloc; + PyGPropsIter_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGPropsIter_Type.tp_doc = "GObject properties iterator"; + PyGPropsIter_Type.tp_iternext = (iternextfunc)pygobject_props_iter_next; + if (PyType_Ready(&PyGPropsIter_Type) < 0) + return; + + PyGObjectWeakRef_Type.tp_dealloc = (destructor)pygobject_weak_ref_dealloc; + PyGObjectWeakRef_Type.tp_call = (ternaryfunc)pygobject_weak_ref_call; + PyGObjectWeakRef_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; + PyGObjectWeakRef_Type.tp_doc = "A GObject weak reference"; + PyGObjectWeakRef_Type.tp_traverse = (traverseproc)pygobject_weak_ref_traverse; + PyGObjectWeakRef_Type.tp_clear = (inquiry)pygobject_weak_ref_clear; + PyGObjectWeakRef_Type.tp_methods = pygobject_weak_ref_methods; + if (PyType_Ready(&PyGObjectWeakRef_Type) < 0) + return; + PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type); +} diff --git a/gi/pygobject.h b/gi/pygobject.h new file mode 100644 index 00000000..76b8b118 --- /dev/null +++ b/gi/pygobject.h @@ -0,0 +1,636 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +#ifndef _PYGOBJECT_H_ +#define _PYGOBJECT_H_ + +#include + +#include +#include + +G_BEGIN_DECLS + +/* PyGClosure is a _private_ structure */ +typedef void (* PyClosureExceptionHandler) (GValue *ret, guint n_param_values, const GValue *params); +typedef struct _PyGClosure PyGClosure; +typedef struct _PyGObjectData PyGObjectData; + +struct _PyGClosure { + GClosure closure; + PyObject *callback; + PyObject *extra_args; /* tuple of extra args to pass to callback */ + PyObject *swap_data; /* other object for gtk_signal_connect__object */ + PyClosureExceptionHandler exception_handler; +}; + +typedef enum { + PYGOBJECT_USING_TOGGLE_REF = 1 << 0, + PYGOBJECT_IS_FLOATING_REF = 1 << 1, + PYGOBJECT_GOBJECT_WAS_FLOATING = 1 << 2, +} PyGObjectFlags; + + /* closures is just an alias for what is found in the + * PyGObjectData */ +typedef struct { + PyObject_HEAD + GObject *obj; + PyObject *inst_dict; /* the instance dictionary -- must be last */ + PyObject *weakreflist; /* list of weak references */ + + /*< private >*/ + /* using union to preserve ABI compatibility (structure size + * must not change) */ + union { + GSList *closures; /* stale field; no longer updated DO-NOT-USE! */ + PyGObjectFlags flags; + } private_flags; + +} PyGObject; + +#define pygobject_get(v) (((PyGObject *)(v))->obj) +#define pygobject_check(v,base) (PyObject_TypeCheck(v,base)) + +typedef struct { + PyObject_HEAD + gpointer boxed; + GType gtype; + gboolean free_on_dealloc; +} PyGBoxed; + +#define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) +#define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) + +typedef struct { + PyObject_HEAD + gpointer pointer; + GType gtype; +} PyGPointer; + +#define pyg_pointer_get(v,t) ((t *)((PyGPointer *)(v))->pointer) +#define pyg_pointer_check(v,typecode) (PyObject_TypeCheck(v, &PyGPointer_Type) && ((PyGPointer *)(v))->gtype == typecode) + +typedef void (*PyGFatalExceptionFunc) (void); +typedef void (*PyGThreadBlockFunc) (void); + +typedef struct { + PyObject_HEAD + GParamSpec *pspec; +} PyGParamSpec; + +#define PyGParamSpec_Get(v) (((PyGParamSpec *)v)->pspec) +#define PyGParamSpec_Check(v) (PyObject_TypeCheck(v, &PyGParamSpec_Type)) + +typedef int (*PyGClassInitFunc) (gpointer gclass, PyTypeObject *pyclass); +typedef PyTypeObject * (*PyGTypeRegistrationFunction) (const gchar *name, + gpointer data); + +struct _PyGObject_Functions { + /* + * All field names in here are considered private, + * use the macros below instead, which provides stability + */ + void (* register_class)(PyObject *dict, const gchar *class_name, + GType gtype, PyTypeObject *type, PyObject *bases); + void (* register_wrapper)(PyObject *self); + PyTypeObject *(* lookup_class)(GType type); + PyObject *(* newgobj)(GObject *obj); + + GClosure *(* closure_new)(PyObject *callback, PyObject *extra_args, + PyObject *swap_data); + void (* object_watch_closure)(PyObject *self, GClosure *closure); + GDestroyNotify destroy_notify; + + GType (* type_from_object)(PyObject *obj); + PyObject *(* type_wrapper_new)(GType type); + + gint (* enum_get_value)(GType enum_type, PyObject *obj, gint *val); + gint (* flags_get_value)(GType flag_type, PyObject *obj, guint *val); + void (* register_gtype_custom)(GType gtype, + PyObject *(* from_func)(const GValue *value), + int (* to_func)(GValue *value, PyObject *obj)); + int (* value_from_pyobject)(GValue *value, PyObject *obj); + PyObject *(* value_as_pyobject)(const GValue *value, gboolean copy_boxed); + + void (* register_interface)(PyObject *dict, const gchar *class_name, + GType gtype, PyTypeObject *type); + + PyTypeObject *boxed_type; + void (* register_boxed)(PyObject *dict, const gchar *class_name, + GType boxed_type, PyTypeObject *type); + PyObject *(* boxed_new)(GType boxed_type, gpointer boxed, + gboolean copy_boxed, gboolean own_ref); + + PyTypeObject *pointer_type; + void (* register_pointer)(PyObject *dict, const gchar *class_name, + GType pointer_type, PyTypeObject *type); + PyObject *(* pointer_new)(GType boxed_type, gpointer pointer); + + void (* enum_add_constants)(PyObject *module, GType enum_type, + const gchar *strip_prefix); + void (* flags_add_constants)(PyObject *module, GType flags_type, + const gchar *strip_prefix); + + const gchar *(* constant_strip_prefix)(const gchar *name, + const gchar *strip_prefix); + + gboolean (* error_check)(GError **error); + + /* hooks to register handlers for getting GDK threads to cooperate + * with python threading */ + void (* set_thread_block_funcs) (PyGThreadBlockFunc block_threads_func, + PyGThreadBlockFunc unblock_threads_func); + PyGThreadBlockFunc block_threads; + PyGThreadBlockFunc unblock_threads; + + PyTypeObject *paramspec_type; + PyObject *(* paramspec_new)(GParamSpec *spec); + GParamSpec *(*paramspec_get)(PyObject *tuple); + int (*pyobj_to_unichar_conv)(PyObject *pyobj, void* ptr); + gboolean (*parse_constructor_args)(GType obj_type, + char **arg_names, + char **prop_names, + GParameter *params, + guint *nparams, + PyObject **py_args); + PyObject *(* param_gvalue_as_pyobject) (const GValue* gvalue, + gboolean copy_boxed, + const GParamSpec* pspec); + int (* gvalue_from_param_pyobject) (GValue* value, + PyObject* py_obj, + const GParamSpec* pspec); + PyTypeObject *enum_type; + PyObject *(*enum_add)(PyObject *module, + const char *type_name_, + const char *strip_prefix, + GType gtype); + PyObject* (*enum_from_gtype)(GType gtype, int value); + + PyTypeObject *flags_type; + PyObject *(*flags_add)(PyObject *module, + const char *type_name_, + const char *strip_prefix, + GType gtype); + PyObject* (*flags_from_gtype)(GType gtype, guint value); + + gboolean threads_enabled; + int (*enable_threads) (void); + + int (*gil_state_ensure) (void); + void (*gil_state_release) (int flag); + + void (*register_class_init) (GType gtype, PyGClassInitFunc class_init); + void (*register_interface_info) (GType gtype, const GInterfaceInfo *info); + void (*closure_set_exception_handler) (GClosure *closure, PyClosureExceptionHandler handler); + + void (*add_warning_redirection) (const char *domain, + PyObject *warning); + void (*disable_warning_redirections) (void); + + /* type_register_custom API now removed, but leave a pointer here to not + * break ABI. */ + void *_type_register_custom; + + gboolean (*gerror_exception_check) (GError **error); + PyObject* (*option_group_new) (GOptionGroup *group); + GType (* type_from_object_strict) (PyObject *obj, gboolean strict); + + PyObject *(* newgobj_full)(GObject *obj, gboolean steal, gpointer g_class); + PyTypeObject *object_type; + int (* value_from_pyobject_with_error)(GValue *value, PyObject *obj); +}; + + +#ifdef DISABLE_THREADING +# define pyg_threads_enabled FALSE +# define pyg_gil_state_ensure() 0 +# define pyg_gil_state_release(state) +# define pyg_begin_allow_threads G_STMT_START { +# define pyg_end_allow_threads } G_STMT_END +#else +# define pyg_threads_enabled TRUE +# define pyg_gil_state_ensure PyGILState_Ensure +# define pyg_gil_state_release PyGILState_Release +# define pyg_begin_allow_threads Py_BEGIN_ALLOW_THREADS +# define pyg_end_allow_threads Py_END_ALLOW_THREADS +#endif + +/* Deprecated, only available for API compatibility. */ +#define pyg_enable_threads() +#define pyg_set_thread_block_funcs(a, b) +#define pyg_block_threads() +#define pyg_unblock_threads() + + +#ifndef _INSIDE_PYGOBJECT_ + +#if defined(NO_IMPORT) || defined(NO_IMPORT_PYGOBJECT) +extern struct _PyGObject_Functions *_PyGObject_API; +#else +struct _PyGObject_Functions *_PyGObject_API; +#endif + +#define pygobject_register_class (_PyGObject_API->register_class) +#define pygobject_register_wrapper (_PyGObject_API->register_wrapper) +#define pygobject_lookup_class (_PyGObject_API->lookup_class) +#define pygobject_new (_PyGObject_API->newgobj) +#define pygobject_new_full (_PyGObject_API->newgobj_full) +#define PyGObject_Type (*_PyGObject_API->object_type) +#define pyg_closure_new (_PyGObject_API->closure_new) +#define pygobject_watch_closure (_PyGObject_API->object_watch_closure) +#define pyg_closure_set_exception_handler (_PyGObject_API->closure_set_exception_handler) +#define pyg_destroy_notify (_PyGObject_API->destroy_notify) +#define pyg_type_from_object_strict (_PyGObject_API->type_from_object_strict) +#define pyg_type_from_object (_PyGObject_API->type_from_object) +#define pyg_type_wrapper_new (_PyGObject_API->type_wrapper_new) +#define pyg_enum_get_value (_PyGObject_API->enum_get_value) +#define pyg_flags_get_value (_PyGObject_API->flags_get_value) +#define pyg_register_gtype_custom (_PyGObject_API->register_gtype_custom) +#define pyg_value_from_pyobject (_PyGObject_API->value_from_pyobject) +#define pyg_value_from_pyobject_with_error (_PyGObject_API->value_from_pyobject_with_error) +#define pyg_value_as_pyobject (_PyGObject_API->value_as_pyobject) +#define pyg_register_interface (_PyGObject_API->register_interface) +#define PyGBoxed_Type (*_PyGObject_API->boxed_type) +#define pyg_register_boxed (_PyGObject_API->register_boxed) +#define pyg_boxed_new (_PyGObject_API->boxed_new) +#define PyGPointer_Type (*_PyGObject_API->pointer_type) +#define pyg_register_pointer (_PyGObject_API->register_pointer) +#define pyg_pointer_new (_PyGObject_API->pointer_new) +#define pyg_enum_add_constants (_PyGObject_API->enum_add_constants) +#define pyg_flags_add_constants (_PyGObject_API->flags_add_constants) +#define pyg_constant_strip_prefix (_PyGObject_API->constant_strip_prefix) +#define pyg_error_check (_PyGObject_API->error_check) +#define PyGParamSpec_Type (*_PyGObject_API->paramspec_type) +#define pyg_param_spec_new (_PyGObject_API->paramspec_new) +#define pyg_param_spec_from_object (_PyGObject_API->paramspec_get) +#define pyg_pyobj_to_unichar_conv (_PyGObject_API->pyobj_to_unichar_conv) +#define pyg_parse_constructor_args (_PyGObject_API->parse_constructor_args) +#define pyg_param_gvalue_as_pyobject (_PyGObject_API->value_as_pyobject) +#define pyg_param_gvalue_from_pyobject (_PyGObject_API->gvalue_from_param_pyobject) +#define PyGEnum_Type (*_PyGObject_API->enum_type) +#define pyg_enum_add (_PyGObject_API->enum_add) +#define pyg_enum_from_gtype (_PyGObject_API->enum_from_gtype) +#define PyGFlags_Type (*_PyGObject_API->flags_type) +#define pyg_flags_add (_PyGObject_API->flags_add) +#define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype) +#define pyg_register_class_init (_PyGObject_API->register_class_init) +#define pyg_register_interface_info (_PyGObject_API->register_interface_info) +#define pyg_add_warning_redirection (_PyGObject_API->add_warning_redirection) +#define pyg_disable_warning_redirections (_PyGObject_API->disable_warning_redirections) +#define pyg_gerror_exception_check (_PyGObject_API->gerror_exception_check) +#define pyg_option_group_new (_PyGObject_API->option_group_new) + + +/** + * pygobject_init: + * @req_major: minimum version major number, or -1 + * @req_minor: minimum version minor number, or -1 + * @req_micro: minimum version micro number, or -1 + * + * Imports and initializes the 'gobject' python module. Can + * optionally check for a required minimum version if @req_major, + * @req_minor, and @req_micro are all different from -1. + * + * Returns: a new reference to the gobject module on success, NULL in + * case of failure (and raises ImportError). + **/ +static inline PyObject * +pygobject_init(int req_major, int req_minor, int req_micro) +{ + PyObject *gobject, *cobject; + + gobject = PyImport_ImportModule("gi._gobject"); + if (!gobject) { + 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); + + +#if PY_VERSION_HEX < 0x03000000 + PyErr_Format(PyExc_ImportError, + "could not import gobject (error was: %s)", + PyString_AsString(py_orig_exc)); +#else + { + /* Can not use PyErr_Format because it doesn't have + * a format string for dealing with PyUnicode objects + * like PyUnicode_FromFormat has + */ + PyObject *errmsg = PyUnicode_FromFormat("could not import gobject (error was: %U)", + py_orig_exc); + + if (errmsg) { + PyErr_SetObject(PyExc_ImportError, + errmsg); + Py_DECREF(errmsg); + } + /* if errmsg is NULL then we might have OOM + * PyErr should already be set and trying to + * return our own error would be futile + */ + } +#endif + Py_DECREF(py_orig_exc); + } else { + PyErr_SetString(PyExc_ImportError, + "could not import gobject (no error given)"); + } + return NULL; + } + + cobject = PyObject_GetAttrString(gobject, "_PyGObject_API"); + if (cobject && PyCapsule_CheckExact(cobject)) + _PyGObject_API = (struct _PyGObject_Functions *) PyCapsule_GetPointer(cobject, "gobject._PyGObject_API"); + else { + PyErr_SetString(PyExc_ImportError, + "could not import gobject (could not find _PyGObject_API object)"); + Py_DECREF(gobject); + return NULL; + } + + if (req_major != -1) + { + int found_major, found_minor, found_micro; + PyObject *version; + + version = PyObject_GetAttrString(gobject, "pygobject_version"); + if (!version) { + PyErr_SetString(PyExc_ImportError, + "could not import gobject (version too old)"); + Py_DECREF(gobject); + return NULL; + } + if (!PyArg_ParseTuple(version, "iii", + &found_major, &found_minor, &found_micro)) { + PyErr_SetString(PyExc_ImportError, + "could not import gobject (version has invalid format)"); + Py_DECREF(version); + Py_DECREF(gobject); + return NULL; + } + Py_DECREF(version); + if (req_major != found_major || + req_minor > found_minor || + (req_minor == found_minor && req_micro > found_micro)) { + PyErr_Format(PyExc_ImportError, + "could not import gobject (version mismatch, %d.%d.%d is required, " + "found %d.%d.%d)", req_major, req_minor, req_micro, + found_major, found_minor, found_micro); + Py_DECREF(gobject); + return NULL; + } + } + return gobject; +} + +/** + * PYLIST_FROMGLIBLIST: + * @type: the type of the GLib list e.g. #GList or #GSList + * @prefix: the prefix of functions that manipulate a list of the type + * given by type. + * + * A macro that creates a type specific code block which converts a GLib + * list (#GSList or #GList) to a Python list. The first two args of the macro + * are used to specify the type and list function prefix so that the type + * specific macros can be generated. + * + * The rest of the args are for the standard args for the type specific + * macro(s) created from this macro. + */ + #define PYLIST_FROMGLIBLIST(type,prefix,py_list,list,item_convert_func,\ + list_free,list_item_free) \ +G_STMT_START \ +{ \ + gint i, len; \ + PyObject *item; \ + void (*glib_list_free)(type*) = list_free; \ + GFunc glib_list_item_free = (GFunc)list_item_free; \ + \ + len = prefix##_length(list); \ + py_list = PyList_New(len); \ + for (i = 0; i < len; i++) { \ + gpointer list_item = prefix##_nth_data(list, i); \ + \ + item = item_convert_func; \ + PyList_SetItem(py_list, i, item); \ + } \ + if (glib_list_item_free != NULL) \ + prefix##_foreach(list, glib_list_item_free, NULL); \ + if (glib_list_free != NULL) \ + glib_list_free(list); \ +} G_STMT_END + +/** + * PYLIST_FROMGLIST: + * @py_list: the name of the Python list + * + * @list: the #GList to be converted to a Python list + * + * @item_convert_func: the function that converts a list item to a Python + * object. The function must refer to the list item using "@list_item" and + * must return a #PyObject* object. An example conversion function is: + * [[ + * PyString_FromString(list_item) + * ]] + * A more elaborate function is: + * [[ + * pyg_boxed_new(GTK_TYPE_RECENT_INFO, list_item, TRUE, TRUE) + * ]] + * @list_free: the name of a function that takes a single arg (the list) and + * frees its memory. Can be NULL if the list should not be freed. An example + * is: + * [[ + * g_list_free + * ]] + * @list_item_free: the name of a #GFunc function that frees the memory used + * by the items in the list or %NULL if the list items do not have to be + * freed. A simple example is: + * [[ + * g_free + * ]] + * + * A macro that adds code that converts a #GList to a Python list. + * + */ +#define PYLIST_FROMGLIST(py_list,list,item_convert_func,list_free,\ + list_item_free) \ + PYLIST_FROMGLIBLIST(GList,g_list,py_list,list,item_convert_func,\ + list_free,list_item_free) + +/** + * PYLIST_FROMGSLIST: + * @py_list: the name of the Python list + * + * @list: the #GSList to be converted to a Python list + * + * @item_convert_func: the function that converts a list item to a Python + * object. The function must refer to the list item using "@list_item" and + * must return a #PyObject* object. An example conversion function is: + * [[ + * PyString_FromString(list_item) + * ]] + * A more elaborate function is: + * [[ + * pyg_boxed_new(GTK_TYPE_RECENT_INFO, list_item, TRUE, TRUE) + * ]] + * @list_free: the name of a function that takes a single arg (the list) and + * frees its memory. Can be %NULL if the list should not be freed. An example + * is: + * [[ + * g_list_free + * ]] + * @list_item_free: the name of a #GFunc function that frees the memory used + * by the items in the list or %NULL if the list items do not have to be + * freed. A simple example is: + * [[ + * g_free + * ]] + * + * A macro that adds code that converts a #GSList to a Python list. + * + */ +#define PYLIST_FROMGSLIST(py_list,list,item_convert_func,list_free,\ + list_item_free) \ + PYLIST_FROMGLIBLIST(GSList,g_slist,py_list,list,item_convert_func,\ + list_free,list_item_free) + +/** + * PYLIST_ASGLIBLIST + * @type: the type of the GLib list e.g. GList or GSList + * @prefix: the prefix of functions that manipulate a list of the type + * given by type e.g. g_list or g_slist + * + * A macro that creates a type specific code block to be used to convert a + * Python list to a GLib list (GList or GSList). The first two args of the + * macro are used to specify the type and list function prefix so that the + * type specific macros can be generated. + * + * The rest of the args are for the standard args for the type specific + * macro(s) created from this macro. + */ +#define PYLIST_ASGLIBLIST(type,prefix,py_list,list,check_func,\ + convert_func,child_free_func,errormsg,errorreturn) \ +G_STMT_START \ +{ \ + Py_ssize_t i, n_list; \ + GFunc glib_child_free_func = (GFunc)child_free_func; \ + \ + if (!(py_list = PySequence_Fast(py_list, ""))) { \ + errormsg; \ + return errorreturn; \ + } \ + n_list = PySequence_Fast_GET_SIZE(py_list); \ + for (i = 0; i < n_list; i++) { \ + PyObject *py_item = PySequence_Fast_GET_ITEM(py_list, i); \ + \ + if (!check_func) { \ + if (glib_child_free_func) \ + prefix##_foreach(list, glib_child_free_func, NULL); \ + prefix##_free(list); \ + Py_DECREF(py_list); \ + errormsg; \ + return errorreturn; \ + } \ + list = prefix##_prepend(list, convert_func); \ + }; \ + Py_DECREF(py_list); \ + list = prefix##_reverse(list); \ +} \ +G_STMT_END +/** + * PYLIST_ASGLIST + * @py_list: the Python list to be converted + * @list: the #GList list to be converted + * @check_func: the expression that takes a #PyObject* arg (must be named + * @py_item) and returns an int value indicating if the Python object matches + * the required list item type (0 - %False or 1 - %True). An example is: + * [[ + * (PyString_Check(py_item)||PyUnicode_Check(py_item)) + * ]] + * @convert_func: the function that takes a #PyObject* arg (must be named + * py_item) and returns a pointer to the converted list object. An example + * is: + * [[ + * pygobject_get(py_item) + * ]] + * @child_free_func: the name of a #GFunc function that frees a GLib list + * item or %NULL if the list item does not have to be freed. This function is + * used to help free the items in a partially created list if there is an + * error. An example is: + * [[ + * g_free + * ]] + * @errormsg: a function that sets up a Python error message. An example is: + * [[ + * PyErr_SetString(PyExc_TypeError, "strings must be a sequence of" "strings + * or unicode objects") + * ]] + * @errorreturn: the value to return if an error occurs, e.g.: + * [[ + * %NULL + * ]] + * + * A macro that creates code that converts a Python list to a #GList. The + * returned list must be freed using the appropriate list free function when + * it's no longer needed. If an error occurs the child_free_func is used to + * release the memory used by the list items and then the list memory is + * freed. + */ +#define PYLIST_ASGLIST(py_list,list,check_func,convert_func,child_free_func,\ + errormsg,errorreturn) \ + PYLIST_ASGLIBLIST(GList,g_list,py_list,list,check_func,convert_func,\ + child_free_func,errormsg,errorreturn) + +/** + * PYLIST_ASGSLIST + * @py_list: the Python list to be converted + * @list: the #GSList list to be converted + * @check_func: the expression that takes a #PyObject* arg (must be named + * @py_item) and returns an int value indicating if the Python object matches + * the required list item type (0 - %False or 1 - %True). An example is: + * [[ + * (PyString_Check(py_item)||PyUnicode_Check(py_item)) + * ]] + * @convert_func: the function that takes a #PyObject* arg (must be named + * py_item) and returns a pointer to the converted list object. An example + * is: + * [[ + * pygobject_get(py_item) + * ]] + * @child_free_func: the name of a #GFunc function that frees a GLib list + * item or %NULL if the list item does not have to be freed. This function is + * used to help free the items in a partially created list if there is an + * error. An example is: + * [[ + * g_free + * ]] + * @errormsg: a function that sets up a Python error message. An example is: + * [[ + * PyErr_SetString(PyExc_TypeError, "strings must be a sequence of" "strings + * or unicode objects") + * ]] + * @errorreturn: the value to return if an error occurs, e.g.: + * [[ + * %NULL + * ]] + * + * A macro that creates code that converts a Python list to a #GSList. The + * returned list must be freed using the appropriate list free function when + * it's no longer needed. If an error occurs the child_free_func is used to + * release the memory used by the list items and then the list memory is + * freed. + */ +#define PYLIST_ASGSLIST(py_list,list,check_func,convert_func,child_free_func,\ + errormsg,errorreturn) \ + PYLIST_ASGLIBLIST(GSList,g_slist,py_list,list,check_func,convert_func,\ + child_free_func,errormsg,errorreturn) + +#endif /* !_INSIDE_PYGOBJECT_ */ + +G_END_DECLS + +#endif /* !_PYGOBJECT_H_ */ diff --git a/gi/pygparamspec.c b/gi/pygparamspec.c new file mode 100644 index 00000000..938f7975 --- /dev/null +++ b/gi/pygparamspec.c @@ -0,0 +1,418 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * pygenum.c: GEnum and GFlag wrappers + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "pygobject-private.h" +#include "pygparamspec.h" + +PYGLIB_DEFINE_TYPE("gobject.GParamSpec", PyGParamSpec_Type, PyGParamSpec); + +static PyObject* +pyg_param_spec_richcompare(PyObject *self, PyObject *other, int op) +{ + if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGParamSpec_Type) + return _pyglib_generic_ptr_richcompare(((PyGParamSpec*)self)->pspec, + ((PyGParamSpec*)other)->pspec, + op); + else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static long +pyg_param_spec_hash(PyGParamSpec *self) +{ + return (long)self->pspec; +} + +static PyObject * +pyg_param_spec_repr(PyGParamSpec *self) +{ + char buf[80]; + + g_snprintf(buf, sizeof(buf), "<%s '%s'>", + G_PARAM_SPEC_TYPE_NAME(self->pspec), + g_param_spec_get_name(self->pspec)); + return PYGLIB_PyUnicode_FromString(buf); +} + +static void +pyg_param_spec_dealloc(PyGParamSpec *self) +{ + g_param_spec_unref(self->pspec); + PyObject_DEL(self); +} + + +static PyObject * +pygenum_from_pspec(GParamSpec *pspec) +{ + PyObject *pyclass; + GParamSpecEnum *enum_pspec; + GType enum_type; + + enum_pspec = G_PARAM_SPEC_ENUM(pspec); + enum_type = G_ENUM_CLASS_TYPE(enum_pspec->enum_class); + pyclass = (PyObject*)g_type_get_qdata(enum_type, pygenum_class_key); + if (pyclass == NULL) { + pyclass = pyg_enum_add(NULL, g_type_name(enum_type), NULL, enum_type); + if (pyclass == NULL) + pyclass = Py_None; + } + + Py_INCREF(pyclass); + return pyclass; +} + +static PyObject * +pygflags_from_pspec(GParamSpec *pspec) +{ + PyObject *pyclass; + GParamSpecFlags *flag_pspec; + GType flag_type; + + flag_pspec = G_PARAM_SPEC_FLAGS(pspec); + flag_type = G_FLAGS_CLASS_TYPE(flag_pspec->flags_class); + pyclass = (PyObject*)g_type_get_qdata(flag_type, pygflags_class_key); + if (pyclass == NULL) { + pyclass = pyg_flags_add(NULL, g_type_name(flag_type), NULL, flag_type); + if (pyclass == NULL) + pyclass = Py_None; + } + Py_INCREF(pyclass); + return pyclass; +} + +static PyObject * +pyg_param_spec_getattr(PyGParamSpec *self, const gchar *attr) +{ + GParamSpec *pspec; + + pspec = self->pspec; + + /* common attributes */ + if (!strcmp(attr, "__gtype__")) { + return pyg_type_wrapper_new(G_PARAM_SPEC_TYPE(pspec)); + } else if (!strcmp(attr, "name")) { + return Py_BuildValue("s", g_param_spec_get_name(pspec)); + } else if (!strcmp(attr, "nick")) { + return Py_BuildValue("s", g_param_spec_get_nick(pspec)); + } else if (!strcmp(attr, "blurb") || !strcmp(attr, "__doc__")) { + return Py_BuildValue("s", g_param_spec_get_blurb(pspec)); + } else if (!strcmp(attr, "flags")) { + return PYGLIB_PyLong_FromLong(pspec->flags); + } else if (!strcmp(attr, "value_type")) { + return pyg_type_wrapper_new(pspec->value_type); + } else if (!strcmp(attr, "owner_type")) { + return pyg_type_wrapper_new(pspec->owner_type); + } + + if (G_IS_PARAM_SPEC_CHAR(pspec)) { + if (!strcmp(attr, "default_value")) { + return PYGLIB_PyUnicode_FromFormat( + "%c", G_PARAM_SPEC_CHAR(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_CHAR(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_CHAR(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { + if (!strcmp(attr, "default_value")) { + return PYGLIB_PyUnicode_FromFormat( + "%c", G_PARAM_SPEC_UCHAR(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_UCHAR(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_UCHAR(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyBool_FromLong(G_PARAM_SPEC_BOOLEAN(pspec)->default_value); + } + } else if (G_IS_PARAM_SPEC_INT(pspec)) { + if (!strcmp(attr, "default_value")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UINT(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_LONG(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_INT64(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + if (!strcmp(attr, "default_value")) { + return PYGLIB_PyUnicode_FromFormat( + "%c", G_PARAM_SPEC_UNICHAR(pspec)->default_value); + } + } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { + if (!strcmp(attr, "default_value")) { + return pyg_enum_from_gtype( + pspec->value_type, G_PARAM_SPEC_ENUM(pspec)->default_value); + } else if (!strcmp(attr, "enum_class")) { + return pygenum_from_pspec(pspec); + } + } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { + if (!strcmp(attr, "default_value")) { + return pyg_flags_from_gtype( + pspec->value_type, G_PARAM_SPEC_FLAGS(pspec)->default_value); + } else if (!strcmp(attr, "flags_class")) { + return pygflags_from_pspec(pspec); + } + } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->maximum); + } else if (!strcmp(attr, "epsilon")) { + return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->epsilon); + } + } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyFloat_FromDouble( + G_PARAM_SPEC_DOUBLE(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->maximum); + } else if (!strcmp(attr, "epsilon")) { + return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->epsilon); + } + } else if (G_IS_PARAM_SPEC_STRING(pspec)) { + if (!strcmp(attr, "default_value")) { + return Py_BuildValue( + "s", G_PARAM_SPEC_STRING(pspec)->default_value); + } else if (!strcmp(attr, "cset_first")) { + return Py_BuildValue( + "s", G_PARAM_SPEC_STRING(pspec)->cset_first); + } else if (!strcmp(attr, "cset_nth")) { + return Py_BuildValue( + "s", G_PARAM_SPEC_STRING(pspec)->cset_nth); + } else if (!strcmp(attr, "substitutor")) { + return Py_BuildValue( + "c", G_PARAM_SPEC_STRING(pspec)->substitutor); + } else if (!strcmp(attr, "null_fold_if_empty")) { + return PyBool_FromLong( + G_PARAM_SPEC_STRING(pspec)->null_fold_if_empty); + } else if (!strcmp(attr, "ensure_non_null")) { + return PyBool_FromLong( + G_PARAM_SPEC_STRING(pspec)->ensure_non_null); + } + } else { + /* This is actually not what's exported by GObjects paramspecs, + * But we exported this in earlier versions, so it's better to keep it here + * compatibility. But don't return it in __dir__, to "hide" it. + */ + if (!strcmp(attr, "default_value")) { + /* XXX: Raise deprecation warning */ + Py_INCREF(Py_None); + return Py_None; + } + } + + PyErr_SetString(PyExc_AttributeError, attr); + return NULL; +} + + +static PyObject * +pyg_param_spec_dir(PyGParamSpec *self, PyObject *dummy) +{ + GParamSpec *pspec = self->pspec; + + if (G_IS_PARAM_SPEC_CHAR(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", "flags", + "maximum", "minimum", "name", "nick", + "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", + "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { + return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_INT(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_UINT(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", + "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_LONG(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_INT64(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", + "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { + return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", "enum_class", + "flags", "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { + return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "flags_class", "name", "nick", + "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { + return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", + "blurb", "epsilon", + "flags", "maximum", "minimum", "name", "nick", "owner_type", + "value_type", + "default_value"); + } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { + return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", "epsilon", + "flags", "maximum", "minimum", "name", "nick", + "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_STRING(pspec)) { + return Py_BuildValue("[ssssssssssssss]", "__doc__", "__gtype__", + "blurb", "cset_first", "cset_nth", "default_value", + "ensure_non_null", "flags", "name", "nick", + "null_fold_if_empty", "owner_type", "substitutor", + "value_type"); + } else { + return Py_BuildValue("[ssssssss]", "__doc__", "__gtype__", "blurb", + "flags", "name", "nick", + "owner_type", "value_type"); + } +} + +static PyMethodDef pyg_param_spec_methods[] = { + { "__dir__", (PyCFunction)pyg_param_spec_dir, METH_NOARGS}, + { NULL, NULL, 0} +}; + +/** + * pyg_param_spec_new: + * @pspec: a GParamSpec. + * + * Creates a wrapper for a GParamSpec. + * + * Returns: the GParamSpec wrapper. + */ +PyObject * +pyg_param_spec_new(GParamSpec *pspec) +{ + PyGParamSpec *self; + + self = (PyGParamSpec *)PyObject_NEW(PyGParamSpec, + &PyGParamSpec_Type); + if (self == NULL) + return NULL; + + self->pspec = g_param_spec_ref(pspec); + return (PyObject *)self; +} + +void +pygobject_paramspec_register_types(PyObject *d) +{ + Py_TYPE(&PyGParamSpec_Type) = &PyType_Type; + PyGParamSpec_Type.tp_dealloc = (destructor)pyg_param_spec_dealloc; + PyGParamSpec_Type.tp_getattr = (getattrfunc)pyg_param_spec_getattr; + PyGParamSpec_Type.tp_richcompare = pyg_param_spec_richcompare; + PyGParamSpec_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGParamSpec_Type.tp_repr = (reprfunc)pyg_param_spec_repr; + PyGParamSpec_Type.tp_hash = (hashfunc)pyg_param_spec_hash; + PyGParamSpec_Type.tp_methods = pyg_param_spec_methods; + + + if (PyType_Ready(&PyGParamSpec_Type)) + return; + PyDict_SetItemString(d, "GParamSpec", (PyObject *)&PyGParamSpec_Type); +} diff --git a/gi/pygparamspec.h b/gi/pygparamspec.h new file mode 100644 index 00000000..b3ba8ca8 --- /dev/null +++ b/gi/pygparamspec.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_PARAMSPEC_H__ +#define __PYGOBJECT_PARAMSPEC_H__ + +#include + +extern PyTypeObject PyGParamSpec_Type; +PyObject * pyg_param_spec_new (GParamSpec *pspec); + +void pygobject_paramspec_register_types(PyObject *d); + +#endif /* __PYGOBJECT_PARAMSPEC_H__ */ diff --git a/gi/pygpointer.c b/gi/pygpointer.c new file mode 100644 index 00000000..575c7511 --- /dev/null +++ b/gi/pygpointer.c @@ -0,0 +1,198 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * pygpointer.c: wrapper for GPointer + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "pygobject-private.h" +#include "pygpointer.h" + +#include "pygi.h" + + +GQuark pygpointer_class_key; + +PYGLIB_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer); + +static void +pyg_pointer_dealloc(PyGPointer *self) +{ + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject* +pyg_pointer_richcompare(PyObject *self, PyObject *other, int op) +{ + if (Py_TYPE(self) == Py_TYPE(other)) + return _pyglib_generic_ptr_richcompare(((PyGPointer*)self)->pointer, + ((PyGPointer*)other)->pointer, + op); + else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static long +pyg_pointer_hash(PyGPointer *self) +{ + return (long)self->pointer; +} + +static PyObject * +pyg_pointer_repr(PyGPointer *self) +{ + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), + (long)self->pointer); + return PYGLIB_PyUnicode_FromString(buf); +} + +static int +pyg_pointer_init(PyGPointer *self, PyObject *args, PyObject *kwargs) +{ + gchar buf[512]; + + if (!PyArg_ParseTuple(args, ":GPointer.__init__")) + return -1; + + self->pointer = NULL; + self->gtype = 0; + + g_snprintf(buf, sizeof(buf), "%s can not be constructed", + Py_TYPE(self)->tp_name); + PyErr_SetString(PyExc_NotImplementedError, buf); + return -1; +} + +static void +pyg_pointer_free(PyObject *op) +{ + PyObject_FREE(op); +} + +/** + * pyg_register_pointer: + * @dict: the module dictionary to store the wrapper class. + * @class_name: the Python name for the wrapper class. + * @pointer_type: the GType of the pointer type being wrapped. + * @type: the wrapper class. + * + * Registers a wrapper for a pointer type. The wrapper class will be + * a subclass of gobject.GPointer, and a reference to the wrapper + * class will be stored in the provided module dictionary. + */ +void +pyg_register_pointer(PyObject *dict, const gchar *class_name, + GType pointer_type, PyTypeObject *type) +{ + PyObject *o; + + g_return_if_fail(dict != NULL); + g_return_if_fail(class_name != NULL); + g_return_if_fail(pointer_type != 0); + + if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_pointer_dealloc; + + Py_TYPE(type) = &PyType_Type; + type->tp_base = &PyGPointer_Type; + + if (PyType_Ready(type) < 0) { + g_warning("could not get type `%s' ready", type->tp_name); + return; + } + + PyDict_SetItemString(type->tp_dict, "__gtype__", + o=pyg_type_wrapper_new(pointer_type)); + Py_DECREF(o); + + g_type_set_qdata(pointer_type, pygpointer_class_key, type); + + PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); +} + +/** + * pyg_pointer_new: + * @pointer_type: the GType of the pointer value. + * @pointer: the pointer value. + * + * Creates a wrapper for a pointer value. Since G_TYPE_POINTER types + * don't register any information about how to copy/free them, there + * is no guarantee that the pointer will remain valid, and there is + * nothing registered to release the pointer when the pointer goes out + * of scope. This is why we don't recommend people use these types. + * + * Returns: the boxed wrapper. + */ +PyObject * +pyg_pointer_new(GType pointer_type, gpointer pointer) +{ + PyGILState_STATE state; + PyGPointer *self; + PyTypeObject *tp; + g_return_val_if_fail(pointer_type != 0, NULL); + + state = pyglib_gil_state_ensure(); + + if (!pointer) { + Py_INCREF(Py_None); + pyglib_gil_state_release(state); + return Py_None; + } + + tp = g_type_get_qdata(pointer_type, pygpointer_class_key); + + if (!tp) + tp = (PyTypeObject *)pygi_type_import_by_g_type(pointer_type); + + if (!tp) + tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */ + self = PyObject_NEW(PyGPointer, tp); + + pyglib_gil_state_release(state); + + if (self == NULL) + return NULL; + + self->pointer = pointer; + self->gtype = pointer_type; + + return (PyObject *)self; +} + +void +pygobject_pointer_register_types(PyObject *d) +{ + pygpointer_class_key = g_quark_from_static_string("PyGPointer::class"); + + PyGPointer_Type.tp_dealloc = (destructor)pyg_pointer_dealloc; + PyGPointer_Type.tp_richcompare = pyg_pointer_richcompare; + PyGPointer_Type.tp_repr = (reprfunc)pyg_pointer_repr; + PyGPointer_Type.tp_hash = (hashfunc)pyg_pointer_hash; + PyGPointer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGPointer_Type.tp_init = (initproc)pyg_pointer_init; + PyGPointer_Type.tp_free = (freefunc)pyg_pointer_free; + PYGOBJECT_REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER); +} diff --git a/gi/pygpointer.h b/gi/pygpointer.h new file mode 100644 index 00000000..f2923daa --- /dev/null +++ b/gi/pygpointer.h @@ -0,0 +1,27 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_POINTER_H__ +#define __PYGOBJECT_POINTER_H__ + +void pygobject_pointer_register_types(PyObject *d); + +#endif /* __PYGOBJECT_POINTER_H__ */ diff --git a/gi/pygtype.c b/gi/pygtype.c new file mode 100644 index 00000000..9dc1153e --- /dev/null +++ b/gi/pygtype.c @@ -0,0 +1,1927 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * pygtype.c: glue code to wrap the GType code. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "pygobject-private.h" +#include "pygparamspec.h" +#include "pygtype.h" + +/* -------------- __gtype__ objects ---------------------------- */ + +typedef struct { + PyObject_HEAD + GType type; +} PyGTypeWrapper; + +PYGLIB_DEFINE_TYPE("gobject.GType", PyGTypeWrapper_Type, PyGTypeWrapper); + +static PyObject* +pyg_type_wrapper_richcompare(PyObject *self, PyObject *other, int op) +{ + if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGTypeWrapper_Type) + return _pyglib_generic_long_richcompare(((PyGTypeWrapper*)self)->type, + ((PyGTypeWrapper*)other)->type, + op); + else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static long +pyg_type_wrapper_hash(PyGTypeWrapper *self) +{ + return (long)self->type; +} + +static PyObject * +pyg_type_wrapper_repr(PyGTypeWrapper *self) +{ + char buf[80]; + const gchar *name = g_type_name(self->type); + + g_snprintf(buf, sizeof(buf), "", + name?name:"invalid", (unsigned long int) self->type); + return PYGLIB_PyUnicode_FromString(buf); +} + +static void +pyg_type_wrapper_dealloc(PyGTypeWrapper *self) +{ + PyObject_DEL(self); +} + +static GQuark +_pyg_type_key(GType type) { + GQuark key; + + if (g_type_is_a(type, G_TYPE_INTERFACE)) { + key = pyginterface_type_key; + } else if (g_type_is_a(type, G_TYPE_ENUM)) { + key = pygenum_class_key; + } else if (g_type_is_a(type, G_TYPE_FLAGS)) { + key = pygflags_class_key; + } else if (g_type_is_a(type, G_TYPE_POINTER)) { + key = pygpointer_class_key; + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + key = pygboxed_type_key; + } else { + key = pygobject_class_key; + } + + return key; +} + +static PyObject * +_wrap_g_type_wrapper__get_pytype(PyGTypeWrapper *self, void *closure) +{ + GQuark key; + PyObject *py_type; + + key = _pyg_type_key(self->type); + + py_type = g_type_get_qdata(self->type, key); + if (!py_type) + py_type = Py_None; + + Py_INCREF(py_type); + return py_type; +} + +static int +_wrap_g_type_wrapper__set_pytype(PyGTypeWrapper *self, PyObject* value, void *closure) +{ + GQuark key; + PyObject *py_type; + + key = _pyg_type_key(self->type); + + py_type = g_type_get_qdata(self->type, key); + Py_CLEAR(py_type); + if (value == Py_None) + g_type_set_qdata(self->type, key, NULL); + else if (PyType_Check(value)) { + Py_INCREF(value); + g_type_set_qdata(self->type, key, value); + } else { + PyErr_SetString(PyExc_TypeError, "Value must be None or a type object"); + return -1; + } + + return 0; +} + +static PyObject * +_wrap_g_type_wrapper__get_name(PyGTypeWrapper *self, void *closure) +{ + const char *name = g_type_name(self->type); + return PYGLIB_PyUnicode_FromString(name ? name : "invalid"); +} + +static PyObject * +_wrap_g_type_wrapper__get_parent(PyGTypeWrapper *self, void *closure) +{ + return pyg_type_wrapper_new(g_type_parent(self->type)); +} + +static PyObject * +_wrap_g_type_wrapper__get_fundamental(PyGTypeWrapper *self, void *closure) +{ + return pyg_type_wrapper_new(g_type_fundamental(self->type)); +} + +static PyObject * +_wrap_g_type_wrapper__get_children(PyGTypeWrapper *self, void *closure) +{ + guint n_children, i; + GType *children; + PyObject *retval; + + children = g_type_children(self->type, &n_children); + + retval = PyList_New(n_children); + for (i = 0; i < n_children; i++) + PyList_SetItem(retval, i, pyg_type_wrapper_new(children[i])); + g_free(children); + + return retval; +} + +static PyObject * +_wrap_g_type_wrapper__get_interfaces(PyGTypeWrapper *self, void *closure) +{ + guint n_interfaces, i; + GType *interfaces; + PyObject *retval; + + interfaces = g_type_interfaces(self->type, &n_interfaces); + + retval = PyList_New(n_interfaces); + for (i = 0; i < n_interfaces; i++) + PyList_SetItem(retval, i, pyg_type_wrapper_new(interfaces[i])); + g_free(interfaces); + + return retval; +} + +static PyObject * +_wrap_g_type_wrapper__get_depth(PyGTypeWrapper *self, void *closure) +{ + return PYGLIB_PyLong_FromLong(g_type_depth(self->type)); +} + +static PyGetSetDef _PyGTypeWrapper_getsets[] = { + { "pytype", (getter)_wrap_g_type_wrapper__get_pytype, (setter)_wrap_g_type_wrapper__set_pytype }, + { "name", (getter)_wrap_g_type_wrapper__get_name, (setter)0 }, + { "fundamental", (getter)_wrap_g_type_wrapper__get_fundamental, (setter)0 }, + { "parent", (getter)_wrap_g_type_wrapper__get_parent, (setter)0 }, + { "children", (getter)_wrap_g_type_wrapper__get_children, (setter)0 }, + { "interfaces", (getter)_wrap_g_type_wrapper__get_interfaces, (setter)0 }, + { "depth", (getter)_wrap_g_type_wrapper__get_depth, (setter)0 }, + { NULL, (getter)0, (setter)0 } +}; + +static PyObject* +_wrap_g_type_is_interface(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_INTERFACE(self->type)); +} + +static PyObject* +_wrap_g_type_is_classed(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_CLASSED(self->type)); +} + +static PyObject* +_wrap_g_type_is_instantiatable(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_INSTANTIATABLE(self->type)); +} + +static PyObject* +_wrap_g_type_is_derivable(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_DERIVABLE(self->type)); +} + +static PyObject* +_wrap_g_type_is_deep_derivable(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_DEEP_DERIVABLE(self->type)); +} + +static PyObject* +_wrap_g_type_is_abstract(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_ABSTRACT(self->type)); +} + +static PyObject* +_wrap_g_type_is_value_abstract(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_VALUE_ABSTRACT(self->type)); +} + +static PyObject* +_wrap_g_type_is_value_type(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_IS_VALUE_TYPE(self->type)); +} + +static PyObject* +_wrap_g_type_has_value_table(PyGTypeWrapper *self) +{ + return PyBool_FromLong(G_TYPE_HAS_VALUE_TABLE(self->type)); +} + +static PyObject* +_wrap_g_type_from_name(PyGTypeWrapper *_, PyObject *args) +{ + char *type_name; + GType type; + + if (!PyArg_ParseTuple(args, "s:GType.from_name", &type_name)) + return NULL; + + type = g_type_from_name(type_name); + if (type == 0) { + PyErr_SetString(PyExc_RuntimeError, "unknown type name"); + return NULL; + } + + return pyg_type_wrapper_new(type); +} + +static PyObject* +_wrap_g_type_is_a(PyGTypeWrapper *self, PyObject *args) +{ + PyObject *gparent; + GType parent; + + if (!PyArg_ParseTuple(args, "O:GType.is_a", &gparent)) + return NULL; + else if ((parent = pyg_type_from_object(gparent)) == 0) + return NULL; + + return PyBool_FromLong(g_type_is_a(self->type, parent)); +} + +static PyMethodDef _PyGTypeWrapper_methods[] = { + { "is_interface", (PyCFunction)_wrap_g_type_is_interface, METH_NOARGS }, + { "is_classed", (PyCFunction)_wrap_g_type_is_classed, METH_NOARGS }, + { "is_instantiatable", (PyCFunction)_wrap_g_type_is_instantiatable, METH_NOARGS }, + { "is_derivable", (PyCFunction)_wrap_g_type_is_derivable, METH_NOARGS }, + { "is_deep_derivable", (PyCFunction)_wrap_g_type_is_deep_derivable, METH_NOARGS }, + { "is_abstract", (PyCFunction)_wrap_g_type_is_abstract, METH_NOARGS }, + { "is_value_abstract", (PyCFunction)_wrap_g_type_is_value_abstract, METH_NOARGS }, + { "is_value_type", (PyCFunction)_wrap_g_type_is_value_type, METH_NOARGS }, + { "has_value_table", (PyCFunction)_wrap_g_type_has_value_table, METH_NOARGS }, + { "from_name", (PyCFunction)_wrap_g_type_from_name, METH_VARARGS | METH_STATIC }, + { "is_a", (PyCFunction)_wrap_g_type_is_a, METH_VARARGS }, + { NULL, 0, 0 } +}; + +static int +pyg_type_wrapper_init(PyGTypeWrapper *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "object", NULL }; + PyObject *py_object; + GType type; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O:GType.__init__", + kwlist, &py_object)) + return -1; + + if (!(type = pyg_type_from_object(py_object))) + return -1; + + self->type = type; + + return 0; +} + +/** + * pyg_type_wrapper_new: + * type: a GType + * + * Creates a Python wrapper for a GType. + * + * Returns: the Python wrapper. + */ +PyObject * +pyg_type_wrapper_new(GType type) +{ + PyGTypeWrapper *self; + + self = (PyGTypeWrapper *)PyObject_NEW(PyGTypeWrapper, + &PyGTypeWrapper_Type); + if (self == NULL) + return NULL; + + self->type = type; + return (PyObject *)self; +} + +/** + * pyg_type_from_object_strict: + * obj: a Python object + * strict: if set to TRUE, raises an exception if it can't perform the + * conversion + * + * converts a python object to a GType. If strict is set, raises an + * exception if it can't perform the conversion, otherwise returns + * PY_TYPE_OBJECT. + * + * Returns: the corresponding GType, or 0 on error. + */ + +GType +pyg_type_from_object_strict(PyObject *obj, gboolean strict) +{ + PyObject *gtype; + GType type; + + /* NULL check */ + if (!obj) { + PyErr_SetString(PyExc_TypeError, "can't get type from NULL object"); + return 0; + } + + /* map some standard types to primitive GTypes ... */ + if (obj == Py_None) + return G_TYPE_NONE; + if (PyType_Check(obj)) { + PyTypeObject *tp = (PyTypeObject *)obj; + + if (tp == &PYGLIB_PyLong_Type) + return G_TYPE_INT; + else if (tp == &PyBool_Type) + return G_TYPE_BOOLEAN; + else if (tp == &PyLong_Type) + return G_TYPE_LONG; + else if (tp == &PyFloat_Type) + return G_TYPE_DOUBLE; + else if (tp == &PYGLIB_PyUnicode_Type) + return G_TYPE_STRING; + else if (tp == &PyBaseObject_Type) + return PY_TYPE_OBJECT; + } + + if (Py_TYPE(obj) == &PyGTypeWrapper_Type) { + return ((PyGTypeWrapper *)obj)->type; + } + + /* handle strings */ + if (PYGLIB_PyUnicode_Check(obj)) { + gchar *name = PYGLIB_PyUnicode_AsString(obj); + + type = g_type_from_name(name); + if (type != 0) { + return type; + } + } + + /* finally, look for a __gtype__ attribute on the object */ + gtype = PyObject_GetAttrString(obj, "__gtype__"); + + if (gtype) { + if (Py_TYPE(gtype) == &PyGTypeWrapper_Type) { + type = ((PyGTypeWrapper *)gtype)->type; + Py_DECREF(gtype); + return type; + } + Py_DECREF(gtype); + } + + PyErr_Clear(); + + /* Some API like those that take GValues can hold a python object as + * a pointer. This is potentially dangerous becuase everything is + * passed in as a PyObject so we can't actually type check it. Only + * fallback to PY_TYPE_OBJECT if strict checking is disabled + */ + if (!strict) + return PY_TYPE_OBJECT; + + PyErr_SetString(PyExc_TypeError, "could not get typecode from object"); + return 0; +} + +/** + * pyg_type_from_object: + * obj: a Python object + * + * converts a python object to a GType. Raises an exception if it + * can't perform the conversion. + * + * Returns: the corresponding GType, or 0 on error. + */ +GType +pyg_type_from_object(PyObject *obj) +{ + /* Legacy call always defaults to strict type checking */ + return pyg_type_from_object_strict(obj, TRUE); +} + +/* -------------- GValue marshalling ------------------ */ + +/** + * pyg_enum_get_value: + * @enum_type: the GType of the flag. + * @obj: a Python object representing the flag value + * @val: a pointer to the location to store the integer representation of the flag. + * + * Converts a Python object to the integer equivalent. The conversion + * will depend on the type of the Python object. If the object is an + * integer, it is passed through directly. If it is a string, it will + * be treated as a full or short enum name as defined in the GType. + * + * Returns: 0 on success or -1 on failure + */ +gint +pyg_enum_get_value(GType enum_type, PyObject *obj, gint *val) +{ + GEnumClass *eclass = NULL; + gint res = -1; + + g_return_val_if_fail(val != NULL, -1); + if (!obj) { + *val = 0; + res = 0; + } else if (PYGLIB_PyLong_Check(obj)) { + *val = PYGLIB_PyLong_AsLong(obj); + res = 0; + + if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { + g_warning("expected enumeration type %s, but got %s instead", + g_type_name(enum_type), + g_type_name(((PyGEnum *) obj)->gtype)); + } + /* Dumb code duplication, but probably not worth it to have yet another macro. */ + } else if (PyLong_Check(obj)) { + *val = PyLong_AsLong(obj); + res = 0; + + if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { + g_warning("expected enumeration type %s, but got %s instead", + g_type_name(enum_type), + g_type_name(((PyGEnum *) obj)->gtype)); + } + } else if (PYGLIB_PyUnicode_Check(obj)) { + GEnumValue *info; + char *str = PYGLIB_PyUnicode_AsString(obj); + + if (enum_type != G_TYPE_NONE) + eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); + else { + PyErr_SetString(PyExc_TypeError, "could not convert string to enum because there is no GType associated to look up the value"); + res = -1; + } + info = g_enum_get_value_by_name(eclass, str); + g_type_class_unref(eclass); + + if (!info) + info = g_enum_get_value_by_nick(eclass, str); + if (info) { + *val = info->value; + res = 0; + } else { + PyErr_SetString(PyExc_TypeError, "could not convert string"); + res = -1; + } + } else { + PyErr_SetString(PyExc_TypeError,"enum values must be strings or ints"); + res = -1; + } + return res; +} + +/** + * pyg_flags_get_value: + * @flag_type: the GType of the flag. + * @obj: a Python object representing the flag value + * @val: a pointer to the location to store the integer representation of the flag. + * + * Converts a Python object to the integer equivalent. The conversion + * will depend on the type of the Python object. If the object is an + * integer, it is passed through directly. If it is a string, it will + * be treated as a full or short flag name as defined in the GType. + * If it is a tuple, then the items are treated as strings and ORed + * together. + * + * Returns: 0 on success or -1 on failure + */ +gint +pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val) +{ + GFlagsClass *fclass = NULL; + gint res = -1; + + g_return_val_if_fail(val != NULL, -1); + if (!obj) { + *val = 0; + res = 0; + } else if (PYGLIB_PyLong_Check(obj)) { + *val = PYGLIB_PyLong_AsUnsignedLong(obj); + res = 0; + } else if (PyLong_Check(obj)) { + *val = PyLong_AsLongLong(obj); + res = 0; + } else if (PYGLIB_PyUnicode_Check(obj)) { + GFlagsValue *info; + char *str = PYGLIB_PyUnicode_AsString(obj); + + if (flag_type != G_TYPE_NONE) + fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); + else { + PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); + res = -1; + } + info = g_flags_get_value_by_name(fclass, str); + g_type_class_unref(fclass); + + if (!info) + info = g_flags_get_value_by_nick(fclass, str); + if (info) { + *val = info->value; + res = 0; + } else { + PyErr_SetString(PyExc_TypeError, "could not convert string"); + res = -1; + } + } else if (PyTuple_Check(obj)) { + int i, len; + + len = PyTuple_Size(obj); + *val = 0; + res = 0; + + if (flag_type != G_TYPE_NONE) + fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); + else { + PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); + res = -1; + } + + for (i = 0; i < len; i++) { + PyObject *item = PyTuple_GetItem(obj, i); + char *str = PYGLIB_PyUnicode_AsString(item); + GFlagsValue *info = g_flags_get_value_by_name(fclass, str); + + if (!info) + info = g_flags_get_value_by_nick(fclass, str); + if (info) { + *val |= info->value; + } else { + PyErr_SetString(PyExc_TypeError, "could not convert string"); + res = -1; + break; + } + } + g_type_class_unref(fclass); + } else { + PyErr_SetString(PyExc_TypeError, + "flag values must be strings, ints, longs, or tuples"); + res = -1; + } + return res; +} + +typedef struct { + fromvaluefunc fromvalue; + tovaluefunc tovalue; +} PyGTypeMarshal; +static GQuark pyg_type_marshal_key = 0; + +static PyGTypeMarshal * +pyg_type_lookup(GType type) +{ + GType ptype = type; + PyGTypeMarshal *tm = NULL; + + /* recursively lookup types */ + while (ptype) { + if ((tm = g_type_get_qdata(ptype, pyg_type_marshal_key)) != NULL) + break; + ptype = g_type_parent(ptype); + } + return tm; +} + +/** + * pyg_register_gtype_custom: + * @gtype: the GType for the new type + * @from_func: a function to convert GValues to Python objects + * @to_func: a function to convert Python objects to GValues + * + * In order to handle specific conversion of gboxed types or new + * fundamental types, you may use this function to register conversion + * handlers. + */ + +void +pyg_register_gtype_custom(GType gtype, + fromvaluefunc from_func, + tovaluefunc to_func) +{ + PyGTypeMarshal *tm; + + if (!pyg_type_marshal_key) + pyg_type_marshal_key = g_quark_from_static_string("PyGType::marshal"); + + tm = g_new(PyGTypeMarshal, 1); + tm->fromvalue = from_func; + tm->tovalue = to_func; + g_type_set_qdata(gtype, pyg_type_marshal_key, tm); +} + +static int +pyg_value_array_from_pyobject(GValue *value, + PyObject *obj, + const GParamSpecValueArray *pspec) +{ + int len; + GValueArray *value_array; + int i; + + len = PySequence_Length(obj); + if (len == -1) { + PyErr_Clear(); + return -1; + } + + if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements) + return -1; + + value_array = g_value_array_new(len); + + for (i = 0; i < len; ++i) { + PyObject *item = PySequence_GetItem(obj, i); + GType type; + GValue item_value = { 0, }; + int status; + + if (! item) { + PyErr_Clear(); + g_value_array_free(value_array); + return -1; + } + + if (pspec && pspec->element_spec) + type = G_PARAM_SPEC_VALUE_TYPE(pspec->element_spec); + else if (item == Py_None) + type = G_TYPE_POINTER; /* store None as NULL */ + else { + type = pyg_type_from_object((PyObject*)Py_TYPE(item)); + if (! type) { + PyErr_Clear(); + g_value_array_free(value_array); + Py_DECREF(item); + return -1; + } + } + + g_value_init(&item_value, type); + status = (pspec && pspec->element_spec) + ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec) + : pyg_value_from_pyobject(&item_value, item); + Py_DECREF(item); + + if (status == -1) { + g_value_array_free(value_array); + g_value_unset(&item_value); + return -1; + } + + g_value_array_append(value_array, &item_value); + g_value_unset(&item_value); + } + + g_value_take_boxed(value, value_array); + return 0; +} + +static int +pyg_array_from_pyobject(GValue *value, + PyObject *obj) +{ + int len; + GArray *array; + int i; + + len = PySequence_Length(obj); + if (len == -1) { + PyErr_Clear(); + return -1; + } + + array = g_array_new(FALSE, TRUE, sizeof(GValue)); + + for (i = 0; i < len; ++i) { + PyObject *item = PySequence_GetItem(obj, i); + GType type; + GValue item_value = { 0, }; + int status; + + if (! item) { + PyErr_Clear(); + g_array_free(array, FALSE); + return -1; + } + + if (item == Py_None) + type = G_TYPE_POINTER; /* store None as NULL */ + else { + type = pyg_type_from_object((PyObject*)Py_TYPE(item)); + if (! type) { + PyErr_Clear(); + g_array_free(array, FALSE); + Py_DECREF(item); + return -1; + } + } + + g_value_init(&item_value, type); + status = pyg_value_from_pyobject(&item_value, item); + Py_DECREF(item); + + if (status == -1) { + g_array_free(array, FALSE); + g_value_unset(&item_value); + return -1; + } + + g_array_append_val(array, item_value); + } + + g_value_take_boxed(value, array); + return 0; +} + +/** + * pyg_value_from_pyobject_with_error: + * @value: the GValue object to store the converted value in. + * @obj: the Python object to convert. + * + * This function converts a Python object and stores the result in a + * GValue. The GValue must be initialised in advance with + * g_value_init(). If the Python object can't be converted to the + * type of the GValue, then an error is returned. + * + * Returns: 0 on success, -1 on error. + */ +int +pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj) +{ + PyObject *tmp; + GType value_type = G_VALUE_TYPE(value); + + switch (G_TYPE_FUNDAMENTAL(value_type)) { + case G_TYPE_INTERFACE: + /* we only handle interface types that have a GObject prereq */ + if (g_type_is_a(value_type, G_TYPE_OBJECT)) { + if (obj == Py_None) + g_value_set_object(value, NULL); + else { + if (!PyObject_TypeCheck(obj, &PyGObject_Type)) { + PyErr_SetString(PyExc_TypeError, "GObject is required"); + return -1; + } + if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj), + value_type)) { + PyErr_SetString(PyExc_TypeError, "Invalid GObject type for assignment"); + return -1; + } + g_value_set_object(value, pygobject_get(obj)); + } + } else { + PyErr_SetString(PyExc_TypeError, "Unsupported conversion"); + return -1; + } + break; + case G_TYPE_CHAR: + if (PYGLIB_PyLong_Check(obj)) { + glong val; + val = PYGLIB_PyLong_AsLong(obj); + if (val >= -128 && val <= 127) + g_value_set_schar(value, (gchar) val); + else + return -1; + } +#if PY_VERSION_HEX < 0x03000000 + else if (PyString_Check(obj)) { + g_value_set_schar(value, PyString_AsString(obj)[0]); + } +#endif + else if (PyUnicode_Check(obj)) { + tmp = PyUnicode_AsUTF8String(obj); + g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]); + Py_DECREF(tmp); + } else { + PyErr_SetString(PyExc_TypeError, "Cannot convert to TYPE_CHAR"); + return -1; + } + + break; + case G_TYPE_UCHAR: + if (PYGLIB_PyLong_Check(obj)) { + glong val; + val = PYGLIB_PyLong_AsLong(obj); + if (val >= 0 && val <= 255) + g_value_set_uchar(value, (guchar) val); + else + return -1; +#if PY_VERSION_HEX < 0x03000000 + } else if (PyString_Check(obj)) { + g_value_set_uchar(value, PyString_AsString(obj)[0]); +#endif + } else if (PyUnicode_Check(obj)) { + tmp = PyUnicode_AsUTF8String(obj); + g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]); + Py_DECREF(tmp); + } else { + PyErr_Clear(); + return -1; + } + break; + case G_TYPE_BOOLEAN: + g_value_set_boolean(value, PyObject_IsTrue(obj)); + break; + case G_TYPE_INT: + g_value_set_int(value, PYGLIB_PyLong_AsLong(obj)); + break; + case G_TYPE_UINT: + { + if (PYGLIB_PyLong_Check(obj)) { + guint val; + + /* check that number is not negative */ + if (PyLong_AsLongLong(obj) < 0) + return -1; + + val = PyLong_AsUnsignedLong(obj); + if (val <= G_MAXUINT) + g_value_set_uint(value, val); + else + return -1; + } else { + g_value_set_uint(value, PyLong_AsUnsignedLong(obj)); + } + } + break; + case G_TYPE_LONG: + g_value_set_long(value, PYGLIB_PyLong_AsLong(obj)); + break; + case G_TYPE_ULONG: +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(obj)) { + long val; + + val = PYGLIB_PyLong_AsLong(obj); + if (val < 0) { + PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property"); + return -1; + } + g_value_set_ulong(value, (gulong)val); + } else +#endif + if (PyLong_Check(obj)) + g_value_set_ulong(value, PyLong_AsUnsignedLong(obj)); + else + return -1; + break; + case G_TYPE_INT64: + g_value_set_int64(value, PyLong_AsLongLong(obj)); + break; + case G_TYPE_UINT64: +#if PY_VERSION_HEX < 0x03000000 + if (PyInt_Check(obj)) { + long v = PyInt_AsLong(obj); + if (v < 0) { + PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property"); + return -1; + } + g_value_set_uint64(value, v); + } else +#endif + if (PyLong_Check(obj)) + g_value_set_uint64(value, PyLong_AsUnsignedLongLong(obj)); + else + return -1; + break; + case G_TYPE_ENUM: + { + gint val = 0; + if (pyg_enum_get_value(G_VALUE_TYPE(value), obj, &val) < 0) { + return -1; + } + g_value_set_enum(value, val); + } + break; + case G_TYPE_FLAGS: + { + guint val = 0; + if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) { + return -1; + } + g_value_set_flags(value, val); + } + break; + case G_TYPE_FLOAT: + g_value_set_float(value, PyFloat_AsDouble(obj)); + break; + case G_TYPE_DOUBLE: + g_value_set_double(value, PyFloat_AsDouble(obj)); + break; + case G_TYPE_STRING: + if (obj == Py_None) { + g_value_set_string(value, NULL); + } else { + PyObject* tmp_str = PyObject_Str(obj); + if (tmp_str == NULL) { + PyErr_Clear(); + if (PyUnicode_Check(obj)) { + tmp = PyUnicode_AsUTF8String(obj); + g_value_set_string(value, PYGLIB_PyBytes_AsString(tmp)); + Py_DECREF(tmp); + } else { + PyErr_SetString(PyExc_TypeError, "Expected string"); + return -1; + } + } else { +#if PY_VERSION_HEX < 0x03000000 + g_value_set_string(value, PyString_AsString(tmp_str)); +#else + tmp = PyUnicode_AsUTF8String(tmp_str); + g_value_set_string(value, PyBytes_AsString(tmp)); + Py_DECREF(tmp); +#endif + } + Py_XDECREF(tmp_str); + } + break; + case G_TYPE_POINTER: + if (obj == Py_None) + g_value_set_pointer(value, NULL); + else if (PyObject_TypeCheck(obj, &PyGPointer_Type) && + G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype)) + g_value_set_pointer(value, pyg_pointer_get(obj, gpointer)); + else if (PYGLIB_CPointer_Check(obj)) + g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL)); + else if (G_VALUE_HOLDS_GTYPE (value)) + g_value_set_gtype (value, pyg_type_from_object (obj)); + else { + PyErr_SetString(PyExc_TypeError, "Expected pointer"); + return -1; + } + break; + case G_TYPE_BOXED: { + PyGTypeMarshal *bm; + + if (obj == Py_None) + g_value_set_boxed(value, NULL); + else if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) + g_value_set_boxed(value, obj); + else if (PyObject_TypeCheck(obj, &PyGBoxed_Type) && + G_VALUE_HOLDS(value, ((PyGBoxed *)obj)->gtype)) + g_value_set_boxed(value, pyg_boxed_get(obj, gpointer)); + else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) { + GType type; + GValue *n_value; + + type = pyg_type_from_object((PyObject*)Py_TYPE(obj)); + if (G_UNLIKELY (! type)) { + return -1; + } + n_value = g_new0 (GValue, 1); + g_value_init (n_value, type); + g_value_take_boxed (value, n_value); + return pyg_value_from_pyobject_with_error (n_value, obj); + } + else if (PySequence_Check(obj) && + G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) + return pyg_value_array_from_pyobject(value, obj, NULL); + else if (PySequence_Check(obj) && + G_VALUE_HOLDS(value, G_TYPE_ARRAY)) + return pyg_array_from_pyobject(value, obj); + else if (PYGLIB_PyUnicode_Check(obj) && + G_VALUE_HOLDS(value, G_TYPE_GSTRING)) { + GString *string; + char *buffer; + Py_ssize_t len; + if (PYGLIB_PyUnicode_AsStringAndSize(obj, &buffer, &len)) + return -1; + string = g_string_new_len(buffer, len); + g_value_set_boxed(value, string); + g_string_free (string, TRUE); + break; + } + else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) + return bm->tovalue(value, obj); + else if (PYGLIB_CPointer_Check(obj)) + g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL)); + else { + PyErr_SetString(PyExc_TypeError, "Expected Boxed"); + return -1; + } + break; + } + case G_TYPE_PARAM: + /* we need to support both the wrapped _gobject.GParamSpec and the GI + * GObject.ParamSpec */ + if (G_IS_PARAM_SPEC (pygobject_get (obj))) + g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj))); + else if (PyGParamSpec_Check(obj)) + g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL)); + else { + PyErr_SetString(PyExc_TypeError, "Expected ParamSpec"); + return -1; + } + break; + case G_TYPE_OBJECT: + if (obj == Py_None) { + g_value_set_object(value, NULL); + } else if (PyObject_TypeCheck(obj, &PyGObject_Type) && + G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj), + G_VALUE_TYPE(value))) { + g_value_set_object(value, pygobject_get(obj)); + } else { + PyErr_SetString(PyExc_TypeError, "Expected GObject"); + return -1; + } + break; + case G_TYPE_VARIANT: + { + if (obj == Py_None) + g_value_set_variant(value, NULL); + else if (pyg_type_from_object_strict(obj, FALSE) == G_TYPE_VARIANT) + g_value_set_variant(value, pyg_boxed_get(obj, GVariant)); + else { + PyErr_SetString(PyExc_TypeError, "Expected Variant"); + return -1; + } + break; + } + default: + { + PyGTypeMarshal *bm; + if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) { + return bm->tovalue(value, obj); + } else { + PyErr_SetString(PyExc_TypeError, "Unknown value type"); + return -1; + } + break; + } + } + + /* If an error occurred, unset the GValue but don't clear the Python error. */ + if (PyErr_Occurred()) { + g_value_unset(value); + return -1; + } + + return 0; +} + +/** + * pyg_value_from_pyobject: + * @value: the GValue object to store the converted value in. + * @obj: the Python object to convert. + * + * Same basic function as pyg_value_from_pyobject_with_error but clears + * any Python errors before returning. + * + * Returns: 0 on success, -1 on error. + */ +int +pyg_value_from_pyobject(GValue *value, PyObject *obj) +{ + int res = pyg_value_from_pyobject_with_error (value, obj); + + if (PyErr_Occurred()) { + PyErr_Clear(); + return -1; + } + return res; +} + +/** + * pyg_value_as_pyobject: + * @value: the GValue object. + * @copy_boxed: true if boxed values should be copied. + * + * This function creates/returns a Python wrapper object that + * represents the GValue passed as an argument. + * + * Returns: a PyObject representing the value. + */ +PyObject * +pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed) +{ + gchar buf[128]; + + switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) { + case G_TYPE_INTERFACE: + if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT)) + return pygobject_new(g_value_get_object(value)); + else + break; + case G_TYPE_CHAR: { + gint8 val = g_value_get_schar(value); + return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1); + } + case G_TYPE_UCHAR: { + guint8 val = g_value_get_uchar(value); + return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1); + } + case G_TYPE_BOOLEAN: { + return PyBool_FromLong(g_value_get_boolean(value)); + } + case G_TYPE_INT: + return PYGLIB_PyLong_FromLong(g_value_get_int(value)); + case G_TYPE_UINT: + { + /* in Python, the Int object is backed by a long. If a + long can hold the whole value of an unsigned int, use + an Int. Otherwise, use a Long object to avoid overflow. + This matches the ULongArg behavior in codegen/argtypes.h */ +#if (G_MAXUINT <= G_MAXLONG) + return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value)); +#else + return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value)); +#endif + } + case G_TYPE_LONG: + return PYGLIB_PyLong_FromLong(g_value_get_long(value)); + case G_TYPE_ULONG: + { + gulong val = g_value_get_ulong(value); + + if (val <= G_MAXLONG) + return PYGLIB_PyLong_FromLong((glong) val); + else + return PyLong_FromUnsignedLong(val); + } + case G_TYPE_INT64: + { + gint64 val = g_value_get_int64(value); + + if (G_MINLONG <= val && val <= G_MAXLONG) + return PYGLIB_PyLong_FromLong((glong) val); + else + return PyLong_FromLongLong(val); + } + case G_TYPE_UINT64: + { + guint64 val = g_value_get_uint64(value); + + if (val <= G_MAXLONG) + return PYGLIB_PyLong_FromLong((glong) val); + else + return PyLong_FromUnsignedLongLong(val); + } + case G_TYPE_ENUM: + return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value)); + case G_TYPE_FLAGS: + return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value)); + case G_TYPE_FLOAT: + return PyFloat_FromDouble(g_value_get_float(value)); + case G_TYPE_DOUBLE: + return PyFloat_FromDouble(g_value_get_double(value)); + case G_TYPE_STRING: + { + const gchar *str = g_value_get_string(value); + + if (str) + return PYGLIB_PyUnicode_FromString(str); + Py_INCREF(Py_None); + return Py_None; + } + case G_TYPE_POINTER: + if (G_VALUE_HOLDS_GTYPE (value)) + return pyg_type_wrapper_new (g_value_get_gtype (value)); + else + return pyg_pointer_new(G_VALUE_TYPE(value), + g_value_get_pointer(value)); + case G_TYPE_BOXED: { + PyGTypeMarshal *bm; + + if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) { + PyObject *ret = (PyObject *)g_value_dup_boxed(value); + if (ret == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return ret; + } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) { + GValue *n_value = g_value_get_boxed (value); + return pyg_value_as_pyobject(n_value, copy_boxed); + } else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) { + GValueArray *array = (GValueArray *) g_value_get_boxed(value); + PyObject *ret = PyList_New(array->n_values); + int i; + for (i = 0; i < array->n_values; ++i) + PyList_SET_ITEM(ret, i, pyg_value_as_pyobject + (array->values + i, copy_boxed)); + return ret; + } else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) { + GString *string = (GString *) g_value_get_boxed(value); + PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len); + return ret; + } + bm = pyg_type_lookup(G_VALUE_TYPE(value)); + if (bm) { + return bm->fromvalue(value); + } else { + if (copy_boxed) + return pyg_boxed_new(G_VALUE_TYPE(value), + g_value_get_boxed(value), TRUE, TRUE); + else + return pyg_boxed_new(G_VALUE_TYPE(value), + g_value_get_boxed(value),FALSE,FALSE); + } + } + case G_TYPE_PARAM: + return pyg_param_spec_new(g_value_get_param(value)); + case G_TYPE_OBJECT: + return pygobject_new(g_value_get_object(value)); + case G_TYPE_VARIANT: + { + GVariant *v = g_value_get_variant(value); + if (v == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE); + } + default: + { + PyGTypeMarshal *bm; + if ((bm = pyg_type_lookup(G_VALUE_TYPE(value)))) + return bm->fromvalue(value); + break; + } + } + g_snprintf(buf, sizeof(buf), "unknown type %s", + g_type_name(G_VALUE_TYPE(value))); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; +} + +/* -------------- PyGClosure ----------------- */ + +static void +pyg_closure_invalidate(gpointer data, GClosure *closure) +{ + PyGClosure *pc = (PyGClosure *)closure; + PyGILState_STATE state; + + state = pyglib_gil_state_ensure(); + Py_XDECREF(pc->callback); + Py_XDECREF(pc->extra_args); + Py_XDECREF(pc->swap_data); + pyglib_gil_state_release(state); + + pc->callback = NULL; + pc->extra_args = NULL; + pc->swap_data = NULL; +} + +static void +pyg_closure_marshal(GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + PyGILState_STATE state; + PyGClosure *pc = (PyGClosure *)closure; + PyObject *params, *ret; + guint i; + + state = pyglib_gil_state_ensure(); + + /* construct Python tuple for the parameter values */ + params = PyTuple_New(n_param_values); + for (i = 0; i < n_param_values; i++) { + /* swap in a different initial data for connect_object() */ + if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { + g_return_if_fail(pc->swap_data != NULL); + Py_INCREF(pc->swap_data); + PyTuple_SetItem(params, 0, pc->swap_data); + } else { + PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); + + /* error condition */ + if (!item) { + goto out; + } + PyTuple_SetItem(params, i, item); + } + } + /* params passed to function may have extra arguments */ + if (pc->extra_args) { + PyObject *tuple = params; + params = PySequence_Concat(tuple, pc->extra_args); + Py_DECREF(tuple); + } + ret = PyObject_CallObject(pc->callback, params); + if (ret == NULL) { + if (pc->exception_handler) + pc->exception_handler(return_value, n_param_values, param_values); + else + PyErr_Print(); + goto out; + } + + if (G_IS_VALUE(return_value) && pyg_value_from_pyobject(return_value, ret) != 0) { + /* If we already have an exception set, use that, otherwise set a + * generic one */ + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "can't convert return value to desired type"); + + if (pc->exception_handler) + pc->exception_handler(return_value, n_param_values, param_values); + else + PyErr_Print(); + } + Py_DECREF(ret); + + out: + Py_DECREF(params); + pyglib_gil_state_release(state); +} + +/** + * pyg_closure_new: + * callback: a Python callable object + * extra_args: a tuple of extra arguments, or None/NULL. + * swap_data: an alternative python object to pass first. + * + * Creates a GClosure wrapping a Python callable and optionally a set + * of additional function arguments. This is needed to attach python + * handlers to signals, for instance. + * + * Returns: the new closure. + */ +GClosure * +pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data) +{ + GClosure *closure; + + g_return_val_if_fail(callback != NULL, NULL); + closure = g_closure_new_simple(sizeof(PyGClosure), NULL); + g_closure_add_invalidate_notifier(closure, NULL, pyg_closure_invalidate); + g_closure_set_marshal(closure, pyg_closure_marshal); + Py_INCREF(callback); + ((PyGClosure *)closure)->callback = callback; + if (extra_args && extra_args != Py_None) { + Py_INCREF(extra_args); + if (!PyTuple_Check(extra_args)) { + PyObject *tmp = PyTuple_New(1); + PyTuple_SetItem(tmp, 0, extra_args); + extra_args = tmp; + } + ((PyGClosure *)closure)->extra_args = extra_args; + } + if (swap_data) { + Py_INCREF(swap_data); + ((PyGClosure *)closure)->swap_data = swap_data; + closure->derivative_flag = TRUE; + } + return closure; +} + +/** + * pyg_closure_set_exception_handler: + * @closure: a closure created with pyg_closure_new() + * @handler: the handler to call when an exception occurs or NULL for none + * + * Sets the handler to call when an exception occurs during closure invocation. + * The handler is responsible for providing a proper return value to the + * closure invocation. If @handler is %NULL, the default handler will be used. + * The default handler prints the exception to stderr and doesn't touch the + * closure's return value. + */ +void +pyg_closure_set_exception_handler(GClosure *closure, + PyClosureExceptionHandler handler) +{ + PyGClosure *pygclosure; + + g_return_if_fail(closure != NULL); + + pygclosure = (PyGClosure *)closure; + pygclosure->exception_handler = handler; +} +/* -------------- PySignalClassClosure ----------------- */ +/* a closure used for the `class closure' of a signal. As this gets + * all the info from the first argument to the closure and the + * invocation hint, we can have a single closure that handles all + * class closure cases. We call a method by the name of the signal + * with "do_" prepended. + * + * We also remove the first argument from the * param list, as it is + * the instance object, which is passed * implicitly to the method + * object. */ + +static void +pyg_signal_class_closure_marshal(GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + PyGILState_STATE state; + GObject *object; + PyObject *object_wrapper; + GSignalInvocationHint *hint = (GSignalInvocationHint *)invocation_hint; + gchar *method_name, *tmp; + PyObject *method; + PyObject *params, *ret; + guint i, len; + + state = pyglib_gil_state_ensure(); + + g_return_if_fail(invocation_hint != NULL); + /* get the object passed as the first argument to the closure */ + object = g_value_get_object(¶m_values[0]); + g_return_if_fail(object != NULL && G_IS_OBJECT(object)); + + /* get the wrapper for this object */ + object_wrapper = pygobject_new(object); + g_return_if_fail(object_wrapper != NULL); + + /* construct method name for this class closure */ + method_name = g_strconcat("do_", g_signal_name(hint->signal_id), NULL); + + /* convert dashes to underscores. For some reason, g_signal_name + * seems to convert all the underscores in the signal name to + dashes??? */ + for (tmp = method_name; *tmp != '\0'; tmp++) + if (*tmp == '-') *tmp = '_'; + + method = PyObject_GetAttrString(object_wrapper, method_name); + g_free(method_name); + + if (!method) { + PyErr_Clear(); + Py_DECREF(object_wrapper); + pyglib_gil_state_release(state); + return; + } + Py_DECREF(object_wrapper); + + /* construct Python tuple for the parameter values; don't copy boxed values + initially because we'll check after the call to see if a copy is needed. */ + params = PyTuple_New(n_param_values - 1); + for (i = 1; i < n_param_values; i++) { + PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); + + /* error condition */ + if (!item) { + Py_DECREF(params); + pyglib_gil_state_release(state); + return; + } + PyTuple_SetItem(params, i - 1, item); + } + + ret = PyObject_CallObject(method, params); + + /* Copy boxed values if others ref them, this needs to be done regardless of + exception status. */ + len = PyTuple_Size(params); + for (i = 0; i < len; i++) { + PyObject *item = PyTuple_GetItem(params, i); + if (item != NULL && PyObject_TypeCheck(item, &PyGBoxed_Type) + && item->ob_refcnt != 1) { + PyGBoxed* boxed_item = (PyGBoxed*)item; + if (!boxed_item->free_on_dealloc) { + boxed_item->boxed = g_boxed_copy(boxed_item->gtype, boxed_item->boxed); + boxed_item->free_on_dealloc = TRUE; + } + } + } + + if (ret == NULL) { + PyErr_Print(); + Py_DECREF(method); + Py_DECREF(params); + pyglib_gil_state_release(state); + return; + } + Py_DECREF(method); + Py_DECREF(params); + if (G_IS_VALUE(return_value)) + pyg_value_from_pyobject(return_value, ret); + Py_DECREF(ret); + pyglib_gil_state_release(state); +} + +/** + * pyg_signal_class_closure_get: + * + * Returns the GClosure used for the class closure of signals. When + * called, it will invoke the method do_signalname (for the signal + * "signalname"). + * + * Returns: the closure. + */ +GClosure * +pyg_signal_class_closure_get(void) +{ + static GClosure *closure; + + if (closure == NULL) { + closure = g_closure_new_simple(sizeof(GClosure), NULL); + g_closure_set_marshal(closure, pyg_signal_class_closure_marshal); + + g_closure_ref(closure); + g_closure_sink(closure); + } + return closure; +} + +GClosure * +gclosure_from_pyfunc(PyGObject *object, PyObject *func) +{ + GSList *l; + PyGObjectData *inst_data; + inst_data = pyg_object_peek_inst_data(object->obj); + if (inst_data) { + for (l = inst_data->closures; l; l = l->next) { + PyGClosure *pyclosure = l->data; + int res = PyObject_RichCompareBool(pyclosure->callback, func, Py_EQ); + if (res == -1) { + PyErr_Clear(); // Is there anything else to do? + } else if (res) { + return (GClosure*)pyclosure; + } + } + } + return NULL; +} + +/* ----- __doc__ descriptor for GObject and GInterface ----- */ + +static void +object_doc_dealloc(PyObject *self) +{ + PyObject_FREE(self); +} + +/* append information about signals of a particular gtype */ +static void +add_signal_docs(GType gtype, GString *string) +{ + GTypeClass *class = NULL; + guint *signal_ids, n_ids = 0, i; + + if (G_TYPE_IS_CLASSED(gtype)) + class = g_type_class_ref(gtype); + signal_ids = g_signal_list_ids(gtype, &n_ids); + + if (n_ids > 0) { + g_string_append_printf(string, "Signals from %s:\n", + g_type_name(gtype)); + + for (i = 0; i < n_ids; i++) { + GSignalQuery query; + guint j; + + g_signal_query(signal_ids[i], &query); + + g_string_append(string, " "); + g_string_append(string, query.signal_name); + g_string_append(string, " ("); + for (j = 0; j < query.n_params; j++) { + g_string_append(string, g_type_name(query.param_types[j])); + if (j != query.n_params - 1) + g_string_append(string, ", "); + } + g_string_append(string, ")"); + if (query.return_type && query.return_type != G_TYPE_NONE) { + g_string_append(string, " -> "); + g_string_append(string, g_type_name(query.return_type)); + } + g_string_append(string, "\n"); + } + g_free(signal_ids); + g_string_append(string, "\n"); + } + if (class) + g_type_class_unref(class); +} + +static void +add_property_docs(GType gtype, GString *string) +{ + GObjectClass *class; + GParamSpec **props; + guint n_props = 0, i; + gboolean has_prop = FALSE; + G_CONST_RETURN gchar *blurb=NULL; + + class = g_type_class_ref(gtype); + props = g_object_class_list_properties(class, &n_props); + + for (i = 0; i < n_props; i++) { + if (props[i]->owner_type != gtype) + continue; /* these are from a parent type */ + + /* print out the heading first */ + if (!has_prop) { + g_string_append_printf(string, "Properties from %s:\n", + g_type_name(gtype)); + has_prop = TRUE; + } + g_string_append_printf(string, " %s -> %s: %s\n", + g_param_spec_get_name(props[i]), + g_type_name(props[i]->value_type), + g_param_spec_get_nick(props[i])); + + /* g_string_append_printf crashes on win32 if the third + argument is NULL. */ + blurb=g_param_spec_get_blurb(props[i]); + if (blurb) + g_string_append_printf(string, " %s\n",blurb); + } + g_free(props); + if (has_prop) + g_string_append(string, "\n"); + g_type_class_unref(class); +} + +static PyObject * +object_doc_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + GType gtype = 0; + GString *string; + PyObject *pystring; + + if (obj && pygobject_check(obj, &PyGObject_Type)) { + gtype = G_OBJECT_TYPE(pygobject_get(obj)); + if (!gtype) + PyErr_SetString(PyExc_RuntimeError, "could not get object type"); + } else { + gtype = pyg_type_from_object(type); + } + if (!gtype) + return NULL; + + string = g_string_new_len(NULL, 512); + + if (g_type_is_a(gtype, G_TYPE_INTERFACE)) + g_string_append_printf(string, "Interface %s\n\n", g_type_name(gtype)); + else if (g_type_is_a(gtype, G_TYPE_OBJECT)) + g_string_append_printf(string, "Object %s\n\n", g_type_name(gtype)); + else + g_string_append_printf(string, "%s\n\n", g_type_name(gtype)); + + if (((PyTypeObject *) type)->tp_doc) + g_string_append_printf(string, "%s\n\n", ((PyTypeObject *) type)->tp_doc); + + if (g_type_is_a(gtype, G_TYPE_OBJECT)) { + GType parent = G_TYPE_OBJECT; + GArray *parents = g_array_new(FALSE, FALSE, sizeof(GType)); + int iparent; + + while (parent) { + g_array_append_val(parents, parent); + parent = g_type_next_base(gtype, parent); + } + + for (iparent = parents->len - 1; iparent >= 0; --iparent) { + GType *interfaces; + guint n_interfaces, i; + + parent = g_array_index(parents, GType, iparent); + add_signal_docs(parent, string); + add_property_docs(parent, string); + + /* add docs for implemented interfaces */ + interfaces = g_type_interfaces(parent, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + add_signal_docs(interfaces[i], string); + g_free(interfaces); + } + g_array_free(parents, TRUE); + } + + pystring = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len); + g_string_free(string, TRUE); + return pystring; +} + +PYGLIB_DEFINE_TYPE("gobject.GObject.__doc__", PyGObjectDoc_Type, PyObject); + +/** + * pyg_object_descr_doc_get: + * + * Returns an object intended to be the __doc__ attribute of GObject + * wrappers. When read in the context of the object it will return + * some documentation about the signals and properties of the object. + * + * Returns: the descriptor. + */ +PyObject * +pyg_object_descr_doc_get(void) +{ + static PyObject *doc_descr = NULL; + + if (!doc_descr) { + Py_TYPE(&PyGObjectDoc_Type) = &PyType_Type; + if (PyType_Ready(&PyGObjectDoc_Type)) + return NULL; + + doc_descr = PyObject_NEW(PyObject, &PyGObjectDoc_Type); + if (doc_descr == NULL) + return NULL; + } + return doc_descr; +} + + +/** + * pyg_pyobj_to_unichar_conv: + * + * Converts PyObject value to a unichar and write result to memory + * pointed to by ptr. Follows the calling convention of a ParseArgs + * converter (O& format specifier) so it may be used to convert function + * arguments. + * + * Returns: 1 if the conversion succeeds and 0 otherwise. If the conversion + * did not succeesd, a Python exception is raised + */ +int pyg_pyobj_to_unichar_conv(PyObject* py_obj, void* ptr) +{ + gunichar* u = ptr; + const Py_UNICODE* uni_buffer; + PyObject* tmp_uni = NULL; + + if (PyUnicode_Check(py_obj)) { + tmp_uni = py_obj; + Py_INCREF(tmp_uni); + } + else { + tmp_uni = PyUnicode_FromObject(py_obj); + if (tmp_uni == NULL) + goto failure; + } + + if ( PyUnicode_GetSize(tmp_uni) != 1) { + PyErr_SetString(PyExc_ValueError, "unicode character value must be 1 character uniode string"); + goto failure; + } + uni_buffer = PyUnicode_AsUnicode(tmp_uni); + if ( uni_buffer == NULL) + goto failure; + *u = uni_buffer[0]; + + Py_DECREF(tmp_uni); + return 1; + + failure: + Py_XDECREF(tmp_uni); + return 0; +} + + +int +pyg_param_gvalue_from_pyobject(GValue* value, + PyObject* py_obj, + const GParamSpec* pspec) +{ + if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + gunichar u; + + if (!pyg_pyobj_to_unichar_conv(py_obj, &u)) { + PyErr_Clear(); + return -1; + } + g_value_set_uint(value, u); + return 0; + } + else if (G_IS_PARAM_SPEC_VALUE_ARRAY(pspec)) + return pyg_value_array_from_pyobject(value, py_obj, + G_PARAM_SPEC_VALUE_ARRAY(pspec)); + else { + return pyg_value_from_pyobject(value, py_obj); + } +} + +PyObject* +pyg_param_gvalue_as_pyobject(const GValue* gvalue, + gboolean copy_boxed, + const GParamSpec* pspec) +{ + if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + gunichar u; + Py_UNICODE uni_buffer[2] = { 0, 0 }; + + u = g_value_get_uint(gvalue); + uni_buffer[0] = u; + return PyUnicode_FromUnicode(uni_buffer, 1); + } + else { + return pyg_value_as_pyobject(gvalue, copy_boxed); + } +} + +gboolean +pyg_gtype_is_custom(GType gtype) +{ + return g_type_get_qdata (gtype, pygobject_custom_key) != NULL; +} + +static PyObject * +_pyg_strv_from_gvalue(const GValue *value) +{ + gchar **argv = (gchar **) g_value_get_boxed(value); + int argc = 0, i; + PyObject *py_argv; + + if (argv) { + while (argv[argc]) + argc++; + } + py_argv = PyList_New(argc); + for (i = 0; i < argc; ++i) + PyList_SET_ITEM(py_argv, i, PYGLIB_PyUnicode_FromString(argv[i])); + return py_argv; +} + +static int +_pyg_strv_to_gvalue(GValue *value, PyObject *obj) +{ + Py_ssize_t argc, i; + gchar **argv; + + if (!(PyTuple_Check(obj) || PyList_Check(obj))) + return -1; + + argc = PySequence_Length(obj); + for (i = 0; i < argc; ++i) + if (!PYGLIB_PyUnicode_Check(PySequence_Fast_GET_ITEM(obj, i))) + return -1; + argv = g_new(gchar *, argc + 1); + for (i = 0; i < argc; ++i) + argv[i] = g_strdup(PYGLIB_PyUnicode_AsString(PySequence_Fast_GET_ITEM(obj, i))); + argv[i] = NULL; + g_value_take_boxed(value, argv); + return 0; +} + +void +pygobject_type_register_types(PyObject *d) +{ + PyGTypeWrapper_Type.tp_dealloc = (destructor)pyg_type_wrapper_dealloc; + PyGTypeWrapper_Type.tp_richcompare = pyg_type_wrapper_richcompare; + PyGTypeWrapper_Type.tp_repr = (reprfunc)pyg_type_wrapper_repr; + PyGTypeWrapper_Type.tp_hash = (hashfunc)pyg_type_wrapper_hash; + PyGTypeWrapper_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGTypeWrapper_Type.tp_methods = _PyGTypeWrapper_methods; + PyGTypeWrapper_Type.tp_getset = _PyGTypeWrapper_getsets; + PyGTypeWrapper_Type.tp_init = (initproc)pyg_type_wrapper_init; + PYGLIB_REGISTER_TYPE(d, PyGTypeWrapper_Type, "GType"); + + /* This type lazily registered in pyg_object_descr_doc_get */ + PyGObjectDoc_Type.tp_dealloc = (destructor)object_doc_dealloc; + PyGObjectDoc_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGObjectDoc_Type.tp_descr_get = (descrgetfunc)object_doc_descr_get; + + pyg_register_gtype_custom(G_TYPE_STRV, + _pyg_strv_from_gvalue, + _pyg_strv_to_gvalue); +} diff --git a/gi/pygtype.h b/gi/pygtype.h new file mode 100644 index 00000000..2f9e7add --- /dev/null +++ b/gi/pygtype.h @@ -0,0 +1,28 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * pyginterface.c: wrapper for the gobject 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_TYPE_H__ +#define __PYGOBJECT_TYPE_H__ + +void pygobject_type_register_types(PyObject *d); + +#endif /* __PYGOBJECT_TYPE_H__ */ diff --git a/gi/types.py b/gi/types.py index 41efc051..c5b4bd5a 100644 --- a/gi/types.py +++ b/gi/types.py @@ -26,7 +26,6 @@ import sys import warnings from . import _gobject -from ._gobject._gobject import GInterface from ._gobject.constants import TYPE_INVALID from .docstring import generate_doc_string @@ -38,6 +37,8 @@ from ._gi import \ register_interface_info, \ hook_up_vfunc_implementation +import gi._gi +GInterface = gi._gi._gobject.GInterface StructInfo # pyflakes diff --git a/tests/Makefile.am b/tests/Makefile.am index a687bbd4..02063d07 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -54,7 +54,7 @@ CLEANFILES += Regress-1.0.gir Regress-1.0.typelib GIMarshallingTests-1.0.gir GIM check_LTLIBRARIES += testhelper.la -testhelper_la_CFLAGS = -I$(top_srcdir)/gi/_gobject -I$(top_srcdir)/gi/_glib $(PYTHON_INCLUDES) $(GLIB_CFLAGS) +testhelper_la_CFLAGS = -I$(top_srcdir)/gi -I$(top_srcdir)/gi/_glib $(PYTHON_INCLUDES) $(GLIB_CFLAGS) testhelper_la_LDFLAGS = -module -avoid-version testhelper_la_LIBADD = $(GLIB_LIBS) testhelper_la_SOURCES = \ -- cgit v1.2.1