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