1 /* This file is part of Ganv.
2  * Copyright 2007-2016 David Robillard <http://drobilla.net>
3  *
4  * Ganv is free software: you can redistribute it and/or modify it under the
5  * terms of the GNU General Public License as published by the Free Software
6  * Foundation, either version 3 of the License, or any later version.
7  *
8  * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY
9  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
11  *
12  * You should have received a copy of the GNU General Public License along
13  * with Ganv.  If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 /* Based on GnomeCanvas, by Federico Mena <federico@nuclecu.unam.mx>
17  * and Raph Levien <raph@gimp.org>
18  * Copyright 1997-2000 Free Software Foundation
19  */
20 
21 #include "ganv-marshal.h"
22 #include "ganv-private.h"
23 #include "gettext.h"
24 
25 #include "ganv/item.h"
26 #include "ganv/types.h"
27 
28 #include <gdk/gdk.h>
29 #include <glib-object.h>
30 #include <glib.h>
31 #include <gtk/gtk.h>
32 
33 #include <stdarg.h>
34 #include <stdio.h>
35 
36 /* All canvas items are derived from GanvItem.  The only information a GanvItem
37  * contains is its parent canvas, its parent canvas item, its bounding box in
38  * world coordinates, and its current affine transformation.
39  *
40  * Items inside a canvas are organized in a tree, where leaves are items
41  * without any children.  Each canvas has a single root item, which can be
42  * obtained with the ganv_canvas_base_get_root() function.
43  *
44  * The abstract GanvItem class does not have any configurable or queryable
45  * attributes.
46  */
47 
48 /* Update flags for items */
49 enum {
50 	GANV_CANVAS_UPDATE_REQUESTED  = 1 << 0,
51 	GANV_CANVAS_UPDATE_AFFINE     = 1 << 1,
52 	GANV_CANVAS_UPDATE_VISIBILITY = 1 << 2
53 };
54 
55 #define GCI_UPDATE_MASK (GANV_CANVAS_UPDATE_REQUESTED \
56                          | GANV_CANVAS_UPDATE_AFFINE \
57                          | GANV_CANVAS_UPDATE_VISIBILITY)
58 
59 enum {
60 	ITEM_PROP_0,
61 	ITEM_PROP_PARENT,
62 	ITEM_PROP_X,
63 	ITEM_PROP_Y,
64 	ITEM_PROP_MANAGED
65 };
66 
67 enum {
68 	ITEM_EVENT,
69 	ITEM_LAST_SIGNAL
70 };
71 
72 static guint item_signals[ITEM_LAST_SIGNAL];
73 
74 G_DEFINE_TYPE_WITH_CODE(GanvItem, ganv_item, GTK_TYPE_OBJECT,
75                         G_ADD_PRIVATE(GanvItem))
76 
77 static GtkObjectClass* item_parent_class;
78 
79 /* Object initialization function for GanvItem */
80 static void
ganv_item_init(GanvItem * item)81 ganv_item_init(GanvItem* item)
82 {
83 	GanvItemPrivate* impl =
84 	    (GanvItemPrivate*)ganv_item_get_instance_private(item);
85 
86 	item->object.flags |= GANV_ITEM_VISIBLE;
87 	item->impl          = impl;
88 	item->impl->managed = FALSE;
89 	item->impl->wrapper = NULL;
90 }
91 
92 /**
93  * ganv_item_new:
94  * @parent: The parent group for the new item.
95  * @type: The object type of the item.
96  * @first_arg_name: A list of object argument name/value pairs, NULL-terminated,
97  * used to configure the item.  For example, "fill_color", "black",
98  * "width_units", 5.0, NULL.
99  * @...: first argument value, second argument name, second argument value, ...
100  *
101  * Creates a new canvas item with @parent as its parent group.  The item is
102  * created at the top of its parent's stack, and starts up as visible.  The item
103  * is of the specified @type, for example, it can be
104  * ganv_canvas_rect_get_type().  The list of object arguments/value pairs is
105  * used to configure the item. If you need to pass construct time parameters, you
106  * should use g_object_new() to pass the parameters and
107  * ganv_item_construct() to set up the canvas item.
108  *
109  * Return value: (transfer full): The newly-created item.
110  **/
111 GanvItem*
ganv_item_new(GanvItem * parent,GType type,const gchar * first_arg_name,...)112 ganv_item_new(GanvItem* parent, GType type, const gchar* first_arg_name, ...)
113 {
114 	g_return_val_if_fail(g_type_is_a(type, ganv_item_get_type()), NULL);
115 
116 	GanvItem* item = GANV_ITEM(g_object_new(type, NULL));
117 
118 	va_list args;
119 	va_start(args, first_arg_name);
120 	ganv_item_construct(item, parent, first_arg_name, args);
121 	va_end(args);
122 
123 	return item;
124 }
125 
126 /* Performs post-creation operations on a canvas item (adding it to its parent
127  * group, etc.)
128  */
129 static void
item_post_create_setup(GanvItem * item)130 item_post_create_setup(GanvItem* item)
131 {
132 	GanvItemClass* parent_class = GANV_ITEM_GET_CLASS(item->impl->parent);
133 	if (!item->impl->managed) {
134 		if (parent_class->add) {
135 			parent_class->add(item->impl->parent, item);
136 		} else {
137 			g_warning("item added to non-parent item\n");
138 		}
139 	}
140 	ganv_canvas_request_redraw_w(item->impl->canvas,
141 	                             item->impl->x1, item->impl->y1,
142 	                             item->impl->x2 + 1, item->impl->y2 + 1);
143 	ganv_canvas_set_need_repick(item->impl->canvas);
144 }
145 
146 static void
ganv_item_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)147 ganv_item_set_property(GObject*      object,
148                        guint         prop_id,
149                        const GValue* value,
150                        GParamSpec*   pspec)
151 {
152 	g_return_if_fail(object != NULL);
153 	g_return_if_fail(GANV_IS_ITEM(object));
154 
155 	GanvItem* item = GANV_ITEM(object);
156 
157 	switch (prop_id) {
158 	case ITEM_PROP_PARENT:
159 		if (item->impl->parent != NULL) {
160 			g_warning("Cannot set `parent' argument after item has "
161 			          "already been constructed.");
162 		} else if (g_value_get_object(value)) {
163 			item->impl->parent = GANV_ITEM(g_value_get_object(value));
164 			item->impl->canvas = item->impl->parent->impl->canvas;
165 			item_post_create_setup(item);
166 		}
167 		break;
168 	case ITEM_PROP_X:
169 		item->impl->x = g_value_get_double(value);
170 		ganv_item_request_update(item);
171 		break;
172 	case ITEM_PROP_Y:
173 		item->impl->y = g_value_get_double(value);
174 		ganv_item_request_update(item);
175 		break;
176 	case ITEM_PROP_MANAGED:
177 		item->impl->managed = g_value_get_boolean(value);
178 		break;
179 	default:
180 		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
181 		break;
182 	}
183 }
184 
185 static void
ganv_item_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)186 ganv_item_get_property(GObject*    object,
187                        guint       prop_id,
188                        GValue*     value,
189                        GParamSpec* pspec)
190 {
191 	g_return_if_fail(object != NULL);
192 	g_return_if_fail(GANV_IS_ITEM(object));
193 
194 	GanvItem* item = GANV_ITEM(object);
195 
196 	switch (prop_id) {
197 	case ITEM_PROP_PARENT:
198 		g_value_set_object(value, item->impl->parent);
199 		break;
200 	case ITEM_PROP_X:
201 		g_value_set_double(value, item->impl->x);
202 		break;
203 	case ITEM_PROP_Y:
204 		g_value_set_double(value, item->impl->y);
205 		break;
206 	case ITEM_PROP_MANAGED:
207 		g_value_set_boolean(value, item->impl->managed);
208 		break;
209 	default:
210 		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
211 		break;
212 	}
213 }
214 
215 /**
216  * ganv_item_construct:
217  * @item: An unconstructed canvas item.
218  * @parent: The parent group for the item.
219  * @first_arg_name: The name of the first argument for configuring the item.
220  * @args: The list of arguments used to configure the item.
221  *
222  * Constructs a canvas item; meant for use only by item implementations.
223  **/
224 void
ganv_item_construct(GanvItem * item,GanvItem * parent,const gchar * first_arg_name,va_list args)225 ganv_item_construct(GanvItem* item, GanvItem* parent,
226                     const gchar* first_arg_name, va_list args)
227 {
228 	g_return_if_fail(GANV_IS_ITEM(item));
229 
230 	item->impl->parent  = parent;
231 	item->impl->wrapper = NULL;
232 	item->impl->canvas  = item->impl->parent->impl->canvas;
233 	item->impl->layer   = 0;
234 
235 	g_object_set_valist(G_OBJECT(item), first_arg_name, args);
236 
237 	item_post_create_setup(item);
238 }
239 
240 /* If the item is visible, requests a redraw of it. */
241 static void
redraw_if_visible(GanvItem * item)242 redraw_if_visible(GanvItem* item)
243 {
244 	if (item->object.flags & GANV_ITEM_VISIBLE) {
245 		ganv_canvas_request_redraw_w(item->impl->canvas,
246 		                             item->impl->x1, item->impl->y1,
247 		                             item->impl->x2 + 1, item->impl->y2 + 1);
248 	}
249 }
250 
251 /* Standard object dispose function for canvas items */
252 static void
ganv_item_dispose(GObject * object)253 ganv_item_dispose(GObject* object)
254 {
255 	GanvItem* item = NULL;
256 
257 	g_return_if_fail(GANV_IS_ITEM(object));
258 
259 	item = GANV_ITEM(object);
260 
261 	if (item->impl->canvas) {
262 		redraw_if_visible(item);
263 		ganv_canvas_forget_item(item->impl->canvas, item);
264 	}
265 
266 	/* Normal destroy stuff */
267 
268 	if (item->object.flags & GANV_ITEM_MAPPED) {
269 		(*GANV_ITEM_GET_CLASS(item)->unmap)(item);
270 	}
271 
272 	if (item->object.flags & GANV_ITEM_REALIZED) {
273 		(*GANV_ITEM_GET_CLASS(item)->unrealize)(item);
274 	}
275 
276 	if (!item->impl->managed && item->impl->parent) {
277 		if (GANV_ITEM_GET_CLASS(item->impl->parent)->remove) {
278 			GANV_ITEM_GET_CLASS(item->impl->parent)->remove(item->impl->parent, item);
279 		} else {
280 			fprintf(stderr, "warning: Item parent has no remove method\n");
281 		}
282 	}
283 
284 	G_OBJECT_CLASS(item_parent_class)->dispose(object);
285 	/* items should remove any reference to item->impl->canvas after the
286 	   first ::destroy */
287 	item->impl->canvas = NULL;
288 }
289 
290 /* Realize handler for canvas items */
291 static void
ganv_item_realize(GanvItem * item)292 ganv_item_realize(GanvItem* item)
293 {
294 	GTK_OBJECT_SET_FLAGS(item, GANV_ITEM_REALIZED);
295 
296 	ganv_item_request_update(item);
297 }
298 
299 /* Unrealize handler for canvas items */
300 static void
ganv_item_unrealize(GanvItem * item)301 ganv_item_unrealize(GanvItem* item)
302 {
303 	GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_REALIZED);
304 }
305 
306 /* Map handler for canvas items */
307 static void
ganv_item_map(GanvItem * item)308 ganv_item_map(GanvItem* item)
309 {
310 	GTK_OBJECT_SET_FLAGS(item, GANV_ITEM_MAPPED);
311 }
312 
313 /* Unmap handler for canvas items */
314 static void
ganv_item_unmap(GanvItem * item)315 ganv_item_unmap(GanvItem* item)
316 {
317 	GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_MAPPED);
318 }
319 
320 /* Update handler for canvas items */
321 static void
ganv_item_update(GanvItem * item,int flags)322 ganv_item_update(GanvItem* item, int flags)
323 {
324 	(void)flags;
325 
326 	GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_NEED_UPDATE);
327 	GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_NEED_VIS);
328 }
329 
330 /* Point handler for canvas items */
331 static double
ganv_item_point(GanvItem * item,double x,double y,GanvItem ** actual_item)332 ganv_item_point(GanvItem* item, double x, double y, GanvItem** actual_item)
333 {
334 	(void)item;
335 	(void)x;
336 	(void)y;
337 
338 	*actual_item = NULL;
339 	return G_MAXDOUBLE;
340 }
341 
342 void
ganv_item_invoke_update(GanvItem * item,int flags)343 ganv_item_invoke_update(GanvItem* item, int flags)
344 {
345 	int child_flags = flags;
346 
347 	/* apply object flags to child flags */
348 
349 	child_flags &= ~GANV_CANVAS_UPDATE_REQUESTED;
350 
351 	if (item->object.flags & GANV_ITEM_NEED_UPDATE) {
352 		child_flags |= GANV_CANVAS_UPDATE_REQUESTED;
353 	}
354 
355 	if (item->object.flags & GANV_ITEM_NEED_VIS) {
356 		child_flags |= GANV_CANVAS_UPDATE_VISIBILITY;
357 	}
358 
359 	if (child_flags & GCI_UPDATE_MASK) {
360 		if (GANV_ITEM_GET_CLASS(item)->update) {
361 			GANV_ITEM_GET_CLASS(item)->update(item, child_flags);
362 			g_assert(!(GTK_OBJECT_FLAGS(item) & GANV_ITEM_NEED_UPDATE));
363 		}
364 	}
365 }
366 
367 /**
368  * ganv_item_set:
369  * @item: A canvas item.
370  * @first_arg_name: The list of object argument name/value pairs used to configure the item.
371  * @...: first argument value, second argument name, second argument value, ...
372  *
373  * Configures a canvas item.  The arguments in the item are set to the specified
374  * values, and the item is repainted as appropriate.
375  **/
376 void
ganv_item_set(GanvItem * item,const gchar * first_arg_name,...)377 ganv_item_set(GanvItem* item, const gchar* first_arg_name, ...)
378 {
379 	va_list args;
380 
381 	va_start(args, first_arg_name);
382 	ganv_item_set_valist(item, first_arg_name, args);
383 	va_end(args);
384 }
385 
386 /**
387  * ganv_item_set_valist:
388  * @item: A canvas item.
389  * @first_arg_name: The name of the first argument used to configure the item.
390  * @args: The list of object argument name/value pairs used to configure the item.
391  *
392  * Configures a canvas item.  The arguments in the item are set to the specified
393  * values, and the item is repainted as appropriate.
394  **/
395 void
ganv_item_set_valist(GanvItem * item,const gchar * first_arg_name,va_list args)396 ganv_item_set_valist(GanvItem* item, const gchar* first_arg_name, va_list args)
397 {
398 	g_return_if_fail(GANV_IS_ITEM(item));
399 
400 	g_object_set_valist(G_OBJECT(item), first_arg_name, args);
401 
402 	ganv_canvas_set_need_repick(item->impl->canvas);
403 }
404 
405 GanvCanvas*
ganv_item_get_canvas(GanvItem * item)406 ganv_item_get_canvas(GanvItem* item)
407 {
408 	return item->impl->canvas;
409 }
410 
411 GanvItem*
ganv_item_get_parent(GanvItem * item)412 ganv_item_get_parent(GanvItem* item)
413 {
414 	return item->impl->parent;
415 }
416 
417 void
ganv_item_raise(GanvItem * item)418 ganv_item_raise(GanvItem* item)
419 {
420 	++item->impl->layer;
421 }
422 
423 void
ganv_item_lower(GanvItem * item)424 ganv_item_lower(GanvItem* item)
425 {
426 	--item->impl->layer;
427 }
428 
429 /**
430  * ganv_item_move:
431  * @item: A canvas item.
432  * @dx: Horizontal offset.
433  * @dy: Vertical offset.
434  **/
435 void
ganv_item_move(GanvItem * item,double dx,double dy)436 ganv_item_move(GanvItem* item, double dx, double dy)
437 {
438 	if (!item || !GANV_IS_ITEM(item)) {
439 		return;
440 	}
441 
442 	item->impl->x += dx;
443 	item->impl->y += dy;
444 
445 	ganv_item_request_update(item);
446 	ganv_canvas_set_need_repick(item->impl->canvas);
447 }
448 
449 /**
450  * ganv_item_show:
451  * @item: A canvas item.
452  *
453  * Shows a canvas item.  If the item was already shown, then no action is taken.
454  **/
455 void
ganv_item_show(GanvItem * item)456 ganv_item_show(GanvItem* item)
457 {
458 	g_return_if_fail(GANV_IS_ITEM(item));
459 
460 	if (!(item->object.flags & GANV_ITEM_VISIBLE)) {
461 		item->object.flags |= GANV_ITEM_VISIBLE;
462 		ganv_canvas_request_redraw_w(item->impl->canvas,
463 		                             item->impl->x1, item->impl->y1,
464 		                             item->impl->x2 + 1, item->impl->y2 + 1);
465 		ganv_canvas_set_need_repick(item->impl->canvas);
466 	}
467 }
468 
469 /**
470  * ganv_item_hide:
471  * @item: A canvas item.
472  *
473  * Hides a canvas item.  If the item was already hidden, then no action is
474  * taken.
475  **/
476 void
ganv_item_hide(GanvItem * item)477 ganv_item_hide(GanvItem* item)
478 {
479 	g_return_if_fail(GANV_IS_ITEM(item));
480 
481 	if (item->object.flags & GANV_ITEM_VISIBLE) {
482 		item->object.flags &= ~GANV_ITEM_VISIBLE;
483 		ganv_canvas_request_redraw_w(item->impl->canvas,
484 		                             item->impl->x1, item->impl->y1,
485 		                             item->impl->x2 + 1, item->impl->y2 + 1);
486 		ganv_canvas_set_need_repick(item->impl->canvas);
487 	}
488 }
489 
490 void
ganv_item_i2w_offset(GanvItem * item,double * px,double * py)491 ganv_item_i2w_offset(GanvItem* item, double* px, double* py)
492 {
493 	double x = 0.0;
494 	double y = 0.0;
495 	while (item) {
496 		x += item->impl->x;
497 		y += item->impl->y;
498 		item = item->impl->parent;
499 	}
500 	*px = x;
501 	*py = y;
502 }
503 
504 /**
505  * ganv_item_i2w:
506  * @item: A canvas item.
507  * @x: X coordinate to convert (input/output value).
508  * @y: Y coordinate to convert (input/output value).
509  *
510  * Converts a coordinate pair from item-relative coordinates to world
511  * coordinates.
512  **/
513 void
ganv_item_i2w(GanvItem * item,double * x,double * y)514 ganv_item_i2w(GanvItem* item, double* x, double* y)
515 {
516 	/*g_return_if_fail(GANV_IS_ITEM(item));
517 	  g_return_if_fail(x != NULL);
518 	  g_return_if_fail(y != NULL);*/
519 
520 	double off_x = 0.0;
521 	double off_y = 0.0;
522 	ganv_item_i2w_offset(item, &off_x, &off_y);
523 
524 	*x += off_x;
525 	*y += off_y;
526 }
527 
528 void
ganv_item_i2w_pair(GanvItem * item,double * x1,double * y1,double * x2,double * y2)529 ganv_item_i2w_pair(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
530 {
531 	double off_x = 0.0;
532 	double off_y = 0.0;
533 	ganv_item_i2w_offset(item, &off_x, &off_y);
534 
535 	*x1 += off_x;
536 	*y1 += off_y;
537 	*x2 += off_x;
538 	*y2 += off_y;
539 }
540 
541 /**
542  * ganv_item_w2i:
543  * @item: A canvas item.
544  * @x: X coordinate to convert (input/output value).
545  * @y: Y coordinate to convert (input/output value).
546  *
547  * Converts a coordinate pair from world coordinates to item-relative
548  * coordinates.
549  **/
550 void
ganv_item_w2i(GanvItem * item,double * x,double * y)551 ganv_item_w2i(GanvItem* item, double* x, double* y)
552 {
553 	double off_x = 0.0;
554 	double off_y = 0.0;
555 	ganv_item_i2w_offset(item, &off_x, &off_y);
556 
557 	*x -= off_x;
558 	*y -= off_y;
559 }
560 
561 /**
562  * ganv_item_grab_focus:
563  * @item: A canvas item.
564  *
565  * Makes the specified item take the keyboard focus, so all keyboard events will
566  * be sent to it.  If the canvas widget itself did not have the focus, it grabs
567  * it as well.
568  **/
569 void
ganv_item_grab_focus(GanvItem * item)570 ganv_item_grab_focus(GanvItem* item)
571 {
572 	ganv_canvas_grab_focus(item->impl->canvas, item);
573 }
574 
575 void
ganv_item_emit_event(GanvItem * item,GdkEvent * event,gint * finished)576 ganv_item_emit_event(GanvItem* item, GdkEvent* event, gint* finished)
577 {
578 	g_signal_emit(item, item_signals[ITEM_EVENT], 0, event, finished);
579 }
580 
581 static void
ganv_item_default_bounds(GanvItem * item,double * x1,double * y1,double * x2,double * y2)582 ganv_item_default_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
583 {
584 	(void)item;
585 
586 	*x1 = *y1 = *x2 = *y2 = 0.0;
587 }
588 
589 /**
590  * ganv_item_get_bounds:
591  * @item: A canvas item.
592  * @x1: Leftmost edge of the bounding box (return value).
593  * @y1: Upper edge of the bounding box (return value).
594  * @x2: Rightmost edge of the bounding box (return value).
595  * @y2: Lower edge of the bounding box (return value).
596  *
597  * Queries the bounding box of a canvas item.  The bounding box may not be
598  * exactly tight, but the canvas items will do the best they can.  The bounds
599  * are returned in the coordinate system of the item's parent.
600  **/
601 void
ganv_item_get_bounds(GanvItem * item,double * x1,double * y1,double * x2,double * y2)602 ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
603 {
604 	GANV_ITEM_GET_CLASS(item)->bounds(item, x1, y1, x2, y2);
605 }
606 
607 /**
608  * ganv_item_request_update:
609  * @item: A canvas item.
610  *
611  * To be used only by item implementations.  Requests that the canvas queue an
612  * update for the specified item.
613  **/
614 void
ganv_item_request_update(GanvItem * item)615 ganv_item_request_update(GanvItem* item)
616 {
617 	if (!item->impl->canvas) {
618 		/* Item is being / has been destroyed, ignore */
619 		return;
620 	}
621 
622 	item->object.flags |= GANV_ITEM_NEED_UPDATE;
623 
624 	if (item->impl->parent != NULL &&
625 	    !(item->impl->parent->object.flags & GANV_ITEM_NEED_UPDATE)) {
626 		/* Recurse up the tree */
627 		ganv_item_request_update(item->impl->parent);
628 	} else {
629 		/* Have reached the top of the tree, make sure the update call gets scheduled. */
630 		ganv_canvas_request_update(item->impl->canvas);
631 	}
632 }
633 
634 void
ganv_item_set_wrapper(GanvItem * item,void * wrapper)635 ganv_item_set_wrapper(GanvItem* item, void* wrapper)
636 {
637 	item->impl->wrapper = wrapper;
638 }
639 
640 void*
ganv_item_get_wrapper(GanvItem * item)641 ganv_item_get_wrapper(GanvItem* item)
642 {
643 	return item->impl->wrapper;
644 }
645 
646 static gboolean
boolean_handled_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)647 boolean_handled_accumulator(GSignalInvocationHint* ihint,
648                             GValue*                return_accu,
649                             const GValue*          handler_return,
650                             gpointer               dummy)
651 {
652 	(void)ihint;
653 	(void)dummy;
654 
655 	gboolean continue_emission = FALSE;
656 	gboolean signal_handled    = FALSE;
657 
658 	signal_handled = g_value_get_boolean(handler_return);
659 	g_value_set_boolean(return_accu, signal_handled);
660 	continue_emission = !signal_handled;
661 
662 	return continue_emission;
663 }
664 
665 /* Class initialization function for GanvItemClass */
666 static void
ganv_item_class_init(GanvItemClass * klass)667 ganv_item_class_init(GanvItemClass* klass)
668 {
669 	GObjectClass* gobject_class = (GObjectClass*)klass;
670 
671 	item_parent_class = (GtkObjectClass*)g_type_class_peek_parent(klass);
672 
673 	gobject_class->set_property = ganv_item_set_property;
674 	gobject_class->get_property = ganv_item_get_property;
675 
676 	g_object_class_install_property
677 		(gobject_class, ITEM_PROP_PARENT,
678 		 g_param_spec_object("parent", NULL, NULL,
679 		                     GANV_TYPE_ITEM,
680 		                     (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
681 
682 	g_object_class_install_property
683 		(gobject_class, ITEM_PROP_X,
684 		 g_param_spec_double("x",
685 		                     _("X"),
686 		                     _("X"),
687 		                     -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
688 		                     (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
689 	g_object_class_install_property
690 		(gobject_class, ITEM_PROP_Y,
691 		 g_param_spec_double("y",
692 		                     _("Y"),
693 		                     _("Y"),
694 		                     -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
695 		                     (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
696 
697 	g_object_class_install_property
698 		(gobject_class, ITEM_PROP_MANAGED,
699 		 g_param_spec_boolean("managed",
700 		                      _("Managed"),
701 		                      _("Whether the item is managed by its parent"),
702 		                      0,
703 		                      (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
704 
705 	item_signals[ITEM_EVENT]
706 		= g_signal_new("event",
707 		               G_TYPE_FROM_CLASS(klass),
708 		               G_SIGNAL_RUN_LAST,
709 		               G_STRUCT_OFFSET(GanvItemClass, event),
710 		               boolean_handled_accumulator, NULL,
711 		               ganv_marshal_BOOLEAN__BOXED,
712 		               G_TYPE_BOOLEAN, 1,
713 		               GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
714 
715 	gobject_class->dispose = ganv_item_dispose;
716 
717 	klass->realize   = ganv_item_realize;
718 	klass->unrealize = ganv_item_unrealize;
719 	klass->map       = ganv_item_map;
720 	klass->unmap     = ganv_item_unmap;
721 	klass->update    = ganv_item_update;
722 	klass->point     = ganv_item_point;
723 	klass->bounds    = ganv_item_default_bounds;
724 }
725