1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * Gimp-Python - allows the writing of Gimp plugins in Python.
3  * Copyright (C) 1997-2002  James Henstridge <james@daa.com.au>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 
23 #define NO_IMPORT_PYGOBJECT
24 #include <pygobject.h>
25 
26 #define GIMP_DISABLE_DEPRECATION_WARNINGS
27 #include "pygimp.h"
28 
29 #define NO_IMPORT_PYGIMPCOLOR
30 #include "pygimpcolor-api.h"
31 
32 #include <glib-object.h>
33 
34 #include <gegl.h>
35 
36 static void
ensure_drawable(PyGimpDrawable * self)37 ensure_drawable(PyGimpDrawable *self)
38 {
39     if (!self->drawable)
40 	self->drawable = gimp_drawable_get(self->ID);
41 }
42 
43 static PyObject *
drw_flush(PyGimpDrawable * self)44 drw_flush(PyGimpDrawable *self)
45 {
46     ensure_drawable(self);
47 
48     gimp_drawable_flush(self->drawable);
49 
50     Py_INCREF(Py_None);
51     return Py_None;
52 }
53 
54 
55 static PyObject *
drw_update(PyGimpDrawable * self,PyObject * args)56 drw_update(PyGimpDrawable *self, PyObject *args)
57 {
58     int x, y;
59     unsigned int w, h;
60 
61     if (!PyArg_ParseTuple(args, "iiii:update", &x, &y, &w, &h))
62 	return NULL;
63 
64     if (!gimp_drawable_update(self->ID, x, y, w, h)) {
65 	PyErr_Format(pygimp_error,
66 		     "could not update drawable (ID %d): "
67 		     "x=%d, y=%d, w=%d, h=%d",
68 		     self->ID, x, y, (int)w, (int)h);
69 	return NULL;
70     }
71 
72     Py_INCREF(Py_None);
73     return Py_None;
74 }
75 
76 
77 static PyObject *
drw_merge_shadow(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)78 drw_merge_shadow(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
79 {
80     gboolean undo = FALSE;
81 
82     static char *kwlist[] = { "undo", NULL };
83 
84     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:merge_shadow", kwlist,
85 				     &undo))
86 	return NULL;
87 
88     if (!gimp_drawable_merge_shadow(self->ID, undo)) {
89 	PyErr_Format(pygimp_error,
90 		     "could not merge the shadow buffer on drawable (ID %d)",
91 		     self->ID);
92 	return NULL;
93     }
94 
95     Py_INCREF(Py_None);
96     return Py_None;
97 }
98 
99 static PyObject *
drw_free_shadow(PyGimpDrawable * self)100 drw_free_shadow(PyGimpDrawable *self)
101 {
102     if (!gimp_drawable_free_shadow(self->ID)) {
103 	PyErr_Format(pygimp_error, "could not free shadow tiles on drawable (ID %d)",
104 		     self->ID);
105 	return NULL;
106     }
107 
108     Py_INCREF(Py_None);
109     return Py_None;
110 }
111 
112 static PyObject *
drw_fill(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)113 drw_fill(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
114 {
115     int fill = GIMP_FILL_FOREGROUND;
116 
117     static char *kwlist[] = { "fill", NULL };
118 
119     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:fill", kwlist, &fill))
120 	return NULL;
121 
122     if (!gimp_drawable_fill(self->ID, fill)) {
123 	PyErr_Format(pygimp_error,
124 		     "could not fill drawable (ID %d) with fill mode %d",
125 		     self->ID, fill);
126 	return NULL;
127     }
128 
129     Py_INCREF(Py_None);
130     return Py_None;
131 }
132 
133 
134 static PyObject *
drw_get_tile(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)135 drw_get_tile(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
136 {
137     GimpTile *t;
138     int shadow, row, col;
139 
140     static char *kwlist[] = { "shadow", "row", "col", NULL };
141 
142     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii:get_tile", kwlist,
143 				     &shadow, &row, &col))
144 	return NULL;
145 
146     ensure_drawable(self);
147 
148     if(row < 0 || row >= self->drawable->ntile_rows ||
149        col < 0 || col >= self->drawable->ntile_cols) {
150         Py_INCREF(Py_None);
151         return Py_None;
152     }
153 
154     t = gimp_drawable_get_tile(self->drawable, shadow, row, col);
155     return pygimp_tile_new(t, self);
156 }
157 
158 static PyObject *
drw_get_tile2(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)159 drw_get_tile2(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
160 {
161     GimpTile *t;
162     int shadow, x, y, row, col;
163 
164     static char *kwlist[] = { "shadow", "x", "y", NULL };
165 
166     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii:get_tile2", kwlist,
167 				     &shadow, &x ,&y))
168 	return NULL;
169 
170     ensure_drawable(self);
171     if(x < 0 || x >= self->drawable->width ||
172        y < 0 || y >= self->drawable->height) {
173         Py_INCREF(Py_None);
174         return Py_None;
175     }
176 
177     col = x / gimp_tile_width ();
178     row = y / gimp_tile_height ();
179 
180     t = gimp_drawable_get_tile(self->drawable, shadow, col, row);
181     return pygimp_tile_new(t, self);
182 }
183 
184 static PyObject *
drw_get_pixel_rgn(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)185 drw_get_pixel_rgn(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
186 {
187     int x, y, width, height, dirty = 1, shadow = 0;
188 
189     static char *kwlist[] = { "x", "y", "width", "height", "dirty", "shadow",
190 			      NULL };
191 
192     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
193 				     "iiii|ii:get_pixel_rgn", kwlist,
194 				     &x, &y, &width, &height, &dirty, &shadow))
195 	return NULL;
196 
197     ensure_drawable(self);
198 
199     return pygimp_pixel_rgn_new(self, x, y, width, height, dirty, shadow);
200 }
201 
202 static PyObject *
drw_offset(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)203 drw_offset(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
204 {
205     int wrap_around;
206     GimpOffsetType fill_type;
207     int offset_x, offset_y;
208 
209     static char *kwlist[] = { "wrap_around", "fill_type",
210 			      "offset_x", "offset_y",
211 			      NULL };
212 
213     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iiii:offset", kwlist,
214 				     &wrap_around, &fill_type,
215 				     &offset_x, &offset_y))
216 	return NULL;
217 
218     if (!gimp_drawable_offset(self->ID, wrap_around, fill_type,
219 			      offset_x, offset_y)) {
220 	PyErr_Format(pygimp_error,
221 		     "could not offset drawable (ID %d) by x: %d, y: %d",
222 		     self->ID, offset_x, offset_y);
223 	return NULL;
224     }
225 
226     Py_INCREF(Py_None);
227     return Py_None;
228 }
229 
230 static PyObject *
drw_parasite_find(PyGimpDrawable * self,PyObject * args)231 drw_parasite_find(PyGimpDrawable *self, PyObject *args)
232 {
233     char *name;
234 
235     if (!PyArg_ParseTuple(args, "s:parasite_find", &name))
236 	return NULL;
237 
238     return pygimp_parasite_new(gimp_item_get_parasite(self->ID, name));
239 }
240 
241 static PyObject *
drw_parasite_attach(PyGimpDrawable * self,PyObject * args)242 drw_parasite_attach(PyGimpDrawable *self, PyObject *args)
243 {
244     PyGimpParasite *parasite;
245 
246     if (!PyArg_ParseTuple(args, "O!:parasite_attach", &PyGimpParasite_Type,
247 			  &parasite))
248 	return NULL;
249 
250     if (!gimp_item_attach_parasite(self->ID, parasite->para)) {
251 	PyErr_Format(pygimp_error,
252 		     "could not attach parasite '%s' on drawable (ID %d)",
253 		     gimp_parasite_name(parasite->para), self->ID);
254 	return NULL;
255     }
256 
257     Py_INCREF(Py_None);
258     return Py_None;
259 }
260 
261 static PyObject *
drw_attach_new_parasite(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)262 drw_attach_new_parasite(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
263 {
264     char         *name;
265     int           flags, size;
266     guint8       *data;
267     GimpParasite *parasite;
268     gboolean      success;
269 
270     static char *kwlist[] = { "name", "flags", "data", NULL };
271 
272     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
273 				     "sis#:attach_new_parasite", kwlist,
274 				     &name, &flags, &data, &size))
275 	return NULL;
276 
277     parasite = gimp_parasite_new (name,
278                                   flags, size + 1, data);
279     success = gimp_item_attach_parasite (self->ID, parasite);
280     gimp_parasite_free (parasite);
281 
282     if (!success) {
283 	PyErr_Format(pygimp_error,
284 		     "could not attach new parasite '%s' to drawable (ID %d)",
285 		     name, self->ID);
286 	return NULL;
287     }
288 
289     Py_INCREF(Py_None);
290     return Py_None;
291 }
292 
293 static PyObject *
drw_parasite_detach(PyGimpDrawable * self,PyObject * args)294 drw_parasite_detach(PyGimpDrawable *self, PyObject *args)
295 {
296     char *name;
297     if (!PyArg_ParseTuple(args, "s:detach_parasite", &name))
298 	return NULL;
299 
300     if (!gimp_item_detach_parasite(self->ID, name)) {
301 	PyErr_Format(pygimp_error,
302 		     "could not detach parasite '%s' from drawable (ID %d)",
303 		     name, self->ID);
304 	return NULL;
305     }
306 
307     Py_INCREF(Py_None);
308     return Py_None;
309 }
310 
311 static PyObject *
drw_parasite_list(PyGimpDrawable * self)312 drw_parasite_list(PyGimpDrawable *self)
313 {
314     gint num_parasites;
315     gchar **parasites;
316     PyObject *ret;
317     gint i;
318 
319     parasites = gimp_item_get_parasite_list(self->ID, &num_parasites);
320 
321     ret = PyTuple_New(num_parasites);
322 
323     for (i = 0; i < num_parasites; i++)
324         PyTuple_SetItem(ret, i, PyString_FromString(parasites[i]));
325 
326     g_strfreev(parasites);
327     return ret;
328 }
329 
330 static PyObject *
drw_get_pixel(PyGimpDrawable * self,PyObject * args)331 drw_get_pixel(PyGimpDrawable *self, PyObject *args)
332 {
333     int x, y;
334     int num_channels, i;
335     guint8 *pixel;
336     PyObject *ret;
337 
338     if (!PyArg_ParseTuple(args, "(ii):get_pixel", &x, &y)) {
339 	PyErr_Clear();
340 	if (!PyArg_ParseTuple(args, "ii:get_pixel", &x, &y))
341 	    return NULL;
342     }
343 
344     pixel = gimp_drawable_get_pixel(self->ID, x, y, &num_channels);
345 
346     if (!pixel) {
347 	PyErr_Format(pygimp_error,
348 		     "could not get pixel (%d, %d) on drawable (ID %d)",
349 		     x, y, self->ID);
350 	return NULL;
351     }
352 
353     ret = PyTuple_New(num_channels);
354 
355     for (i = 0; i < num_channels; i++)
356 	PyTuple_SetItem(ret, i, PyInt_FromLong(pixel[i]));
357 
358     g_free(pixel);
359 
360     return ret;
361 }
362 
363 static PyObject *
drw_set_pixel(PyGimpDrawable * self,PyObject * args)364 drw_set_pixel(PyGimpDrawable *self, PyObject *args)
365 {
366     int x, y;
367     int num_channels, i, val;
368     guint8 *pixel;
369     PyObject *seq, *item;
370     gboolean is_string, error = TRUE;
371 
372     if (!PyArg_ParseTuple(args, "(ii)O:set_pixel", &x, &y, &seq)) {
373 	PyErr_Clear();
374 	if (!PyArg_ParseTuple(args, "iiO:set_pixel", &x, &y, &seq))
375 	    return NULL;
376     }
377 
378     if (!PyString_Check(seq)) {
379 	if (!PySequence_Check(seq)) {
380 	    PyErr_SetString(PyExc_TypeError,
381 			    "pixel values must be a sequence");
382 	    return NULL;
383 	}
384 
385 	is_string = FALSE;
386 
387 	num_channels = PySequence_Length(seq);
388 	pixel = g_new(guint8, num_channels);
389 
390 	for (i = 0; i < num_channels; i++) {
391 	    item = PySequence_GetItem(seq, i);
392 
393 	    if (!PyInt_Check(item)) {
394 		PyErr_SetString(PyExc_TypeError,
395 				"pixel values must be a sequence of ints");
396 		goto out;
397 	    }
398 
399 	    val = PyInt_AsLong(item);
400 
401 	    if (val < 0 || val > 255) {
402 		PyErr_SetString(PyExc_TypeError,
403 				"pixel values must be between 0 and 255");
404 		goto out;
405 	    }
406 
407 	    pixel[i] = val;
408 	}
409     } else {
410 	is_string = TRUE;
411 
412 	num_channels = PyString_Size(seq);
413 	pixel = (guint8 *)PyString_AsString(seq);
414     }
415 
416     error = !gimp_drawable_set_pixel(self->ID, x, y, num_channels, pixel);
417 
418     if (error)
419 	PyErr_Format(pygimp_error,
420 		     "could not set %d-element pixel (%d, %d) on "
421 		     "drawable (ID %d)",
422 		     num_channels, x, y, self->ID);
423 
424 out:
425     if (!is_string)
426 	g_free(pixel);
427 
428     if (!error) {
429 	Py_INCREF(Py_None);
430 	return Py_None;
431     } else
432 	return NULL;
433 }
434 
435 static PyObject *
drw_mask_intersect(PyGimpDrawable * self)436 drw_mask_intersect(PyGimpDrawable *self)
437 {
438     int x, y, width, height;
439 
440     if (!gimp_drawable_mask_intersect(self->ID, &x, &y, &width, &height)) {
441 	PyErr_Format(pygimp_error,
442 		     "could not get selection bounds of drawable (ID %d)",
443 		     self->ID);
444 	return NULL;
445     }
446 
447     return Py_BuildValue("(iiii)", x, y, width, height);
448 }
449 
450 static PyObject *
transform_result(PyGimpDrawable * self,gint32 id,const char * err_desc)451 transform_result(PyGimpDrawable *self, gint32 id, const char *err_desc)
452 {
453     if (id == self->ID) {
454 	Py_INCREF(self);
455 	return (PyObject *)self;
456     } else if (id != -1) {
457 	return pygimp_drawable_new(NULL, id);
458     } else {
459 	PyErr_Format(pygimp_error, "could not %s drawable (ID %d)",
460 		     err_desc, self->ID);
461 	return NULL;
462     }
463 }
464 
465 static PyObject *
drw_transform_flip(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)466 drw_transform_flip(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
467 {
468     double x0, y0, x1, y1;
469     int transform_direction, interpolation, recursion_level = 3;
470     gboolean supersample = FALSE, clip_result = FALSE;
471     gint32 id;
472 
473     static char *kwlist[] = { "x0", "y0", "x1", "y1",
474 			      "transform_direction", "interpolation",
475 			      "supersample", "recursion_level",
476 			      "clip_result", NULL };
477 
478     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
479 				     "ddddii|iii:transform_flip", kwlist,
480 				     &x0, &y0, &x1, &y1, &transform_direction,
481 				     &interpolation, &supersample,
482 				     &recursion_level, &clip_result))
483 	return NULL;
484 
485     gimp_context_push ();
486     gimp_context_set_transform_direction (transform_direction);
487     gimp_context_set_interpolation (interpolation);
488     gimp_context_set_transform_resize (clip_result);
489 
490     id = gimp_item_transform_flip (self->ID, x0, y0, x1, y1);
491 
492     gimp_context_pop ();
493 
494     return transform_result(self, id, "flip");
495 }
496 
497 static PyObject *
drw_transform_flip_simple(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)498 drw_transform_flip_simple(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
499 {
500     int flip_type;
501     gboolean auto_center, clip_result = FALSE;
502     double axis;
503     gint32 id;
504 
505     static char *kwlist[] = { "flip_type", "auto_center", "axis",
506 			      "clip_result", NULL };
507 
508     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
509 				     "iid|i:transform_flip_simple", kwlist,
510 				     &flip_type, &auto_center, &axis,
511 				     &clip_result))
512 	return NULL;
513 
514     gimp_context_push ();
515     gimp_context_set_transform_resize (clip_result);
516 
517     id = gimp_item_transform_flip_simple (self->ID, flip_type,
518                                           auto_center, axis);
519 
520     gimp_context_pop ();
521 
522     return transform_result(self, id, "flip");
523 }
524 
525 static PyObject *
drw_transform_flip_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)526 drw_transform_flip_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
527 {
528     double x0, y0, x1, y1;
529     gboolean interpolate = FALSE, clip_result = FALSE;
530     gint32 id;
531 
532     static char *kwlist[] = { "x0", "y0", "x1", "y1", "interpolate",
533 			      "clip_result", NULL };
534 
535     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
536 				     "dddd|ii:transform_flip_default", kwlist,
537 				     &x0, &y0, &x1, &y1, &interpolate,
538 				     &clip_result))
539 	return NULL;
540 
541     gimp_context_push ();
542     if (! interpolate)
543         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
544     gimp_context_set_transform_resize (clip_result);
545 
546     id = gimp_item_transform_flip (self->ID, x0, y0, x1, y1);
547 
548     gimp_context_pop ();
549 
550     return transform_result(self, id, "flip");
551 }
552 
553 static PyObject *
drw_transform_perspective(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)554 drw_transform_perspective(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
555 {
556     double x0, y0, x1, y1, x2, y2, x3, y3;
557     int transform_direction, interpolation, recursion_level = 3;
558     gboolean supersample = FALSE, clip_result = FALSE;
559     gint32 id;
560 
561     static char *kwlist[] = { "x0", "y0", "x1", "y1", "x2", "y2", "x3", "y3",
562 			      "transform_direction", "interpolation",
563 			      "supersample", "recursion_level",
564 			      "clip_result", NULL };
565 
566     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
567 				     "ddddddddii|iii:transform_perspective",
568 				     kwlist,
569 				     &x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3,
570 				     &transform_direction, &interpolation,
571 				     &supersample, &recursion_level,
572 				     &clip_result))
573 	return NULL;
574 
575     gimp_context_push ();
576     gimp_context_set_transform_direction (transform_direction);
577     gimp_context_set_interpolation (interpolation);
578     gimp_context_set_transform_resize (clip_result);
579 
580     id = gimp_item_transform_perspective (self->ID,
581                                           x0, y0, x1, y1, x2, y2, x3, y3);
582 
583     gimp_context_pop ();
584 
585     return transform_result(self, id, "apply perspective transform to");
586 }
587 
588 static PyObject *
drw_transform_perspective_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)589 drw_transform_perspective_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
590 {
591     double x0, y0, x1, y1, x2, y2, x3, y3;
592     gboolean interpolate = FALSE, clip_result = FALSE;
593     gint32 id;
594 
595     static char *kwlist[] = { "x0", "y0", "x1", "y1", "x2", "y2", "x3", "y3",
596 			      "interpolate", "clip_result", NULL };
597 
598     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
599 				     "dddddddd|ii:transform_perspective_default",
600 				     kwlist,
601 				     &x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3,
602 				     &interpolate, &clip_result))
603 	return NULL;
604 
605     gimp_context_push ();
606     if (! interpolate)
607         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
608     gimp_context_set_transform_resize (clip_result);
609 
610     id = gimp_item_transform_perspective (self->ID,
611                                           x0, y0, x1, y1, x2, y2, x3, y3);
612 
613     gimp_context_pop ();
614 
615     return transform_result(self, id, "apply perspective transform to");
616 }
617 
618 static PyObject *
drw_transform_rotate(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)619 drw_transform_rotate(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
620 {
621     double angle;
622     gboolean auto_center, supersample = FALSE, clip_result = FALSE;
623     int center_x, center_y, transform_direction, interpolation,
624 	recursion_level = 3;
625     gint32 id;
626 
627     static char *kwlist[] = { "angle", "auto_center", "center_x", "center_y",
628 			      "transform_direction", "interpolation",
629 			      "supersample", "recursion_level",
630 			      "clip_result", NULL };
631 
632     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
633 				     "diiiii|iii:transform_rotate", kwlist,
634 				     &angle, &auto_center, &center_x, &center_y,
635 				     &transform_direction, &interpolation,
636 				     &supersample, &recursion_level,
637 				     &clip_result))
638 	return NULL;
639 
640     gimp_context_push ();
641     gimp_context_set_transform_direction (transform_direction);
642     gimp_context_set_interpolation (interpolation);
643     gimp_context_set_transform_resize (clip_result);
644 
645     id = gimp_item_transform_rotate (self->ID, angle, auto_center,
646                                      center_x, center_y);
647 
648     gimp_context_pop ();
649 
650     return transform_result(self, id, "rotate");
651 }
652 
653 static PyObject *
drw_transform_rotate_simple(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)654 drw_transform_rotate_simple(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
655 {
656     int rotate_type, center_x, center_y;
657     gboolean auto_center, clip_result = FALSE;
658     gint32 id;
659 
660     static char *kwlist[] = { "rotate_type", "auto_center",
661 			      "center_x", "center_y",
662 			      "clip_result", NULL };
663 
664     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
665 				     "iiii|i:transform_rotate_simple", kwlist,
666 				     &rotate_type, &auto_center,
667 				     &center_x, &center_y,
668 				     &clip_result))
669 	return NULL;
670 
671     gimp_context_push ();
672     gimp_context_set_transform_resize (clip_result);
673 
674    id = gimp_item_transform_rotate_simple (self->ID, rotate_type,
675                                            auto_center,
676                                            center_x, center_y);
677 
678     gimp_context_pop ();
679 
680     return transform_result(self, id, "rotate");
681 }
682 
683 static PyObject *
drw_transform_rotate_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)684 drw_transform_rotate_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
685 {
686     double angle;
687     gboolean auto_center, interpolate = FALSE, clip_result = FALSE;
688     int center_x, center_y;
689     gint32 id;
690 
691     static char *kwlist[] = { "angle", "auto_center", "center_x", "center_y",
692 			      "interpolate", "clip_result", NULL };
693 
694     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
695 				     "dddd|ii:transform_rotate_default", kwlist,
696 				     &angle, &auto_center, &center_x, &center_y,
697 				     &interpolate, &clip_result))
698 	return NULL;
699 
700     gimp_context_push ();
701     if (! interpolate)
702         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
703     gimp_context_set_transform_resize (clip_result);
704 
705     id = gimp_item_transform_rotate (self->ID, angle, auto_center,
706                                      center_x, center_y);
707 
708     gimp_context_pop ();
709 
710     return transform_result(self, id, "rotate");
711 }
712 
713 static PyObject *
drw_transform_scale(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)714 drw_transform_scale(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
715 {
716     double x0, y0, x1, y1;
717     int transform_direction, interpolation, recursion_level = 3;
718     gboolean supersample = FALSE, clip_result = FALSE;
719     gint32 id;
720 
721     static char *kwlist[] = { "x0", "y0", "x1", "y1",
722 			      "transform_direction", "interpolation",
723 			      "supersample", "recursion_level",
724 			      "clip_result", NULL };
725 
726     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
727 				     "ddddii|iii:transform_scale", kwlist,
728 				     &x0, &y0, &x1, &y1, &transform_direction,
729 				     &interpolation, &supersample,
730 				     &recursion_level, &clip_result))
731 	return NULL;
732 
733     gimp_context_push ();
734     gimp_context_set_transform_direction (transform_direction);
735     gimp_context_set_interpolation (interpolation);
736     gimp_context_set_transform_resize (clip_result);
737 
738     id = gimp_item_transform_scale (self->ID, x0, y0, x1, y1);
739 
740     gimp_context_pop ();
741 
742     return transform_result(self, id, "scale");
743 }
744 
745 static PyObject *
drw_transform_scale_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)746 drw_transform_scale_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
747 {
748     double x0, y0, x1, y1;
749     gboolean interpolate = FALSE, clip_result = FALSE;
750     gint32 id;
751 
752     static char *kwlist[] = { "x0", "y0", "x1", "y1", "interpolate",
753 			      "clip_result", NULL };
754 
755     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
756 				     "dddd|ii:transform_scale_default", kwlist,
757 				     &x0, &y0, &x1, &y1, &interpolate,
758 				     &clip_result))
759 	return NULL;
760 
761     gimp_context_push ();
762     if (! interpolate)
763         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
764     gimp_context_set_transform_resize (clip_result);
765 
766     id = gimp_item_transform_scale (self->ID, x0, y0, x1, y1);
767 
768     gimp_context_pop ();
769 
770     return transform_result(self, id, "scale");
771 }
772 
773 static PyObject *
drw_transform_shear(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)774 drw_transform_shear(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
775 {
776     int shear_type, transform_direction, interpolation, recursion_level = 3;
777     double magnitude;
778     gboolean supersample = FALSE, clip_result = FALSE;
779     gint32 id;
780 
781     static char *kwlist[] = { "shear_type", "magnitude",
782 			      "transform_direction", "interpolation",
783 			      "supersample", "recursion_level",
784 			      "clip_result", NULL };
785 
786     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
787 				     "idii|iii:transform_shear", kwlist,
788 				     &shear_type, &magnitude,
789 				     &transform_direction, &interpolation,
790 				     &supersample, &recursion_level,
791 				     &clip_result))
792 	return NULL;
793 
794     gimp_context_push ();
795     gimp_context_set_transform_direction (transform_direction);
796     gimp_context_set_interpolation (interpolation);
797     gimp_context_set_transform_resize (clip_result);
798 
799     id = gimp_item_transform_shear (self->ID, shear_type, magnitude);
800 
801     gimp_context_pop ();
802 
803     return transform_result(self, id, "shear");
804 }
805 
806 static PyObject *
drw_transform_shear_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)807 drw_transform_shear_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
808 {
809     int shear_type;
810     double magnitude;
811     gboolean interpolate = FALSE, clip_result = FALSE;
812     gint32 id;
813 
814     static char *kwlist[] = { "shear_type", "magnitude", "interpolate",
815 			      "clip_result", NULL };
816 
817     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
818 				     "id|ii:transform_shear_default", kwlist,
819 				     &shear_type, &magnitude, &interpolate,
820 				     &clip_result))
821 	return NULL;
822 
823     gimp_context_push ();
824     if (! interpolate)
825         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
826     gimp_context_set_transform_resize (clip_result);
827 
828     id = gimp_item_transform_shear (self->ID, shear_type, magnitude);
829 
830     gimp_context_pop ();
831 
832     return transform_result(self, id, "shear");
833 }
834 
835 static PyObject *
drw_transform_2d(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)836 drw_transform_2d(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
837 {
838     double source_x, source_y, scale_x, scale_y, angle, dest_x, dest_y;
839     int transform_direction, interpolation, recursion_level = 3;
840     gboolean supersample = FALSE, clip_result = FALSE;
841     gint32 id;
842 
843     static char *kwlist[] = { "source_x", "source_y", "scale_x", "scale_y",
844 			      "angle", "dest_x", "dest_y",
845 			      "transform_direction", "interpolation",
846 			      "supersample", "recursion_level",
847 			      "clip_result", NULL };
848 
849     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
850 				     "dddddddii|iii:transform_2d", kwlist,
851 				     &source_x, &source_y, &scale_x, &scale_y,
852 				     &angle, &dest_x, &dest_y,
853 				     &transform_direction, &interpolation,
854 				     &supersample, &recursion_level,
855 				     &clip_result))
856 	return NULL;
857 
858     gimp_context_push ();
859     gimp_context_set_transform_direction (transform_direction);
860     gimp_context_set_interpolation (interpolation);
861     gimp_context_set_transform_resize (clip_result);
862 
863     id = gimp_item_transform_2d (self->ID, source_x, source_y,
864                                  scale_x, scale_y, angle, dest_x, dest_y);
865 
866     gimp_context_pop ();
867 
868     return transform_result(self, id, "apply 2d transform to");
869 }
870 
871 static PyObject *
drw_transform_2d_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)872 drw_transform_2d_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
873 {
874     double source_x, source_y, scale_x, scale_y, angle, dest_x, dest_y;
875     gboolean interpolate = FALSE, clip_result = FALSE;
876     gint32 id;
877 
878     static char *kwlist[] = { "source_x", "source_y", "scale_x", "scale_y",
879 			      "angle", "dest_x", "dest_y", "interpolate",
880 			      "clip_result", NULL };
881 
882     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
883 				     "ddddddd|ii:transform_2d_default", kwlist,
884 				     &source_x, &source_y, &scale_x, &scale_y,
885 				     &angle, &dest_x, &dest_y, &interpolate,
886 				     &clip_result))
887 	return NULL;
888 
889     gimp_context_push ();
890     if (! interpolate)
891         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
892     gimp_context_set_transform_resize (clip_result);
893 
894     id = gimp_item_transform_2d (self->ID, source_x, source_y,
895                                  scale_x, scale_y, angle, dest_x, dest_y);
896 
897     gimp_context_pop ();
898 
899     return transform_result(self, id, "apply 2d transform to");
900 }
901 
902 static PyObject *
drw_transform_matrix(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)903 drw_transform_matrix(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
904 {
905     double coeff_0_0, coeff_0_1, coeff_0_2,
906 	   coeff_1_0, coeff_1_1, coeff_1_2,
907 	   coeff_2_0, coeff_2_1, coeff_2_2;
908     int transform_direction, interpolation, recursion_level = 3;
909     gboolean supersample = FALSE, clip_result = FALSE;
910     gint32 id;
911 
912     static char *kwlist[] = { "coeff_0_0", "coeff_0_1", "coeff_0_2",
913 			      "coeff_1_0", "coeff_1_1", "coeff_1_2",
914 			      "coeff_2_0", "coeff_2_1", "coeff_2_2",
915 			      "transform_direction", "interpolation",
916 			      "supersample", "recursion_level",
917 			      "clip_result", NULL };
918 
919     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
920 				     "dddddddddii|iii:transform_matrix", kwlist,
921 				     &coeff_0_0, &coeff_0_1, &coeff_0_2,
922 				     &coeff_1_0, &coeff_1_1, &coeff_1_2,
923 				     &coeff_2_0, &coeff_2_1, &coeff_2_2,
924 				     &transform_direction, &interpolation,
925 				     &supersample, &recursion_level,
926 				     &clip_result))
927 	return NULL;
928 
929     gimp_context_push ();
930     gimp_context_set_transform_direction (transform_direction);
931     gimp_context_set_interpolation (interpolation);
932     gimp_context_set_transform_resize (clip_result);
933 
934     id = gimp_item_transform_matrix (self->ID,
935                                      coeff_0_0, coeff_0_1, coeff_0_2,
936                                      coeff_1_0, coeff_1_1, coeff_1_2,
937                                      coeff_2_0, coeff_2_1, coeff_2_2);
938 
939     gimp_context_pop ();
940 
941     return transform_result(self, id, "apply 2d matrix transform to");
942 }
943 
944 static PyObject *
drw_transform_matrix_default(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)945 drw_transform_matrix_default(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
946 {
947     double coeff_0_0, coeff_0_1, coeff_0_2,
948 	   coeff_1_0, coeff_1_1, coeff_1_2,
949 	   coeff_2_0, coeff_2_1, coeff_2_2;
950     gboolean interpolate = FALSE, clip_result = FALSE;
951     gint32 id;
952 
953     static char *kwlist[] = { "coeff_0_0", "coeff_0_1", "coeff_0_2",
954 			      "coeff_1_0", "coeff_1_1", "coeff_1_2",
955 			      "coeff_2_0", "coeff_2_1", "coeff_2_2",
956 			      "interpolate", "clip_result", NULL };
957 
958     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
959 				     "ddddddddd|ii:transform_matrix_default",
960 				     kwlist,
961 				     &coeff_0_0, &coeff_0_1, &coeff_0_2,
962 				     &coeff_1_0, &coeff_1_1, &coeff_1_2,
963 				     &coeff_2_0, &coeff_2_1, &coeff_2_2,
964 				     &interpolate, &clip_result))
965 	return NULL;
966 
967     gimp_context_push ();
968     if (! interpolate)
969         gimp_context_set_interpolation (GIMP_INTERPOLATION_NONE);
970     gimp_context_set_transform_resize (clip_result);
971 
972     id = gimp_item_transform_matrix (self->ID,
973                                      coeff_0_0, coeff_0_1, coeff_0_2,
974                                      coeff_1_0, coeff_1_1, coeff_1_2,
975                                      coeff_2_0, coeff_2_1, coeff_2_2);
976 
977     gimp_context_pop ();
978 
979     return transform_result(self, id, "apply 2d matrix transform to");
980 }
981 
982 static PyObject *
drw_get_data(PyGimpDrawable * self,PyObject * args,PyObject * kwargs)983 drw_get_data(PyGimpDrawable *self, PyObject *args, PyObject *kwargs)
984 {
985     static char *kwlist[] = { "format", NULL };
986     gchar  *format = "RGBA float";
987     const Babl *bbl_format;
988     void *output_buffer;
989     GeglBuffer *buffer;
990     int bpp;
991     Py_ssize_t size;
992     PyObject *buffer_data, *ret;
993     PyObject *array_module;
994     PyObject *array_type;
995     char array_data_type;
996 
997     if (!PyArg_ParseTupleAndKeywords (args, kwargs,
998                                       "|s:get_data",
999                                       kwlist, &format
1000                                       ))
1001         return NULL;
1002 
1003     if (g_str_has_suffix (format, "double")) {
1004         array_data_type = 'd';
1005     } else if (g_str_has_suffix (format, "float")) {
1006         array_data_type = 'f';
1007     }
1008      else if (g_str_has_suffix (format, "u16")) {
1009         array_data_type = 'H';
1010     } else if (g_str_has_suffix (format, "u8")) {
1011         array_data_type = 'B';
1012     } else {
1013         PyErr_Warn (PyExc_Warning,
1014             "Could not find appropriate data format - returning raw bytes");
1015         array_data_type = 'B';
1016     }
1017 
1018     bbl_format = babl_format (format);
1019     bpp = babl_format_get_bytes_per_pixel (bbl_format);
1020     ensure_drawable(self);
1021     buffer = gimp_drawable_get_buffer (self->ID);
1022     size = bpp * self->drawable->width * self->drawable->height;
1023     output_buffer = g_malloc ((gsize) size);
1024     if (output_buffer == NULL) {
1025         return PyErr_NoMemory();
1026     }
1027     gegl_buffer_get (buffer,
1028                      GEGL_RECTANGLE (0, 0, self->drawable->width, self->drawable->height),
1029                      1.0,
1030                      bbl_format,
1031                      output_buffer,
1032                      GEGL_AUTO_ROWSTRIDE,
1033                      GEGL_ABYSS_NONE);
1034     buffer_data = PyString_FromStringAndSize (output_buffer, size);
1035 
1036     array_module = PyImport_ImportModule ("array");
1037     if (!array_module) {
1038         PyErr_SetString (pygimp_error, "could not import array module");
1039         return NULL;
1040     }
1041 
1042     array_type = PyObject_GetAttrString (array_module, "array");
1043     Py_DECREF(array_module);
1044     if (!array_type) {
1045         PyErr_SetString (pygimp_error, "could not get array.array type");
1046         return NULL;
1047      }
1048 
1049     ret = PyObject_CallFunction (array_type, "cO", array_data_type, buffer_data);
1050     if (!ret) {
1051         PyErr_SetString (pygimp_error, "could not create array object");
1052         return NULL;
1053      }
1054 
1055     Py_DECREF (buffer_data);
1056     g_free (output_buffer);
1057 
1058     return ret;
1059 }
1060 
1061 
1062 /* for inclusion with the methods of layer and channel objects */
1063 static PyMethodDef drw_methods[] = {
1064     {"flush",	(PyCFunction)drw_flush,	METH_NOARGS},
1065     {"update",	(PyCFunction)drw_update,	METH_VARARGS},
1066     {"merge_shadow",	(PyCFunction)drw_merge_shadow,	METH_VARARGS | METH_KEYWORDS},
1067     {"free_shadow", (PyCFunction)drw_free_shadow, METH_NOARGS},
1068     {"fill",	(PyCFunction)drw_fill,	METH_VARARGS | METH_KEYWORDS},
1069     {"get_tile",	(PyCFunction)drw_get_tile,	METH_VARARGS | METH_KEYWORDS},
1070     {"get_tile2",	(PyCFunction)drw_get_tile2,	METH_VARARGS | METH_KEYWORDS},
1071     {"get_pixel_rgn", (PyCFunction)drw_get_pixel_rgn, METH_VARARGS | METH_KEYWORDS},
1072     {"get_data", (PyCFunction)drw_get_data, METH_VARARGS | METH_KEYWORDS,
1073      "Takes a BABL format string, returns a Python array.array object"},
1074     {"offset", (PyCFunction)drw_offset, METH_VARARGS | METH_KEYWORDS},
1075     {"parasite_find",       (PyCFunction)drw_parasite_find, METH_VARARGS},
1076     {"parasite_attach",     (PyCFunction)drw_parasite_attach, METH_VARARGS},
1077     {"attach_new_parasite",(PyCFunction)drw_attach_new_parasite,METH_VARARGS | METH_KEYWORDS},
1078     {"parasite_detach",     (PyCFunction)drw_parasite_detach, METH_VARARGS},
1079     {"parasite_list",     (PyCFunction)drw_parasite_list, METH_VARARGS},
1080     {"get_pixel",	(PyCFunction)drw_get_pixel, METH_VARARGS},
1081     {"set_pixel",	(PyCFunction)drw_set_pixel, METH_VARARGS},
1082     {"mask_intersect",	(PyCFunction)drw_mask_intersect, METH_NOARGS},
1083     {"transform_flip",	(PyCFunction)drw_transform_flip, METH_VARARGS | METH_KEYWORDS},
1084     {"transform_flip_simple",	(PyCFunction)drw_transform_flip_simple, METH_VARARGS | METH_KEYWORDS},
1085     {"transform_flip_default",	(PyCFunction)drw_transform_flip_default, METH_VARARGS | METH_KEYWORDS},
1086     {"transform_perspective",	(PyCFunction)drw_transform_perspective, METH_VARARGS | METH_KEYWORDS},
1087     {"transform_perspective_default",	(PyCFunction)drw_transform_perspective_default, METH_VARARGS | METH_KEYWORDS},
1088     {"transform_rotate",	(PyCFunction)drw_transform_rotate, METH_VARARGS | METH_KEYWORDS},
1089     {"transform_rotate_simple",	(PyCFunction)drw_transform_rotate_simple, METH_VARARGS | METH_KEYWORDS},
1090     {"transform_rotate_default",	(PyCFunction)drw_transform_rotate_default, METH_VARARGS | METH_KEYWORDS},
1091     {"transform_scale",	(PyCFunction)drw_transform_scale, METH_VARARGS | METH_KEYWORDS},
1092     {"transform_scale_default",	(PyCFunction)drw_transform_scale_default, METH_VARARGS | METH_KEYWORDS},
1093     {"transform_shear",	(PyCFunction)drw_transform_shear, METH_VARARGS | METH_KEYWORDS},
1094     {"transform_shear_default",	(PyCFunction)drw_transform_shear_default, METH_VARARGS | METH_KEYWORDS},
1095     {"transform_2d",	(PyCFunction)drw_transform_2d, METH_VARARGS | METH_KEYWORDS},
1096     {"transform_2d_default",	(PyCFunction)drw_transform_2d_default, METH_VARARGS | METH_KEYWORDS},
1097     {"transform_matrix",	(PyCFunction)drw_transform_matrix, METH_VARARGS | METH_KEYWORDS},
1098     {"transform_matrix_default",	(PyCFunction)drw_transform_matrix_default, METH_VARARGS | METH_KEYWORDS},
1099     {NULL, NULL, 0}
1100 };
1101 
1102 static PyObject *
drw_get_ID(PyGimpDrawable * self,void * closure)1103 drw_get_ID(PyGimpDrawable *self, void *closure)
1104 {
1105     return PyInt_FromLong(self->ID);
1106 }
1107 
1108 static PyObject *
drw_get_name(PyGimpDrawable * self,void * closure)1109 drw_get_name(PyGimpDrawable *self, void *closure)
1110 {
1111     return PyString_FromString(gimp_item_get_name(self->ID));
1112 }
1113 
1114 static int
drw_set_name(PyGimpDrawable * self,PyObject * value,void * closure)1115 drw_set_name(PyGimpDrawable *self, PyObject *value, void *closure)
1116 {
1117     if (value == NULL) {
1118         PyErr_SetString(PyExc_TypeError, "cannot delete name");
1119         return -1;
1120     }
1121 
1122     if (!PyString_Check(value) && !PyUnicode_Check(value)) {
1123         PyErr_SetString(PyExc_TypeError, "type mismatch");
1124         return -1;
1125     }
1126 
1127     gimp_item_set_name(self->ID, PyString_AsString(value));
1128 
1129     return 0;
1130 }
1131 
1132 static PyObject *
drw_get_bpp(PyGimpDrawable * self,void * closure)1133 drw_get_bpp(PyGimpDrawable *self, void *closure)
1134 {
1135     return PyInt_FromLong(gimp_drawable_bpp(self->ID));
1136 }
1137 
1138 static PyObject *
drw_get_has_alpha(PyGimpDrawable * self,void * closure)1139 drw_get_has_alpha(PyGimpDrawable *self, void *closure)
1140 {
1141     return PyBool_FromLong(gimp_drawable_has_alpha(self->ID));
1142 }
1143 
1144 static PyObject *
drw_get_height(PyGimpDrawable * self,void * closure)1145 drw_get_height(PyGimpDrawable *self, void *closure)
1146 {
1147     return PyInt_FromLong(gimp_drawable_height(self->ID));
1148 }
1149 
1150 static PyObject *
drw_get_image(PyGimpDrawable * self,void * closure)1151 drw_get_image(PyGimpDrawable *self, void *closure)
1152 {
1153     return pygimp_image_new(gimp_item_get_image(self->ID));
1154 }
1155 
1156 static PyObject *
drw_get_is_rgb(PyGimpDrawable * self,void * closure)1157 drw_get_is_rgb(PyGimpDrawable *self, void *closure)
1158 {
1159     return PyBool_FromLong(gimp_drawable_is_rgb(self->ID));
1160 }
1161 
1162 static PyObject *
drw_get_is_gray(PyGimpDrawable * self,void * closure)1163 drw_get_is_gray(PyGimpDrawable *self, void *closure)
1164 {
1165     return PyBool_FromLong(gimp_drawable_is_gray(self->ID));
1166 }
1167 
1168 static PyObject *
drw_get_is_indexed(PyGimpDrawable * self,void * closure)1169 drw_get_is_indexed(PyGimpDrawable *self, void *closure)
1170 {
1171     return PyBool_FromLong(gimp_drawable_is_indexed(self->ID));
1172 }
1173 
1174 static PyObject *
drw_get_is_layer_mask(PyGimpDrawable * self,void * closure)1175 drw_get_is_layer_mask(PyGimpDrawable *self, void *closure)
1176 {
1177     return PyBool_FromLong(gimp_item_is_layer_mask(self->ID));
1178 }
1179 
1180 static PyObject *
drw_get_mask_bounds(PyGimpDrawable * self,void * closure)1181 drw_get_mask_bounds(PyGimpDrawable *self, void *closure)
1182 {
1183     gint x1, y1, x2, y2;
1184 
1185     gimp_drawable_mask_bounds(self->ID, &x1, &y1, &x2, &y2);
1186     return Py_BuildValue("(iiii)", x1, y1, x2, y2);
1187 }
1188 
1189 static PyObject *
drw_get_mask_intersect(PyGimpDrawable * self,void * closure)1190 drw_get_mask_intersect(PyGimpDrawable *self, void *closure)
1191 {
1192     gint x, y, w, h;
1193 
1194     if(!gimp_drawable_mask_intersect(self->ID, &x, &y, &w, &h))
1195       return Py_BuildValue("");
1196     return Py_BuildValue("(iiii)", x, y, w, h);
1197 }
1198 
1199 static PyObject *
drw_get_offsets(PyGimpDrawable * self,void * closure)1200 drw_get_offsets(PyGimpDrawable *self, void *closure)
1201 {
1202     gint x, y;
1203 
1204     gimp_drawable_offsets(self->ID, &x, &y);
1205 
1206     return Py_BuildValue("(ii)", x, y);
1207 }
1208 
1209 static PyObject *
drw_get_type(PyGimpDrawable * self,void * closure)1210 drw_get_type(PyGimpDrawable *self, void *closure)
1211 {
1212     return PyInt_FromLong(gimp_drawable_type(self->ID));
1213 }
1214 
1215 static PyObject *
drw_get_type_with_alpha(PyGimpDrawable * self,void * closure)1216 drw_get_type_with_alpha(PyGimpDrawable *self, void *closure)
1217 {
1218     return PyInt_FromLong(gimp_drawable_type_with_alpha(self->ID));
1219 }
1220 
1221 static PyObject *
drw_get_width(PyGimpDrawable * self,void * closure)1222 drw_get_width(PyGimpDrawable *self, void *closure)
1223 {
1224     return PyInt_FromLong(gimp_drawable_width(self->ID));
1225 }
1226 
1227 static PyObject *
drw_get_linked(PyGimpDrawable * self,void * closure)1228 drw_get_linked(PyGimpDrawable *self, void *closure)
1229 {
1230     return PyBool_FromLong(gimp_item_get_linked(self->ID));
1231 }
1232 
1233 static int
drw_set_linked(PyGimpDrawable * self,PyObject * value,void * closure)1234 drw_set_linked(PyGimpDrawable *self, PyObject *value, void *closure)
1235 {
1236     if (value == NULL) {
1237         PyErr_SetString(PyExc_TypeError, "cannot delete linked");
1238         return -1;
1239     }
1240 
1241     if (!PyInt_Check(value)) {
1242 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1243 	return -1;
1244     }
1245 
1246     gimp_item_set_linked(self->ID, PyInt_AsLong(value));
1247 
1248     return 0;
1249 }
1250 
1251 static PyObject *
drw_get_tattoo(PyGimpDrawable * self,void * closure)1252 drw_get_tattoo(PyGimpDrawable *self, void *closure)
1253 {
1254     return PyInt_FromLong(gimp_item_get_tattoo(self->ID));
1255 }
1256 
1257 static int
drw_set_tattoo(PyGimpDrawable * self,PyObject * value,void * closure)1258 drw_set_tattoo(PyGimpDrawable *self, PyObject *value, void *closure)
1259 {
1260     if (value == NULL) {
1261         PyErr_SetString(PyExc_TypeError, "cannot delete tattoo");
1262         return -1;
1263     }
1264 
1265     if (!PyInt_Check(value)) {
1266         PyErr_SetString(PyExc_TypeError, "type mismatch");
1267         return -1;
1268     }
1269 
1270     gimp_item_set_tattoo(self->ID, PyInt_AsLong(value));
1271 
1272     return 0;
1273 }
1274 
1275 static PyObject *
drw_get_visible(PyGimpDrawable * self,void * closure)1276 drw_get_visible(PyGimpDrawable *self, void *closure)
1277 {
1278     return PyBool_FromLong(gimp_item_get_visible(self->ID));
1279 }
1280 
1281 static int
drw_set_visible(PyGimpDrawable * self,PyObject * value,void * closure)1282 drw_set_visible(PyGimpDrawable *self, PyObject *value, void *closure)
1283 {
1284     if (value == NULL) {
1285         PyErr_SetString(PyExc_TypeError, "cannot delete visible");
1286         return -1;
1287     }
1288 
1289     if (!PyInt_Check(value)) {
1290         PyErr_SetString(PyExc_TypeError, "type mismatch");
1291         return -1;
1292     }
1293 
1294     gimp_item_set_visible(self->ID, PyInt_AsLong(value));
1295 
1296     return 0;
1297 }
1298 
1299 static  PyGetSetDef drw_getsets[] = {
1300     { "ID", (getter)drw_get_ID, (setter)0 },
1301     { "name", (getter)drw_get_name, (setter)drw_set_name },
1302     { "bpp", (getter)drw_get_bpp, (setter)0 },
1303     { "has_alpha", (getter)drw_get_has_alpha, (setter)0 },
1304     { "height", (getter)drw_get_height, (setter)0 },
1305     { "image", (getter)drw_get_image, (setter)0 },
1306     { "is_rgb", (getter)drw_get_is_rgb, (setter)0 },
1307     { "is_gray", (getter)drw_get_is_gray, (setter)0 },
1308     { "is_grey", (getter)drw_get_is_gray, (setter)0 },
1309     { "is_indexed", (getter)drw_get_is_indexed, (setter)0 },
1310     { "is_layer_mask", (getter)drw_get_is_layer_mask, (setter)0 },
1311     { "mask_bounds", (getter)drw_get_mask_bounds, (setter)0 },
1312     { "mask_intersect", (getter)drw_get_mask_intersect, (setter)0 },
1313     { "offsets", (getter)drw_get_offsets, (setter)0 },
1314     { "type", (getter)drw_get_type, (setter)0 },
1315     { "type_with_alpha", (getter)drw_get_type_with_alpha, (setter)0 },
1316     { "width", (getter)drw_get_width, (setter)0 },
1317     { "linked", (getter)drw_get_linked, (setter)drw_set_linked },
1318     { "tattoo", (getter)drw_get_tattoo, (setter)drw_set_tattoo },
1319     { "visible", (getter)drw_get_visible, (setter)drw_set_visible },
1320     { NULL, (getter)0, (setter)0 }
1321 };
1322 
1323 static void
drw_dealloc(PyGimpDrawable * self)1324 drw_dealloc(PyGimpDrawable *self)
1325 {
1326     if (self->drawable)
1327 	gimp_drawable_detach(self->drawable);
1328 
1329     PyObject_DEL(self);
1330 }
1331 
1332 static PyObject *
drw_repr(PyGimpDrawable * self)1333 drw_repr(PyGimpDrawable *self)
1334 {
1335     PyObject *s;
1336     gchar *name;
1337 
1338     name = gimp_item_get_name(self->ID);
1339     s = PyString_FromFormat("<gimp.Drawable '%s'>", name ? name : "(null)");
1340     g_free(name);
1341 
1342     return s;
1343 }
1344 
1345 static int
drw_cmp(PyGimpDrawable * self,PyGimpDrawable * other)1346 drw_cmp(PyGimpDrawable *self, PyGimpDrawable *other)
1347 {
1348     if (self->ID == other->ID)
1349 	return 0;
1350     if (self->ID > other->ID)
1351 	return -1;
1352     return 1;
1353 }
1354 
1355 PyTypeObject PyGimpDrawable_Type = {
1356     PyObject_HEAD_INIT(NULL)
1357     0,                                  /* ob_size */
1358     "gimp.Drawable",                    /* tp_name */
1359     sizeof(PyGimpDrawable),             /* tp_basicsize */
1360     0,                                  /* tp_itemsize */
1361     /* methods */
1362     (destructor)drw_dealloc,            /* tp_dealloc */
1363     (printfunc)0,                       /* tp_print */
1364     (getattrfunc)0,                     /* tp_getattr */
1365     (setattrfunc)0,                     /* tp_setattr */
1366     (cmpfunc)drw_cmp,                   /* tp_compare */
1367     (reprfunc)drw_repr,                 /* tp_repr */
1368     0,                                  /* tp_as_number */
1369     0,                                  /* tp_as_sequence */
1370     0,                                  /* tp_as_mapping */
1371     (hashfunc)0,                        /* tp_hash */
1372     (ternaryfunc)0,                     /* tp_call */
1373     (reprfunc)0,                        /* tp_str */
1374     (getattrofunc)0,                    /* tp_getattro */
1375     (setattrofunc)0,                    /* tp_setattro */
1376     0,					/* tp_as_buffer */
1377     Py_TPFLAGS_DEFAULT,	                /* tp_flags */
1378     NULL, /* Documentation string */
1379     (traverseproc)0,			/* tp_traverse */
1380     (inquiry)0,				/* tp_clear */
1381     (richcmpfunc)0,			/* tp_richcompare */
1382     0,					/* tp_weaklistoffset */
1383     (getiterfunc)0,			/* tp_iter */
1384     (iternextfunc)0,			/* tp_iternext */
1385     drw_methods,			/* tp_methods */
1386     0,					/* tp_members */
1387     drw_getsets,			/* tp_getset */
1388     &PyGimpItem_Type,			/* tp_base */
1389     (PyObject *)0,			/* tp_dict */
1390     0,					/* tp_descr_get */
1391     0,					/* tp_descr_set */
1392     0,					/* tp_dictoffset */
1393     (initproc)0,                        /* tp_init */
1394     (allocfunc)0,			/* tp_alloc */
1395     (newfunc)0,				/* tp_new */
1396 };
1397 
1398 
1399 PyObject *
pygimp_drawable_new(GimpDrawable * drawable,gint32 ID)1400 pygimp_drawable_new(GimpDrawable *drawable, gint32 ID)
1401 {
1402     PyObject *self;
1403 
1404     if (drawable != NULL)
1405     ID = drawable->drawable_id;
1406 
1407     if (!gimp_item_is_valid(ID)) {
1408 	Py_INCREF(Py_None);
1409 	return Py_None;
1410     }
1411 
1412     /* create the appropriate object type */
1413     if (gimp_item_is_layer(ID))
1414 	self = pygimp_layer_new(ID);
1415     else
1416 	self = pygimp_channel_new(ID);
1417 
1418     if (self == NULL)
1419 	return NULL;
1420 
1421     if (PyObject_TypeCheck(self, &PyGimpDrawable_Type))
1422     ((PyGimpDrawable *)self)->drawable = drawable;
1423 
1424     return self;
1425 }
1426 
1427 /* End of code for Drawable objects */
1428 /* -------------------------------------------------------- */
1429 
1430 
1431 static PyObject *
lay_copy(PyGimpLayer * self,PyObject * args,PyObject * kwargs)1432 lay_copy(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
1433 {
1434     int nreturn_vals;
1435     GimpParam *return_vals;
1436     gboolean add_alpha = FALSE;
1437     gint32 id = -1;
1438 
1439     static char *kwlist[] = { "add_alpha", NULL };
1440 
1441     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:copy", kwlist,
1442 				     &add_alpha))
1443 	return NULL;
1444 
1445     return_vals = gimp_run_procedure("gimp-layer-copy",
1446 				     &nreturn_vals,
1447 				     GIMP_PDB_LAYER, self->ID,
1448 				     GIMP_PDB_INT32, add_alpha,
1449 				     GIMP_PDB_END);
1450 
1451     if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
1452 	id = return_vals[1].data.d_layer;
1453     else
1454 	PyErr_Format(pygimp_error,
1455 		     "could not create new layer copy from layer (ID %d)",
1456 		     self->ID);
1457 
1458     gimp_destroy_params(return_vals, nreturn_vals);
1459 
1460     return id != -1 ? pygimp_layer_new(id) : NULL;
1461 }
1462 
1463 
1464 static PyObject *
lay_add_alpha(PyGimpLayer * self)1465 lay_add_alpha(PyGimpLayer *self)
1466 {
1467     if (!gimp_layer_add_alpha(self->ID)) {
1468 	PyErr_Format(pygimp_error, "could not add alpha to layer (ID %d)",
1469 		     self->ID);
1470 	return NULL;
1471     }
1472 
1473     Py_INCREF(Py_None);
1474     return Py_None;
1475 }
1476 
1477 
1478 static PyObject *
lay_add_mask(PyGimpLayer * self,PyObject * args)1479 lay_add_mask(PyGimpLayer *self, PyObject *args)
1480 {
1481     PyGimpChannel *mask;
1482 
1483     if (!PyArg_ParseTuple(args, "O!:add_mask", &PyGimpChannel_Type, &mask))
1484 	return NULL;
1485 
1486     if (!gimp_layer_add_mask(self->ID, mask->ID)) {
1487 	PyErr_Format(pygimp_error,
1488 		     "could not add mask (ID %d) to layer (ID %d)",
1489 		     mask->ID, self->ID);
1490 	return NULL;
1491     }
1492 
1493     Py_INCREF(Py_None);
1494     return Py_None;
1495 }
1496 
1497 static PyObject *
lay_create_mask(PyGimpLayer * self,PyObject * args)1498 lay_create_mask(PyGimpLayer *self, PyObject *args)
1499 {
1500     int type;
1501     gint32 id;
1502 
1503     if (!PyArg_ParseTuple(args, "i:create_mask", &type))
1504 	return NULL;
1505 
1506     id = gimp_layer_create_mask(self->ID, type);
1507 
1508     if (id == -1) {
1509 	PyErr_Format(pygimp_error,
1510 		     "could not create mask of type %d on layer (ID %d)",
1511 		     type, self->ID);
1512 	return NULL;
1513     }
1514 
1515     return pygimp_channel_new(id);
1516 }
1517 
1518 static PyObject *
lay_remove_mask(PyGimpLayer * self,PyObject * args)1519 lay_remove_mask(PyGimpLayer *self, PyObject *args)
1520 {
1521     int mode;
1522 
1523     if (!PyArg_ParseTuple(args, "i:remove_mask", &mode))
1524 	return NULL;
1525 
1526     if (!gimp_layer_remove_mask(self->ID, mode)) {
1527 	PyErr_Format(pygimp_error,
1528 		     "could not remove mask from layer (ID %d) with mode %d",
1529 		      self->ID, mode);
1530 	return NULL;
1531     }
1532 
1533     Py_INCREF(Py_None);
1534     return Py_None;
1535 }
1536 
1537 
1538 static PyObject *
lay_resize(PyGimpLayer * self,PyObject * args,PyObject * kwargs)1539 lay_resize(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
1540 {
1541     unsigned int new_h, new_w;
1542     int offs_x = 0, offs_y = 0;
1543 
1544     static char *kwlist[] = { "width", "height", "offset_x", "offset_y", NULL };
1545 
1546     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:resize", kwlist,
1547 				     &new_w, &new_h, &offs_x, &offs_y))
1548 	return NULL;
1549 
1550     if (!gimp_layer_resize(self->ID, new_w, new_h, offs_x, offs_y)) {
1551 	PyErr_Format(pygimp_error,
1552 		     "could not resize layer (ID %d) to size %dx%d "
1553 		     "(offset %d, %d)",
1554 		     self->ID, new_w, new_h, offs_x, offs_y);
1555 	return NULL;
1556     }
1557 
1558     Py_INCREF(Py_None);
1559     return Py_None;
1560 }
1561 
1562 static PyObject *
lay_resize_to_image_size(PyGimpLayer * self)1563 lay_resize_to_image_size(PyGimpLayer *self)
1564 {
1565     if (!gimp_layer_resize_to_image_size(self->ID)) {
1566 	PyErr_Format(pygimp_error,
1567 		     "could not resize layer (ID %d) to image size",
1568 		     self->ID);
1569 	return NULL;
1570     }
1571 
1572     Py_INCREF(Py_None);
1573     return Py_None;
1574 }
1575 
1576 static PyObject *
lay_scale(PyGimpLayer * self,PyObject * args,PyObject * kwargs)1577 lay_scale(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
1578 {
1579     int new_width, new_height;
1580     int interpolation = -1;
1581     gboolean local_origin = FALSE;
1582 
1583     static char *kwlist[] = { "width", "height", "local_origin",
1584                               "interpolation", NULL };
1585 
1586     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:scale", kwlist,
1587 				     &new_width, &new_height,
1588                                      &local_origin, &interpolation))
1589 	return NULL;
1590 
1591     if (interpolation != -1) {
1592         gimp_context_push();
1593         gimp_context_set_interpolation(interpolation);
1594     }
1595 
1596     if (!gimp_layer_scale(self->ID, new_width, new_height, local_origin)) {
1597         PyErr_Format(pygimp_error,
1598                      "could not scale layer (ID %d) to size %dx%d",
1599                      self->ID, new_width, new_height);
1600         if (interpolation != -1) {
1601             gimp_context_pop();
1602         }
1603         return NULL;
1604     }
1605 
1606     if (interpolation != -1) {
1607         gimp_context_pop();
1608     }
1609 
1610     Py_INCREF(Py_None);
1611     return Py_None;
1612 }
1613 
1614 
1615 static PyObject *
lay_translate(PyGimpLayer * self,PyObject * args,PyObject * kwargs)1616 lay_translate(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
1617 {
1618     int offs_x, offs_y;
1619 
1620     static char *kwlist[] = { "offset_x", "offset_y", NULL };
1621 
1622     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:translate", kwlist,
1623 				     &offs_x, &offs_y))
1624 	return NULL;
1625 
1626     if (!gimp_item_transform_translate(self->ID, offs_x, offs_y)) {
1627 	PyErr_Format(pygimp_error,
1628 		     "could not translate layer (ID %d) to offset %d, %d",
1629 		     self->ID, offs_x, offs_y);
1630 	return NULL;
1631     }
1632 
1633     Py_INCREF(Py_None);
1634     return Py_None;
1635 }
1636 
1637 
1638 static PyObject *
lay_set_offsets(PyGimpLayer * self,PyObject * args,PyObject * kwargs)1639 lay_set_offsets(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
1640 {
1641     int offs_x, offs_y;
1642 
1643     static char *kwlist[] = { "offset_x", "offset_y", NULL };
1644 
1645     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_offsets", kwlist,
1646 				     &offs_x, &offs_y))
1647 	return NULL;
1648 
1649     if (!gimp_layer_set_offsets(self->ID, offs_x, offs_y)) {
1650 	PyErr_Format(pygimp_error,
1651 		     "could not set offset %d, %d on layer (ID %d)",
1652 		     offs_x, offs_y, self->ID);
1653 	return NULL;
1654     }
1655 
1656     Py_INCREF(Py_None);
1657     return Py_None;
1658 }
1659 
1660 static PyMethodDef lay_methods[] = {
1661     {"copy",	(PyCFunction)lay_copy,	METH_VARARGS | METH_KEYWORDS},
1662     {"add_alpha",	(PyCFunction)lay_add_alpha,	METH_NOARGS},
1663     {"add_mask",        (PyCFunction)lay_add_mask,      METH_VARARGS},
1664     {"create_mask",	(PyCFunction)lay_create_mask,	METH_VARARGS},
1665     {"remove_mask",     (PyCFunction)lay_remove_mask,   METH_VARARGS},
1666     {"resize",	(PyCFunction)lay_resize,	METH_VARARGS | METH_KEYWORDS},
1667     {"resize_to_image_size",	(PyCFunction)lay_resize_to_image_size,	METH_NOARGS},
1668     {"scale",	(PyCFunction)lay_scale,	METH_VARARGS | METH_KEYWORDS},
1669     {"translate",	(PyCFunction)lay_translate,	METH_VARARGS | METH_KEYWORDS},
1670     {"set_offsets",	(PyCFunction)lay_set_offsets,	METH_VARARGS | METH_KEYWORDS},
1671     {NULL,		NULL}		/* sentinel */
1672 };
1673 
1674 static PyObject *
lay_get_is_floating_sel(PyGimpLayer * self,void * closure)1675 lay_get_is_floating_sel(PyGimpLayer *self, void *closure)
1676 {
1677     return PyBool_FromLong(gimp_layer_is_floating_sel(self->ID));
1678 }
1679 
1680 static PyObject *
lay_get_mask(PyGimpLayer * self,void * closure)1681 lay_get_mask(PyGimpLayer *self, void *closure)
1682 {
1683     gint32 id = gimp_layer_get_mask(self->ID);
1684 
1685     if (id == -1) {
1686 	Py_INCREF(Py_None);
1687 	return Py_None;
1688     }
1689 
1690     return pygimp_channel_new(id);
1691 }
1692 
1693 static PyObject *
lay_get_apply_mask(PyGimpLayer * self,void * closure)1694 lay_get_apply_mask(PyGimpLayer *self, void *closure)
1695 {
1696     return PyBool_FromLong(gimp_layer_get_apply_mask(self->ID));
1697 }
1698 
1699 static int
lay_set_apply_mask(PyGimpLayer * self,PyObject * value,void * closure)1700 lay_set_apply_mask(PyGimpLayer *self, PyObject *value, void *closure)
1701 {
1702     if (value == NULL) {
1703         PyErr_SetString(PyExc_TypeError, "cannot delete apply_mask");
1704         return -1;
1705     }
1706 
1707     if (!PyInt_Check(value)) {
1708 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1709 	return -1;
1710     }
1711 
1712     if (!gimp_layer_set_apply_mask(self->ID, PyInt_AsLong(value))) {
1713 	PyErr_Format(pygimp_error,
1714 		     "could not set layer mask on layer (ID %d)",
1715 		     self->ID);
1716 	return -1;
1717     }
1718 
1719     return 0;
1720 }
1721 
1722 static PyObject *
lay_get_edit_mask(PyGimpLayer * self,void * closure)1723 lay_get_edit_mask(PyGimpLayer *self, void *closure)
1724 {
1725     return PyBool_FromLong(gimp_layer_get_edit_mask(self->ID));
1726 }
1727 
1728 static int
lay_set_edit_mask(PyGimpLayer * self,PyObject * value,void * closure)1729 lay_set_edit_mask(PyGimpLayer *self, PyObject *value, void *closure)
1730 {
1731     if (value == NULL) {
1732         PyErr_SetString(PyExc_TypeError, "cannot delete edit_mask");
1733         return -1;
1734     }
1735 
1736     if (!PyInt_Check(value)) {
1737 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1738 	return -1;
1739     }
1740 
1741     if (!gimp_layer_set_edit_mask(self->ID, PyInt_AsLong(value))) {
1742 	PyErr_Format(pygimp_error,
1743 		     "could not set layer mask active on layer (ID %d)",
1744 		     self->ID);
1745 	return -1;
1746     }
1747 
1748     return 0;
1749 }
1750 
1751 static PyObject *
lay_get_mode(PyGimpLayer * self,void * closure)1752 lay_get_mode(PyGimpLayer *self, void *closure)
1753 {
1754     return PyInt_FromLong(gimp_layer_get_mode(self->ID));
1755 }
1756 
1757 static int
lay_set_mode(PyGimpLayer * self,PyObject * value,void * closure)1758 lay_set_mode(PyGimpLayer *self, PyObject *value, void *closure)
1759 {
1760     if (value == NULL) {
1761         PyErr_SetString(PyExc_TypeError, "cannot delete mode");
1762         return -1;
1763     }
1764 
1765     if (!PyInt_Check(value)) {
1766 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1767 	return -1;
1768     }
1769 
1770     if (!gimp_layer_set_mode(self->ID, PyInt_AsLong(value))) {
1771 	PyErr_Format(pygimp_error, "could not set mode on layer (ID %d)",
1772 		     self->ID);
1773 	return -1;
1774     }
1775 
1776     return 0;
1777 }
1778 
1779 static PyObject *
lay_get_opacity(PyGimpLayer * self,void * closure)1780 lay_get_opacity(PyGimpLayer *self, void *closure)
1781 {
1782     return PyFloat_FromDouble(gimp_layer_get_opacity(self->ID));
1783 }
1784 
1785 static int
lay_set_opacity(PyGimpLayer * self,PyObject * value,void * closure)1786 lay_set_opacity(PyGimpLayer *self, PyObject *value, void *closure)
1787 {
1788     if (value == NULL) {
1789         PyErr_SetString(PyExc_TypeError, "cannot delete opacity");
1790         return -1;
1791     }
1792 
1793     if (!PyFloat_Check(value)) {
1794 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1795 	return -1;
1796     }
1797 
1798     if (!gimp_layer_set_opacity(self->ID, PyFloat_AsDouble(value))) {
1799 	PyErr_Format(pygimp_error, "could not set opacity on layer (ID %d)",
1800 		     self->ID);
1801 	return -1;
1802     }
1803 
1804     return 0;
1805 }
1806 
1807 static PyObject *
lay_get_lock_alpha(PyGimpLayer * self,void * closure)1808 lay_get_lock_alpha(PyGimpLayer *self, void *closure)
1809 {
1810     return PyBool_FromLong(gimp_layer_get_lock_alpha(self->ID));
1811 }
1812 
1813 static int
lay_set_lock_alpha(PyGimpLayer * self,PyObject * value,void * closure)1814 lay_set_lock_alpha(PyGimpLayer *self, PyObject *value, void *closure)
1815 {
1816     if (value == NULL) {
1817         PyErr_SetString(PyExc_TypeError,
1818 			"cannot delete lock_alpha");
1819         return -1;
1820     }
1821 
1822     if (!PyInt_Check(value)) {
1823 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1824 	return -1;
1825     }
1826 
1827     if (!gimp_layer_set_lock_alpha(self->ID, PyInt_AsLong(value))) {
1828 	PyErr_Format(pygimp_error,
1829 	             "could not set lock alpha setting on layer (ID %d)",
1830 		     self->ID);
1831 	return -1;
1832     }
1833 
1834     return 0;
1835 }
1836 
1837 static PyObject *
lay_get_show_mask(PyGimpLayer * self,void * closure)1838 lay_get_show_mask(PyGimpLayer *self, void *closure)
1839 {
1840     return PyBool_FromLong(gimp_layer_get_show_mask(self->ID));
1841 }
1842 
1843 static int
lay_set_show_mask(PyGimpLayer * self,PyObject * value,void * closure)1844 lay_set_show_mask(PyGimpLayer *self, PyObject *value, void *closure)
1845 {
1846     if (value == NULL) {
1847         PyErr_SetString(PyExc_TypeError, "cannot delete show_mask");
1848         return -1;
1849     }
1850 
1851     if (!PyInt_Check(value)) {
1852 	PyErr_SetString(PyExc_TypeError, "type mismatch");
1853 	return -1;
1854     }
1855 
1856     if (!gimp_layer_set_show_mask(self->ID, PyInt_AsLong(value))) {
1857 	PyErr_Format(pygimp_error,
1858 	             "could not set mask visibility on layer (ID %d)",
1859 		     self->ID);
1860 	return -1;
1861     }
1862 
1863     return 0;
1864 }
1865 
1866 static PyObject *
lay_get_preserve_trans(PyGimpLayer * self,void * closure)1867 lay_get_preserve_trans(PyGimpLayer *self, void *closure)
1868 {
1869     if (PyErr_Warn(PyExc_DeprecationWarning, "use lock_alpha attribute") < 0)
1870 	return NULL;
1871 
1872     return lay_get_lock_alpha(self, closure);
1873 }
1874 
1875 static int
lay_set_preserve_trans(PyGimpLayer * self,PyObject * value,void * closure)1876 lay_set_preserve_trans(PyGimpLayer *self, PyObject *value, void *closure)
1877 {
1878     if (PyErr_Warn(PyExc_DeprecationWarning, "use lock_alpha attribute") < 0)
1879 	return -1;
1880 
1881     return lay_set_lock_alpha(self, value, closure);
1882 }
1883 
1884 static PyGetSetDef lay_getsets[] = {
1885     { "is_floating_sel", (getter)lay_get_is_floating_sel, (setter)0 },
1886     { "mask", (getter)lay_get_mask, (setter)0 },
1887     { "apply_mask", (getter)lay_get_apply_mask, (setter)lay_set_apply_mask },
1888     { "edit_mask", (getter)lay_get_edit_mask, (setter)lay_set_edit_mask },
1889     { "mode", (getter)lay_get_mode, (setter)lay_set_mode },
1890     { "opacity", (getter)lay_get_opacity, (setter)lay_set_opacity },
1891     { "lock_alpha", (getter)lay_get_lock_alpha, (setter)lay_set_lock_alpha },
1892     { "show_mask", (getter)lay_get_show_mask, (setter)lay_set_show_mask },
1893     { "preserve_trans", (getter)lay_get_preserve_trans,
1894       (setter)lay_set_preserve_trans },
1895     { NULL, (getter)0, (setter)0 }
1896 };
1897 
1898 static PyObject *
lay_repr(PyGimpLayer * self)1899 lay_repr(PyGimpLayer *self)
1900 {
1901     PyObject *s;
1902     gchar *name;
1903 
1904     name = gimp_item_get_name(self->ID);
1905     s = PyString_FromFormat("<gimp.Layer '%s'>", name ? name : "(null)");
1906     g_free(name);
1907 
1908     return s;
1909 }
1910 
1911 static int
lay_init(PyGimpLayer * self,PyObject * args,PyObject * kwargs)1912 lay_init(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
1913 {
1914     PyGimpImage *img;
1915     char *name;
1916     unsigned int width, height;
1917     GimpImageType type = GIMP_RGB_IMAGE;
1918     double opacity = 100.0;
1919     GimpLayerMode mode = GIMP_LAYER_MODE_NORMAL;
1920 
1921 
1922     if (!PyArg_ParseTuple(args, "O!sii|idi:gimp.Layer.__init__",
1923 			  &PyGimpImage_Type, &img, &name, &width, &height,
1924 			  &type, &opacity, &mode))
1925 	return -1;
1926 
1927     self->ID = gimp_layer_new(img->ID, name, width, height,
1928 			      type, opacity, mode);
1929 
1930     self->drawable = NULL;
1931 
1932     if (self->ID < 0) {
1933 	PyErr_Format(pygimp_error,
1934 		     "could not create %dx%d layer '%s' of type %d on "
1935 		     "image (ID %d)",
1936 		     width, height, name, type, img->ID);
1937 	return -1;
1938     }
1939 
1940     return 0;
1941 }
1942 
1943 PyTypeObject PyGimpLayer_Type = {
1944     PyObject_HEAD_INIT(NULL)
1945     0,                                  /* ob_size */
1946     "gimp.Layer",                       /* tp_name */
1947     sizeof(PyGimpLayer),                /* tp_basicsize */
1948     0,                                  /* tp_itemsize */
1949     /* methods */
1950     (destructor)drw_dealloc,            /* tp_dealloc */
1951     (printfunc)0,                       /* tp_print */
1952     (getattrfunc)0,                     /* tp_getattr */
1953     (setattrfunc)0,                     /* tp_setattr */
1954     (cmpfunc)drw_cmp,                   /* tp_compare */
1955     (reprfunc)lay_repr,                 /* tp_repr */
1956     0,                                  /* tp_as_number */
1957     0,                                  /* tp_as_sequence */
1958     0,                                  /* tp_as_mapping */
1959     (hashfunc)0,                        /* tp_hash */
1960     (ternaryfunc)0,                     /* tp_call */
1961     (reprfunc)0,                        /* tp_str */
1962     (getattrofunc)0,                    /* tp_getattro */
1963     (setattrofunc)0,                    /* tp_setattro */
1964     0,					/* tp_as_buffer */
1965     Py_TPFLAGS_DEFAULT,	                /* tp_flags */
1966     NULL, /* Documentation string */
1967     (traverseproc)0,			/* tp_traverse */
1968     (inquiry)0,				/* tp_clear */
1969     (richcmpfunc)0,			/* tp_richcompare */
1970     0,					/* tp_weaklistoffset */
1971     (getiterfunc)0,			/* tp_iter */
1972     (iternextfunc)0,			/* tp_iternext */
1973     lay_methods,			/* tp_methods */
1974     0,					/* tp_members */
1975     lay_getsets,			/* tp_getset */
1976     &PyGimpDrawable_Type,		/* tp_base */
1977     (PyObject *)0,			/* tp_dict */
1978     0,					/* tp_descr_get */
1979     0,					/* tp_descr_set */
1980     0,					/* tp_dictoffset */
1981     (initproc)lay_init,                 /* tp_init */
1982     (allocfunc)0,			/* tp_alloc */
1983     (newfunc)0,				/* tp_new */
1984 };
1985 
1986 PyObject *
pygimp_layer_new(gint32 ID)1987 pygimp_layer_new(gint32 ID)
1988 {
1989     PyGimpLayer *self;
1990 
1991     if (!gimp_item_is_valid(ID) || !gimp_item_is_layer(ID)) {
1992         Py_INCREF(Py_None);
1993         return Py_None;
1994     }
1995 
1996 
1997     if (gimp_item_is_group(ID)) {
1998         self = PyObject_NEW(PyGimpGroupLayer, &PyGimpGroupLayer_Type);
1999     }
2000     else {
2001         self = PyObject_NEW(PyGimpLayer, &PyGimpLayer_Type);
2002     }
2003 
2004     if (self == NULL)
2005         return NULL;
2006 
2007     self->ID = ID;
2008     self->drawable = NULL;
2009 
2010     return (PyObject *)self;
2011 }
2012 
2013 /* End of code for Layer objects */
2014 /* -------------------------------------------------------- */
2015 
2016 /* Since this help will primarily be seen from within
2017  * GIMP's Python console, we should make it fit in that
2018  * window's default size.
2019  */
2020 
2021 #define GROUPLAYER_DOC ""                                \
2022 "gimp.GroupLayer(img, name="", opacity=100.0,   "        \
2023 "mode=gimp.LAYER_MODE_NORMAL)\n"                         \
2024 "\n"                                                     \
2025 " Creates a new GroupLayer object that has to be \n"     \
2026 "subsequently added to an image. Use Image.add_layer \n" \
2027 "or pdb.gimp_image_insert_layer calls to do that. \n"    \
2028 
2029 static PyMethodDef grouplay_methods[] = {
2030     {NULL,              NULL}           /* sentinel */
2031 };
2032 
2033 static PyObject *
grouplay_get_layers(PyGimpGroupLayer * self,void * closure)2034 grouplay_get_layers(PyGimpGroupLayer *self, void *closure)
2035 {
2036     gint32 *layers;
2037     gint n_layers, i;
2038     PyObject *ret;
2039 
2040     layers = gimp_item_get_children(self->ID, &n_layers);
2041 
2042     ret = PyList_New(n_layers);
2043 
2044     for (i = 0; i < n_layers; i++)
2045         PyList_SetItem(ret, i, pygimp_group_layer_new(layers[i]));
2046 
2047     g_free(layers);
2048 
2049     return ret;
2050 }
2051 
2052 static PyGetSetDef grouplay_getsets[] = {
2053     { "layers", (getter)grouplay_get_layers, (setter)0 },
2054     { NULL, (getter)0, (setter)0 }
2055 };
2056 
2057 static PyObject *
grouplay_repr(PyGimpLayer * self)2058 grouplay_repr(PyGimpLayer *self)
2059 {
2060     PyObject *s;
2061     gchar *name;
2062 
2063     name = gimp_item_get_name(self->ID);
2064     s = PyString_FromFormat("<gimp.GroupLayer '%s'>", name ? name : "(null)");
2065     g_free(name);
2066 
2067     return s;
2068 }
2069 
2070 static int
grouplay_init(PyGimpLayer * self,PyObject * args,PyObject * kwargs)2071 grouplay_init(PyGimpLayer *self, PyObject *args, PyObject *kwargs)
2072 {
2073     PyGimpImage *img;
2074     char *name = "Layer Group";
2075     GimpImageType type = GIMP_RGB_IMAGE;
2076     double opacity = 100.0;
2077     GimpLayerMode mode = GIMP_LAYER_MODE_NORMAL;
2078 
2079 
2080     if (!PyArg_ParseTuple(args, "O!|sdi:gimp.Layer.__init__",
2081                           &PyGimpImage_Type, &img, &name,
2082                           &opacity, &mode))
2083         return -1;
2084 
2085     self->ID = gimp_layer_group_new(img->ID);
2086 
2087     self->drawable = NULL;
2088 
2089     if (self->ID < 0) {
2090         PyErr_Format(pygimp_error,
2091                      "could not create layer group '%s' of type %d on "
2092                      "image (ID %d)",
2093                      name, type, img->ID);
2094         return -1;
2095     }
2096 
2097     gimp_layer_set_opacity(self->ID, opacity);
2098     gimp_layer_set_mode(self->ID, mode);
2099 
2100     gimp_item_set_name(self->ID, name);
2101 
2102     return 0;
2103 }
2104 
2105 PyTypeObject PyGimpGroupLayer_Type = {
2106     PyObject_HEAD_INIT(NULL)
2107     0,                                  /* ob_size */
2108     "gimp.GroupLayer",                  /* tp_name */
2109     sizeof(PyGimpGroupLayer),           /* tp_basicsize */
2110     0,                                  /* tp_itemsize */
2111     /* methods */
2112     (destructor)drw_dealloc,            /* tp_dealloc */
2113     (printfunc)0,                       /* tp_print */
2114     (getattrfunc)0,                     /* tp_getattr */
2115     (setattrfunc)0,                     /* tp_setattr */
2116     (cmpfunc)drw_cmp,                   /* tp_compare */
2117     (reprfunc)grouplay_repr,            /* tp_repr */
2118     0,                                  /* tp_as_number */
2119     0,                                  /* tp_as_sequence */
2120     0,                                  /* tp_as_mapping */
2121     (hashfunc)0,                        /* tp_hash */
2122     (ternaryfunc)0,                     /* tp_call */
2123     (reprfunc)0,                        /* tp_str */
2124     (getattrofunc)0,                    /* tp_getattro */
2125     (setattrofunc)0,                    /* tp_setattro */
2126     0,                                  /* tp_as_buffer */
2127     Py_TPFLAGS_DEFAULT,                 /* tp_flags */
2128     GROUPLAYER_DOC, /* Documentation string */
2129     (traverseproc)0,                    /* tp_traverse */
2130     (inquiry)0,                         /* tp_clear */
2131     (richcmpfunc)0,                     /* tp_richcompare */
2132     0,                                  /* tp_weaklistoffset */
2133     (getiterfunc)0,                     /* tp_iter */
2134     (iternextfunc)0,                    /* tp_iternext */
2135     grouplay_methods,                   /* tp_methods */
2136     0,                                  /* tp_members */
2137     grouplay_getsets,                   /* tp_getset */
2138     &PyGimpLayer_Type,                  /* tp_base */
2139     (PyObject *)0,                      /* tp_dict */
2140     0,                                  /* tp_descr_get */
2141     0,                                  /* tp_descr_set */
2142     0,                                  /* tp_dictoffset */
2143     (initproc)grouplay_init,            /* tp_init */
2144     (allocfunc)0,                       /* tp_alloc */
2145     (newfunc)0,                         /* tp_new */
2146 };
2147 
2148 PyObject *
pygimp_group_layer_new(gint32 ID)2149 pygimp_group_layer_new(gint32 ID)
2150 {
2151     PyGimpGroupLayer *self;
2152 
2153     if (!gimp_item_is_valid(ID) || !gimp_item_is_layer(ID)) {
2154         Py_INCREF(Py_None);
2155         return Py_None;
2156     }
2157 
2158     if (!gimp_item_is_group(ID)) {
2159         return pygimp_layer_new(ID);
2160     }
2161 
2162     self = PyObject_NEW(PyGimpGroupLayer, &PyGimpGroupLayer_Type);
2163 
2164     if (self == NULL)
2165         return NULL;
2166 
2167     self->ID = ID;
2168     self->drawable = NULL;
2169 
2170     return (PyObject *)self;
2171 }
2172 
2173 /* End of code for GroupLayer objects */
2174 /* -------------------------------------------------------- */
2175 
2176 
2177 static PyObject *
chn_copy(PyGimpChannel * self)2178 chn_copy(PyGimpChannel *self)
2179 {
2180     gint32 id;
2181 
2182     id = gimp_channel_copy(self->ID);
2183 
2184     if (id == -1) {
2185 	PyErr_Format(pygimp_error,
2186 		     "could not create new channel copy from channel (ID %d)",
2187 		     self->ID);
2188 	return NULL;
2189     }
2190 
2191     return pygimp_channel_new(id);
2192 }
2193 
2194 static PyObject *
chn_combine_masks(PyGimpChannel * self,PyObject * args,PyObject * kwargs)2195 chn_combine_masks(PyGimpChannel *self, PyObject *args, PyObject *kwargs)
2196 {
2197     PyGimpChannel *channel2;
2198     GimpChannelOps operation;
2199     int offx = 0, offy = 0;
2200 
2201     static char *kwlist[] = { "channel", "operation", "offset_x", "offset_y",
2202 			      NULL };
2203 
2204     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|ii:combine_masks",
2205 				     kwlist,
2206 				     &PyGimpChannel_Type, &channel2,
2207 				     &operation, &offx, &offy))
2208 	return NULL;
2209 
2210     if (!gimp_channel_combine_masks(self->ID, channel2->ID, operation,
2211 				    offx, offy)) {
2212 	PyErr_Format(pygimp_error,
2213 		     "could not combine masks with channels (ID %d and ID %d) "
2214 		     "with operation %d, offset %d, %d",
2215 		     self->ID, channel2->ID, operation, offx, offy);
2216 	return NULL;
2217     }
2218 
2219     Py_INCREF(Py_None);
2220     return Py_None;
2221 }
2222 
2223 static PyMethodDef chn_methods[] = {
2224     {"copy",	(PyCFunction)chn_copy,	METH_NOARGS},
2225     {"combine_masks",	(PyCFunction)chn_combine_masks,	METH_VARARGS},
2226     {NULL,		NULL}		/* sentinel */
2227 };
2228 
2229 static PyObject *
chn_get_color(PyGimpChannel * self,void * closure)2230 chn_get_color(PyGimpChannel *self, void *closure)
2231 {
2232     GimpRGB rgb;
2233 
2234     if (!gimp_channel_get_color(self->ID, &rgb)) {
2235 	PyErr_Format(pygimp_error,
2236 		     "could not get compositing color of channel (ID %d)",
2237 		     self->ID);
2238 	return NULL;
2239     }
2240 
2241     return pygimp_rgb_new(&rgb);
2242 }
2243 
2244 static int
chn_set_color(PyGimpChannel * self,PyObject * value,void * closure)2245 chn_set_color(PyGimpChannel *self, PyObject *value, void *closure)
2246 {
2247     guchar r, g, b;
2248     GimpRGB tmprgb, *rgb;
2249 
2250     if (value == NULL) {
2251         PyErr_SetString(PyExc_TypeError, "cannot delete color");
2252         return -1;
2253     }
2254 
2255     if (pygimp_rgb_check(value)) {
2256 	rgb = pyg_boxed_get(value, GimpRGB);
2257     } else if (PyTuple_Check(value) &&
2258 	       PyArg_ParseTuple(value, "(BBB)", &r, &g, &b)) {
2259 	gimp_rgb_set_uchar(&tmprgb, r, g, b);
2260 	rgb = &tmprgb;
2261     } else {
2262 	PyErr_Clear();
2263 	PyErr_SetString(PyExc_TypeError, "type mismatch");
2264 	return -1;
2265     }
2266 
2267     if (!gimp_channel_set_color(self->ID, rgb)) {
2268 	PyErr_Format(pygimp_error,
2269 		     "could not set compositing color on channel (ID %d)",
2270 		     self->ID);
2271 	return -1;
2272     }
2273 
2274     return 0;
2275 }
2276 
2277 static PyObject *
chn_get_opacity(PyGimpLayer * self,void * closure)2278 chn_get_opacity(PyGimpLayer *self, void *closure)
2279 {
2280     return PyFloat_FromDouble(gimp_channel_get_opacity(self->ID));
2281 }
2282 
2283 static int
chn_set_opacity(PyGimpLayer * self,PyObject * value,void * closure)2284 chn_set_opacity(PyGimpLayer *self, PyObject *value, void *closure)
2285 {
2286     if (value == NULL) {
2287         PyErr_SetString(PyExc_TypeError, "cannot delete opacity");
2288         return -1;
2289     }
2290 
2291     if (!PyFloat_Check(value)) {
2292 	PyErr_SetString(PyExc_TypeError, "type mismatch");
2293 	return -1;
2294     }
2295 
2296     if (!gimp_channel_set_opacity(self->ID, PyFloat_AsDouble(value))) {
2297 	PyErr_Format(pygimp_error,
2298 		     "could not set opacity on channel (ID %d)",
2299 		     self->ID);
2300 	return -1;
2301     }
2302 
2303     return 0;
2304 }
2305 
2306 static PyObject *
chn_get_show_masked(PyGimpLayer * self,void * closure)2307 chn_get_show_masked(PyGimpLayer *self, void *closure)
2308 {
2309     return PyBool_FromLong(gimp_channel_get_show_masked(self->ID));
2310 }
2311 
2312 static int
chn_set_show_masked(PyGimpLayer * self,PyObject * value,void * closure)2313 chn_set_show_masked(PyGimpLayer *self, PyObject *value, void *closure)
2314 {
2315     if (value == NULL) {
2316         PyErr_SetString(PyExc_TypeError, "cannot delete show_masked");
2317         return -1;
2318     }
2319 
2320     if (!PyInt_Check(value)) {
2321 	PyErr_SetString(PyExc_TypeError, "type mismatch");
2322 	return -1;
2323     }
2324 
2325     if (!gimp_channel_set_show_masked(self->ID, PyInt_AsLong(value))) {
2326 	PyErr_Format(pygimp_error,
2327 		     "could not set composite method on channel (ID %d)",
2328 		     self->ID);
2329 	return -1;
2330     }
2331 
2332     return 0;
2333 }
2334 
2335 static PyGetSetDef chn_getsets[] = {
2336     { "color", (getter)chn_get_color, (setter)chn_set_color },
2337     { "colour", (getter)chn_get_color, (setter)chn_set_color },
2338     { "opacity", (getter)chn_get_opacity, (setter)chn_set_opacity },
2339     { "show_masked", (getter)chn_get_show_masked, (setter)chn_set_show_masked},
2340     { NULL, (getter)0, (setter)0 }
2341 };
2342 
2343 static PyObject *
chn_repr(PyGimpChannel * self)2344 chn_repr(PyGimpChannel *self)
2345 {
2346     PyObject *s;
2347     gchar *name;
2348 
2349     name = gimp_item_get_name(self->ID);
2350     s = PyString_FromFormat("<gimp.Channel '%s'>", name ? name : "(null)");
2351     g_free(name);
2352 
2353     return s;
2354 }
2355 
2356 static int
chn_init(PyGimpChannel * self,PyObject * args,PyObject * kwargs)2357 chn_init(PyGimpChannel *self, PyObject *args, PyObject *kwargs)
2358 {
2359     PyGimpImage *img;
2360     PyObject *color;
2361     char *name;
2362     unsigned int width, height, r, g, b;
2363     double opacity;
2364     GimpRGB tmprgb, *rgb;
2365 
2366     if (!PyArg_ParseTuple(args, "O!siidO:gimp.Channel.__init__",
2367 			  &PyGimpImage_Type, &img, &name, &width,
2368 			  &height, &opacity, &color))
2369 	return -1;
2370 
2371     if (pygimp_rgb_check(color)) {
2372 	rgb = pyg_boxed_get(color, GimpRGB);
2373     } else if (PyTuple_Check(color) &&
2374 	       PyArg_ParseTuple(color, "(BBB)", &r, &g, &b)) {
2375 	gimp_rgb_set_uchar(&tmprgb, r, g, b);
2376 	rgb = &tmprgb;
2377     } else {
2378 	PyErr_Clear();
2379 	PyErr_SetString(PyExc_TypeError, "type mismatch");
2380 	return -1;
2381     }
2382 
2383     self->ID = gimp_channel_new(img->ID, name, width, height, opacity, rgb);
2384 
2385     self->drawable = NULL;
2386 
2387     if (self->ID < 0) {
2388 	PyErr_Format(pygimp_error,
2389 		     "could not create %dx%d channel '%s' on image (ID %d)",
2390 		     width, height, name, img->ID);
2391 	return -1;
2392     }
2393 
2394     return 0;
2395 }
2396 
2397 PyTypeObject PyGimpChannel_Type = {
2398     PyObject_HEAD_INIT(NULL)
2399     0,                                  /* ob_size */
2400     "gimp.Channel",                     /* tp_name */
2401     sizeof(PyGimpChannel),              /* tp_basicsize */
2402     0,                                  /* tp_itemsize */
2403     /* methods */
2404     (destructor)drw_dealloc,            /* tp_dealloc */
2405     (printfunc)0,                       /* tp_print */
2406     (getattrfunc)0,                     /* tp_getattr */
2407     (setattrfunc)0,                     /* tp_setattr */
2408     (cmpfunc)drw_cmp,                   /* tp_compare */
2409     (reprfunc)chn_repr,                 /* tp_repr */
2410     0,                                  /* tp_as_number */
2411     0,                                  /* tp_as_sequence */
2412     0,                                  /* tp_as_mapping */
2413     (hashfunc)0,                        /* tp_hash */
2414     (ternaryfunc)0,                     /* tp_call */
2415     (reprfunc)0,                        /* tp_str */
2416     (getattrofunc)0,                    /* tp_getattro */
2417     (setattrofunc)0,                    /* tp_setattro */
2418     0,					/* tp_as_buffer */
2419     Py_TPFLAGS_DEFAULT,	                /* tp_flags */
2420     NULL, /* Documentation string */
2421     (traverseproc)0,			/* tp_traverse */
2422     (inquiry)0,				/* tp_clear */
2423     (richcmpfunc)0,			/* tp_richcompare */
2424     0,					/* tp_weaklistoffset */
2425     (getiterfunc)0,			/* tp_iter */
2426     (iternextfunc)0,			/* tp_iternext */
2427     chn_methods,			/* tp_methods */
2428     0,					/* tp_members */
2429     chn_getsets,			/* tp_getset */
2430     &PyGimpDrawable_Type,		/* tp_base */
2431     (PyObject *)0,			/* tp_dict */
2432     0,					/* tp_descr_get */
2433     0,					/* tp_descr_set */
2434     0,					/* tp_dictoffset */
2435     (initproc)chn_init,                 /* tp_init */
2436     (allocfunc)0,			/* tp_alloc */
2437     (newfunc)0,				/* tp_new */
2438 };
2439 
2440 PyObject *
pygimp_channel_new(gint32 ID)2441 pygimp_channel_new(gint32 ID)
2442 {
2443     PyGimpChannel *self;
2444 
2445     if (!gimp_item_is_valid(ID) || !gimp_item_is_channel(ID)) {
2446 	Py_INCREF(Py_None);
2447 	return Py_None;
2448     }
2449 
2450     self = PyObject_NEW(PyGimpChannel, &PyGimpChannel_Type);
2451 
2452     if (self == NULL)
2453 	return NULL;
2454 
2455     self->ID = ID;
2456     self->drawable = NULL;
2457 
2458     return (PyObject *)self;
2459 }
2460