/* -*- 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "pygobject-private.h"
#include "pythread.h"
#include <gobject/gvaluecollector.h>
#ifdef HAVE_FFI_H
#include "ffi-marshaller.h"
static GSignalCMarshaller marshal_generic = g_cclosure_marshal_generic_ffi;
#else
static GSignalCMarshaller marshal_generic = 0;
#endif
static PyObject *gerror_exc = NULL;
static gboolean use_gil_state_api = FALSE;
static PyObject *_pyg_signal_accumulator_true_handled_func;
static GHashTable *log_handlers = NULL;
static gboolean log_handlers_disabled = FALSE;
GQuark pyginterface_type_key;
GQuark pygobject_class_init_key;
GQuark pyginterface_info_key;
GQuark pygboxed_type_key;
GQuark pygobject_class_key;
GQuark pygobject_wrapper_key;
GQuark pygboxed_marshal_key;
GQuark pygenum_class_key;
GQuark pygflags_class_key;
GQuark pygpointer_class_key;
GQuark pygobject_has_updated_constructor_key;
GQuark pygobject_instance_data_key;
static void pyg_flags_add_constants(PyObject *module, GType flags_type,
const gchar *strip_prefix);
/* -------------- GDK threading hooks ---------------------------- */
/**
* pyg_set_thread_block_funcs:
* @block_threads_func: a function to block Python threads.
* @unblock_threads_func: a function to unblock Python threads.
*
* an interface to allow pygtk to add hooks to handle threading
* similar to the old PyGTK 0.6.x releases. May not work quite right
* anymore.
*/
static void
pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func,
PyGThreadBlockFunc unblock_threads_func)
{
g_return_if_fail(pygobject_api_functions.block_threads == NULL &&
pygobject_api_functions.unblock_threads == NULL);
pygobject_api_functions.block_threads = block_threads_func;
pygobject_api_functions.unblock_threads = unblock_threads_func;
}
static void
object_free(PyObject *op)
{
PyObject_FREE(op);
}
/**
* 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 = pyg_gil_state_ensure();
Py_DECREF(obj);
pyg_gil_state_release(state);
}
/* ---------------- GBoxed functions -------------------- */
GType PY_TYPE_OBJECT = 0;
static gpointer
pyobject_copy(gpointer boxed)
{
PyObject *object = boxed;
Py_INCREF(object);
return object;
}
static void
pyobject_free(gpointer boxed)
{
PyObject *object = boxed;
PyGILState_STATE state;
state = pyg_gil_state_ensure();
Py_DECREF(object);
pyg_gil_state_release(state);
}
/* ---------------- GInterface functions -------------------- */
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", self->ob_type->tp_name);
PyErr_SetString(PyExc_NotImplementedError, buf);
return -1;
}
PyTypeObject PyGInterface_Type = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"gobject.GInterface", /* tp_name */
sizeof(PyObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)0, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)0, /* tp_getattr */
(setattrfunc)0, /* tp_setattr */
(cmpfunc)0, /* tp_compare */
(reprfunc)0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)0, /* tp_hash */
(ternaryfunc)0, /* tp_call */
(reprfunc)0, /* tp_str */
(getattrofunc)0, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
NULL, /* Documentation string */
(traverseproc)0, /* tp_traverse */
(inquiry)0, /* tp_clear */
(richcmpfunc)0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)0, /* tp_iter */
(iternextfunc)0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
(PyTypeObject *)0, /* tp_base */
(PyObject *)0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pyg_interface_init, /* tp_init */
(allocfunc)0, /* tp_alloc */
(newfunc)0, /* tp_new */
(freefunc)object_free, /* tp_free */
(inquiry)0, /* tp_is_gc */
(PyObject *)0, /* tp_bases */
};
/**
* 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.
*/
static void
pyg_register_interface(PyObject *dict, const gchar *class_name,
GType gtype, PyTypeObject *type)
{
PyObject *o;
type->ob_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);
}
static void
pyg_register_interface_info(GType gtype, const GInterfaceInfo *info)
{
g_type_set_qdata(gtype, pyginterface_info_key, (gpointer) info);
}
static const GInterfaceInfo *
pyg_lookup_interface_info(GType gtype)
{
return g_type_get_qdata(gtype, pyginterface_info_key);
}
/* -------------- GMainContext objects ---------------------------- */
/* ---------------- 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 PyString_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;
#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 = _pyg_type_from_name(name);
if (type != 0)
return pyg_type_wrapper_new(type);
PyErr_Format(PyExc_RuntimeError, "%s: unknown type name: %s",
PyString_AsString(PyObject_Repr((PyObject*)self)),
name);
return NULL;
}
static PyObject *
pyg_type_parent (PyObject *self, PyObject *args)
{
PyObject *gtype;
GType type, parent;
#if 0
if (PyErr_Warn(PyExc_DeprecationWarning,
"gobject.type_parent is deprecated; "
"use GType.parent instead"))
return NULL;
#endif
if (!PyArg_ParseTuple(args, "O:gobject.type_parent", >ype))
return NULL;
if ((type = pyg_type_from_object(gtype)) == 0)
return NULL;
parent = g_type_parent(type);
if (parent != 0)
return pyg_type_wrapper_new(parent);
PyErr_SetString(PyExc_RuntimeError, "no parent for type");
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 PyObject *
pyg_type_children (PyObject *self, PyObject *args)
{
PyObject *gtype, *list;
GType type, *children;
guint n_children, i;
#if 0
if (PyErr_Warn(PyExc_DeprecationWarning,
"gobject.type_children is deprecated; "
"use GType.children instead"))
return NULL;
#endif
if (!PyArg_ParseTuple(args, "O:gobject.type_children", >ype))
return NULL;
if ((type = pyg_type_from_object(gtype)) == 0)
return NULL;
children = g_type_children(type, &n_children);
if (children) {
list = PyList_New(0);
for (i = 0; i < n_children; i++) {
PyObject *o;
PyList_Append(list, o=pyg_type_wrapper_new(children[i]));
Py_DECREF(o);
}
g_free(children);
return list;
}
PyErr_SetString(PyExc_RuntimeError, "invalid type, or no children");
return NULL;
}
static PyObject *
pyg_type_interfaces (PyObject *self, PyObject *args)
{
PyObject *gtype, *list;
GType type, *interfaces;
guint n_interfaces, i;
#if 0
if (PyErr_Warn(PyExc_DeprecationWarning,
"gobject.type_interfaces is deprecated; "
"use GType.interfaces instead"))
return NULL;
#endif
if (!PyArg_ParseTuple(args, "O:gobject.type_interfaces", >ype))
return NULL;
if ((type = pyg_type_from_object(gtype)) == 0)
return NULL;
interfaces = g_type_interfaces(type, &n_interfaces);
if (interfaces) {
list = PyList_New(0);
for (i = 0; i < n_interfaces; i++) {
PyObject *o;
PyList_Append(list, o=pyg_type_wrapper_new(interfaces[i]));
Py_DECREF(o);
}
g_free(interfaces);
return list;
}
PyErr_SetString(PyExc_RuntimeError, "invalid type, or no interfaces");
return NULL;
}
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 = pyg_gil_state_ensure();
object_wrapper = pygobject_new(object);
if (object_wrapper == NULL) {
pyg_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);
pyg_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 = pyg_gil_state_ensure();
object_wrapper = pygobject_new(object);
if (object_wrapper == NULL) {
pyg_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);
pyg_gil_state_release(state);
}
static void
pyg_object_class_init(GObjectClass *class, PyObject *py_class)
{
class->set_property = pyg_object_set_property;
class->get_property = pyg_object_get_property;
}
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 = pyg_gil_state_ensure();
if (ihint->detail)
py_detail = PyString_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);
}
pyg_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 == _pyg_signal_accumulator_true_handled_func)
accumulator = g_signal_accumulator_true_handled;
else {
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,
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 (GType instance_type, PyObject *signals)
{
gboolean ret = TRUE;
GObjectClass *oclass;
Py_ssize_t pos = 0;
PyObject *key, *value, *overridden_signals = NULL;
overridden_signals = PyDict_New();
oclass = g_type_class_ref(instance_type);
while (PyDict_Next(signals, &pos, &key, &value)) {
const gchar *signal_name;
gchar *signal_name_canon, *c;
if (!PyString_Check(key)) {
PyErr_SetString(PyExc_TypeError,
"__gsignals__ keys must be strings");
ret = FALSE;
break;
}
signal_name = PyString_AsString (key);
if (value == Py_None ||
(PyString_Check(value) &&
!strcmp(PyString_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;
}
g_type_class_unref(oclass);
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,
(gint *)&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;
pspec = g_param_spec_pointer (prop_name, nick, blurb, flags);
break;
case G_TYPE_OBJECT:
if (!PyArg_ParseTuple(args, ""))
return NULL;
pspec = g_param_spec_object (prop_name, nick, blurb, prop_type, 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;
}
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 (!PyInt_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,
PyInt_AsLong(item));
return pspec;
}
static gboolean
add_properties (GType instance_type, PyObject *properties)
{
gboolean ret = TRUE;
GObjectClass *oclass;
Py_ssize_t pos = 0;
PyObject *key, *value;
oclass = g_type_class_ref(instance_type);
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 (!PyString_Check(key)) {
PyErr_SetString(PyExc_TypeError,
"__gproperties__ keys must be strings");
ret = FALSE;
break;
}
prop_name = PyString_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 (!PyInt_Check(item)) {
PyErr_SetString(PyExc_TypeError,
"last element in __gproperties__ value tuple must be an int");
ret = FALSE;
break;
}
flags = PyInt_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(oclass, 1, pspec);
} else {
PyObject *type, *value, *traceback;
ret = FALSE;
PyErr_Fetch(&type, &value, &traceback);
if (PyString_Check(value)) {
char msg[256];
g_snprintf(msg, 256,
"%s (while registering property '%s' for GType '%s')",
PyString_AsString(value),
prop_name, g_type_name(instance_type));
Py_DECREF(value);
value = PyString_FromString(msg);
}
PyErr_Restore(type, value, traceback);
break;
}
}
g_type_class_unref(oclass);
return ret;
}
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;
/* make name for new GType */
name_serial = 1;
/* give up after 1000 tries, just in case.. */
while (name_serial < 1000)
{
snprintf(name_serial_str, 16, "-v%i", name_serial);
module = PyObject_GetAttrString((PyObject *)class, "__module__");
if (module && PyString_Check(module)) {
type_name = g_strconcat(PyString_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 (_pyg_type_from_name(type_name) == 0)
break; /* we now have a unique name */
++name_serial;
}
return type_name;
}
static GStaticPrivate pygobject_contruction_wrapper = G_STATIC_PRIVATE_INIT;
static inline void
pygobject_init_wrapper_set(PyObject *wrapper)
{
g_static_private_set(&pygobject_contruction_wrapper, wrapper, NULL);
}
static inline PyObject *
pygobject_init_wrapper_get(void)
{
return (PyObject *) g_static_private_get(&pygobject_contruction_wrapper);
}
static void
pygobject__g_instance_init(GTypeInstance *instance,
gpointer g_class)
{
GObject *object = (GObject *) instance;
PyObject *wrapper, *args, *kwargs;
if (!g_type_get_qdata(G_OBJECT_TYPE(object),
pygobject_has_updated_constructor_key))
return;
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 = pyg_gil_state_ensure();
wrapper = pygobject_new_full(object, FALSE, g_class);
args = PyTuple_New(0);
kwargs = PyDict_New();
if (wrapper->ob_type->tp_init(wrapper, args, kwargs))
PyErr_Print();
Py_DECREF(args);
Py_DECREF(kwargs);
pyg_gil_state_release(state);
}
}
int
pyg_type_register(PyTypeObject *class, const char *type_name)
{
PyObject *gtype, *gsignals, *gproperties, *overridden_signals;
GType parent_type, instance_type;
GType *parent_interfaces;
guint n_parent_interfaces;
gint i;
GTypeQuery query;
gpointer gclass;
gpointer has_new_constructor_api;
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 (type_name == NULL)
g_free(new_type_name);
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));
return -1;
}
/* store pointer to the class with the GType */
Py_INCREF(class);
g_type_set_qdata(instance_type, g_quark_from_string("PyGObject::class"),
class);
/* set new value of __gtype__ on class */
gtype = pyg_type_wrapper_new(instance_type);
PyDict_SetItemString(class->tp_dict, "__gtype__", gtype);
Py_DECREF(gtype);
/* propagate new constructor API compatility flag from parent to child type */
has_new_constructor_api =
g_type_get_qdata(parent_type,
pygobject_has_updated_constructor_key);
if (has_new_constructor_api != NULL)
g_type_set_qdata(instance_type, pygobject_has_updated_constructor_key,
has_new_constructor_api);
/* 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());
}
/* Register interfaces that are already defined by the parent
* type and are going to be reimplemented */
if (class->tp_bases) {
for (i = 0; i < PyTuple_GET_SIZE(class->tp_bases); ++i)
{
PyTypeObject *base =
(PyTypeObject *) PyTuple_GET_ITEM(class->tp_bases, i);
GType itype;
const GInterfaceInfo *iinfo;
GInterfaceInfo iinfo_copy;
guint parent_interface_iter;
if (((PyTypeObject *) base)->tp_base != &PyGInterface_Type)
continue;
itype = pyg_type_from_object((PyObject *) base);
/* ignore interface unless defined in parent type */
if (n_parent_interfaces == 0)
continue;
for (parent_interface_iter = 0;
parent_interface_iter < n_parent_interfaces;
++parent_interface_iter)
{
if (parent_interfaces[parent_interface_iter] == itype)
break;
}
if (parent_interface_iter == n_parent_interfaces)
continue;
iinfo = pyg_lookup_interface_info(itype);
iinfo_copy = *iinfo;
iinfo_copy.interface_data = class;
if (!iinfo) {
char *msg;
msg = g_strdup_printf("Interface type %s "
"has no python implementation support",
base->tp_name);
PyErr_Warn(PyExc_RuntimeWarning, msg);
g_free(msg);
continue;
}
g_type_add_interface_static(instance_type, itype, &iinfo_copy);
}
} else
g_warning("type has no tp_bases");
/* we look this up in the instance dictionary, so we don't
* accidentally get a parent type's __gsignals__ attribute. */
gsignals = PyDict_GetItemString(class->tp_dict, "__gsignals__");
if (gsignals) {
if (!PyDict_Check(gsignals)) {
PyErr_SetString(PyExc_TypeError,
"__gsignals__ attribute not a dict!");
g_free(parent_interfaces);
return -1;
}
if (!(overridden_signals = add_signals(instance_type, gsignals))) {
g_free(parent_interfaces);
return -1;
}
if (PyDict_SetItemString(class->tp_dict, "__gsignals__",
overridden_signals)) {
g_free(parent_interfaces);
return -1;
}
Py_DECREF(overridden_signals);
} else {
PyErr_Clear();
}
/* we look this up in the instance dictionary, so we don't
* accidentally get a parent type's __gsignals__ attribute. */
gproperties = PyDict_GetItemString(class->tp_dict, "__gproperties__");
if (gproperties) {
if (!PyDict_Check(gproperties)) {
PyErr_SetString(PyExc_TypeError,
"__gproperties__ attribute not a dict!");
g_free(parent_interfaces);
return -1;
}
if (!add_properties(instance_type, gproperties)) {
g_free(parent_interfaces);
return -1;
}
PyDict_DelItemString(class->tp_dict, "__gproperties__");
/* Borrowed reference. Py_DECREF(gproperties); */
} else {
PyErr_Clear();
}
/* Register new interfaces, that are _not_ already defined by
* the parent type */
if (class->tp_bases) {
for (i = 0; i < PyTuple_GET_SIZE(class->tp_bases); ++i)
{
PyTypeObject *base =
(PyTypeObject *) PyTuple_GET_ITEM(class->tp_bases, i);
GType itype;
const GInterfaceInfo *iinfo;
GInterfaceInfo iinfo_copy;
guint parent_interface_iter;
if (((PyTypeObject *) base)->tp_base != &PyGInterface_Type)
continue;
itype = pyg_type_from_object((PyObject *) base);
/* ignore interface if already defined in parent type */
if (n_parent_interfaces != 0) {
for (parent_interface_iter = 0;
parent_interface_iter < n_parent_interfaces;
++parent_interface_iter)
{
if (parent_interfaces[parent_interface_iter] == itype)
break;
}
}
if (parent_interface_iter < n_parent_interfaces)
continue;
iinfo = pyg_lookup_interface_info(itype);
iinfo_copy = *iinfo;
iinfo_copy.interface_data = class;
if (!iinfo) {
char *msg;
msg = g_strdup_printf("Interface type %s "
"has no python implementation support",
base->tp_name);
PyErr_Warn(PyExc_RuntimeWarning, msg);
g_free(msg);
continue;
}
g_type_add_interface_static(instance_type, itype, &iinfo_copy);
}
} else
g_warning("type has no tp_bases");
gclass = g_type_class_ref(instance_type);
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 (gsignals)
PyDict_DelItemString(class->tp_dict, "__gsignals__");
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;
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 PyInt_FromLong(signal_id);
PyErr_SetString(PyExc_RuntimeError, "could not create signal");
return NULL;
}
static PyObject *
pyg_signal_list_names (PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "type", NULL };
PyObject *py_itype, *list;
GObjectClass *class = NULL;
GType itype;
guint n;
guint *ids;
guint i;
gpointer iface = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"O:gobject.signal_list_names",
kwlist, &py_itype))
return NULL;
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);
}
ids = g_signal_list_ids(itype, &n);
list = PyTuple_New((gint)n);
if (list != NULL) {
for (i = 0; i < n; i++)
PyTuple_SetItem(list, i,
PyString_FromString(g_signal_name(ids[i])));
}
g_free(ids);
if (class)
g_type_class_unref(class);
else
g_type_default_interface_unref(iface);
return list;
}
static PyObject *
pyg_signal_list_ids (PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "type", NULL };
PyObject *py_itype, *list;
GObjectClass *class = NULL;
GType itype;
guint n;
guint *ids;
guint i;
gpointer iface = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"O:gobject.signal_list_ids",
kwlist, &py_itype))
return NULL;
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);
}
ids = g_signal_list_ids(itype, &n);
list = PyTuple_New((gint)n);
if (list == NULL) {
g_free(ids);
g_type_class_unref(class);
return NULL;
}
for (i = 0; i < n; i++)
PyTuple_SetItem(list, i, PyInt_FromLong(ids[i]));
g_free(ids);
if (class)
g_type_class_unref(class);
else
g_type_default_interface_unref(iface);
return list;
}
static PyObject *
pyg_signal_lookup (PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "name", "type", NULL };
PyObject *py_itype;
GObjectClass *class = NULL;
GType itype;
gchar *signal_name;
guint id;
gpointer iface = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO:gobject.signal_lookup",
kwlist, &signal_name, &py_itype))
return NULL;
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);
if (class)
g_type_class_unref(class);
else
g_type_default_interface_unref(iface);
return PyInt_FromLong(id);
}
static PyObject *
pyg_signal_name (PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "signal_id", NULL };
const gchar *signal_name;
guint id;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:gobject.signal_name",
kwlist, &id))
return NULL;
signal_name = g_signal_name(id);
if (signal_name)
return PyString_FromString(signal_name);
Py_INCREF(Py_None);
return Py_None;
}
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, PyInt_FromLong(query.signal_id));
PyTuple_SET_ITEM(py_query, 1, PyString_FromString(query.signal_name));
PyTuple_SET_ITEM(py_query, 2, pyg_type_wrapper_new(query.itype));
PyTuple_SET_ITEM(py_query, 3, PyInt_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;
int 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 (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;
const gchar *key_str = PyString_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_type_name(type), key_str);
goto cleanup;
}
g_value_init(¶ms[n_params].value,
G_PARAM_SPEC_VALUE_TYPE(pspec));
if (pyg_param_gvalue_from_pyobject(¶ms[n_params].value,
value, pspec) < 0) {
PyErr_Format(PyExc_TypeError,
"could not convert value for property `%s' from %s to %s",
key_str, value->ob_type->tp_name,
g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)));
goto cleanup;
}
params[n_params].name = g_strdup(key_str);
n_params++;
}
}
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) {
self = (PyGObject *) pygobject_new_full((GObject *)obj, FALSE, NULL);
g_object_unref(obj);
pygobject_sink(obj);
} else
self = NULL;
return (PyObject *) self;
}
static gint
get_handler_priority(gint *priority, PyObject *kwargs)
{
Py_ssize_t len, pos;
PyObject *key, *val;
/* no keyword args? leave as default */
if (kwargs == NULL) return 0;
len = PyDict_Size(kwargs);
if (len == 0) return 0;
if (len != 1) {
PyErr_SetString(PyExc_TypeError,
"expecting at most one keyword argument");
return -1;
}
pos = 0;
PyDict_Next(kwargs, &pos, &key, &val);
if (!PyString_Check(key)) {
PyErr_SetString(PyExc_TypeError,
"keyword argument name is not a string");
return -1;
}
if (strcmp(PyString_AsString(key), "priority") != 0) {
PyErr_SetString(PyExc_TypeError,
"only 'priority' keyword argument accepted");
return -1;
}
*priority = PyInt_AsLong(val);
if (PyErr_Occurred()) {
PyErr_Clear();
PyErr_SetString(PyExc_ValueError, "could not get priority value");
return -1;
}
return 0;
}
gboolean
pyg_handler_marshal(gpointer user_data)
{
PyObject *tuple, *ret;
gboolean res;
PyGILState_STATE state;
g_return_val_if_fail(user_data != NULL, FALSE);
state = pyg_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);
}
pyg_gil_state_release(state);
return res;
}
static PyObject *
pyg_idle_add(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *first, *callback, *cbargs = NULL, *data;
gint len, priority = G_PRIORITY_DEFAULT_IDLE;
guint handler_id;
len = PyTuple_Size(args);
if (len < 1) {
PyErr_SetString(PyExc_TypeError,
"idle_add requires at least 1 argument");
return NULL;
}
first = PySequence_GetSlice(args, 0, 1);
if (!PyArg_ParseTuple(first, "O:idle_add", &callback)) {
Py_DECREF(first);
return NULL;
}
Py_DECREF(first);
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "first argument not callable");
return NULL;
}
if (get_handler_priority(&priority, kwargs) < 0)
return NULL;
cbargs = PySequence_GetSlice(args, 1, len);
if (cbargs == NULL)
return NULL;
data = Py_BuildValue("(ON)", callback, cbargs);
if (data == NULL)
return NULL;
handler_id = g_idle_add_full(priority, pyg_handler_marshal, data,
pyg_destroy_notify);
return PyInt_FromLong(handler_id);
}
static PyObject *
pyg_timeout_add(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *first, *callback, *cbargs = NULL, *data;
gint len, priority = G_PRIORITY_DEFAULT;
guint interval, handler_id;
len = PyTuple_Size(args);
if (len < 2) {
PyErr_SetString(PyExc_TypeError,
"timeout_add requires at least 2 args");
return NULL;
}
first = PySequence_GetSlice(args, 0, 2);
if (!PyArg_ParseTuple(first, "IO:timeout_add", &interval, &callback)) {
Py_DECREF(first);
return NULL;
}
Py_DECREF(first);
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "second argument not callable");
return NULL;
}
if (get_handler_priority(&priority, kwargs) < 0)
return NULL;
cbargs = PySequence_GetSlice(args, 2, len);
if (cbargs == NULL)
return NULL;
data = Py_BuildValue("(ON)", callback, cbargs);
if (data == NULL)
return NULL;
handler_id = g_timeout_add_full(priority, interval,
pyg_handler_marshal, data,
pyg_destroy_notify);
return PyInt_FromLong(handler_id);
}
#if GLIB_CHECK_VERSION(2,13,5)
static PyObject *
pyg_timeout_add_seconds(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *first, *callback, *cbargs = NULL, *data;
gint len, priority = G_PRIORITY_DEFAULT;
guint interval, handler_id;
len = PyTuple_Size(args);
if (len < 2) {
PyErr_SetString(PyExc_TypeError,
"timeout_add_seconds requires at least 2 args");
return NULL;
}
first = PySequence_GetSlice(args, 0, 2);
if (!PyArg_ParseTuple(first, "IO:timeout_add_seconds", &interval, &callback)) {
Py_DECREF(first);
return NULL;
}
Py_DECREF(first);
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "second argument not callable");
return NULL;
}
if (get_handler_priority(&priority, kwargs) < 0)
return NULL;
cbargs = PySequence_GetSlice(args, 2, len);
if (cbargs == NULL)
return NULL;
data = Py_BuildValue("(ON)", callback, cbargs);
if (data == NULL)
return NULL;
handler_id = g_timeout_add_seconds_full(priority, interval,
pyg_handler_marshal, data,
pyg_destroy_notify);
return PyInt_FromLong(handler_id);
}
#endif
static gboolean
iowatch_marshal(GIOChannel *source,
GIOCondition condition,
gpointer user_data)
{
PyGILState_STATE state;
PyObject *tuple, *func, *firstargs, *args, *ret;
gboolean res;
g_return_val_if_fail(user_data != NULL, FALSE);
state = pyg_gil_state_ensure();
tuple = (PyObject *)user_data;
func = PyTuple_GetItem(tuple, 0);
/* arg vector is (fd, condtion, *args) */
firstargs = Py_BuildValue("(Oi)", PyTuple_GetItem(tuple, 1), condition);
args = PySequence_Concat(firstargs, PyTuple_GetItem(tuple, 2));
Py_DECREF(firstargs);
ret = PyObject_CallObject(func, args);
Py_DECREF(args);
if (!ret) {
PyErr_Print();
res = FALSE;
} else {
if (ret == Py_None) {
if (PyErr_Warn(PyExc_Warning, "gobject.io_add_watch callback returned None;"
" should return True/False")) {
PyErr_Print();
}
}
res = PyObject_IsTrue(ret);
Py_DECREF(ret);
}
pyg_gil_state_release(state);
return res;
}
static PyObject *
pyg_io_add_watch(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *first, *pyfd, *callback, *cbargs = NULL, *data;
gint fd, priority = G_PRIORITY_DEFAULT, condition;
Py_ssize_t len;
GIOChannel *iochannel;
guint handler_id;
len = PyTuple_Size(args);
if (len < 3) {
PyErr_SetString(PyExc_TypeError,
"io_add_watch requires at least 3 args");
return NULL;
}
first = PySequence_GetSlice(args, 0, 3);
if (!PyArg_ParseTuple(first, "OiO:io_add_watch", &pyfd, &condition,
&callback)) {
Py_DECREF(first);
return NULL;
}
Py_DECREF(first);
fd = PyObject_AsFileDescriptor(pyfd);
if (fd < 0) {
return NULL;
}
if (!PyCallable_Check(callback)) {
PyErr_SetString(PyExc_TypeError, "second argument not callable");
return NULL;
}
if (get_handler_priority(&priority, kwargs) < 0)
return NULL;
cbargs = PySequence_GetSlice(args, 3, len);
if (cbargs == NULL)
return NULL;
data = Py_BuildValue("(OON)", callback, pyfd, cbargs);
if (data == NULL)
return NULL;
iochannel = g_io_channel_unix_new(fd);
handler_id = g_io_add_watch_full(iochannel, priority, condition,
iowatch_marshal, data,
(GDestroyNotify)pyg_destroy_notify);
g_io_channel_unref(iochannel);
return PyInt_FromLong(handler_id);
}
static PyObject *
pyg_source_remove(PyObject *self, PyObject *args)
{
guint tag;
if (!PyArg_ParseTuple(args, "i:source_remove", &tag))
return NULL;
return PyBool_FromLong(g_source_remove(tag));
}
static PyObject *
pyg_main_context_default(PyObject *unused)
{
return pyg_main_context_new(g_main_context_default());
}
static int pyg_thread_state_tls_key = -1;
/* Enable threading; note that the GIL must be held by the current
thread when this function is called */
static int
pyg_enable_threads (void)
{
if (getenv ("PYGTK_USE_GIL_STATE_API"))
use_gil_state_api = TRUE;
#ifndef DISABLE_THREADING
if (!pygobject_api_functions.threads_enabled) {
PyEval_InitThreads();
if (!g_threads_got_initialized)
g_thread_init(NULL);
pygobject_api_functions.threads_enabled = TRUE;
pyg_thread_state_tls_key = PyThread_create_key();
}
return 0;
#else
PyErr_SetString(PyExc_RuntimeError,
"pygtk threading disabled at compile time");
return -1;
#endif
}
static int
pyg_gil_state_ensure_py23 (void)
{
return PyGILState_Ensure();
}
static void
pyg_gil_state_release_py23 (int flag)
{
PyGILState_Release(flag);
}
static PyObject *
pyg_threads_init (PyObject *unused, PyObject *args, PyObject *kwargs)
{
if (pyg_enable_threads())
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
struct _PyGChildData {
PyObject *func;
PyObject *data;
};
static void
child_watch_func(GPid pid, gint status, gpointer data)
{
struct _PyGChildData *child_data = (struct _PyGChildData *) data;
PyObject *retval;
PyGILState_STATE gil;
gil = pyg_gil_state_ensure();
if (child_data->data)
retval = PyObject_CallFunction(child_data->func, "iiO", pid, status,
child_data->data);
else
retval = PyObject_CallFunction(child_data->func, "ii", pid, status);
if (retval)
Py_DECREF(retval);
else
PyErr_Print();
pyg_gil_state_release(gil);
}
static void
child_watch_dnotify(gpointer data)
{
struct _PyGChildData *child_data = (struct _PyGChildData *) data;
Py_DECREF(child_data->func);
Py_XDECREF(child_data->data);
g_free(child_data);
}
static PyObject *
pyg_child_watch_add(PyObject *unused, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "pid", "function", "data", "priority", NULL };
guint id;
gint priority = G_PRIORITY_DEFAULT;
int pid;
PyObject *func, *user_data = NULL;
struct _PyGChildData *child_data;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"iO|Oi:gobject.child_watch_add", kwlist,
&pid, &func, &user_data, &priority))
return NULL;
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError,
"gobject.child_watch_add: second argument must be callable");
return NULL;
}
child_data = g_new(struct _PyGChildData, 1);
child_data->func = func;
child_data->data = user_data;
Py_INCREF(child_data->func);
if (child_data->data)
Py_INCREF(child_data->data);
id = g_child_watch_add_full(priority, pid, child_watch_func,
child_data, child_watch_dnotify);
return PyInt_FromLong(id);
}
static PyObject *
pyg_pid_close(PyIntObject *self, PyObject *args, PyObject *kwargs)
{
g_spawn_close_pid((GPid) self->ob_ival);
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef pyg_pid_methods[] = {
{ "close", (PyCFunction)pyg_pid_close, METH_NOARGS },
{ NULL, NULL, 0 }
};
static void
pyg_pid_free(PyIntObject *gpid)
{
g_spawn_close_pid((GPid) gpid->ob_ival);
PyInt_Type.tp_free((void *) gpid);
}
static int
pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyErr_SetString(PyExc_TypeError, "gobject.Pid cannot be manually instantiated");
return -1;
}
static PyTypeObject PyGPid_Type = {
PyObject_HEAD_INIT(NULL)
0,
"gobject.Pid",
sizeof(PyIntObject),
0,
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
pyg_pid_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
pyg_pid_tp_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
(freefunc)pyg_pid_free, /* tp_free */
0, /* tp_is_gc */
};
static PyObject *
pyg_pid_new(GPid pid)
{
PyIntObject *pygpid;
pygpid = PyObject_NEW(PyIntObject, &PyGPid_Type);
pygpid->ob_ival = pid;
return (PyObject *) pygpid;
}
struct _PyGChildSetupData {
PyObject *func;
PyObject *data;
};
static void
_pyg_spawn_async_callback(gpointer user_data)
{
struct _PyGChildSetupData *data;
PyObject *retval;
PyGILState_STATE gil;
data = (struct _PyGChildSetupData *) user_data;
gil = pyg_gil_state_ensure();
if (data->data)
retval = PyObject_CallFunction(data->func, "O", data->data);
else
retval = PyObject_CallFunction(data->func, NULL);
if (retval)
Py_DECREF(retval);
else
PyErr_Print();
Py_DECREF(data->func);
Py_XDECREF(data->data);
g_free(data);
pyg_gil_state_release(gil);
}
static PyObject *
pyg_spawn_async(PyObject *unused, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "argv", "envp", "working_directory", "flags",
"child_setup", "user_data", "standard_input",
"standard_output", "standard_error", NULL };
PyObject *pyargv, *pyenvp = NULL;
char **argv, **envp = NULL;
PyObject *func = NULL, *user_data = NULL;
char *working_directory = NULL;
int flags = 0, _stdin = -1, _stdout = -1, _stderr = -1;
PyObject *pystdin = NULL, *pystdout = NULL, *pystderr = NULL;
gint *standard_input, *standard_output, *standard_error;
struct _PyGChildSetupData *callback_data = NULL;
GError *error = NULL;
GPid child_pid = -1;
Py_ssize_t len, i;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gobject.spawn_async",
kwlist,
&pyargv, &pyenvp, &working_directory, &flags,
&func, &user_data,
&pystdin, &pystdout, &pystderr))
return NULL;
if (pystdin && PyObject_IsTrue(pystdin))
standard_input = &_stdin;
else
standard_input = NULL;
if (pystdout && PyObject_IsTrue(pystdout))
standard_output = &_stdout;
else
standard_output = NULL;
if (pystderr && PyObject_IsTrue(pystderr))
standard_error = &_stderr;
else
standard_error = NULL;
/* parse argv */
if (!PySequence_Check(pyargv)) {
PyErr_SetString(PyExc_TypeError,
"gobject.spawn_async: "
"first argument must be a sequence of strings");
return NULL;
}
len = PySequence_Length(pyargv);
argv = g_new0(char *, len + 1);
for (i = 0; i < len; ++i) {
PyObject *tmp = PySequence_ITEM(pyargv, i);
if (!PyString_Check(tmp)) {
PyErr_SetString(PyExc_TypeError,
"gobject.spawn_async: "
"first argument must be a sequence of strings");
g_free(argv);
Py_XDECREF(tmp);
return NULL;
}
argv[i] = PyString_AsString(tmp);
Py_DECREF(tmp);
}
/* parse envp */
if (pyenvp) {
if (!PySequence_Check(pyenvp)) {
PyErr_SetString(PyExc_TypeError,
"gobject.spawn_async: "
"second argument must be a sequence of strings");
g_free(argv);
return NULL;
}
len = PySequence_Length(pyenvp);
envp = g_new0(char *, len + 1);
for (i = 0; i < len; ++i) {
PyObject *tmp = PySequence_ITEM(pyenvp, i);
if (!PyString_Check(tmp)) {
PyErr_SetString(PyExc_TypeError,
"gobject.spawn_async: "
"second argument must be a sequence of strings");
g_free(envp);
Py_XDECREF(tmp);
g_free(argv);
return NULL;
}
envp[i] = PyString_AsString(tmp);
Py_DECREF(tmp);
}
}
if (func) {
callback_data = g_new(struct _PyGChildSetupData, 1);
callback_data->func = func;
callback_data->data = user_data;
Py_INCREF(callback_data->func);
if (callback_data->data)
Py_INCREF(callback_data->data);
}
if (!g_spawn_async_with_pipes(working_directory, argv, envp, flags,
func? _pyg_spawn_async_callback : NULL,
callback_data, &child_pid,
standard_input,
standard_output,
standard_error,
&error))
{
g_free(argv);
if (envp) g_free(envp);
if (callback_data) {
Py_DECREF(callback_data->func);
Py_XDECREF(callback_data->data);
g_free(callback_data);
}
pyg_error_check(&error);
return NULL;
}
g_free(argv);
if (envp) g_free(envp);
if (standard_input)
pystdin = PyInt_FromLong(*standard_input);
else {
Py_INCREF(Py_None);
pystdin = Py_None;
}
if (standard_output)
pystdout = PyInt_FromLong(*standard_output);
else {
Py_INCREF(Py_None);
pystdout = Py_None;
}
if (standard_error)
pystderr = PyInt_FromLong(*standard_error);
else {
Py_INCREF(Py_None);
pystderr = Py_None;
}
return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr);
}
static PyObject *
pyg_markup_escape_text(PyObject *unused, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "text", NULL };
char *text_in, *text_out;
int text_size;
PyObject *retval;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s#:gobject.markup_escape_text", kwlist,
&text_in, &text_size))
return NULL;
text_out = g_markup_escape_text(text_in, text_size);
retval = PyString_FromString(text_out);
g_free(text_out);
return retval;
}
static PyObject *
pyg_get_current_time(PyObject *unused)
{
GTimeVal timeval;
double ret;
g_get_current_time(&timeval);
ret = (double)timeval.tv_sec + (double)timeval.tv_usec * 0.000001;
return PyFloat_FromDouble(ret);
}
static PyObject *
pyg_main_depth(PyObject *unused)
{
return PyInt_FromLong(g_main_depth());
}
static PyObject *
pyg_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 = pyg_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:
pyg_gil_state_release(state);
return retval;
}
static PyObject *
pyg_add_emission_hook(PyGObject *self, PyObject *args)
{
PyObject *first, *callback, *extra_args, *data;
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)) {
PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
PyString_AsString(PyObject_Repr((PyObject*)self)),
name);
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_remove_emission_hook(PyGObject *self, PyObject *args)
{
PyObject *pygtype;
char *name;
guint signal_id;
gulong hook_id;
GType gtype;
if (!PyArg_ParseTuple(args, "Osk:gobject.remove_emission_hook",
&pygtype, &name, &hook_id))
return NULL;
if ((gtype = pyg_type_from_object(pygtype)) == 0) {
return NULL;
}
if (!g_signal_parse_name(name, gtype, &signal_id, NULL, TRUE)) {
PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
PyString_AsString(PyObject_Repr((PyObject*)self)),
name);
return NULL;
}
g_signal_remove_emission_hook(signal_id, hook_id);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass)
{
Py_INCREF(metaclass);
PyGObject_MetaType = metaclass;
Py_INCREF(metaclass);
PyGObject_Type.ob_type = metaclass;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
pyg_filename_display_name(PyGObject *self, PyObject *args)
{
PyObject *py_display_name;
char *filename, *display_name;
if (!PyArg_ParseTuple(args, "s:gobject.filename_display_name",
&filename))
return NULL;
display_name = g_filename_display_name(filename);
py_display_name = PyUnicode_DecodeUTF8(display_name, strlen(display_name), NULL);
g_free(display_name);
return py_display_name;
}
static PyObject *
pyg_filename_display_basename(PyGObject *self, PyObject *args)
{
PyObject *py_display_basename;
char *filename, *display_basename;
if (!PyArg_ParseTuple(args, "s:gobject.filename_display_basename",
&filename))
return NULL;
display_basename = g_filename_display_basename(filename);
py_display_basename = PyUnicode_DecodeUTF8(display_basename, strlen(display_basename), NULL);
g_free(display_basename);
return py_display_basename;
}
static PyObject *
pyg_filename_from_utf8(PyGObject *self, PyObject *args)
{
char *filename, *utf8string;
Py_ssize_t utf8string_len;
gsize bytes_written;
GError *error = NULL;
PyObject *py_filename;
if (!PyArg_ParseTuple(args, "s#:gobject.filename_from_utf8",
&utf8string, &utf8string_len))
return NULL;
filename = g_filename_from_utf8(utf8string, utf8string_len, NULL, &bytes_written, &error);
if (pyg_error_check(&error)) {
g_free(filename);
return NULL;
}
py_filename = PyString_FromStringAndSize(filename, bytes_written);
g_free(filename);
return py_filename;
}
PyObject*
pyg_set_application_name(PyObject *self, PyObject *args)
{
char *s;
if (!PyArg_ParseTuple(args, "s:gobject.set_application_name", &s))
return NULL;
g_set_application_name(s);
Py_INCREF(Py_None);
return Py_None;
}
PyObject*
pyg_set_prgname(PyObject *self, PyObject *args)
{
char *s;
if (!PyArg_ParseTuple(args, "s:gobject.set_prgname", &s))
return NULL;
g_set_prgname(s);
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef pygobject_functions[] = {
{ "type_name", pyg_type_name, METH_VARARGS },
{ "type_from_name", pyg_type_from_name, METH_VARARGS },
{ "type_parent", pyg_type_parent, METH_VARARGS },
{ "type_is_a", pyg_type_is_a, METH_VARARGS },
{ "type_children", pyg_type_children, METH_VARARGS },
{ "type_interfaces", pyg_type_interfaces, METH_VARARGS },
{ "type_register", _wrap_pyg_type_register, METH_VARARGS },
{ "signal_new", pyg_signal_new, METH_VARARGS },
{ "signal_list_names",
(PyCFunction)pyg_signal_list_names, METH_VARARGS|METH_KEYWORDS },
{ "signal_list_ids",
(PyCFunction)pyg_signal_list_ids, METH_VARARGS|METH_KEYWORDS },
{ "signal_lookup",
(PyCFunction)pyg_signal_lookup, METH_VARARGS|METH_KEYWORDS },
{ "signal_name",
(PyCFunction)pyg_signal_name, METH_VARARGS|METH_KEYWORDS },
{ "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 },
{ "idle_add",
(PyCFunction)pyg_idle_add, METH_VARARGS|METH_KEYWORDS },
{ "timeout_add",
(PyCFunction)pyg_timeout_add, METH_VARARGS|METH_KEYWORDS },
#if GLIB_CHECK_VERSION(2,13,5)
{ "timeout_add_seconds",
(PyCFunction)pyg_timeout_add_seconds, METH_VARARGS|METH_KEYWORDS },
#endif
{ "io_add_watch",
(PyCFunction)pyg_io_add_watch, METH_VARARGS|METH_KEYWORDS },
{ "source_remove",
pyg_source_remove, METH_VARARGS },
{ "main_context_default",
(PyCFunction)pyg_main_context_default, METH_NOARGS },
{ "threads_init",
(PyCFunction)pyg_threads_init, METH_VARARGS|METH_KEYWORDS },
{ "child_watch_add",
(PyCFunction)pyg_child_watch_add, METH_VARARGS|METH_KEYWORDS },
{ "spawn_async",
(PyCFunction)pyg_spawn_async, METH_VARARGS|METH_KEYWORDS },
{ "markup_escape_text",
(PyCFunction)pyg_markup_escape_text, METH_VARARGS|METH_KEYWORDS },
{ "get_current_time",
(PyCFunction)pyg_get_current_time, METH_NOARGS },
{ "main_depth",
(PyCFunction)pyg_main_depth, METH_NOARGS },
{ "signal_accumulator_true_handled",
(PyCFunction)pyg_signal_accumulator_true_handled, METH_VARARGS },
{ "add_emission_hook",
(PyCFunction)pyg_add_emission_hook, METH_VARARGS },
{ "remove_emission_hook",
(PyCFunction)pyg_remove_emission_hook, METH_VARARGS },
{ "_install_metaclass",
(PyCFunction)pyg__install_metaclass, METH_O },
{ "filename_display_name",
(PyCFunction)pyg_filename_display_name, METH_VARARGS },
{ "filename_display_basename",
(PyCFunction)pyg_filename_display_basename, METH_VARARGS },
{ "filename_from_utf8",
(PyCFunction)pyg_filename_from_utf8, METH_VARARGS },
{ "set_application_name",
(PyCFunction)pyg_set_application_name, METH_VARARGS },
{ "set_prgname",
(PyCFunction)pyg_set_prgname, 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 j;
prefix_len = strlen(strip_prefix);
/* strip off prefix from value name, while keeping it a valid
* identifier */
for (j = prefix_len; j >= 0; j--) {
if (g_ascii_isalpha(name[j]) || name[j] == '_') {
return &name[j];
}
}
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.
*/
gboolean
pyg_error_check(GError **error)
{
PyGILState_STATE state;
g_return_val_if_fail(error != NULL, FALSE);
if (*error != NULL) {
PyObject *exc_instance;
PyObject *d;
state = pyg_gil_state_ensure();
exc_instance = PyObject_CallFunction(gerror_exc, "z",
(*error)->message);
PyObject_SetAttrString(exc_instance, "domain",
d=PyString_FromString(g_quark_to_string((*error)->domain)));
Py_DECREF(d);
PyObject_SetAttrString(exc_instance, "code",
d=PyInt_FromLong((*error)->code));
Py_DECREF(d);
if ((*error)->message) {
PyObject_SetAttrString(exc_instance, "message",
d=PyString_FromString((*error)->message));
Py_DECREF(d);
} else {
PyObject_SetAttrString(exc_instance, "message", Py_None);
}
PyErr_SetObject(gerror_exc, exc_instance);
Py_DECREF(exc_instance);
g_clear_error(error);
pyg_gil_state_release(state);
return TRUE;
}
return FALSE;
}
/**
* 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.
*/
gboolean
pyg_gerror_exception_check(GError **error)
{
PyObject *type, *value, *traceback;
PyObject *py_message, *py_domain, *py_code;
const char *bad_gerror_message;
PyErr_Fetch(&type, &value, &traceback);
if (type == NULL)
return 0;
PyErr_NormalizeException(&type, &value, &traceback);
if (value == NULL) {
PyErr_Restore(type, value, traceback);
PyErr_Print();
return -2;
}
if (!value || !PyErr_GivenExceptionMatches(type, (PyObject *) gerror_exc)) {
PyErr_Restore(type, value, traceback);
PyErr_Print();
return -2;
}
Py_DECREF(type);
Py_XDECREF(traceback);
py_message = PyObject_GetAttrString(value, "message");
if (!py_message || !PyString_Check(py_message)) {
bad_gerror_message = "gobject.GError instances must have a 'message' string attribute";
goto bad_gerror;
}
py_domain = PyObject_GetAttrString(value, "domain");
if (!py_domain || !PyString_Check(py_domain)) {
bad_gerror_message = "gobject.GError instances must have a 'domain' string attribute";
Py_DECREF(py_message);
goto bad_gerror;
}
py_code = PyObject_GetAttrString(value, "code");
if (!py_code || !PyInt_Check(py_code)) {
bad_gerror_message = "gobject.GError instances must have a 'code' int attribute";
Py_DECREF(py_message);
Py_DECREF(py_domain);
goto bad_gerror;
}
g_set_error(error, g_quark_from_string(PyString_AsString(py_domain)),
PyInt_AsLong(py_code), PyString_AsString(py_message));
Py_DECREF(py_message);
Py_DECREF(py_code);
Py_DECREF(py_domain);
return -1;
bad_gerror:
Py_DECREF(value);
g_set_error(error, g_quark_from_static_string("pygobject"), 0, bad_gerror_message);
PyErr_SetString(PyExc_ValueError, bad_gerror_message);
PyErr_Print();
return -2;
}
static PyObject *
build_gerror( void )
{
PyObject *dict;
PyObject *gerror_class;
dict = PyDict_New();
/* This is a hack to work around the deprecation warning of
* BaseException.message in Python 2.6+.
* GError has also an "message" attribute.
*/
PyDict_SetItemString(dict, "message", Py_None);
gerror_class = PyErr_NewException("gobject.GError", PyExc_RuntimeError, dict);
Py_DECREF(dict);
return gerror_class;
}
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, PyString_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 (!PyString_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(PyString_AsString(PySequence_Fast_GET_ITEM(obj, i)));
argv[i] = NULL;
g_value_take_boxed(value, argv);
return 0;
}
/**
* 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;
}
int
pygobject_constructv(PyGObject *self,
guint n_parameters,
GParameter *parameters)
{
if (self->obj == NULL) {
GObject *obj;
pygobject_init_wrapper_set((PyObject *) self);
obj = g_object_newv(pyg_type_from_object((PyObject *) self),
n_parameters, parameters);
pygobject_init_wrapper_set(NULL);
if (self->obj == NULL) {
self->obj = obj;
pygobject_sink(obj);
pygobject_register_wrapper((PyObject *) self);
}
} else {
int i;
for (i = 0; i < n_parameters; ++i)
g_object_set_property(self->obj,
parameters[i].name,
¶meters[i].value);
}
return 0;
}
/* This function is mostly juste copy-paste from g_object_new, but
* calls pygobject_constructv instead of g_object_newv */
int
pygobject_construct(PyGObject *self, const char *first_property_name, ...)
{
va_list var_args;
GObjectClass *class;
GParameter *params;
const gchar *name;
guint n_params = 0, n_alloced_params = 16;
GType object_type = pyg_type_from_object((PyObject *) self);
int retval;
if (!first_property_name)
return pygobject_constructv(self, 0, NULL);
va_start(var_args, first_property_name);
class = g_type_class_ref(object_type);
params = g_new(GParameter, n_alloced_params);
name = first_property_name;
while (name)
{
gchar *error = NULL;
GParamSpec *pspec = g_object_class_find_property(class, name);
if (!pspec)
{
g_warning("%s: object class `%s' has no property named `%s'",
G_STRFUNC,
g_type_name(object_type),
name);
break;
}
if (n_params >= n_alloced_params)
{
n_alloced_params += 16;
params = g_renew(GParameter, params, n_alloced_params);
}
params[n_params].name = name;
params[n_params].value.g_type = 0;
g_value_init(¶ms[n_params].value, G_PARAM_SPEC_VALUE_TYPE(pspec));
G_VALUE_COLLECT(¶ms[n_params].value, var_args, 0, &error);
if (error)
{
g_warning("%s: %s", G_STRFUNC, error);
g_free(error);
g_value_unset(¶ms[n_params].value);
break;
}
n_params++;
name = va_arg(var_args, gchar*);
}
retval = pygobject_constructv(self, n_params, params);
while (n_params--)
g_value_unset(¶ms[n_params].value);
g_free(params);
va_end(var_args);
g_type_class_unref(class);
return retval;
}
void
pyg_set_object_has_new_constructor(GType type)
{
g_type_set_qdata(type, pygobject_has_updated_constructor_key, GINT_TO_POINTER(1));
}
#define GET_INT(x) (((PyIntObject*)x)->ob_ival)
PyObject *
pyg_integer_richcompare(PyObject *v, PyObject *w, int op)
{
PyObject *result;
gboolean t;
switch (op) {
case Py_EQ: t = GET_INT(v) == GET_INT(w); break;
case Py_NE: t = GET_INT(v) != GET_INT(w); break;
case Py_LE: t = GET_INT(v) <= GET_INT(w); break;
case Py_GE: t = GET_INT(v) >= GET_INT(w); break;
case Py_LT: t = GET_INT(v) < GET_INT(w); break;
case Py_GT: t = GET_INT(v) > GET_INT(w); break;
default: g_assert_not_reached();
}
result = t ? Py_True : Py_False;
Py_INCREF(result);
return result;
}
#undef GET_INT
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 = pyg_gil_state_ensure();
PyErr_Warn(warning, (char *) message);
pyg_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_register_sinkfunc,
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,
FALSE, /* threads_enabled */
pyg_enable_threads,
pyg_gil_state_ensure_py23,
pyg_gil_state_release_py23,
pyg_register_class_init,
pyg_register_interface_info,
pyg_closure_set_exception_handler,
pygobject_constructv,
pygobject_construct,
pyg_set_object_has_new_constructor,
add_warning_redirection,
disable_warning_redirections,
pyg_type_register_custom_callback,
pyg_gerror_exception_check
};
#define REGISTER_TYPE(d, type, name) \
type.ob_type = &PyType_Type; \
type.tp_alloc = PyType_GenericAlloc; \
type.tp_new = PyType_GenericNew; \
if (PyType_Ready(&type)) \
return; \
PyDict_SetItemString(d, name, (PyObject *)&type);
#define REGISTER_GTYPE(d, type, name, gtype) \
REGISTER_TYPE(d, type, name); \
PyDict_SetItemString(type.tp_dict, "__gtype__", \
o=pyg_type_wrapper_new(gtype)); \
Py_DECREF(o);
DL_EXPORT(void)
init_gobject(void)
{
PyObject *m, *d, *o, *tuple, *features;
PyObject *descr;
PyObject *warning;
PyGParamSpec_Type.ob_type = &PyType_Type;
m = Py_InitModule("gobject._gobject", pygobject_functions);
d = PyModule_GetDict(m);
g_type_init();
pygboxed_type_key = g_quark_from_static_string("PyGBoxed::class");
pygboxed_marshal_key = g_quark_from_static_string("PyGBoxed::marshal");
pygenum_class_key = g_quark_from_static_string("PyGEnum::class");
pygflags_class_key = g_quark_from_static_string("PyGFlags::class");
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");
pyginterface_type_key = g_quark_from_static_string("PyGInterface::type");
pyginterface_info_key = g_quark_from_static_string("PyGInterface::info");
pygpointer_class_key = g_quark_from_static_string("PyGPointer::class");
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");
REGISTER_TYPE(d, PyGTypeWrapper_Type, "GType");
if (!PY_TYPE_OBJECT)
PY_TYPE_OBJECT = g_boxed_type_register_static("PyObject",
pyobject_copy,
pyobject_free);
gerror_exc = build_gerror();
PyDict_SetItemString(d, "GError", gerror_exc);
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());
pyg_set_object_has_new_constructor(G_TYPE_OBJECT);
/* GObject properties descriptor */
if (PyType_Ready(&PyGProps_Type) < 0)
return;
if (PyType_Ready(&PyGPropsDescr_Type) < 0)
return;
if (PyType_Ready(&PyGPropsIter_Type) < 0)
return;
descr = PyObject_New(PyObject, &PyGPropsDescr_Type);
PyDict_SetItemString(PyGObject_Type.tp_dict, "props", descr);
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());
REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED);
REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER);
PyGEnum_Type.tp_base = &PyInt_Type;
REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM);
PyGFlags_Type.tp_base = &PyInt_Type;
REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS);
PyGPid_Type.tp_base = &PyInt_Type;
REGISTER_TYPE(d, PyGPid_Type, "Pid");
REGISTER_TYPE(d, PyGMainLoop_Type, "MainLoop");
REGISTER_TYPE(d, PyGMainContext_Type, "MainContext");
REGISTER_TYPE(d, PyGIOChannel_Type, "IOChannel");
REGISTER_TYPE(d, PyGSource_Type, "Source");
REGISTER_TYPE(d, PyGIdle_Type, "Idle");
REGISTER_TYPE(d, PyGTimeout_Type, "Timeout");
REGISTER_TYPE(d, PyGPollFD_Type, "PollFD");
PyType_Ready(&PyGObjectWeakRef_Type);
PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type);
REGISTER_TYPE(d, PyGOptionContext_Type, "OptionContext");
REGISTER_TYPE(d, PyGOptionGroup_Type, "OptionGroup");
/* glib version */
tuple = Py_BuildValue ("(iii)", glib_major_version, glib_minor_version,
glib_micro_version);
PyDict_SetItemString(d, "glib_version", tuple);
Py_DECREF(tuple);
/* pygobject version */
tuple = Py_BuildValue ("(iii)",
PYGOBJECT_MAJOR_VERSION,
PYGOBJECT_MINOR_VERSION,
PYGOBJECT_MICRO_VERSION);
PyDict_SetItemString(d, "pygobject_version", tuple);
/* backwards compatibility */
PyDict_SetItemString(d, "pygtk_version", tuple);
Py_DECREF(tuple);
/* for addon libraries ... */
PyDict_SetItemString(d, "_PyGObject_API",
o=PyCObject_FromVoidPtr(&pygobject_api_functions,NULL));
Py_DECREF(o);
/* features */
features = PyDict_New();
#ifdef HAVE_FFI_H
PyDict_SetItemString(features, "generic-c-marshaller", Py_True);
#endif
PyDict_SetItemString(d, "features", features);
Py_DECREF(features);
/* some constants */
PyModule_AddIntConstant(m, "SIGNAL_RUN_FIRST", G_SIGNAL_RUN_FIRST);
PyModule_AddIntConstant(m, "SIGNAL_RUN_LAST", G_SIGNAL_RUN_LAST);
PyModule_AddIntConstant(m, "SIGNAL_RUN_CLEANUP", G_SIGNAL_RUN_CLEANUP);
PyModule_AddIntConstant(m, "SIGNAL_NO_RECURSE", G_SIGNAL_NO_RECURSE);
PyModule_AddIntConstant(m, "SIGNAL_DETAILED", G_SIGNAL_DETAILED);
PyModule_AddIntConstant(m, "SIGNAL_ACTION", G_SIGNAL_ACTION);
PyModule_AddIntConstant(m, "SIGNAL_NO_HOOKS", G_SIGNAL_NO_HOOKS);
PyModule_AddIntConstant(m, "PARAM_READABLE", G_PARAM_READABLE);
PyModule_AddIntConstant(m, "PARAM_WRITABLE", G_PARAM_WRITABLE);
PyModule_AddIntConstant(m, "PARAM_CONSTRUCT", G_PARAM_CONSTRUCT);
PyModule_AddIntConstant(m, "PARAM_CONSTRUCT_ONLY", G_PARAM_CONSTRUCT_ONLY);
PyModule_AddIntConstant(m, "PARAM_LAX_VALIDATION", G_PARAM_LAX_VALIDATION);
PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE);
PyModule_AddIntConstant(m, "PRIORITY_HIGH", G_PRIORITY_HIGH);
PyModule_AddIntConstant(m, "PRIORITY_DEFAULT", G_PRIORITY_DEFAULT);
PyModule_AddIntConstant(m, "PRIORITY_HIGH_IDLE", G_PRIORITY_HIGH_IDLE);
PyModule_AddIntConstant(m, "PRIORITY_DEFAULT_IDLE",G_PRIORITY_DEFAULT_IDLE);
PyModule_AddIntConstant(m, "PRIORITY_LOW", G_PRIORITY_LOW);
PyModule_AddIntConstant(m, "IO_IN", G_IO_IN);
PyModule_AddIntConstant(m, "IO_OUT", G_IO_OUT);
PyModule_AddIntConstant(m, "IO_PRI", G_IO_PRI);
PyModule_AddIntConstant(m, "IO_ERR", G_IO_ERR);
PyModule_AddIntConstant(m, "IO_HUP", G_IO_HUP);
PyModule_AddIntConstant(m, "IO_NVAL", G_IO_NVAL);
#define addint(x) PyModule_AddIntConstant(m, #x, G_##x)
addint(IO_STATUS_ERROR);
addint(IO_STATUS_NORMAL);
addint(IO_STATUS_EOF);
addint(IO_STATUS_AGAIN);
addint(IO_FLAG_APPEND);
addint(IO_FLAG_NONBLOCK);
addint(IO_FLAG_IS_READABLE);
addint(IO_FLAG_IS_WRITEABLE);
addint(IO_FLAG_IS_SEEKABLE);
addint(IO_FLAG_MASK);
addint(IO_FLAG_GET_MASK);
addint(IO_FLAG_SET_MASK);
addint(OPTION_FLAG_HIDDEN);
addint(OPTION_FLAG_IN_MAIN);
addint(OPTION_FLAG_REVERSE);
addint(OPTION_FLAG_NO_ARG);
addint(OPTION_FLAG_FILENAME);
addint(OPTION_FLAG_OPTIONAL_ARG);
addint(OPTION_FLAG_NOALIAS);
addint(OPTION_ERROR_UNKNOWN_OPTION);
addint(OPTION_ERROR_BAD_VALUE);
addint(OPTION_ERROR_FAILED);
#undef addint
PyModule_AddStringConstant(m, "OPTION_REMAINING", G_OPTION_REMAINING);
PyModule_AddStringConstant(m, "OPTION_ERROR", (char*) g_quark_to_string(G_OPTION_ERROR));
PyModule_AddIntConstant(m, "SPAWN_LEAVE_DESCRIPTORS_OPEN",
G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
PyModule_AddIntConstant(m, "SPAWN_DO_NOT_REAP_CHILD",
G_SPAWN_DO_NOT_REAP_CHILD);
PyModule_AddIntConstant(m, "SPAWN_SEARCH_PATH",
G_SPAWN_SEARCH_PATH);
PyModule_AddIntConstant(m, "SPAWN_STDOUT_TO_DEV_NULL",
G_SPAWN_STDOUT_TO_DEV_NULL);
PyModule_AddIntConstant(m, "SPAWN_STDERR_TO_DEV_NULL",
G_SPAWN_STDERR_TO_DEV_NULL);
PyModule_AddIntConstant(m, "SPAWN_CHILD_INHERITS_STDIN",
G_SPAWN_CHILD_INHERITS_STDIN);
PyModule_AddIntConstant(m, "SPAWN_FILE_AND_ARGV_ZERO",
G_SPAWN_FILE_AND_ARGV_ZERO);
/* 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));
pyg_register_gtype_custom(G_TYPE_STRV,
_pyg_strv_from_gvalue,
_pyg_strv_to_gvalue);
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);
/* signal registration recognizes this special accumulator 'constant' */
_pyg_signal_accumulator_true_handled_func = \
PyDict_GetItemString(d, "signal_accumulator_true_handled");
}
syntax highlighted by Code2HTML, v. 0.9.1