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 ¬ify); 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