Update to 2.28 for TINF-96
[profile/ivi/pygobject2.git] / gobject / pygobject.c
index 2671fa9..6c2f06c 100644 (file)
@@ -29,7 +29,7 @@
 #include "pyginterface.h"
 #include "pygparamspec.h"
 
-#include "pygi-external.h"
+#include "pygi.h"
 
 
 static void pygobject_dealloc(PyGObject *self);
@@ -50,6 +50,7 @@ GQuark pygobject_class_init_key;
 GQuark pygobject_wrapper_key;
 GQuark pygobject_has_updated_constructor_key;
 GQuark pygobject_instance_data_key;
+GQuark pygobject_ref_sunk_key;
 
 
 /* -------------- class <-> wrapper manipulation --------------- */
@@ -135,6 +136,12 @@ PyTypeObject *PyGObject_MetaType = NULL;
 void
 pygobject_sink(GObject *obj)
 {
+    gboolean sunk = FALSE;
+
+    /* We use a gobject data key to avoid running the sink funcs more than once. */
+    if (g_object_get_qdata (obj, pygobject_ref_sunk_key))
+        return;
+
     if (sink_funcs) {
        gint i;
 
@@ -142,18 +149,17 @@ pygobject_sink(GObject *obj)
            if (g_type_is_a(G_OBJECT_TYPE(obj),
                            g_array_index(sink_funcs, SinkFunc, i).type)) {
                g_array_index(sink_funcs, SinkFunc, i).sinkfunc(obj);
-               return;
+
+               sunk = TRUE;
+                break;
            }
        }
     }
-    if (G_IS_INITIALLY_UNOWNED(obj) && !g_object_is_floating(obj)) {
-        /* GtkWindow and GtkInvisible does not return a ref to caller of
-         * g_object_new.
-         */
-        g_object_ref(obj);
-    } else if (g_object_is_floating(obj)) {
+
+    if (!sunk && G_IS_INITIALLY_UNOWNED (obj))
         g_object_ref_sink(obj);
-    }
+
+    g_object_set_qdata (obj, pygobject_ref_sunk_key, GINT_TO_POINTER (1));
 }
 
 /**
@@ -255,7 +261,7 @@ build_parameter_list(GObjectClass *class)
        name = g_strdup(g_param_spec_get_name(props[i]));
        /* hyphens cannot belong in identifiers */
        g_strdelimit(name, "-", '_');
-       prop_str = _PyUnicode_FromString(name);
+       prop_str = PYGLIB_PyUnicode_FromString(name);
        
        PyList_SetItem(props_list, i, prop_str);
        g_free(name);
@@ -276,7 +282,7 @@ PyGProps_getattro(PyGProps *self, PyObject *attr)
     GValue value = { 0, };
     PyObject *ret;
 
-    attr_name = _PyUnicode_AsString(attr);
+    attr_name = PYGLIB_PyUnicode_AsString(attr);
     if (!attr_name) {
         PyErr_Clear();
         return PyObject_GenericGetAttr((PyObject *)self, attr);
@@ -288,6 +294,12 @@ PyGProps_getattro(PyGProps *self, PyObject *attr)
        return build_parameter_list(class);
     }
 
+    if (self->pygobject != NULL) {
+        ret = pygi_get_property_value (self->pygobject, attr_name);
+        if (ret != NULL)
+            return ret;
+    }
+
     pspec = g_object_class_find_property(class, attr_name);
     g_type_class_unref(class);
 
@@ -361,6 +373,7 @@ PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue)
     GParamSpec *pspec;
     char *attr_name;
     GObject *obj;
+    int ret = -1;
     
     if (pvalue == NULL) {
        PyErr_SetString(PyExc_TypeError, "properties cannot be "
@@ -368,7 +381,7 @@ PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue)
        return -1;
     }
 
-    attr_name = _PyUnicode_AsString(attr);
+    attr_name = PYGLIB_PyUnicode_AsString(attr);
     if (!attr_name) {
         PyErr_Clear();
         return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue);
