[pygobject] Remove gobjectmodule



commit 2ad711b25064e106ab80a9358c932e51e9c871e2
Author: Christoph Reiter <reiter christoph gmail com>
Date:   Wed Mar 21 19:30:26 2018 +0100

    Remove gobjectmodule
    
    This finishes what was started in b2529624b3925adbef2671025e08cbf747f162e8
    and moves the remaining code mostly into gimodule.
    
    While this makes the large file even larger, it's a good starting point
    for more cleanups.

 gi/Makefile.am        |    2 -
 gi/gimodule.c         | 1721 +++++++++++++++++++++++++++++++++++++++++++-
 gi/gimodule.h         |   10 +
 gi/gobjectmodule.c    | 1897 -------------------------------------------------
 gi/gobjectmodule.h    |   27 -
 gi/pygboxed.h         |    2 -
 gi/pygi-util.c        |   42 +-
 gi/pygi-util.h        |    1 +
 gi/pygi-value.c       |   34 +
 gi/pygi-value.h       |    3 +
 gi/pygobject-object.c |   59 +-
 gi/pygobject-object.h |    1 +
 12 files changed, 1863 insertions(+), 1936 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 38410755..38209410 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -34,8 +34,6 @@ pygidir = $(pyexecdir)/gi
 pygi_LTLIBRARIES = _gi.la
 
 _gi_la_SOURCES = \
-       gobjectmodule.c \
-       gobjectmodule.h \
        pygboxed.c \
        pygboxed.h \
        pygenum.c \
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 4bcb5fb9..136f74dd 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -47,9 +47,13 @@
 #include "pygoptioncontext.h"
 #include "pygoptiongroup.h"
 #include "pygspawn.h"
-#include "gobjectmodule.h"
 #include "pygparamspec.h"
 #include "pygpointer.h"
+#include "pygobject-internal.h"
+#include "pygi-value.h"
+#include "pygi-property.h"
+#include "pygi-util.h"
+#include "gimodule.h"
 
 #include <pyglib-python-compat.h>
 
@@ -57,10 +61,6 @@ PyObject *PyGIWarning;
 PyObject *PyGIDeprecationWarning;
 PyObject *_PyGIDefaultArgPlaceholder;
 
