1/* -*- Mode: C; c-basic-offset: 4 -*-
2 * pygtk- Python bindings for the GTK toolkit.
3 * Copyright (C) 2007  Gian Mario Tagliaretti
4 *
5 *   gtkbuilder.override: overrides for various builder functions.
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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 */
22
23%%
24headers
25
26static gboolean
27pylist_to_strv (PyObject *list,
28                char   ***strvp)
29{
30    int i, len;
31    char **ret;
32
33    *strvp = NULL;
34
35    if (list == Py_None)
36        return TRUE;
37
38    if (!PySequence_Check (list))
39    {
40        PyErr_Format (PyExc_TypeError,
41		      "argument must be a list or tuple of strings");
42        return FALSE;
43    }
44
45    if ((len = PySequence_Size (list)) < 0)
46        return FALSE;
47
48    ret = g_new (char*, len + 1);
49    for (i = 0; i <= len; ++i)
50        ret[i] = NULL;
51
52    for (i = 0; i < len; ++i)
53    {
54        PyObject *item = PySequence_GetItem (list, i);
55
56        if (!item)
57        {
58            g_strfreev (ret);
59            return FALSE;
60        }
61
62        if (!PyString_Check (item))
63        {
64            Py_DECREF (item);
65            g_strfreev (ret);
66            PyErr_Format (PyExc_TypeError,
67			  "argument must be a list of strings");
68            return FALSE;
69        }
70
71        ret[i] = g_strdup (PyString_AsString (item));
72        Py_DECREF (item);
73    }
74
75    *strvp = ret;
76    return TRUE;
77}
78
79typedef struct{
80    PyObject    *obj;
81    PyObject    *data;
82    PyObject    *missing_handlers;
83    gboolean     exception_pending;
84} PyGCustomSignalNotify;
85
86%%
87override gtk_builder_connect_signals kwargs
88static void
89connect_many(GtkBuilder *builder, GObject *obj,
90	     const gchar *signal_name, const gchar *handler_name,
91	     GObject *connect_object, GConnectFlags flags, gpointer user_data)
92{
93    PyGCustomSignalNotify   *notify = user_data;
94    PyObject                *handler_dict = notify->obj;
95    PyObject                *tuple, *self;
96    GClosure                *closure = NULL;
97
98    if (notify->exception_pending)
99        return;
100
101    tuple = PyMapping_GetItemString(handler_dict, (gchar *)handler_name);
102    if (!tuple) {
103	PyErr_Clear();
104        tuple = PyObject_GetAttrString(handler_dict, (gchar *)handler_name);
105        if (!tuple) {
106            gchar *error_message;
107            PyObject *name_obj;
108
109            PyErr_Clear();
110
111            name_obj = PyString_FromString(handler_name);
112            PyList_Append(notify->missing_handlers, name_obj);
113            Py_DECREF(name_obj);
114
115            error_message = g_strdup_printf("missing handler '%s'", handler_name);
116            if (PyErr_Warn(NULL, error_message)) {
117                /* PyErr_Warn requests us to raise the warning as exception.  That can
118                 * happen when user explicitly used warnings.filterwarnings('error'...).
119                 * So, we will not call any Python code anymore and raise the exception
120                 * from connect_signals(). */
121                notify->exception_pending = TRUE;
122            }
123
124            g_free(error_message);
125            return;
126        }
127    }
128
129    if (PyTuple_Check(tuple)) {
130	PyObject *callback = PyTuple_GetItem(tuple, 0);
131	PyObject *extra = PySequence_GetSlice(tuple, 1, PyTuple_Size(tuple));
132	PyObject *other = NULL;
133
134	if (connect_object)
135	    other = pygobject_new((GObject *)connect_object);
136
137	closure = pyg_closure_new(callback, extra, other);
138	Py_DECREF(extra);
139    } else if (PyCallable_Check(tuple)) {
140	PyObject *other = NULL;
141
142	if (connect_object)
143	    other = pygobject_new((GObject *)connect_object);
144
145	closure = pyg_closure_new(tuple, notify->data, other);
146    } else {
147	g_warning("handler for `%s' not callable or a tuple", handler_name);
148	Py_DECREF(tuple);
149	return;
150    }
151    Py_DECREF(tuple);
152    self = pygobject_new(obj);
153    g_signal_connect_closure(obj, signal_name, closure, flags);
154    pygobject_watch_closure(self, closure);
155    Py_DECREF(self);
156}
157
158static PyObject *
159_wrap_gtk_builder_connect_signals(PyGObject *self, PyObject *args,
160                                  PyObject *kwargs)
161{
162    static char *kwlist[] = { "object", "user_data", NULL };
163    PyGCustomSignalNotify   notify;
164    PyObject                *object, *user_data = NULL;
165
166    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
167				     "O|O:GtkBuilder.connect_signals", kwlist,
168				     &object, &user_data))
169	return NULL;
170
171    notify.obj = object;
172    notify.data = user_data;
173    notify.missing_handlers = PyList_New(0);
174    notify.exception_pending = FALSE;
175
176    if (!notify.missing_handlers)
177        return NULL;
178
179    gtk_builder_connect_signals_full(GTK_BUILDER(self->obj),
180                                     connect_many,
181                                     &notify);
182
183    if (notify.exception_pending) {
184        Py_DECREF(notify.missing_handlers);
185        return NULL;
186    }
187    else if (PyObject_IsTrue(notify.missing_handlers))
188        return notify.missing_handlers;
189    else {
190        Py_DECREF(notify.missing_handlers);
191        Py_INCREF(Py_None);
192        return Py_None;
193    }
194}
195
196%%
197override gtk_builder_get_objects noargs
198static PyObject *
199_wrap_gtk_builder_get_objects(PyGObject *self)
200{
201    GSList *l, *objects;
202    PyObject *pyobjects;
203
204    pyobjects = PyList_New(0);
205    objects = gtk_builder_get_objects(GTK_BUILDER(self->obj));
206    for (l = objects; l; l = l->next)
207    {
208        PyObject *item = pygobject_new((GObject *)l->data);
209        PyList_Append(pyobjects, item);
210        Py_DECREF(item);
211    }
212    g_slist_free(objects);
213
214    return pyobjects;
215}
216
217%%
218override gtk_builder_add_objects_from_file kwargs
219static PyObject *
220_wrap_gtk_builder_add_objects_from_file(PyGObject *self,
221					PyObject *args,
222					PyObject *kwargs)
223{
224    static char *kwlist[] = { "filename", "object_ids", NULL };
225    const gchar *filename;
226    PyObject *py_obj_ids;
227    char **object_ids;
228    guint ret;
229    GError *error = NULL;
230
231    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
232				     "sO:GtkBuilder.add_objects_from_file",
233				     kwlist, &filename, &py_obj_ids))
234        return NULL;
235
236    if (!pylist_to_strv (py_obj_ids, &object_ids))
237        return NULL;
238
239    ret = gtk_builder_add_objects_from_file (GTK_BUILDER (self->obj),
240					     filename, object_ids, &error);
241    g_strfreev (object_ids);
242
243    if (pyg_error_check(&error))
244        return NULL;
245
246    return PyInt_FromLong(ret);
247}
248
249%%
250override gtk_builder_add_objects_from_string kwargs
251static PyObject *
252_wrap_gtk_builder_add_objects_from_string(PyGObject *self,
253					  PyObject *args,
254					  PyObject *kwargs)
255{
256    static char *kwlist[] = { "buffer", "object_ids", NULL };
257    const gchar *buffer;
258    gsize lenght = -1;
259    PyObject *py_obj_ids;
260    char **object_ids;
261    guint ret;
262    GError *error = NULL;
263
264    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
265				     "sO:GtkBuilder.add_objects_from_string",
266				     kwlist, &buffer, &py_obj_ids))
267        return NULL;
268
269    if (!pylist_to_strv (py_obj_ids, &object_ids))
270        return NULL;
271
272    ret = gtk_builder_add_objects_from_string (GTK_BUILDER (self->obj),
273					       buffer, lenght,
274					       object_ids, &error);
275    g_strfreev (object_ids);
276
277    if (pyg_error_check(&error))
278        return NULL;
279
280    return PyInt_FromLong(ret);
281}
282