@@ -380,6 +393,13 @@ PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue)
         return -1;
     }
 
+    ret = pygi_set_property_value (self->pygobject, attr_name, pvalue);
+    if (ret == 0)
+        return 0;
+    else if (ret == -1)
+        if (PyErr_Occurred())
+            return -1;
+
     obj = self->pygobject->obj;
     pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), attr_name);
     if (!pspec) {
@@ -540,7 +560,7 @@ pygobject_register_class(PyObject *dict, const gchar *type_name,
      */
     s = strrchr(type->tp_name, '.');
     if (s != NULL) {
-       mod_name = _PyUnicode_FromStringAndSize(type->tp_name, (int)(s - type->tp_name));
+       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);
     }
@@ -795,12 +815,15 @@ static void
 pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present)
 {
     static int slot_offsets[] = { offsetof(PyTypeObject, tp_richcompare),
-                                 offsetof(PyTypeObject, tp_compare),
-                                 offsetof(PyTypeObject, tp_hash),
-                                 offsetof(PyTypeObject, tp_iter),
-                                 offsetof(PyTypeObject, tp_repr),
-                                 offsetof(PyTypeObject, tp_str),
-                                 offsetof(PyTypeObject, tp_print) };
+#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. */
@@ -965,6 +988,13 @@ pygobject_new(GObject *obj)
     return pygobject_new_full(obj, TRUE, NULL);
 }
 
+PyObject *
+pygobject_new_sunk(GObject *obj)
+{
+    g_object_set_qdata (obj, pygobject_ref_sunk_key, GINT_TO_POINTER (1));
+    return pygobject_new_full(obj, TRUE, NULL);
+}
+
 static void
 pygobject_unwatch_closure(gpointer data, GClosure *closure)
 {
@@ -1009,8 +1039,14 @@ PYGLIB_DEFINE_TYPE("gobject.GObject", PyGObject_Type, PyGObject);
 static void
 pygobject_dealloc(PyGObject *self)
 {
-    PyObject_ClearWeakRefs((PyObject *)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 */
@@ -1021,12 +1057,29 @@ pygobject_dealloc(PyGObject *self)
     PyObject_GC_Del(self);
 }
 
-static int
-pygobject_compare(PyGObject *self, PyGObject *v)
+static PyObject*
+pygobject_richcompare(PyObject *self, PyObject *other, int op)
 {
-    if (self->obj == v->obj) return 0;
-    if (self->obj > v->obj)  return -1;
-    return 1;
+    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
@@ -1046,7 +1099,7 @@ pygobject_repr(PyGObject *self)
               (long)self,
               self->obj ? G_OBJECT_TYPE_NAME(self->obj) : "uninitialized",
                (long)self->obj);
-    return _PyUnicode_FromString(buf);
+    return PYGLIB_PyUnicode_FromString(buf);
 }
 
 
@@ -1103,6 +1156,45 @@ 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(&param->value, G_PARAM_SPEC_VALUE_TYPE(pspec));
+            if (pyg_param_gvalue_from_pyobject(&param->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 ----------------- */
 
@@ -1133,35 +1225,9 @@ pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs)
        return -1;
     }
 
-    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;
-           gchar *key_str = _PyUnicode_AsString(key);
-
-           pspec = g_object_class_find_property (class, key_str);
-           if (!pspec) {
-               PyErr_Format(PyExc_TypeError,
-                            "object of type `%s' doesn't support property `%s'",
-                            g_type_name(object_type), key_str);
-               goto cleanup;
-           }
-           g_value_init(&params[n_params].value,
-                        G_PARAM_SPEC_VALUE_TYPE(pspec));
-           if (pyg_value_from_pyobject(&params[n_params].value, value)) {
-               PyErr_Format(PyExc_TypeError,
-                            "could not convert value for property `%s'",
-                            key_str);
-               goto cleanup;
-           }
-           params[n_params].name = g_strdup(key_str);
-           n_params++;
-       }
-    }
+    if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, &params))
+        goto cleanup;
+
     if (pygobject_constructv(self, n_params, params))
        PyErr_SetString(PyExc_RuntimeError, "could not create object");
           