-
-/* Defined by PYGLIB_MODULE_START */
-extern PyObject *pyglib__gobject_module_create (void);
-
 /* Returns a new flag/enum type or %NULL */
 static PyObject *
 flags_enum_from_gtype (GType g_type,
@@ -86,6 +86,1319 @@ flags_enum_from_gtype (GType g_type,
     return new_type;
 }
 
+static void pyg_flags_add_constants(PyObject *module, GType flags_type,
+                                   const gchar *strip_prefix);
+
+/**
+ * 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_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 = PyGILState_Ensure ();
+    PyErr_Warn (PyExc_DeprecationWarning,
+                "Using pyg_set_thread_block_funcs is not longer needed. "
+                "PyGObject always uses Py_BLOCK/UNBLOCK_THREADS.");
+    PyGILState_Release (state);
+}
+
+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;
+}
+
+/**
+ * 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(&params[param_i].value, spec->value_type);
+        if (pyg_value_from_pyobject(&params[param_i].value, py_args[arg_i]) == -1) {
+            guint 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(&params[i].value);
+            return FALSE;
+        }
+        ++param_i;
+    }
+    g_type_class_unref(oclass);
+    *nparams = param_i;
+    return TRUE;
+}
+
+/* Only for backwards compatibility */
+static int
+pygobject_enable_threads(void)
+{
+    return 0;
+}
+
+static int
+pygobject_gil_state_ensure (void)
+{
+    return PyGILState_Ensure ();
+}
+
+static void
+pygobject_gil_state_release (int flag)
+{
+    PyGILState_Release(flag);
+}
+
+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 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, *pvalue, *traceback;
+           ret = FALSE;
+            PyErr_Fetch(&type, &pvalue, &traceback);
+            if (PYGLIB_PyUnicode_Check(pvalue)) {
+                char msg[256];
+                g_snprintf(msg, 256,
+                          "%s (while registering property '%s' for GType '%s')",
+               PYGLIB_PyUnicode_AsString(pvalue),
+                          prop_name, G_OBJECT_CLASS_NAME(klass));
+                Py_DECREF(pvalue);
+                value = PYGLIB_PyUnicode_FromString(msg);
+            }
+            PyErr_Restore(type, pvalue, traceback);
+           break;
+       }
+    }
+
+    return ret;
+}
+
+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;
+}
+
+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 = PyGILState_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);
+    }
+    PyGILState_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 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 void
+pyg_object_get_property (GObject *object, guint property_id,
+                        GValue *value, GParamSpec *pspec)
+{
+    PyObject *object_wrapper, *retval;
+    PyGILState_STATE state;
+
+    state = PyGILState_Ensure();
+
+    object_wrapper = g_object_get_qdata(object, pygobject_wrapper_key);
+
+    if (object_wrapper)
+      Py_INCREF (object_wrapper);
+    else
+      object_wrapper = pygobject_new(object);
+
+    if (object_wrapper == NULL) {
+       PyGILState_Release(state);
+       return;
+    }
+
+    retval = pygi_call_do_get_property (object_wrapper, pspec);
+    if (retval && pyg_value_from_pyobject (value, retval) < 0) {
+        PyErr_Print();
+    }
+    Py_DECREF(object_wrapper);
+    Py_XDECREF(retval);
+
+    PyGILState_Release(state);
+}
+
+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 = PyGILState_Ensure();
+
+    object_wrapper = g_object_get_qdata(object, pygobject_wrapper_key);
+
+    if (object_wrapper)
+      Py_INCREF (object_wrapper);
+    else
+      object_wrapper = pygobject_new(object);
+
+    if (object_wrapper == NULL) {
+       PyGILState_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);
+
+    PyGILState_Release(state);
+}
+
+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 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);
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+    obj = g_object_newv(pyg_type_from_object((PyObject *) self),
+                        n_parameters, parameters);
+G_GNUC_END_IGNORE_DEPRECATIONS
+    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 = PyGILState_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);
+        PyGILState_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);
+    }
+}
+
+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 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);
+       g_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 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 *
+_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 GHashTable *log_handlers = NULL;
+static gboolean log_handlers_disabled = FALSE;
+
+static void
+remove_handler(gpointer domain,
+               gpointer handler,
+              gpointer unused)
+{
+    g_log_remove_handler(domain, GPOINTER_TO_UINT(handler));
+}
+
+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 = PyGILState_Ensure();
+       PyErr_Warn(warning, (char *) message);
+       PyGILState_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
+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;
+    }
+}
+
+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);
+}
 
 static PyObject *
 _wrap_pyg_enum_add (PyObject *self,
@@ -619,6 +1932,267 @@ pyg_channel_read(PyObject* self, PyObject *args, PyObject *kwargs)
     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 = PyGILState_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(&param_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:
+    PyGILState_Release(state);
+    return retval;
+}
+
+/**
+ * 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.
+ */
+static void
+pyg_destroy_notify(gpointer user_data)
+{
+    PyObject *obj = (PyObject *)user_data;
+    PyGILState_STATE state;
+
+    state = PyGILState_Ensure();
+    Py_DECREF(obj);
+    PyGILState_Release(state);
+}
+
+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_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_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__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 PyMethodDef _gi_functions[] = {
     { "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
     { "enum_register_new_gtype_and_add", (PyCFunction) _wrap_pyg_enum_register_new_gtype_and_add, 
METH_VARARGS | METH_KEYWORDS },
@@ -662,6 +2236,143 @@ static struct PyGI_API CAPI = {
   pygi_register_foreign_struct,
 };
 
+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,
+
+  pygi_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,
+
+  TRUE, /* threads_enabled */
+
+  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 */
+
+  pygi_gerror_exception_check,
+
+  pyg_option_group_new,
+  pyg_type_from_object_strict,
+
+  pygobject_new_full,
+  &PyGObject_Type,
+
+  pyg_value_from_pyobject_with_error
+};
+
+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));
+}
+
+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);
+}
+
 PYGLIB_MODULE_START(_gi, "_gi")
 {
     PyObject *api;
diff --git a/gi/gimodule.h b/gi/gimodule.h
new file mode 100644
index 00000000..7917ef6a
--- /dev/null
+++ b/gi/gimodule.h
@@ -0,0 +1,10 @@
+#ifndef _PYGOBJECT_GIMODULE_H_
+#define _PYGOBJECT_GIMODULE_H_
+
+#include "pygobject-internal.h"
+
+int           pygobject_constructv (PyGObject   *self,
+                                    guint        n_parameters,
+                                    GParameter  *parameters);
+
+#endif /*_PYGOBJECT_GIMODULE_H_*/
diff --git a/gi/pygboxed.h b/gi/pygboxed.h
index 93b3de65..6db26e82 100644
--- a/gi/pygboxed.h
+++ b/gi/pygboxed.h
@@ -29,8 +29,6 @@ void       pyg_register_boxed (PyObject *dict, const gchar *class_name,
 PyObject * pyg_boxed_new      (GType boxed_type, gpointer boxed,
                                gboolean copy_boxed, gboolean own_ref);
 
-const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix);
-
 void pygobject_boxed_register_types(PyObject *d);
 
 #endif /* __PYGOBJECT_BOXED_H__ */
diff --git a/gi/pygi-util.c b/gi/pygi-util.c
index 1d9201e6..c06806b5 100644
--- a/gi/pygi-util.c
+++ b/gi/pygi-util.c
@@ -2,8 +2,6 @@
  * 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
@@ -40,3 +38,43 @@ pyg_integer_richcompare(PyObject *v, PyObject *w, int op)
     Py_INCREF(result);
     return result;
 }
