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