@@ -1249,13 +1315,13 @@ pygobject_get_properties(PyGObject *self, PyObject *args)
         GValue value = { 0 };
         PyObject *item;
 
-        if (!_PyUnicode_Check(py_property)) {
+        if (!PYGLIB_PyUnicode_Check(py_property)) {
             PyErr_SetString(PyExc_TypeError,
                             "Expected string argument for property.");
             return NULL;
         }
 
-        property_name = _PyUnicode_AsString(py_property);
+        property_name = PYGLIB_PyUnicode_AsString(py_property);
 
         pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj),
                                         property_name);
@@ -1331,7 +1397,7 @@ pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs)
     pos = 0;
 
     while (kwargs && PyDict_Next (kwargs, &pos, &key, &value)) {
-       gchar *key_str = _PyUnicode_AsString(key);
+       gchar *key_str = PYGLIB_PyUnicode_AsString(key);
        GParamSpec *pspec;
 
        pspec = g_object_class_find_property(class, key_str);
@@ -1468,14 +1534,18 @@ pygobject_connect(PyGObject *self, PyObject *args)
     if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
                             &sigid, &detail, TRUE)) {
        PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
                     name);
        return NULL;
     }
     extra_args = PySequence_GetSlice(args, 2, len);
     if (extra_args == NULL)
        return NULL;
-    closure = pyg_closure_new(callback, extra_args, NULL);
+
+    closure = pygi_signal_closure_new(self, name, callback, extra_args, NULL);
+    if (closure == NULL)
+        closure = pyg_closure_new(callback, extra_args, NULL);
+
     pygobject_watch_closure((PyObject *)self, closure);
     handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
                                               closure, FALSE);
@@ -1517,14 +1587,18 @@ pygobject_connect_after(PyGObject *self, PyObject *args)
     if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
                             &sigid, &detail, TRUE)) {
        PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
                     name);
        return NULL;
     }
     extra_args = PySequence_GetSlice(args, 2, len);
     if (extra_args == NULL)
        return NULL;
-    closure = pyg_closure_new(callback, extra_args, NULL);
+
+    closure = pygi_signal_closure_new(self, name, callback, extra_args, NULL);
+    if (closure == NULL)
+        closure = pyg_closure_new(callback, extra_args, NULL);
+
     pygobject_watch_closure((PyObject *)self, closure);
     handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
                                               closure, TRUE);
@@ -1566,14 +1640,18 @@ pygobject_connect_object(PyGObject *self, PyObject *args)
     if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
                             &sigid, &detail, TRUE)) {
        PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
                     name);
        return NULL;
     }
     extra_args = PySequence_GetSlice(args, 3, len);
     if (extra_args == NULL)
        return NULL;
-    closure = pyg_closure_new(callback, extra_args, object);
+
+    closure = pygi_signal_closure_new(self, name, callback, extra_args, object);
+    if (closure == NULL)
+        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, FALSE);
@@ -1615,14 +1693,18 @@ pygobject_connect_object_after(PyGObject *self, PyObject *args)
     if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
                             &sigid, &detail, TRUE)) {
        PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
                     name);
        return NULL;
     }
     extra_args = PySequence_GetSlice(args, 3, len);
     if (extra_args == NULL)
        return NULL;
-    closure = pyg_closure_new(callback, extra_args, object);
+
+    closure = pygi_signal_closure_new(self, name, callback, extra_args, object);
+    if (closure == NULL)
+        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, TRUE);
@@ -1714,7 +1796,7 @@ pygobject_emit(PyGObject *self, PyObject *args)
     if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
                             &signal_id, &detail, TRUE)) {
        PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
                     name);
        return NULL;
     }
@@ -1790,7 +1872,7 @@ pygobject_stop_emission(PyGObject *self, PyObject *args)
     if (!g_signal_parse_name(signal, G_OBJECT_TYPE(self->obj),
                             &signal_id, &detail, TRUE)) {
        PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
                     signal);
        return NULL;
     }
