1/* -*- Mode: C; c-basic-offset: 4 -*-
2 * pygtk- Python bindings for the GTK toolkit.
3 * Copyright (C) 1998-2003  James Henstridge
4 *
5 *   libglade.override: overrides for the gtk.glade module.
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%%
23headers
24#define NO_IMPORT_PYGOBJECT
25#include <pygobject.h>
26#include <glade/glade.h>
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30#include <libintl.h>
31
32#include <glib-object.h>
33
34typedef struct {
35    GladeXML parent;
36    PyObject *typedict;
37} PyGladeXML;
38
39typedef struct {
40    GladeXMLClass parent_class;
41} PyGladeXMLClass;
42
43static void  pyglade_xml_init (PyGladeXML *self);
44static void  pyglade_xml_class_init (PyGladeXMLClass *class);
45static GType        pyglade_xml_get_type            (void);
46static GType pyglade_xml_lookup_type (GladeXML*self, const char *gtypename);
47
48#define PYGLADE_TYPE_XML            (pyglade_xml_get_type())
49#define PYGLADE_XML(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PYGLADE_TYPE_XML, PyGladeXML))
50#define PYGLADE_XML_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PYGLADE_TYPE_XML, PyGladeXMLClass))
51#define PYGLADE_IS_XML(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PYGLADE_TYPE_XML))
52#define PYGLADE_IS_XML_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), PYGLADE_TYPE_XML))
53#define PYGLADE_XML_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PYGLADE_TYPE_XML, PygladeXMLClass))
54
55static GType
56pyglade_xml_get_type (void)
57{
58    static GType xml_type = 0;
59
60    if (!xml_type) {
61	static const GTypeInfo xml_info = {
62	    sizeof(PyGladeXMLClass),
63	    (GBaseInitFunc) NULL,
64	    (GBaseFinalizeFunc) NULL,
65	    (GClassInitFunc) pyglade_xml_class_init,
66	    (GClassFinalizeFunc) NULL,
67	    NULL,
68
69	    sizeof (PyGladeXML),
70	    0, /* n_preallocs */
71	    (GInstanceInitFunc) pyglade_xml_init,
72	};
73
74	xml_type = g_type_register_static(GLADE_TYPE_XML, "PyGladeXML",
75					  &xml_info, 0);
76    }
77    return xml_type;
78
79}
80
81static void
82pyglade_xml_init (PyGladeXML *self)
83{
84    self->typedict = PyDict_New();
85}
86
87static void
88pyglade_xml_class_init (PyGladeXMLClass *class)
89{
90    GladeXMLClass *xml_class = (GladeXMLClass*)class;
91    xml_class->lookup_type = pyglade_xml_lookup_type;
92}
93
94static GType
95pyglade_xml_lookup_type(GladeXML *glade, const char *gtypename)
96{
97    PyGladeXML *self;
98    PyObject *item;
99
100    g_return_val_if_fail (PYGLADE_IS_XML (glade), G_TYPE_INVALID);
101
102    self = PYGLADE_XML(glade);
103    if (self->typedict) {
104        item = PyMapping_GetItemString(self->typedict, (char *) gtypename);
105	if (!item) {
106	    PyErr_Clear();
107	    item = NULL;
108	}
109    } else
110        item = NULL;
111
112    if (item != NULL) {
113	GType type;
114
115	if ((type = pyg_type_from_object(item)) == 0)
116            type = G_TYPE_INVALID;
117
118        Py_DECREF(item);
119	return type;
120    }
121
122    return g_type_from_name(gtypename);
123}
124
125static PyGladeXML *
126pyglade_xml_new (char * fname, char * root, char *domain, PyObject *dict)
127{
128    PyGladeXML *self = g_object_new(PYGLADE_TYPE_XML, NULL);
129
130    /* This must be done before, since it's used inside of
131     * glade_xml_construct
132     */
133    self->typedict = dict;
134    if (!glade_xml_construct(GLADE_XML(self), fname, root, domain)) {
135	g_object_unref(self);
136	return NULL;
137    }
138      /* the reference is borrowed, and we don't need anymore */
139    self->typedict = NULL;
140
141    return self;
142}
143
144%%
145modulename gtk.glade
146%%
147import gobject.GObject as PyGObject_Type
148import gtk.Widget as PyGtkWidget_Type
149%%
150ignore-glob *_get_type
151%%
152ignore
153  glade_init
154  glade_provide
155  glade_require
156  glade_xml_construct
157  glade_xml_signal_connect_data
158  glade_xml_signal_connect_full
159  glade_xml_signal_autoconnect_full
160%%
161override glade_xml_signal_connect
162static void
163connect_one(const gchar *handler_name, GObject *obj,
164            const gchar *signal_name, const gchar *signal_data,
165            GObject *connect_object, gboolean after, gpointer user_data)
166{
167    GClosure *closure = NULL;
168    PyObject *callback = PyTuple_GetItem((PyObject *)user_data, 0);
169    PyObject *extra = PyTuple_GetItem((PyObject *)user_data, 1);
170    PyObject *self;
171
172    if (connect_object) {
173        PyObject *other;
174
175        other = pygobject_new(connect_object);
176	closure = pyg_closure_new(callback, extra, other);
177    } else {
178	closure = pyg_closure_new(callback, extra, NULL);
179    }
180
181    self = pygobject_new(obj);
182    g_signal_connect_closure(obj, signal_name, closure, after);
183    pygobject_watch_closure(self, closure);
184    Py_DECREF(self);
185}
186
187static PyObject *
188_wrap_glade_xml_signal_connect(PyGObject *self, PyObject *args)
189{
190    guint len;
191    PyObject *first, *callback, *extra_args = NULL, *data;
192    gchar *handler_name;
193
194    len = PyTuple_Size(args);
195    if (len < 2) {
196	PyErr_SetString(PyExc_TypeError,
197		"GladeXML.signal_connect requires at least 2 arguments");
198	return NULL;
199    }
200    first = PySequence_GetSlice(args, 0, 2);
201    if (!PyArg_ParseTuple(first, "sO:GladeXML.signal_connect", &handler_name,
202			  &callback)) {
203	Py_DECREF(first);
204	return NULL;
205    }
206    Py_DECREF(first);
207    if (!PyCallable_Check(callback)) {
208	PyErr_SetString(PyExc_TypeError, "second argument must be callable");
209	return NULL;
210    }
211    extra_args = PySequence_GetSlice(args, 2, len);
212    if (extra_args == NULL)
213	return NULL;
214    data = Py_BuildValue("(ON)", callback, extra_args);
215    glade_xml_signal_connect_full(GLADE_XML(self->obj), handler_name,
216				  connect_one, data);
217    Py_DECREF(data);
218    Py_INCREF(Py_None);
219    return Py_None;
220}
221%%
222override glade_xml_signal_autoconnect kwargs
223static void
224connect_many(const gchar *handler_name, GObject *obj,
225	     const gchar *signal_name, const gchar *signal_data,
226	     GObject *connect_object, gboolean after, gpointer user_data)
227{
228    PyObject *handler_dict = user_data;
229    PyObject *tuple, *self;
230    GClosure *closure = NULL;
231
232    tuple = PyMapping_GetItemString(handler_dict, (gchar *)handler_name);
233    if (!tuple) {
234	PyErr_Clear();
235        tuple = PyObject_GetAttrString(handler_dict, (gchar *)handler_name);
236        if (!tuple) {
237            PyErr_Clear();
238            return;
239        }
240    }
241
242    if (PyTuple_Check(tuple)) {
243	PyObject *callback = PyTuple_GetItem(tuple, 0);
244	PyObject *extra = PySequence_GetSlice(tuple, 1, PyTuple_Size(tuple));
245	PyObject *other = NULL;
246
247	if (connect_object)
248	    other = pygobject_new((GObject *)connect_object);
249
250	closure = pyg_closure_new(callback, extra, other);
251	Py_DECREF(extra);
252    } else if (PyCallable_Check(tuple)) {
253	PyObject *other = NULL;
254
255	if (connect_object)
256	    other = pygobject_new((GObject *)connect_object);
257
258	closure = pyg_closure_new(tuple, NULL, other);
259    } else {
260	g_warning("handler for `%s' not callable or a tuple", handler_name);
261	Py_DECREF(tuple);
262	return;
263    }
264    Py_DECREF(tuple);
265    self = pygobject_new(obj);
266    g_signal_connect_closure(obj, signal_name, closure, after);
267    pygobject_watch_closure(self, closure);
268    Py_DECREF(self);
269}
270
271static PyObject *
272_wrap_glade_xml_signal_autoconnect(PyGObject *self, PyObject *args,
273				   PyObject *kwargs)
274{
275    static char *kwlist[] = { "dict", NULL };
276    PyObject *object;
277
278    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
279				     "O:GladeXML.signal_autoconnect", kwlist,
280				     &object))
281	return NULL;
282
283    glade_xml_signal_autoconnect_full(GLADE_XML(self->obj),
284				      connect_many,
285				      object);
286    Py_INCREF(Py_None);
287    return Py_None;
288}
289%%
290override glade_xml_get_widget_prefix kwargs
291static PyObject *
292_wrap_glade_xml_get_widget_prefix(PyGObject *self, PyObject *args,
293				  PyObject *kwargs)
294{
295    static char *kwlist[] = { "name", NULL };
296    char *name;
297    GList *ret, *tmp;
298    PyObject *py_ret;
299
300    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
301				     "s:GladeXML.get_widget_prefix", kwlist,
302				     &name))
303	return NULL;
304    ret = glade_xml_get_widget_prefix(GLADE_XML(self->obj), name);
305    py_ret = PyList_New(0);
306    for (tmp = ret; tmp != NULL; tmp = tmp->next) {
307	GtkWidget *widget = tmp->data;
308	PyObject *py_widget = pygobject_new((GObject *)widget);
309
310	if (!py_widget) {
311	    g_list_free(ret);
312	    Py_DECREF(py_ret);
313	    return NULL;
314	}
315	PyList_Append(py_ret, py_widget);
316	Py_DECREF(py_widget);
317    }
318    g_list_free(ret);
319    return py_ret;
320}
321%%
322override glade_bindtextdomain kwargs
323static PyObject *
324_wrap_glade_bindtextdomain(PyObject *self, PyObject *args, PyObject *kwargs)
325{
326    static char *kwlist[] = { "domainname", "dirname", NULL };
327    char *domainname, *dirname = NULL, *ret;
328
329    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
330				     "s|s:glade.bindtextdomain", kwlist,
331				     &domainname, &dirname))
332	return NULL;
333    ret = bindtextdomain(domainname, dirname);
334    if (!ret) {
335	PyErr_SetString(PyExc_MemoryError, "Not enough memory available.");
336	return NULL;
337    }
338#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
339    bind_textdomain_codeset(domainname, "UTF-8");
340#endif
341    return PyString_FromString(ret);
342}
343%%
344override glade_textdomain kwargs
345static PyObject *
346_wrap_glade_textdomain(PyObject *self, PyObject *args, PyObject *kwargs)
347{
348    static char *kwlist[] = { "domainname", NULL };
349    char *domainname = NULL, *ret;
350
351    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
352				     "|s:glade.textdomain", kwlist,
353				     &domainname))
354	return NULL;
355    ret = textdomain(domainname);
356    if (!ret) {
357	PyErr_SetString(PyExc_MemoryError, "Not enough memory available.");
358	return NULL;
359    }
360    return PyString_FromString(ret);
361}
362%%
363override glade_set_custom_handler
364
365/* stores the handler set by set_custom_handler */
366static PyObject *pyglade_handler = NULL;
367static PyObject *pyglade_user_data = NULL;
368
369static GtkWidget *
370pyglade_custom_widget_handler(GladeXML *xml,
371			      gchar *func_name,
372			      gchar *name,
373			      gchar *string1,
374			      gchar *string2,
375			      gint int1,
376			      gint int2,
377			      gpointer user_data)
378{
379    PyObject *firstargs, *args;
380    PyObject *widget;
381    GtkWidget *ret;
382
383    g_return_val_if_fail(pyglade_handler != NULL, NULL);
384    g_return_val_if_fail(pyglade_user_data != NULL, NULL);
385
386    firstargs = Py_BuildValue("Nssssii", pygobject_new((GObject *)xml),
387			      func_name, name, string1, string2,
388			      int1, int2);
389    args = PySequence_Concat(firstargs, pyglade_user_data);
390    Py_DECREF(firstargs);
391
392    widget = PyObject_CallObject(pyglade_handler, args);
393    Py_DECREF(args);
394    if (!widget) {
395	PyErr_Print();
396	ret = NULL;
397    } else if (pygobject_check(widget, &PyGtkWidget_Type)) {
398	/* this leaks a reference :( */
399	ret = GTK_WIDGET(pygobject_get(widget));
400    } else {
401	Py_DECREF(widget);
402	g_warning("return value of custom widget handler was not a GtkWidget");
403	ret = NULL;
404    }
405
406    return ret;
407}
408
409static PyObject *
410_wrap_glade_set_custom_handler(PyObject *self, PyObject *args)
411{
412    PyObject *first, *handler, *user_data;
413    gint len;
414
415    len = PyTuple_Size(args);
416    if (len < 1) {
417	PyErr_SetString(PyExc_TypeError, "set_custom_handler requires at least 1 argument");
418	return NULL;
419    }
420    first = PySequence_GetSlice(args, 0, 1);
421    if (!PyArg_ParseTuple(first, "O:set_custom_handler", &handler)) {
422	Py_DECREF(first);
423	return NULL;
424    }
425    Py_DECREF(first);
426    if (!PyCallable_Check(handler)) {
427	PyErr_SetString(PyExc_TypeError, "handler must be callable");
428	return NULL;
429    }
430    user_data = PySequence_GetSlice(args, 1, len);
431
432    /* clear saved data */
433    Py_XDECREF(pyglade_handler);
434    pyglade_handler = NULL;
435    Py_XDECREF(pyglade_user_data);
436    pyglade_user_data = NULL;
437
438    /* store new handlers */
439    Py_INCREF(handler);
440    pyglade_handler = handler;
441    pyglade_user_data = user_data;
442
443    /* set handler */
444    glade_set_custom_handler(pyglade_custom_widget_handler, NULL);
445
446    Py_INCREF(Py_None);
447    return Py_None;
448}
449%%
450override glade_set_custom_widget_callbacks kwargs
451static GtkWidget *
452pyglade_custom_widget_callbacks_handler(GladeXML *xml,
453					gchar *func_name,
454					gchar *name,
455					gchar *string1,
456					gchar *string2,
457					gint int1,
458					gint int2,
459					gpointer user_data)
460{
461    PyObject *handler, *widget;
462    GtkWidget *ret;
463
464    handler = PyMapping_GetItemString(pyglade_user_data, func_name);
465    if (!handler) {
466        PyErr_Clear();
467        handler = PyObject_GetAttrString(pyglade_user_data, func_name);
468        if (!handler) {
469            PyErr_Clear();
470	    g_warning("could not find handler %s", func_name);
471            return NULL;
472        }
473    }
474    if (!PyCallable_Check(handler)) {
475	g_warning("object is not callable");
476	return NULL;
477    }
478
479    widget = PyObject_CallFunction(handler, NULL);
480    if (pygobject_check(widget, &PyGtkWidget_Type)) {
481	/* this leaks a reference :( */
482	ret = GTK_WIDGET(pygobject_get(widget));
483    } else {
484	Py_DECREF(widget);
485	g_warning("return value of custom widget handler was not a GtkWidget");
486	ret = NULL;
487    }
488    return ret;
489}
490static PyObject *
491_wrap_glade_set_custom_widget_callbacks(PyObject *self, PyObject *args,
492					PyObject *kwargs)
493{
494    static char *kwlist[] = { "dict", NULL };
495    PyObject *object;
496
497    if (PyErr_Warn(PyExc_DeprecationWarning, "use set_custom_handler instead") < 0)
498	return NULL;
499
500    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
501				     "O:GladeXML.set_custom_widget_callbacks",
502				     kwlist, &object))
503	return NULL;
504
505    /* clear saved data */
506    Py_XDECREF(pyglade_handler);
507    pyglade_handler = NULL;
508    Py_XDECREF(pyglade_user_data);
509    pyglade_user_data = NULL;
510
511    /* store new handlers */
512    Py_INCREF(object);
513    pyglade_user_data = object;
514
515    glade_set_custom_handler(pyglade_custom_widget_callbacks_handler, NULL);
516
517    Py_INCREF(Py_None);
518    return Py_None;
519}
520%%
521override glade_xml_new kwargs
522static int
523_wrap_glade_xml_new(PyGObject *self, PyObject *args, PyObject *kwargs)
524{
525    static char *kwlist[] = { "fname", "root", "domain", "typedict", NULL };
526    char *fname, *root = NULL, *domain = NULL;
527    PyObject *pydict = NULL;
528
529    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
530				     "s|zzO:GladeXML.__init__",
531				     kwlist, &fname, &root, &domain,
532				     &pydict))
533        return -1;
534
535    if (pydict && !PyMapping_Check(pydict)) {
536        PyErr_SetString(PyExc_TypeError,
537			"typedict must be a mapping");
538	return -1;
539    }
540
541    self->obj = (GObject *) pyglade_xml_new(fname, root, domain, pydict);
542
543    if (!self->obj) {
544        PyErr_SetString(PyExc_RuntimeError, "could not create GladeXML object");
545        return -1;
546    }
547    pygobject_register_wrapper((PyObject *)self);
548    return 0;
549}
550