cdb766c2a32bbe37cf7e9d1ef729647fa88000fe
[platform/upstream/python-gobject.git] / gi / pygboxed.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * pygtk- Python bindings for the GTK toolkit.
3  * Copyright (C) 1998-2003  James Henstridge
4  *
5  *   pygboxed.c: wrapper for GBoxed
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include <pyglib.h>
26 #include "pygobject-private.h"
27 #include "pygboxed.h"
28
29 #include "pygi.h"
30 #include "pygi-type.h"
31
32 GQuark pygboxed_type_key;
33 GQuark pygboxed_marshal_key;
34
35 PYGLIB_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed);
36
37 static void
38 pyg_boxed_dealloc(PyGBoxed *self)
39 {
40     if (self->free_on_dealloc && pyg_boxed_get_ptr (self)) {
41         PyGILState_STATE state = pyglib_gil_state_ensure();
42         g_boxed_free (self->gtype, pyg_boxed_get_ptr (self));
43         pyglib_gil_state_release(state);
44     }
45
46     Py_TYPE(self)->tp_free((PyObject *)self);
47 }
48
49 static PyObject*
50 pyg_boxed_richcompare(PyObject *self, PyObject *other, int op)
51 {
52     if (Py_TYPE(self) == Py_TYPE(other) &&
53         PyObject_IsInstance(self, (PyObject*)&PyGBoxed_Type))
54         return _pyglib_generic_ptr_richcompare (pyg_boxed_get_ptr (self),
55                                                 pyg_boxed_get_ptr (other),
56                                                 op);
57     else {
58         Py_INCREF(Py_NotImplemented);
59         return Py_NotImplemented;
60     }
61 }
62
63
64 static long
65 pyg_boxed_hash(PyGBoxed *self)
66 {
67     return (long)pyg_boxed_get_ptr (self);
68 }
69
70 static PyObject *
71 pyg_boxed_repr(PyGBoxed *boxed)
72 {
73     PyObject *module, *repr, *self = (PyObject *)boxed;
74     gchar *module_str, *namespace;
75
76     module = PyObject_GetAttrString (self, "__module__");
77     if (module == NULL)
78         return NULL;
79
80     if (!PYGLIB_PyUnicode_Check (module)) {
81         Py_DECREF (module);
82         return NULL;
83     }
84
85     module_str = PYGLIB_PyUnicode_AsString (module);
86     namespace = g_strrstr (module_str, ".");
87     if (namespace == NULL) {
88         namespace = module_str;
89     } else {
90         namespace += 1;
91     }
92
93     repr = PYGLIB_PyUnicode_FromFormat ("<%s.%s object at %p (%s at %p)>",
94                                         namespace, Py_TYPE (self)->tp_name,
95                                         self, g_type_name (boxed->gtype),
96                                         pyg_boxed_get_ptr (boxed));
97     Py_DECREF (module);
98     return repr;
99 }
100
101 static int
102 pyg_boxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs)
103 {
104     gchar buf[512];
105
106     if (!PyArg_ParseTuple(args, ":GBoxed.__init__"))
107         return -1;
108
109     pyg_boxed_set_ptr (self, NULL);
110     self->gtype = 0;
111     self->free_on_dealloc = FALSE;
112
113     g_snprintf(buf, sizeof(buf), "%s can not be constructed",
114                Py_TYPE(self)->tp_name);
115     PyErr_SetString(PyExc_NotImplementedError, buf);
116     return -1;
117 }
118
119 static void
120 pyg_boxed_free(PyObject *op)
121 {
122   PyObject_FREE(op);
123 }
124
125 static PyObject *
126 pyg_boxed_copy(PyGBoxed *self)
127 {
128     return pyg_boxed_new (self->gtype, pyg_boxed_get_ptr (self), TRUE, TRUE);
129 }
130
131
132
133 static PyMethodDef pygboxed_methods[] = {
134     { "copy", (PyCFunction) pyg_boxed_copy, METH_NOARGS },
135     { NULL, NULL, 0 }
136 };
137
138
139 /**
140  * pyg_register_boxed:
141  * @dict: the module dictionary to store the wrapper class.
142  * @class_name: the Python name for the wrapper class.
143  * @boxed_type: the GType of the boxed type being wrapped.
144  * @type: the wrapper class.
145  *
146  * Registers a wrapper for a boxed type.  The wrapper class will be a
147  * subclass of gobject.GBoxed, and a reference to the wrapper class
148  * will be stored in the provided module dictionary.
149  */
150 void
151 pyg_register_boxed(PyObject *dict, const gchar *class_name,
152                    GType boxed_type, PyTypeObject *type)
153 {
154     PyObject *o;
155
156     g_return_if_fail(dict != NULL);
157     g_return_if_fail(class_name != NULL);
158     g_return_if_fail(boxed_type != 0);
159
160     if (!type->tp_dealloc)  type->tp_dealloc  = (destructor)pyg_boxed_dealloc;
161
162     Py_TYPE(type) = &PyType_Type;
163     type->tp_base = &PyGBoxed_Type;
164
165     if (PyType_Ready(type) < 0) {
166         g_warning("could not get type `%s' ready", type->tp_name);
167         return;
168     }
169
170     PyDict_SetItemString(type->tp_dict, "__gtype__",
171                          o=pyg_type_wrapper_new(boxed_type));
172     Py_DECREF(o);
173
174     g_type_set_qdata(boxed_type, pygboxed_type_key, type);
175
176     PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type);
177 }
178
179 /**
180  * pyg_boxed_new:
181  * @boxed_type: the GType of the boxed value.
182  * @boxed: the boxed value.
183  * @copy_boxed: whether the new boxed wrapper should hold a copy of the value.
184  * @own_ref: whether the boxed wrapper should own the boxed value.
185  *
186  * Creates a wrapper for a boxed value.  If @copy_boxed is set to
187  * True, the wrapper will hold a copy of the value, instead of the
188  * value itself.  If @own_ref is True, then the value held by the
189  * wrapper will be freed when the wrapper is deallocated.  If
190  * @copy_boxed is True, then @own_ref must also be True.
191  *
192  * Returns: the boxed wrapper or %NULL and sets an exception.
193  */
194 PyObject *
195 pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed,
196               gboolean own_ref)
197 {
198     PyGILState_STATE state;
199     PyGBoxed *self;
200     PyTypeObject *tp;
201
202     g_return_val_if_fail(boxed_type != 0, NULL);
203     g_return_val_if_fail(!copy_boxed || (copy_boxed && own_ref), NULL);
204
205     state = pyglib_gil_state_ensure();
206
207     if (!boxed) {
208         Py_INCREF(Py_None);
209         pyglib_gil_state_release(state);
210         return Py_None;
211     }
212
213     tp = g_type_get_qdata(boxed_type, pygboxed_type_key);
214
215     if (!tp)
216         tp = (PyTypeObject *)pygi_type_import_by_g_type(boxed_type);
217
218     if (!tp)
219         tp = (PyTypeObject *)&PyGBoxed_Type; /* fallback */
220
221     if (!PyType_IsSubtype (tp, &PyGBoxed_Type)) {
222         PyErr_Format (PyExc_RuntimeError, "%s isn't a GBoxed", tp->tp_name);
223         pyglib_gil_state_release (state);
224         return NULL;
225     }
226
227     self = (PyGBoxed *)tp->tp_alloc(tp, 0);
228
229     if (self == NULL) {
230         pyglib_gil_state_release(state);
231         return NULL;
232     }
233
234     if (copy_boxed)
235         boxed = g_boxed_copy(boxed_type, boxed);
236     pyg_boxed_set_ptr (self, boxed);
237     self->gtype = boxed_type;
238     self->free_on_dealloc = own_ref;
239
240     pyglib_gil_state_release(state);
241     
242     return (PyObject *)self;
243 }
244
245 void
246 pygobject_boxed_register_types(PyObject *d)
247 {
248     pygboxed_type_key        = g_quark_from_static_string("PyGBoxed::class");
249     pygboxed_marshal_key     = g_quark_from_static_string("PyGBoxed::marshal");
250
251     PyGBoxed_Type.tp_dealloc = (destructor)pyg_boxed_dealloc;
252     PyGBoxed_Type.tp_richcompare = pyg_boxed_richcompare;
253     PyGBoxed_Type.tp_repr = (reprfunc)pyg_boxed_repr;
254     PyGBoxed_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
255     PyGBoxed_Type.tp_methods = pygboxed_methods;
256     PyGBoxed_Type.tp_init = (initproc)pyg_boxed_init;
257     PyGBoxed_Type.tp_free = (freefunc)pyg_boxed_free;
258     PyGBoxed_Type.tp_hash = (hashfunc)pyg_boxed_hash;
259     
260     PYGOBJECT_REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED);
261 }