@@ -1938,7 +2020,7 @@ pygobject_disconnect_by_func(PyGObject *self, PyObject *args)
     closure = gclosure_from_pyfunc(self, pyfunc);
     if (!closure) {
        PyErr_Format(PyExc_TypeError, "nothing connected to %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
        return NULL;
     }
     
@@ -1947,7 +2029,7 @@ pygobject_disconnect_by_func(PyGObject *self, PyObject *args)
                                                  0, 0,
                                                  closure,
                                                  NULL, NULL);
-    return _PyLong_FromLong(retval);
+    return PYGLIB_PyLong_FromLong(retval);
 }
 
 static PyObject *
@@ -1970,7 +2052,7 @@ pygobject_handler_block_by_func(PyGObject *self, PyObject *args)
     closure = gclosure_from_pyfunc(self, pyfunc);
     if (!closure) {
        PyErr_Format(PyExc_TypeError, "nothing connected to %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
        return NULL;
     }
     
@@ -1979,7 +2061,7 @@ pygobject_handler_block_by_func(PyGObject *self, PyObject *args)
                                             0, 0,
                                             closure,
                                             NULL, NULL);
-    return _PyLong_FromLong(retval);
+    return PYGLIB_PyLong_FromLong(retval);
 }
 
 static PyObject *
@@ -2002,7 +2084,7 @@ pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args)
     closure = gclosure_from_pyfunc(self, pyfunc);
     if (!closure) {
        PyErr_Format(PyExc_TypeError, "nothing connected to %s",
-                    _PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
+                    PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
        return NULL;
     }
     
@@ -2011,7 +2093,7 @@ pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args)
                                               0, 0,
                                               closure,
                                               NULL, NULL);
-    return _PyLong_FromLong(retval);
+    return PYGLIB_PyLong_FromLong(retval);
 }
 
 static PyMethodDef pygobject_methods[] = {
@@ -2020,7 +2102,7 @@ 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_KEYWORDS },
+    { "set_properties", (PyCFunction)pygobject_set_properties, METH_VARARGS|METH_KEYWORDS },
     { "freeze_notify", (PyCFunction)pygobject_freeze_notify, METH_VARARGS },
     { "notify", (PyCFunction)pygobject_notify, METH_VARARGS },
     { "thaw_notify", (PyCFunction)pygobject_thaw_notify, METH_VARARGS },
@@ -2066,7 +2148,7 @@ pygobject_get_dict(PyGObject *self, void *closure)
 static PyObject *
 pygobject_get_refcount(PyGObject *self, void *closure)
 {
-    return _PyLong_FromLong(self->obj->ref_count);
+    return PYGLIB_PyLong_FromLong(self->obj->ref_count);
 }
 
 static int
@@ -2252,6 +2334,7 @@ pygobject_object_register_types(PyObject *d)
     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");
+    pygobject_ref_sunk_key = g_quark_from_static_string("PyGObject::ref-sunk");
 
     /* GObject */
     if (!PY_TYPE_OBJECT)
@@ -2259,7 +2342,7 @@ pygobject_object_register_types(PyObject *d)
                                                      pyobject_copy,
                                                      pyobject_free);
     PyGObject_Type.tp_dealloc = (destructor)pygobject_dealloc;
-    PyGObject_Type.tp_compare = (cmpfunc)pygobject_compare;
+    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;
@@ -2302,7 +2385,7 @@ pygobject_object_register_types(PyObject *d)
     descr = PyObject_New(PyObject, &PyGPropsDescr_Type);
     PyDict_SetItemString(PyGObject_Type.tp_dict, "props", descr);
     PyDict_SetItemString(PyGObject_Type.tp_dict, "__module__",
-                        o=_PyUnicode_FromString("gobject._gobject"));
+                        o=PYGLIB_PyUnicode_FromString("gobject._gobject"));
     Py_DECREF(o);
 
     /* GPropsIter */