1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * pygtk- Python bindings for the GTK toolkit.
3 * Copyright (C) 1998-2003 James Henstridge
4 *
5 * gtk-types.c: wrappers for some specialised GTK types.
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 #define PY_SSIZE_T_CLEAN
23
24 #include <gtk/gtk.h>
25 #include "pygtk-private.h"
26 #include <structmember.h>
27
28 #if PY_VERSION_HEX < 0x02050000
29 typedef int Py_ssize_t;
30 #define PY_SSIZE_T_MAX INT_MAX
31 #define PY_SSIZE_T_MIN INT_MIN
32 typedef inquiry lenfunc;
33 typedef intargfunc ssizeargfunc;
34 typedef intobjargproc ssizeobjargproc;
35 #endif
36
37 #if 0
38 PyObject *
39 PyGdkWindow_New(GdkWindow *win)
40 {
41 PyGdkWindow_Object *self;
42
43 self = (PyGdkWindow_Object *)PyObject_NEW(PyGdkWindow_Object,
44 &PyGdkWindow_Type);
45 if (self == NULL)
46 return NULL;
47 self->obj = win;
48 g_object_ref(self->obj);
49 return (PyObject *)self;
50 }
51 #endif
52
53 PyObject *
PyGdkAtom_New(GdkAtom atom)54 PyGdkAtom_New(GdkAtom atom)
55 {
56 PyGdkAtom_Object *self;
57
58 self = (PyGdkAtom_Object *)PyObject_NEW(PyGdkAtom_Object, &PyGdkAtom_Type);
59 if (self == NULL)
60 return NULL;
61 self->atom = atom;
62 self->name = NULL;
63 return (PyObject *)self;
64 }
65
66
67 /* style & rc-style helper code */
68 #define NUM_STATES 5
69 staticforward PyTypeObject PyGtkStyleHelper_Type;
70 staticforward PyTypeObject PyGtkRcStyleHelper_Type;
71
72 PyObject *
_pygtk_style_helper_new(GtkStyle * style,int type,gpointer array)73 _pygtk_style_helper_new(GtkStyle *style, int type, gpointer array)
74 {
75 PyGtkStyleHelper_Object *self;
76
77 self = (PyGtkStyleHelper_Object *)PyObject_NEW(PyGtkStyleHelper_Object,
78 &PyGtkStyleHelper_Type);
79 if (self == NULL)
80 return NULL;
81
82 self->style = g_object_ref(style);
83 self->type = type;
84 self->array = array;
85 return (PyObject *)self;
86 }
87
88 static void
pygtk_style_helper_dealloc(PyGtkStyleHelper_Object * self)89 pygtk_style_helper_dealloc(PyGtkStyleHelper_Object *self)
90 {
91 g_object_unref(self->style);
92 PyObject_DEL(self);
93 }
94
95 static Py_ssize_t
pygtk_style_helper_length(PyGtkStyleHelper_Object * self)96 pygtk_style_helper_length(PyGtkStyleHelper_Object *self)
97 {
98 return NUM_STATES;
99 }
100
101 static PyObject *
pygtk_style_helper_getitem(PyGtkStyleHelper_Object * self,Py_ssize_t pos)102 pygtk_style_helper_getitem(PyGtkStyleHelper_Object *self, Py_ssize_t pos)
103 {
104 if (pos < 0) pos += NUM_STATES;
105 if (pos < 0 || pos >= NUM_STATES) {
106 PyErr_SetString(PyExc_IndexError, "index out of range");
107 return NULL;
108 }
109 switch (self->type) {
110 case STYLE_COLOUR_ARRAY:
111 {
112 GdkColor *array = (GdkColor *)self->array;
113 return pyg_boxed_new(GDK_TYPE_COLOR, &array[pos], TRUE, TRUE);
114 }
115 case STYLE_GC_ARRAY:
116 {
117 GdkGC **array = (GdkGC **)self->array;
118 return pygobject_new((GObject *)array[pos]);
119 }
120 case STYLE_PIXMAP_ARRAY:
121 {
122 GdkPixmap **array = (GdkPixmap **)self->array;
123 if ((long)array[pos] == GDK_PARENT_RELATIVE)
124 return PyLong_FromLong(GDK_PARENT_RELATIVE);
125 return pygobject_new((GObject *)array[pos]);
126 }
127 }
128 g_assert_not_reached();
129 return NULL;
130 }
131
132 static int
pygtk_style_helper_setitem(PyGtkStyleHelper_Object * self,Py_ssize_t pos,PyObject * value)133 pygtk_style_helper_setitem(PyGtkStyleHelper_Object *self, Py_ssize_t pos,
134 PyObject *value)
135 {
136 extern PyTypeObject PyGdkGC_Type;
137 extern PyTypeObject PyGdkPixmap_Type;
138
139 if (pos < 0) pos += NUM_STATES;
140 if (pos < 0 || pos >= NUM_STATES) {
141 PyErr_SetString(PyExc_IndexError, "index out of range");
142 return -1;
143 }
144 switch (self->type) {
145 case STYLE_COLOUR_ARRAY:
146 {
147 GdkColor *array = (GdkColor *)self->array;
148
149 if (!pyg_boxed_check(value, GDK_TYPE_COLOR)) {
150 PyErr_SetString(PyExc_TypeError, "can only assign a GdkColor");
151 return -1;
152 }
153 array[pos] = *pyg_boxed_get(value, GdkColor);
154 return 0;
155 }
156 case STYLE_GC_ARRAY:
157 {
158 GdkGC **array = (GdkGC **)self->array;
159
160 if (!pygobject_check(value, &PyGdkGC_Type)) {
161 PyErr_SetString(PyExc_TypeError, "can only assign a GdkGC");
162 return -1;
163 }
164 if (array[pos]) {
165 g_object_unref(array[pos]);
166 }
167 array[pos] = GDK_GC(g_object_ref(pygobject_get(value)));
168 return 0;
169 }
170 case STYLE_PIXMAP_ARRAY:
171 {
172 GdkPixmap **array = (GdkPixmap **)self->array;
173 GdkPixmap *cvalue = NULL;
174
175 if (pygobject_check(value, &PyGdkPixmap_Type))
176 cvalue = GDK_PIXMAP(g_object_ref(pygobject_get(value)));
177 else if (PyLong_Check(value)) {
178 if (PyLong_AsLong(value) != GDK_PARENT_RELATIVE) {
179 PyErr_SetString(PyExc_TypeError,
180 "can only assign a GdkPixmap, None or "
181 "GDK_PARENT_RELATIVE");
182 return -1;
183 }
184 cvalue = (GdkPixmap*)GDK_PARENT_RELATIVE;
185 } else if (value != Py_None) {
186 PyErr_SetString(PyExc_TypeError,
187 "can only assign a GdkPixmap, None or "
188 "GDK_PARENT_RELATIVE");
189 return -1;
190 }
191
192 if (array[pos] && (long)array[pos] != GDK_PARENT_RELATIVE) {
193 g_object_unref(array[pos]);
194 }
195 array[pos] = cvalue;
196 return 0;
197 }
198 }
199 g_assert_not_reached();
200 return -1;
201 }
202
203 static PySequenceMethods pygtk_style_helper_seqmethods = {
204 (lenfunc)pygtk_style_helper_length,
205 0,
206 0,
207 (ssizeargfunc)pygtk_style_helper_getitem,
208 0,
209 (ssizeobjargproc)pygtk_style_helper_setitem,
210 0,
211 };
212 static PyTypeObject PyGtkStyleHelper_Type = {
213 PyObject_HEAD_INIT(NULL)
214 0,
215 "gtk.GtkStyleHelper",
216 sizeof(PyGtkStyleHelper_Object),
217 0,
218 (destructor)pygtk_style_helper_dealloc,
219 (printfunc)0,
220 (getattrfunc)0,
221 (setattrfunc)0,
222 (cmpfunc)0,
223 (reprfunc)0,
224 0,
225 &pygtk_style_helper_seqmethods,
226 0,
227 (hashfunc)0,
228 (ternaryfunc)0,
229 (reprfunc)0,
230 (getattrofunc)0,
231 (setattrofunc)0,
232 0,
233 Py_TPFLAGS_DEFAULT,
234 NULL
235 };
236
237 PyObject *
_pygtk_rc_style_helper_new(GtkRcStyle * rc_style,int type,gpointer array,GtkRcFlags is_set_flag)238 _pygtk_rc_style_helper_new(GtkRcStyle *rc_style, int type, gpointer array, GtkRcFlags is_set_flag)
239 {
240 PyGtkRcStyleHelper_Object *self;
241
242 self = (PyGtkRcStyleHelper_Object *)PyObject_NEW(PyGtkRcStyleHelper_Object,
243 &PyGtkRcStyleHelper_Type);
244 if (self == NULL)
245 return NULL;
246
247 self->rc_style = g_object_ref(rc_style);
248 self->type = type;
249 self->array = array;
250 self->is_set_flag = is_set_flag;
251 return (PyObject *)self;
252 }
253
254 static void
pygtk_rc_style_helper_dealloc(PyGtkRcStyleHelper_Object * self)255 pygtk_rc_style_helper_dealloc(PyGtkRcStyleHelper_Object *self)
256 {
257 g_object_unref(self->rc_style);
258 PyObject_DEL(self);
259 }
260
261 static Py_ssize_t
pygtk_rc_style_helper_length(PyGtkRcStyleHelper_Object * self)262 pygtk_rc_style_helper_length(PyGtkRcStyleHelper_Object *self)
263 {
264 return NUM_STATES;
265 }
266
267 static PyObject *
pygtk_rc_style_helper_getitem(PyGtkRcStyleHelper_Object * self,Py_ssize_t pos)268 pygtk_rc_style_helper_getitem(PyGtkRcStyleHelper_Object *self, Py_ssize_t pos)
269 {
270 if (pos < 0) pos += NUM_STATES;
271 if (pos < 0 || pos >= NUM_STATES) {
272 PyErr_SetString(PyExc_IndexError, "index out of range");
273 return NULL;
274 }
275 switch (self->type) {
276 case RC_STYLE_STRING_ARRAY:
277 {
278 gchar **array = (gchar **)self->array;
279 if (array[pos])
280 return PyString_FromString(array[pos]);
281 else {
282 Py_INCREF(Py_None);
283 return Py_None;
284 }
285 }
286 case RC_STYLE_COLOUR_ARRAY:
287 if (self->rc_style->color_flags[pos] & self->is_set_flag) {
288 GdkColor *array = (GdkColor *)self->array;
289 return pyg_boxed_new(GDK_TYPE_COLOR, &array[pos], TRUE, TRUE);
290 }
291 else {
292 Py_INCREF(Py_None);
293 return Py_None;
294 }
295 }
296 g_assert_not_reached();
297 return NULL;
298 }
299
300 static int
pygtk_rc_style_helper_setitem(PyGtkRcStyleHelper_Object * self,Py_ssize_t pos,PyObject * value)301 pygtk_rc_style_helper_setitem(PyGtkRcStyleHelper_Object *self, Py_ssize_t pos,
302 PyObject *value)
303 {
304 extern PyTypeObject PyGdkGC_Type;
305 extern PyTypeObject PyGdkPixmap_Type;
306
307 if (pos < 0) pos += NUM_STATES;
308 if (pos < 0 || pos >= NUM_STATES) {
309 PyErr_SetString(PyExc_IndexError, "index out of range");
310 return -1;
311 }
312 switch (self->type) {
313 case RC_STYLE_STRING_ARRAY:
314 {
315 gchar **array = (gchar **)self->array;
316 gchar *string;
317 PyObject *as_string;
318
319 if (value == Py_None)
320 string = NULL;
321 else if ((as_string = PyObject_Str(value)) != NULL) {
322 string = g_strdup(PyString_AsString(as_string));
323 Py_DECREF(as_string);
324 }
325 else
326 return -1;
327
328 g_free(array[pos]);
329 array[pos] = string;
330 return 0;
331 }
332 case RC_STYLE_COLOUR_ARRAY:
333 if (value == Py_None) {
334 self->rc_style->color_flags[pos] &= ~self->is_set_flag;
335 return 0;
336 }
337 if (pyg_boxed_check(value, GDK_TYPE_COLOR)) {
338 GdkColor *array = (GdkColor *)self->array;
339 array[pos] = *pyg_boxed_get(value, GdkColor);
340 self->rc_style->color_flags[pos] |= self->is_set_flag;
341 return 0;
342 }
343 else {
344 PyErr_SetString(PyExc_TypeError, "can only assign a gtk.gdk.Color or None");
345 return -1;
346 }
347 }
348 g_assert_not_reached();
349 return -1;
350 }
351
352 static PySequenceMethods pygtk_rc_style_helper_seqmethods = {
353 (lenfunc)pygtk_rc_style_helper_length,
354 0,
355 0,
356 (ssizeargfunc)pygtk_rc_style_helper_getitem,
357 0,
358 (ssizeobjargproc)pygtk_rc_style_helper_setitem,
359 0,
360 };
361 static PyTypeObject PyGtkRcStyleHelper_Type = {
362 PyObject_HEAD_INIT(NULL)
363 0,
364 "gtk.GtkRcStyleHelper",
365 sizeof(PyGtkRcStyleHelper_Object),
366 0,
367 (destructor)pygtk_rc_style_helper_dealloc,
368 (printfunc)0,
369 (getattrfunc)0,
370 (setattrfunc)0,
371 (cmpfunc)0,
372 (reprfunc)0,
373 0,
374 &pygtk_rc_style_helper_seqmethods,
375 0,
376 (hashfunc)0,
377 (ternaryfunc)0,
378 (reprfunc)0,
379 (getattrofunc)0,
380 (setattrofunc)0,
381 0,
382 Py_TPFLAGS_DEFAULT,
383 NULL
384 };
385
386 #if 0
387 static void
388 PyGdkWindow_Dealloc(PyGdkWindow_Object *self)
389 {
390 if (gdk_drawable_get_type(self->obj) == GDK_WINDOW_PIXMAP)
391 g_object_unref(self->obj);
392 else
393 g_object_unref(self->obj);
394 PyObject_DEL(self);
395 }
396
397 static int
398 PyGdkWindow_Compare(PyGdkWindow_Object *self, PyGdkWindow_Object *v)
399 {
400 if (self->obj == v->obj) return 0;
401 if (self->obj > v->obj) return -1;
402 return 1;
403 }
404
405 static long
406 PyGdkWindow_Hash(PyGdkWindow_Object *self)
407 {
408 return (long)self->obj;
409 }
410
411 static PyObject *
412 PyGdkWindow_Repr(PyGdkWindow_Object *self)
413 {
414 char buf[100];
415 if (gdk_drawable_get_type(self->obj) == GDK_WINDOW_PIXMAP)
416 sprintf(buf, "<GdkPixmap at %lx>", (long)PyGdkWindow_Get(self));
417 else
418 sprintf(buf, "<GdkWindow at %lx>", (long)PyGdkWindow_Get(self));
419 return PyString_FromString(buf);
420 }
421
422 static PyObject *
423 PyGdkWindow_NewGC(PyGdkWindow_Object *self, PyObject *args, PyObject *kws)
424 {
425 int i = 0;
426 PyObject *key, *value;
427 char *strkey;
428 GdkGCValues values;
429 GdkGCValuesMask mask = 0;
430 GdkGC *gc;
431
432 if (kws != NULL)
433 while (PyDict_Next(kws, &i, &key, &value)) {
434 strkey = PyString_AsString(key);
435 if (!strcmp(strkey, "foreground")) {
436 if (!PyGdkColor_Check(value)) {
437 PyErr_SetString(PyExc_TypeError,
438 "foreground argument takes a GdkColor");
439 return NULL;
440 }
441 mask |= GDK_GC_FOREGROUND;
442 values.foreground.red = PyGdkColor_Get(value)->red;
443 values.foreground.green = PyGdkColor_Get(value)->green;
444 values.foreground.blue = PyGdkColor_Get(value)->blue;
445 values.foreground.pixel = PyGdkColor_Get(value)->pixel;
446 } else if (!strcmp(strkey, "background")) {
447 if (!PyGdkColor_Check(value)) {
448 PyErr_SetString(PyExc_TypeError,
449 "background argument takes a GdkColor");
450 return NULL;
451 }
452 mask |= GDK_GC_BACKGROUND;
453 values.background.red = PyGdkColor_Get(value)->red;
454 values.background.green = PyGdkColor_Get(value)->green;
455 values.background.blue = PyGdkColor_Get(value)->blue;
456 values.background.pixel = PyGdkColor_Get(value)->pixel;
457 } else if (!strcmp(strkey, "font")) {
458 if (!PyGdkFont_Check(value)) {
459 PyErr_SetString(PyExc_TypeError,
460 "font argument takes a GdkFont");
461 return NULL;
462 }
463 mask |= GDK_GC_FONT;
464 values.font = PyGdkFont_Get(value);
465 } else if (!strcmp(strkey, "tile")) {
466 if (!PyGdkWindow_Check(value)) {
467 PyErr_SetString(PyExc_TypeError,
468 "tile argument takes a GdkPixmap");
469 return NULL;
470 }
471 mask |= GDK_GC_TILE;
472 values.tile = PyGdkWindow_Get(value);
473 } else if (!strcmp(strkey, "stipple")) {
474 if (!PyGdkWindow_Check(value)) {
475 PyErr_SetString(PyExc_TypeError,
476 "stipple argument takes a GdkPixmap");
477 return NULL;
478 }
479 mask |= GDK_GC_STIPPLE;
480 values.stipple = PyGdkWindow_Get(value);
481 } else if (!strcmp(strkey, "clip_mask")) {
482 if (!PyGdkWindow_Check(value)) {
483 PyErr_SetString(PyExc_TypeError,
484 "clip_mask argument takes a GdkPixmap");
485 return NULL;
486 }
487 mask |= GDK_GC_CLIP_MASK;
488 values.clip_mask = PyGdkWindow_Get(value);
489 } else {
490 int i = 0;
491 #ifndef offsetof
492 #define offsetof(type, member) ( (int) &((type*)0)->member)
493 #endif
494 #define OFF(x) offsetof(GdkGCValues, x)
495 static struct {char *name;GdkGCValuesMask mask;int offs; } others[] = {
496 {"function", GDK_GC_FUNCTION, OFF(function)},
497 {"fill", GDK_GC_FILL, OFF(fill)},
498 {"subwindow_mode", GDK_GC_SUBWINDOW, OFF(subwindow_mode)},
499 {"ts_x_origin", GDK_GC_TS_X_ORIGIN, OFF(ts_x_origin)},
500 {"ts_y_origin", GDK_GC_TS_Y_ORIGIN, OFF(ts_y_origin)},
501 {"clip_x_origin", GDK_GC_CLIP_X_ORIGIN, OFF(clip_x_origin)},
502 {"clip_y_origin", GDK_GC_CLIP_Y_ORIGIN, OFF(clip_y_origin)},
503 {"graphics_exposures", GDK_GC_EXPOSURES, OFF(graphics_exposures)},
504 {"line_width", GDK_GC_LINE_WIDTH, OFF(line_width)},
505 {"line_style", GDK_GC_LINE_STYLE, OFF(line_style)},
506 {"cap_style", GDK_GC_CAP_STYLE, OFF(cap_style)},
507 {"join_style", GDK_GC_JOIN_STYLE, OFF(join_style)},
508 {NULL, 0, 0}
509 };
510 #undef OFF
511 while (others[i].name != NULL) {
512 if (!strcmp(strkey, others[i].name)) {
513 if (!PyInt_Check(value)) {
514 char buf[80];
515 g_snprintf(buf, sizeof(buf),
516 "%s argument expects an integer",
517 others[i].name);
518 PyErr_SetString(PyExc_TypeError, buf);
519 return NULL;
520 }
521 mask |= others[i].mask;
522 *((int *)((char *)&values + others[i].offs)) =
523 PyInt_AsLong(value);
524 break;
525 }
526 i++;
527 }
528 if (others[i].name == NULL) {
529 PyErr_SetString(PyExc_TypeError, "unknown argument");
530 return NULL;
531 }
532 }
533 }
534 if (!PyArg_ParseTuple(args, ":GdkWindow.new_gc"))
535 return NULL;
536 gc = gdk_gc_new_with_values(PyGdkWindow_Get(self), &values, mask);
537 value = PyGdkGC_New(gc);
538 g_object_unref(gc);
539 return value;
540 }
541
542 static PyObject *
543 PyGdkWindow_SetCursor(PyGdkWindow_Object *self, PyObject *args)
544 {
545 PyObject *cursor;
546
547 if (!PyArg_ParseTuple(args, "O!:GdkWindow.set_cursor", &PyGdkCursor_Type,
548 &cursor))
549 return NULL;
550 gdk_window_set_cursor(self->obj, PyGdkCursor_Get(cursor));
551 Py_INCREF(Py_None);
552 return Py_None;
553 }
554
555 static PyObject *
556 PyGdkWindow_PropertyGet(PyGdkWindow_Object *self, PyObject *args)
557 {
558 PyObject *py_property, py_type = NULL;
559 gint pdelete = FALSE;
560
561 GdkAtom atype, property, type;
562 gint aformat, alength;
563 guchar *data;
564
565 if (!PyArg_ParseTuple(args, "O|Oi:GdkWindow.property_get", &py_property,
566 &py_type, &pdelete)) {
567 return NULL;
568 }
569
570 property = pygdk_atom_from_pyobject(py_property);
571 if (Pyerr_Occurred())
572 return NULL;
573
574 type = pygdk_atom_from_pyobject(py_type);
575 if (Pyerr_Occurred())
576 return NULL;
577
578 if (gdk_property_get(self->obj, property, type, 0, G_MAXLONG,
579 pdelete, &atype, &aformat, &alength, &data)) {
580 /* success */
581 PyObject *pdata = NULL;
582 gint i;
583 guint16 *data16;
584 guint32 *data32;
585 switch (aformat) {
586 case 8:
587 if ((pdata = PyString_FromStringAndSize(data, alength)) == NULL)
588 return NULL;
589 break;
590 case 16:
591 data16 = (guint16 *)data;
592 if ((pdata = PyTuple_New(alength)) == NULL)
593 return NULL;
594 for (i = 0; i < alength; i++)
595 PyTuple_SetItem(pdata, i, PyInt_FromLong(data16[i]));
596 break;
597 case 32:
598 data32 = (guint32 *)data;
599 if ((pdata = PyTuple_New(alength)) == NULL)
600 return NULL;
601 for (i = 0; i < alength; i++)
602 PyTuple_SetItem(pdata, i, PyInt_FromLong(data32[i]));
603 break;
604 default:
605 g_warning("got a property format != 8, 16 or 32");
606 g_assert_not_reached();
607 }
608 g_free(data);
609 return Py_BuildValue("(NiN)", PyGdkAtom_New(atype), aformat, pdata);
610 } else {
611 Py_INCREF(Py_None);
612 return Py_None;
613 }
614 }
615
616 static PyObject *
617 PyGdkWindow_PropertyChange(PyGdkWindow_Object *self, PyObject *args)
618 {
619 PyObject *py_property, *py_type;
620 GdkAtom property, type;
621 gint format;
622 PyObject *py_mode, *pdata;
623 GdkPropMode mode;
624 guchar *data = NULL;
625 gint nelements;
626
627 if (!PyArg_ParseTuple(args, "OOiOO:GdkWindow.property_change",
628 &py_property, &py_type, &format, &py_mode, &pdata)) {
629 return NULL;
630 }
631
632 property = pygdk_atom_from_pyobject(py_property);
633 if (Pyerr_Occurred())
634 return NULL;
635
636 type = pygdk_atom_from_pyobject(py_type);
637 if (Pyerr_Occurred())
638 return NULL;
639
640 if (pygtk_enum_get_value(GDK_TYPE_PROP_MODE, py_mode, (gint *)&mode))
641 return NULL;
642 switch (format) {
643 case 8:
644 if (!PyString_Check(pdata)) {
645 PyErr_SetString(PyExc_TypeError, "data not a string and format=8");
646 return NULL;
647 }
648 data = PyString_AsString(pdata);
649 nelements = PyString_Size(pdata);
650 break;
651 case 16:
652 {
653 guint16 *data16;
654 gint i;
655
656 if (!PySequence_Check(pdata)) {
657 PyErr_SetString(PyExc_TypeError,
658 "data not a sequence and format=16");
659 return NULL;
660 }
661 nelements = PySequence_Length(pdata);
662 data16 = g_new(guint16, nelements);
663 data = (guchar *)data16;
664 for (i = 0; i < nelements; i++) {
665 PyObject *item = PySequence_GetItem(pdata, i);
666 Py_DECREF(item);
667 item = PyNumber_Int(item);
668 if (!item) {
669 g_free(data16);
670 PyErr_Clear();
671 PyErr_SetString(PyExc_TypeError,"data element not an int");
672 return NULL;
673 }
674 data16[i] = PyInt_AsLong(item);
675 Py_DECREF(item);
676 }
677 }
678 break;
679 case 32:
680 {
681 guint32 *data32;
682 gint i;
683
684 if (!PySequence_Check(pdata)) {
685 PyErr_SetString(PyExc_TypeError,
686 "data not a sequence and format=32");
687 return NULL;
688 }
689 nelements = PySequence_Length(pdata);
690 data32 = g_new(guint32, nelements);
691 data = (guchar *)data32;
692 for (i = 0; i < nelements; i++) {
693 PyObject *item = PySequence_GetItem(pdata, i);
694 Py_DECREF(item);
695 item = PyNumber_Int(item);
696 if (!item) {
697 g_free(data32);
698 PyErr_Clear();
699 PyErr_SetString(PyExc_TypeError,"data element not an int");
700 return NULL;
701 }
702 data32[i] = PyInt_AsLong(item);
703 Py_DECREF(item);
704 }
705 }
706 break;
707 default:
708 PyErr_SetString(PyExc_TypeError, "format must be 8, 16 or 32");
709 return NULL;
710 break;
711 }
712 gdk_property_change(self->obj, property, type, format, mode, data,
713 nelements);
714 if (format != 8)
715 g_free(data);
716 Py_INCREF(Py_None);
717 return Py_None;
718 }
719
720 static PyObject *
721 PyGdkWindow_PropertyDelete(PyGdkWindow_Object *self, PyObject *args)
722 {
723 PyObject py_property;
724 GdkAtom property;
725
726 if (!PyArg_ParseTuple(args, "O:GdkWindow.property_delete", &property)) {
727 return NULL;
728 }
729
730 property = pygdk_atom_from_pyobject(py_property);
731 if (Pyerr_Occurred())
732 return NULL;
733
734 gdk_property_delete(self->obj, property);
735 Py_INCREF(Py_None);
736 return Py_None;
737 }
738
739 static PyObject *
740 PyGdkWindow_Raise(PyGdkWindow_Object *self, PyObject *args)
741 {
742 if (!PyArg_ParseTuple(args, ":GdkWindow._raise"))
743 return NULL;
744 gdk_window_raise(self->obj);
745 Py_INCREF(Py_None);
746 return Py_None;
747 }
748
749 static PyObject *
750 PyGdkWindow_Lower(PyGdkWindow_Object *self, PyObject *args)
751 {
752 if (!PyArg_ParseTuple(args, ":GdkWindow.lower"))
753 return NULL;
754 gdk_window_lower(self->obj);
755 Py_INCREF(Py_None);
756 return Py_None;
757 }
758
759 static PyObject *
760 PyGdkWindow_InputGetPointer(PyGdkWindow_Object *self, PyObject *args)
761 {
762 guint32 deviceid;
763 gdouble x = 0.0, y = 0.0, pressure = 0.0, xtilt = 0.0, ytilt = 0.0;
764 GdkModifierType mask = 0;
765
766 if (!PyArg_ParseTuple(args, "i:GdkWindow.input_get_pointer", &deviceid))
767 return NULL;
768 gdk_input_window_get_pointer(self->obj, deviceid, &x, &y, &pressure,
769 &xtilt, &ytilt, &mask);
770 return Py_BuildValue("(dddddi)", x, y, pressure, xtilt, ytilt, mask);
771 }
772
773 static PyMethodDef PyGdkWindow_methods[] = {
774 {"new_gc", (PyCFunction)PyGdkWindow_NewGC, METH_VARARGS|METH_KEYWORDS, NULL},
775 {"set_cursor", (PyCFunction)PyGdkWindow_SetCursor, METH_VARARGS, NULL},
776 {"property_get", (PyCFunction)PyGdkWindow_PropertyGet, METH_VARARGS, NULL},
777 {"property_change", (PyCFunction)PyGdkWindow_PropertyChange, METH_VARARGS, NULL},
778 {"property_delete", (PyCFunction)PyGdkWindow_PropertyDelete, METH_VARARGS, NULL},
779 {"_raise", (PyCFunction)PyGdkWindow_Raise, METH_VARARGS, NULL},
780 {"lower", (PyCFunction)PyGdkWindow_Lower, METH_VARARGS, NULL},
781 {"input_get_pointer", (PyCFunction)PyGdkWindow_InputGetPointer, METH_VARARGS, NULL},
782 {NULL, 0, 0, NULL}
783 };
784
785 static PyObject *
786 PyGdkWindow_GetAttr(PyGdkWindow_Object *self, char *key)
787 {
788 GdkWindow *win = PyGdkWindow_Get(self);
789 gint x, y;
790 GdkModifierType p_mask;
791
792 if (!strcmp(key, "__members__"))
793 return Py_BuildValue("[sssssssssssss]", "children", "colormap", "depth",
794 "height", "parent", "pointer", "pointer_state",
795 "toplevel", "type", "width", "x", "xid", "y");
796 if (!strcmp(key, "width")) {
797 gdk_drawable_get_size(win, &x, NULL);
798 return PyInt_FromLong(x);
799 }
800 if (!strcmp(key, "height")) {
801 gdk_drawable_get_size(win, NULL, &y);
802 return PyInt_FromLong(y);
803 }
804 if (!strcmp(key, "x")) {
805 gdk_window_get_position(win, &x, NULL);
806 return PyInt_FromLong(x);
807 }
808 if (!strcmp(key, "y")) {
809 gdk_window_get_position(win, NULL, &y);
810 return PyInt_FromLong(y);
811 }
812 if (!strcmp(key, "colormap"))
813 return PyGdkColormap_New(gdk_drawable_get_colormap(win));
814 if (!strcmp(key, "pointer")) {
815 gdk_window_get_pointer(win, &x, &y, NULL);
816 return Py_BuildValue("(ii)", x, y);
817 }
818 if (!strcmp(key, "pointer_state")) {
819 gdk_window_get_pointer(win, NULL, NULL, &p_mask);
820 return PyInt_FromLong(p_mask);
821 }
822 if (!strcmp(key, "parent")) {
823 GdkWindow *par = gdk_window_get_parent(win);
824 if (par)
825 return PyGdkWindow_New(par);
826 Py_INCREF(Py_None);
827 return Py_None;
828 }
829 if (!strcmp(key, "toplevel"))
830 return PyGdkWindow_New(gdk_window_get_toplevel(win));
831 if (!strcmp(key, "children")) {
832 GList *children, *tmp;
833 PyObject *ret;
834 children = gdk_window_get_children(win);
835 if ((ret = PyList_New(0)) == NULL)
836 return NULL;
837 for (tmp = children; tmp != NULL; tmp = tmp->next) {
838 PyObject *win = PyGdkWindow_New(tmp->data);
839 if (win == NULL) {
840 Py_DECREF(ret);
841 return NULL;
842 }
843 PyList_Append(ret, win);
844 Py_DECREF(win);
845 }
846 g_list_free(children);
847 return ret;
848 }
849 if (!strcmp(key, "type"))
850 return PyInt_FromLong(gdk_drawable_get_type(win));
851 if (!strcmp(key, "depth")) {
852 gdk_window_get_geometry(win, NULL, NULL, NULL, NULL, &x);
853 return PyInt_FromLong(x);
854 }
855 #ifdef WITH_XSTUFF
856 if (!strcmp(key, "xid"))
857 return PyInt_FromLong(GDK_WINDOW_XWINDOW(win));
858 #endif
859
860 return Py_FindMethod(PyGdkWindow_methods, (PyObject *)self, key);
861 }
862
863 PyTypeObject PyGdkWindow_Type = {
864 PyObject_HEAD_INIT(NULL)
865 0,
866 "GdkWindow",
867 sizeof(PyGdkWindow_Object),
868 0,
869 (destructor)PyGdkWindow_Dealloc,
870 (printfunc)0,
871 (getattrfunc)PyGdkWindow_GetAttr,
872 (setattrfunc)0,
873 (cmpfunc)PyGdkWindow_Compare,
874 (reprfunc)PyGdkWindow_Repr,
875 0,
876 0,
877 0,
878 (hashfunc)PyGdkWindow_Hash,
879 (ternaryfunc)0,
880 (reprfunc)0,
881 (getattrofunc)0,
882 (setattrofunc)0,
883 0,
884 Py_TPFLAGS_DEFAULT,
885 NULL
886 };
887 #endif
888
889 GdkAtom
pygdk_atom_from_pyobject(PyObject * object)890 pygdk_atom_from_pyobject(PyObject *object)
891 {
892 if (object == NULL)
893 return NULL;
894 if (PyString_Check(object))
895 return gdk_atom_intern(PyString_AsString(object), FALSE);
896 if (PyGdkAtom_Check(object))
897 return PyGdkAtom_Get(object);
898 PyErr_SetString(PyExc_TypeError, "unable to convert argument to GdkAtom");
899 return NULL;
900 }
901
902 static void
pygdk_atom_dealloc(PyGdkAtom_Object * self)903 pygdk_atom_dealloc(PyGdkAtom_Object *self)
904 {
905 if (self->name) g_free(self->name);
906 PyObject_DEL(self);
907 }
908
909 static long
pygdk_atom_hash(PyGdkAtom_Object * self)910 pygdk_atom_hash(PyGdkAtom_Object *self)
911 {
912 return (long)self->atom;
913 }
914
915 static PyObject *
pygdk_atom_repr(PyGdkAtom_Object * self)916 pygdk_atom_repr(PyGdkAtom_Object *self)
917 {
918 char buf[256];
919 if (!self->name) self->name = gdk_atom_name(self->atom);
920 g_snprintf(buf, 256, "<GdkAtom 0x%lx = '%s'>", (unsigned long)self->atom,
921 self->name?self->name:"(null)");
922 return PyString_FromString(buf);
923 }
924
925 static PyObject *
pygdk_atom_str(PyGdkAtom_Object * self)926 pygdk_atom_str(PyGdkAtom_Object *self)
927 {
928 if (!self->name) self->name = gdk_atom_name(self->atom);
929 if (self->name)
930 return PyString_FromString(self->name);
931 return pygdk_atom_repr(self);
932 }
933
934 static PyObject *
pygdk_atom_richcompare(PyGdkAtom_Object * self,PyGdkAtom_Object * v,int op)935 pygdk_atom_richcompare(PyGdkAtom_Object *self, PyGdkAtom_Object *v, int op)
936 {
937 PyObject *result = Py_NotImplemented;
938
939 if (PyString_Check(v)) {
940 PyObject *str = pygdk_atom_str(self);
941 result = PyObject_RichCompare(str, (PyObject *)v, op);
942 Py_DECREF(str);
943 return result;
944 }
945 if (PyGdkAtom_Check(v)) {
946 switch (op) {
947 case Py_LT:
948 result = (self->atom < v->atom) ? Py_True : Py_False;
949 break;
950 case Py_LE:
951 result = (self->atom <= v->atom) ? Py_True : Py_False;
952 break;
953 case Py_EQ:
954 result = (self->atom == v->atom) ? Py_True : Py_False;
955 break;
956 case Py_NE:
957 result = (self->atom != v->atom) ? Py_True : Py_False;
958 break;
959 case Py_GE:
960 result = (self->atom >= v->atom) ? Py_True : Py_False;
961 break;
962 case Py_GT:
963 result = (self->atom > v->atom) ? Py_True : Py_False;
964 break;
965 default:
966 break;
967 }
968 }
969 Py_INCREF(result);
970 return result;
971 }
972
973 PyTypeObject PyGdkAtom_Type = {
974 PyObject_HEAD_INIT(NULL)
975 0,
976 "gtk.gdk.GdkAtom",
977 sizeof(PyGdkAtom_Object),
978 0,
979 (destructor)pygdk_atom_dealloc,
980 (printfunc)0,
981 (getattrfunc)0,
982 (setattrfunc)0,
983 (cmpfunc)0,
984 (reprfunc)pygdk_atom_repr,
985 0,
986 0,
987 0,
988 (hashfunc)pygdk_atom_hash,
989 (ternaryfunc)0,
990 (reprfunc)pygdk_atom_str,
991 (getattrofunc)0,
992 (setattrofunc)0,
993 0,
994 Py_TPFLAGS_DEFAULT,
995 NULL,
996 0,
997 0,
998 (richcmpfunc)pygdk_atom_richcompare,
999 };
1000
1001 typedef struct {
1002 PyObject_HEAD
1003 GtkTreeModel *model;
1004 GtkTreeIter iter;
1005 } PyGtkTreeModelRow;
1006 staticforward PyTypeObject PyGtkTreeModelRow_Type;
1007
1008 PyObject *
_pygtk_tree_model_row_new(GtkTreeModel * model,GtkTreeIter * iter)1009 _pygtk_tree_model_row_new(GtkTreeModel *model, GtkTreeIter *iter)
1010 {
1011 PyGtkTreeModelRow *self;
1012
1013 self = (PyGtkTreeModelRow *) PyObject_NEW(PyGtkTreeModelRow,
1014 &PyGtkTreeModelRow_Type);
1015 if (self == NULL)
1016 return NULL;
1017 self->model = g_object_ref(model);
1018 self->iter = *iter;
1019 return (PyObject *)self;
1020 }
1021
1022 static void
pygtk_tree_model_row_dealloc(PyGtkTreeModelRow * self)1023 pygtk_tree_model_row_dealloc(PyGtkTreeModelRow *self)
1024 {
1025 g_object_unref(self->model);
1026 PyObject_DEL(self);
1027 }
1028
1029 static Py_ssize_t
pygtk_tree_model_row_length(PyGtkTreeModelRow * self)1030 pygtk_tree_model_row_length(PyGtkTreeModelRow *self)
1031 {
1032 return gtk_tree_model_get_n_columns(self->model);
1033 }
1034
1035 static PyObject *
pygtk_tree_model_row_getitem(PyGtkTreeModelRow * self,Py_ssize_t column)1036 pygtk_tree_model_row_getitem(PyGtkTreeModelRow *self, Py_ssize_t column)
1037 {
1038 gint n_columns;
1039 GValue value = { 0, };
1040 PyObject *ret;
1041
1042 n_columns = gtk_tree_model_get_n_columns(self->model);
1043 if (column < 0 || column >= n_columns) {
1044 PyErr_SetString(PyExc_IndexError, "column index out of range");
1045 return NULL;
1046 }
1047 gtk_tree_model_get_value(self->model, &self->iter, column, &value);
1048 ret = pyg_value_as_pyobject(&value, TRUE);
1049 g_value_unset(&value);
1050 return ret;
1051 }
1052
1053 static int
pygtk_tree_model_row_setitem(PyGtkTreeModelRow * self,Py_ssize_t column,PyObject * pyvalue)1054 pygtk_tree_model_row_setitem(PyGtkTreeModelRow *self, Py_ssize_t column,
1055 PyObject *pyvalue)
1056 {
1057 gint n_columns;
1058 GValue value = { 0, };
1059
1060 if (!GTK_IS_LIST_STORE(self->model) && !GTK_IS_TREE_STORE(self->model)) {
1061 PyErr_SetString(PyExc_TypeError,
1062 "can not set cells in this tree model");
1063 return -1;
1064 }
1065
1066 n_columns = gtk_tree_model_get_n_columns(self->model);
1067 if (column < 0 || column >= n_columns) {
1068 PyErr_SetString(PyExc_IndexError, "column index out of range");
1069 return -1;
1070 }
1071 g_value_init(&value, gtk_tree_model_get_column_type(self->model, column));
1072 if (pyg_value_from_pyobject(&value, pyvalue)) {
1073 PyErr_SetString(PyExc_TypeError,
1074 "value is of wrong type for this column");
1075 return -1;
1076 }
1077 if (GTK_IS_LIST_STORE(self->model))
1078 gtk_list_store_set_value(GTK_LIST_STORE(self->model), &self->iter,
1079 column, &value);
1080 else if (GTK_IS_TREE_STORE(self->model))
1081 gtk_tree_store_set_value(GTK_TREE_STORE(self->model), &self->iter,
1082 column, &value);
1083 g_value_unset(&value);
1084 return 0;
1085 }
1086
1087 static PySequenceMethods pygtk_tree_model_row_seqmethods = {
1088 (lenfunc)pygtk_tree_model_row_length,
1089 0,
1090 0,
1091 (ssizeargfunc)pygtk_tree_model_row_getitem,
1092 0,
1093 (ssizeobjargproc)pygtk_tree_model_row_setitem,
1094 0
1095 };
1096
1097 static PyObject *
pygtk_tree_model_row_iterchildren(PyGtkTreeModelRow * self)1098 pygtk_tree_model_row_iterchildren(PyGtkTreeModelRow *self)
1099 {
1100 return _pygtk_tree_model_row_iter_new(self->model, &self->iter);
1101 }
1102
1103 static PyMethodDef pygtk_tree_model_row_methods[] = {
1104 { "iterchildren", (PyCFunction)pygtk_tree_model_row_iterchildren, METH_NOARGS },
1105 { NULL, NULL, 0 }
1106 };
1107
1108 static PyObject *
pygtk_tree_model_row_get_next(PyGtkTreeModelRow * self,void * closure)1109 pygtk_tree_model_row_get_next(PyGtkTreeModelRow *self, void *closure)
1110 {
1111 GtkTreeIter iter;
1112
1113 iter = self->iter;
1114 if (gtk_tree_model_iter_next(self->model, &iter))
1115 return _pygtk_tree_model_row_new(self->model, &iter);
1116 Py_INCREF(Py_None);
1117 return Py_None;
1118 }
1119
1120 static PyObject *
pygtk_tree_model_row_get_parent(PyGtkTreeModelRow * self,void * closure)1121 pygtk_tree_model_row_get_parent(PyGtkTreeModelRow *self, void *closure)
1122 {
1123 GtkTreeIter parent;
1124
1125 if (gtk_tree_model_iter_parent(self->model, &parent, &self->iter))
1126 return _pygtk_tree_model_row_new(self->model, &parent);
1127 Py_INCREF(Py_None);
1128 return Py_None;
1129 }
1130
1131 static PyObject *
pygtk_tree_model_row_get_model(PyGtkTreeModelRow * self,void * closure)1132 pygtk_tree_model_row_get_model(PyGtkTreeModelRow *self, void *closure)
1133 {
1134 return pygobject_new((GObject *)self->model);
1135 }
1136
1137 static PyObject *
pygtk_tree_model_row_get_path(PyGtkTreeModelRow * self,void * closure)1138 pygtk_tree_model_row_get_path(PyGtkTreeModelRow *self, void *closure)
1139 {
1140 GtkTreePath *path;
1141 PyObject *ret;
1142
1143 path = gtk_tree_model_get_path(self->model, &self->iter);
1144 if (!path) {
1145 PyErr_SetString(PyExc_RuntimeError, "could not get tree path");
1146 return NULL;
1147 }
1148 ret = pygtk_tree_path_to_pyobject(path);
1149 gtk_tree_path_free(path);
1150 return ret;
1151 }
1152
1153 static PyObject *
pygtk_tree_model_row_get_iter(PyGtkTreeModelRow * self,void * closure)1154 pygtk_tree_model_row_get_iter(PyGtkTreeModelRow *self, void *closure)
1155 {
1156 return pyg_boxed_new(GTK_TYPE_TREE_ITER, &self->iter, TRUE, TRUE);
1157 }
1158
1159 static PyGetSetDef pygtk_tree_model_row_getsets[] = {
1160 { "next", (getter)pygtk_tree_model_row_get_next, (setter)0 },
1161 { "parent", (getter)pygtk_tree_model_row_get_parent, (setter)0 },
1162 { "model", (getter)pygtk_tree_model_row_get_model, (setter)0 },
1163 { "path", (getter)pygtk_tree_model_row_get_path, (setter)0 },
1164 { "iter", (getter)pygtk_tree_model_row_get_iter, (setter)0 },
1165 { NULL, (getter)0, (setter)0 }
1166 };
1167
1168 static PyTypeObject PyGtkTreeModelRow_Type = {
1169 PyObject_HEAD_INIT(NULL)
1170 0,
1171 "gtk.TreeModelRow",
1172 sizeof(PyGtkTreeModelRow),
1173 0,
1174 (destructor)pygtk_tree_model_row_dealloc,
1175 (printfunc)0,
1176 (getattrfunc)0,
1177 (setattrfunc)0,
1178 (cmpfunc)0,
1179 (reprfunc)0,
1180 0,
1181 &pygtk_tree_model_row_seqmethods,
1182 0,
1183 (hashfunc)0,
1184 (ternaryfunc)0,
1185 (reprfunc)0,
1186 (getattrofunc)0,
1187 (setattrofunc)0,
1188 0,
1189 Py_TPFLAGS_DEFAULT,
1190 NULL,
1191 (traverseproc)0,
1192 (inquiry)0,
1193 (richcmpfunc)0,
1194 0,
1195 (getiterfunc)0,
1196 (iternextfunc)0,
1197 pygtk_tree_model_row_methods,
1198 0,
1199 pygtk_tree_model_row_getsets
1200 };
1201
1202 typedef struct {
1203 PyObject_HEAD
1204 GtkTreeModel *model;
1205 gboolean has_more;
1206 GtkTreeIter iter;
1207 } PyGtkTreeModelRowIter;
1208 staticforward PyTypeObject PyGtkTreeModelRowIter_Type;
1209
1210 PyObject *
_pygtk_tree_model_row_iter_new(GtkTreeModel * model,GtkTreeIter * parent_iter)1211 _pygtk_tree_model_row_iter_new(GtkTreeModel *model, GtkTreeIter *parent_iter)
1212 {
1213 PyGtkTreeModelRowIter *self;
1214
1215 self = (PyGtkTreeModelRowIter *) PyObject_NEW(PyGtkTreeModelRowIter,
1216 &PyGtkTreeModelRowIter_Type);
1217 if (self == NULL)
1218 return NULL;
1219 self->model = g_object_ref(model);
1220 /* iterate through child nodes */
1221 self->has_more = gtk_tree_model_iter_children(self->model, &self->iter,
1222 parent_iter);
1223 return (PyObject *)self;
1224 }
1225
1226 static void
pygtk_tree_model_row_iter_dealloc(PyGtkTreeModelRowIter * self)1227 pygtk_tree_model_row_iter_dealloc(PyGtkTreeModelRowIter *self)
1228 {
1229 g_object_unref(self->model);
1230 PyObject_DEL(self);
1231 }
1232
1233 static PyObject *
pygtk_tree_model_row_iter_getiter(PyGtkTreeModelRowIter * self)1234 pygtk_tree_model_row_iter_getiter(PyGtkTreeModelRowIter *self)
1235 {
1236 Py_INCREF(self);
1237 return (PyObject *)self;
1238 }
1239
1240 static PyObject *
pygtk_tree_model_row_iter_next(PyGtkTreeModelRowIter * self)1241 pygtk_tree_model_row_iter_next(PyGtkTreeModelRowIter *self)
1242 {
1243 PyObject *row;
1244
1245 if (!self->has_more) {
1246 PyErr_SetNone(PyExc_StopIteration);
1247 return NULL;
1248 }
1249
1250 row = _pygtk_tree_model_row_new(self->model, &self->iter);
1251
1252 /* move to next iter */
1253 self->has_more = gtk_tree_model_iter_next(self->model, &self->iter);
1254
1255 return row;
1256 }
1257
1258 static PyTypeObject PyGtkTreeModelRowIter_Type = {
1259 PyObject_HEAD_INIT(NULL)
1260 0,
1261 "gtk.TreeModelRowIter",
1262 sizeof(PyGtkTreeModelRowIter),
1263 0,
1264 (destructor)pygtk_tree_model_row_iter_dealloc,
1265 (printfunc)0,
1266 (getattrfunc)0,
1267 (setattrfunc)0,
1268 (cmpfunc)0,
1269 (reprfunc)0,
1270 0,
1271 0,
1272 0,
1273 (hashfunc)0,
1274 (ternaryfunc)0,
1275 (reprfunc)0,
1276 (getattrofunc)0,
1277 (setattrofunc)0,
1278 0,
1279 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_ITER,
1280 NULL,
1281 (traverseproc)0,
1282 (inquiry)0,
1283 (richcmpfunc)0,
1284 0,
1285 (getiterfunc)pygtk_tree_model_row_iter_getiter,
1286 (iternextfunc)pygtk_tree_model_row_iter_next
1287 };
1288
1289 int
_pygtk_tree_model_remove_row(GtkTreeModel * model,GtkTreeIter * iter)1290 _pygtk_tree_model_remove_row(GtkTreeModel *model, GtkTreeIter *iter)
1291 {
1292 GtkTreeModel *child;
1293 GtkTreeIter citer;
1294
1295 if (GTK_IS_LIST_STORE(model)) {
1296 gtk_list_store_remove(GTK_LIST_STORE(model), iter);
1297 return 0;
1298 }
1299
1300 if (GTK_IS_TREE_STORE(model)) {
1301 gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
1302 return 0;
1303 }
1304
1305 if (GTK_IS_TREE_MODEL_SORT(model)) {
1306 child = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));
1307 gtk_tree_model_sort_convert_iter_to_child_iter(
1308 GTK_TREE_MODEL_SORT(model), &citer, iter);
1309 return _pygtk_tree_model_remove_row(child, &citer);
1310 }
1311
1312 if (GTK_IS_TREE_MODEL_FILTER(model)) {
1313 child = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
1314 gtk_tree_model_filter_convert_iter_to_child_iter(
1315 GTK_TREE_MODEL_FILTER(model), &citer, iter);
1316 return _pygtk_tree_model_remove_row(child, &citer);
1317 }
1318
1319 PyErr_SetString(PyExc_TypeError,
1320 "cannot remove rows in this tree model");
1321 return -1;
1322 }
1323
1324 int
_pygtk_tree_model_set_row(GtkTreeModel * model,GtkTreeIter * iter,PyObject * items)1325 _pygtk_tree_model_set_row(GtkTreeModel *model, GtkTreeIter *iter,
1326 PyObject *items)
1327 {
1328 gint n_columns, i;
1329 GtkTreeModel *child;
1330 GtkTreeIter citer;
1331
1332 if (!GTK_IS_LIST_STORE(model) && !GTK_IS_TREE_STORE(model) &&
1333 !GTK_IS_TREE_MODEL_SORT(model) && !GTK_IS_TREE_MODEL_FILTER(model)) {
1334 PyErr_SetString(PyExc_TypeError,
1335 "cannot set cells in this tree model");
1336 return -1;
1337 }
1338
1339 if (GTK_IS_TREE_MODEL_SORT(model)) {
1340 child = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));
1341 gtk_tree_model_sort_convert_iter_to_child_iter(
1342 GTK_TREE_MODEL_SORT(model), &citer, iter);
1343 return _pygtk_tree_model_set_row(child, &citer, items);
1344 }
1345
1346 if (GTK_IS_TREE_MODEL_FILTER(model)) {
1347 child = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
1348 gtk_tree_model_filter_convert_iter_to_child_iter(
1349 GTK_TREE_MODEL_FILTER(model), &citer, iter);
1350 return _pygtk_tree_model_set_row(child, &citer, items);
1351 }
1352
1353 if (!PySequence_Check(items)) {
1354 PyErr_SetString(PyExc_TypeError, "expecting a sequence");
1355 return -1;
1356 }
1357 n_columns = gtk_tree_model_get_n_columns(model);
1358 if (PySequence_Length(items) != n_columns) {
1359 PyErr_SetString(PyExc_ValueError, "row sequence has wrong length");
1360 return -1;
1361 }
1362 for (i = 0; i < n_columns; i++) {
1363 GValue value = { 0, };
1364 PyObject *item;
1365
1366 item = PySequence_GetItem(items, i);
1367 if (!item)
1368 return -1;
1369 g_value_init(&value, gtk_tree_model_get_column_type(model, i));
1370 if (pyg_value_from_pyobject(&value, item)) {
1371 Py_DECREF(item);
1372 PyErr_SetString(PyExc_TypeError,
1373 "value is of wrong type for this column");
1374 return -1;
1375 }
1376
1377 if (GTK_IS_LIST_STORE(model))
1378 gtk_list_store_set_value(GTK_LIST_STORE(model), iter, i, &value);
1379 else if (GTK_IS_TREE_STORE(model))
1380 gtk_tree_store_set_value(GTK_TREE_STORE(model), iter, i, &value);
1381
1382 g_value_unset(&value);
1383 Py_DECREF(item);
1384 }
1385 return 0;
1386 }
1387
1388 PyObject *
pygtk_tree_path_to_pyobject(GtkTreePath * path)1389 pygtk_tree_path_to_pyobject(GtkTreePath *path)
1390 {
1391 gint len, i, *indices;
1392 PyObject *ret;
1393
1394 len = gtk_tree_path_get_depth(path);
1395 indices = gtk_tree_path_get_indices(path);
1396 ret = PyTuple_New(len);
1397 for (i = 0; i < len; i++)
1398 PyTuple_SetItem(ret, i, PyInt_FromLong(indices[i]));
1399 return ret;
1400 }
1401
1402 GtkTreePath *
pygtk_tree_path_from_pyobject(PyObject * object)1403 pygtk_tree_path_from_pyobject(PyObject *object)
1404 {
1405 if (PyString_Check(object)) {
1406 GtkTreePath *path;
1407
1408 path = gtk_tree_path_new_from_string(PyString_AsString(object));
1409 return path;
1410 } else if (PyInt_Check(object)) {
1411 GtkTreePath *path;
1412
1413 path = gtk_tree_path_new();
1414 gtk_tree_path_append_index(path, PyInt_AsLong(object));
1415 return path;
1416 } else if (PyTuple_Check(object)) {
1417 GtkTreePath *path;
1418 guint len, i;
1419
1420 len = PyTuple_Size(object);
1421 if (len < 1)
1422 return NULL;
1423 path = gtk_tree_path_new();
1424 for (i = 0; i < len; i++) {
1425 PyObject *item = PyTuple_GetItem(object, i);
1426 gint index = PyInt_AsLong(item);
1427 if (PyErr_Occurred()) {
1428 gtk_tree_path_free(path);
1429 PyErr_Clear();
1430 return NULL;
1431 }
1432 gtk_tree_path_append_index(path, index);
1433 }
1434 return path;
1435 }
1436 return NULL;
1437 }
1438
1439 /* marshalers for the boxed types. Uses uppercase notation so that
1440 * the macro below can automatically install them. */
1441 static PyObject *
PyGtkTreePath_from_value(const GValue * value)1442 PyGtkTreePath_from_value(const GValue *value)
1443 {
1444 GtkTreePath *path = (GtkTreePath *)g_value_get_boxed(value);
1445
1446 return pygtk_tree_path_to_pyobject(path);
1447 }
1448 static int
PyGtkTreePath_to_value(GValue * value,PyObject * object)1449 PyGtkTreePath_to_value(GValue *value, PyObject *object)
1450 {
1451 GtkTreePath *path = pygtk_tree_path_from_pyobject(object);
1452
1453 if (path) {
1454 g_value_set_boxed(value, path);
1455 gtk_tree_path_free(path);
1456 return 0;
1457 }
1458 return -1;
1459 }
1460
1461 gboolean
pygdk_rectangle_from_pyobject(PyObject * object,GdkRectangle * rectangle)1462 pygdk_rectangle_from_pyobject(PyObject *object, GdkRectangle *rectangle)
1463 {
1464 g_return_val_if_fail(rectangle != NULL, FALSE);
1465
1466 if (pyg_boxed_check(object, GDK_TYPE_RECTANGLE)) {
1467 *rectangle = *pyg_boxed_get(object, GdkRectangle);
1468 return TRUE;
1469 }
1470 if (PyArg_ParseTuple(object, "iiii", &rectangle->x, &rectangle->y,
1471 &rectangle->width, &rectangle->height)) {
1472 return TRUE;
1473 }
1474 PyErr_Clear();
1475 PyErr_SetString(PyExc_TypeError, "could not convert to GdkRectangle");
1476 return FALSE;
1477 }
1478
1479 static PyObject *
PyGdkRectangle_from_value(const GValue * value)1480 PyGdkRectangle_from_value(const GValue *value)
1481 {
1482 GdkRectangle *rect = (GdkRectangle *)g_value_get_boxed(value);
1483
1484 return pyg_boxed_new(GDK_TYPE_RECTANGLE, rect, TRUE, TRUE);
1485 }
1486 static int
PyGdkRectangle_to_value(GValue * value,PyObject * object)1487 PyGdkRectangle_to_value(GValue *value, PyObject *object)
1488 {
1489 GdkRectangle rect;
1490
1491 if (!pygdk_rectangle_from_pyobject(object, &rect))
1492 return -1;
1493
1494 g_value_set_boxed(value, &rect);
1495 return 0;
1496 }
1497
1498 /* We have to set ob_type here because stupid win32 does not allow you
1499 * to use variables from another dll in a global variable initialisation.
1500 */
1501 void
_pygtk_register_boxed_types(PyObject * moddict)1502 _pygtk_register_boxed_types(PyObject *moddict)
1503 {
1504 PyGtkStyleHelper_Type.ob_type = &PyType_Type;
1505 PyGtkRcStyleHelper_Type.ob_type = &PyType_Type;
1506 PyGdkAtom_Type.ob_type = &PyType_Type;
1507 PyGtkTreeModelRow_Type.ob_type = &PyType_Type;
1508 PyGtkTreeModelRowIter_Type.ob_type = &PyType_Type;
1509
1510 PyType_Ready(&PyGtkStyleHelper_Type);
1511 PyType_Ready(&PyGtkRcStyleHelper_Type);
1512 PyType_Ready(&PyGdkAtom_Type);
1513 PyType_Ready(&PyGtkTreeModelRow_Type);
1514 PyType_Ready(&PyGtkTreeModelRowIter_Type);
1515
1516 PyDict_SetItemString(moddict, "GdkAtomType", (PyObject *)&PyGdkAtom_Type);
1517
1518 pyg_register_boxed_custom(GTK_TYPE_TREE_PATH,
1519 PyGtkTreePath_from_value,
1520 PyGtkTreePath_to_value);
1521 pyg_register_boxed_custom(GDK_TYPE_RECTANGLE,
1522 PyGdkRectangle_from_value,
1523 PyGdkRectangle_to_value);
1524 }
1525