+
+/**
+ * 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)
+{
+    size_t 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 + 1; i > 0; i--) {
+       if (g_ascii_isalpha(name[i - 1]) || name[i - 1] == '_') {
+           return &name[i - 1];
+       }
+    }
+    return name;
+}
diff --git a/gi/pygi-util.h b/gi/pygi-util.h
index c7bc1d58..9da3f6b1 100644
--- a/gi/pygi-util.h
+++ b/gi/pygi-util.h
@@ -9,6 +9,7 @@
 G_BEGIN_DECLS
 
 PyObject * pyg_integer_richcompare(PyObject *v, PyObject *w, int op);
+const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix);
 
 #if PY_VERSION_HEX >= 0x03000000
 
diff --git a/gi/pygi-value.c b/gi/pygi-value.c
index 814bb024..2a40aaa2 100644
--- a/gi/pygi-value.c
+++ b/gi/pygi-value.c
@@ -999,3 +999,37 @@ error:
     g_free (argv);
     return -1;
 }
+
+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);
+}
+
+PyObject *
+pyg__gvalue_set(PyObject *module, PyObject *args)
+{
+    PyObject *pygvalue;
+    PyObject *pyobject;
+
+    if (!PyArg_ParseTuple (args, "OO:_gi._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;
+}
diff --git a/gi/pygi-value.h b/gi/pygi-value.h
index 5b2eac19..43709a30 100644
--- a/gi/pygi-value.h
+++ b/gi/pygi-value.h
@@ -45,6 +45,9 @@ PyObject *pygi_value_to_py_structured_type (const GValue *value,
                                             GType fundamental,
                                             gboolean copy_boxed);
 
+PyObject *pyg__gvalue_get(PyObject *module, PyObject *pygvalue);
+PyObject *pyg__gvalue_set(PyObject *module, PyObject *args);
+
 G_END_DECLS
 
 #endif /* __PYGI_VALUE_H__ */
diff --git a/gi/pygobject-object.c b/gi/pygobject-object.c
index 2b25c07c..f99a331d 100644
--- a/gi/pygobject-object.c
+++ b/gi/pygobject-object.c
@@ -26,7 +26,7 @@
 #include "pygparamspec.h"
 #include "pygtype.h"
 #include "pygboxed.h"
-#include "gobjectmodule.h"
+#include "gimodule.h"
 
 #include "pygi-value.h"
 #include "pygi-type.h"
@@ -2434,3 +2434,60 @@ pygobject_object_register_types(PyObject *d)
         return;
     PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type);
 }
+
+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, &params))
+        goto cleanup;
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+    obj = g_object_newv(type, n_params, params);
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+    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(&params[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;
+}
diff --git a/gi/pygobject-object.h b/gi/pygobject-object.h
index fb39a259..70315289 100644
--- a/gi/pygobject-object.h
+++ b/gi/pygobject-object.h
@@ -50,6 +50,7 @@ void          pygobject_watch_closure    (PyObject *self, GClosure *closure);
 void          pygobject_object_register_types(PyObject *d);
 void          pygobject_ref_float(PyGObject *self);
 void          pygobject_ref_sink(PyGObject *self);
+PyObject *    pyg_object_new             (PyGObject *self, PyObject *args, PyObject *kwargs);
 
 GClosure *    gclosure_from_pyfunc(PyGObject *object, PyObject *func);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]