1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
3 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
6 * This file is part of the Gnome Library.
8 * The Gnome Library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * The Gnome Library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with the Gnome Library; see the file COPYING.LIB. If not,
20 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
27 * FooCanvas widget - Tk-like canvas widget for Gnome
29 * FooCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
30 * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
33 * Authors: Federico Mena <federico@nuclecu.unam.mx>
34 * Raph Levien <raph@gimp.org>
38 * TO-DO list for the canvas:
40 * - Allow to specify whether FooCanvasImage sizes are in units or pixels (scale or don't scale).
42 * - Implement a flag for foo_canvas_item_reparent() that tells the function to keep the item
43 * visually in the same place, that is, to keep it in the same place with respect to the canvas
46 * - GC put functions for items.
48 * - Widget item (finish it).
50 * - GList *foo_canvas_gimme_all_items_contained_in_this_area (FooCanvas *canvas, Rectangle area);
52 * - Retrofit all the primitive items with microtile support.
54 * - Curve support for line item.
56 * - Arc item (Havoc has it; to be integrated in FooCanvasEllipse).
58 * - Sane font handling API.
60 * - Get_arg methods for items:
61 * - How to fetch the outline width and know whether it is in pixels or units?
69 #include <gdk/gdkprivate.h>
71 #include "foo-canvas.h"
72 #include "foo-canvas-i18n.h"
74 #include "foo-canvas-marshal.h"
76 static void foo_canvas_request_update (FooCanvas
*canvas
);
77 static void group_add (FooCanvasGroup
*group
,
79 static void group_remove (FooCanvasGroup
*group
,
81 static void redraw_and_repick_if_mapped (FooCanvasItem
*item
);
83 /*** FooCanvasItem ***/
85 /* Some convenience stuff */
86 #define GCI_UPDATE_MASK (FOO_CANVAS_UPDATE_REQUESTED | FOO_CANVAS_UPDATE_DEEP)
87 #define GCI_EPSILON 1e-18
100 static void foo_canvas_item_class_init (FooCanvasItemClass
*klass
);
101 static void foo_canvas_item_init (FooCanvasItem
*item
);
102 static int emit_event (FooCanvas
*canvas
, GdkEvent
*event
);
104 static guint item_signals
[ITEM_LAST_SIGNAL
];
106 static GtkObjectClass
*item_parent_class
;
108 static gpointer accessible_item_parent_class
;
109 static gpointer accessible_parent_class
;
113 * foo_canvas_item_get_type:
115 * Registers the &FooCanvasItem class if necessary, and returns the type ID
118 * Return value: The type ID of the &FooCanvasItem class.
121 foo_canvas_item_get_type (void)
123 static GType canvas_item_type
= 0;
125 if (!canvas_item_type
) {
126 static const GTypeInfo canvas_item_info
= {
127 sizeof (FooCanvasItemClass
),
128 (GBaseInitFunc
) NULL
,
129 (GBaseFinalizeFunc
) NULL
,
130 (GClassInitFunc
) foo_canvas_item_class_init
,
131 NULL
, /* class_finalize */
132 NULL
, /* class_data */
133 sizeof (FooCanvasItem
),
135 (GInstanceInitFunc
) foo_canvas_item_init
138 canvas_item_type
= g_type_register_static (gtk_object_get_type (),
144 return canvas_item_type
;
147 /* Object initialization function for FooCanvasItem */
149 foo_canvas_item_init (FooCanvasItem
*item
)
151 item
->object
.flags
|= FOO_CANVAS_ITEM_VISIBLE
;
155 * foo_canvas_item_new:
156 * @parent: The parent group for the new item.
157 * @type: The object type of the item.
158 * @first_arg_name: A list of object argument name/value pairs, NULL-terminated,
159 * used to configure the item. For example, "fill_color", "black",
160 * "width_units", 5.0, NULL.
163 * Creates a new canvas item with @parent as its parent group. The item is
164 * created at the top of its parent's stack, and starts up as visible. The item
165 * is of the specified @type, for example, it can be
166 * foo_canvas_rect_get_type(). The list of object arguments/value pairs is
167 * used to configure the item.
169 * Return value: The newly-created item.
172 foo_canvas_item_new (FooCanvasGroup
*parent
, GType type
, const gchar
*first_arg_name
, ...)
177 g_return_val_if_fail (FOO_IS_CANVAS_GROUP (parent
), NULL
);
178 g_return_val_if_fail (g_type_is_a (type
, foo_canvas_item_get_type ()), NULL
);
180 item
= FOO_CANVAS_ITEM (g_object_new (type
, NULL
));
182 va_start (args
, first_arg_name
);
183 foo_canvas_item_construct (item
, parent
, first_arg_name
, args
);
190 /* Performs post-creation operations on a canvas item (adding it to its parent
194 item_post_create_setup (FooCanvasItem
*item
)
196 group_add (FOO_CANVAS_GROUP (item
->parent
), item
);
198 redraw_and_repick_if_mapped (item
);
201 /* Set_property handler for canvas items */
203 foo_canvas_item_set_property (GObject
*gobject
, guint param_id
,
204 const GValue
*value
, GParamSpec
*pspec
)
208 g_return_if_fail (FOO_IS_CANVAS_ITEM (gobject
));
210 item
= FOO_CANVAS_ITEM (gobject
);
213 case ITEM_PROP_PARENT
:
214 if (item
->parent
!= NULL
) {
215 g_warning ("Cannot set `parent' argument after item has "
216 "already been constructed.");
217 } else if (g_value_get_object (value
)) {
218 item
->parent
= FOO_CANVAS_ITEM (g_value_get_object (value
));
219 item
->canvas
= item
->parent
->canvas
;
220 item_post_create_setup (item
);
223 case ITEM_PROP_VISIBLE
:
224 if (g_value_get_boolean (value
)) {
225 foo_canvas_item_show (item
);
227 foo_canvas_item_hide (item
);
231 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, param_id
, pspec
);
236 /* Get_property handler for canvas items */
238 foo_canvas_item_get_property (GObject
*gobject
, guint param_id
,
239 GValue
*value
, GParamSpec
*pspec
)
243 g_return_if_fail (FOO_IS_CANVAS_ITEM (gobject
));
245 item
= FOO_CANVAS_ITEM (gobject
);
248 case ITEM_PROP_VISIBLE
:
249 g_value_set_boolean (value
, item
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
);
252 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, param_id
, pspec
);
258 * foo_canvas_item_construct:
259 * @item: An unconstructed canvas item.
260 * @parent: The parent group for the item.
261 * @first_arg_name: The name of the first argument for configuring the item.
262 * @args: The list of arguments used to configure the item.
264 * Constructs a canvas item; meant for use only by item implementations.
267 foo_canvas_item_construct (FooCanvasItem
*item
, FooCanvasGroup
*parent
,
268 const gchar
*first_arg_name
, va_list args
)
270 g_return_if_fail (FOO_IS_CANVAS_GROUP (parent
));
271 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
273 item
->parent
= FOO_CANVAS_ITEM (parent
);
274 item
->canvas
= item
->parent
->canvas
;
276 g_object_set_valist (G_OBJECT (item
), first_arg_name
, args
);
278 item_post_create_setup (item
);
283 redraw_and_repick_if_mapped (FooCanvasItem
*item
)
285 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
) {
286 foo_canvas_item_request_redraw (item
);
287 item
->canvas
->need_repick
= TRUE
;
291 /* Dispose handler for canvas items */
293 foo_canvas_item_dispose (GObject
*object
)
297 g_return_if_fail (FOO_IS_CANVAS_ITEM (object
));
299 item
= FOO_CANVAS_ITEM (object
);
302 foo_canvas_item_request_redraw (item
);
304 /* Make the canvas forget about us */
306 if (item
== item
->canvas
->current_item
) {
307 item
->canvas
->current_item
= NULL
;
308 item
->canvas
->need_repick
= TRUE
;
311 if (item
== item
->canvas
->new_current_item
) {
312 item
->canvas
->new_current_item
= NULL
;
313 item
->canvas
->need_repick
= TRUE
;
316 if (item
== item
->canvas
->grabbed_item
) {
317 GdkDisplay
*display
= gtk_widget_get_display (GTK_WIDGET (item
->canvas
));
318 item
->canvas
->grabbed_item
= NULL
;
319 gdk_display_pointer_ungrab (display
, GDK_CURRENT_TIME
);
322 if (item
== item
->canvas
->focused_item
)
323 item
->canvas
->focused_item
= NULL
;
325 /* Normal destroy stuff */
327 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
328 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
330 if (item
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
)
331 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unrealize
) (item
);
334 group_remove (FOO_CANVAS_GROUP (item
->parent
), item
);
339 G_OBJECT_CLASS (item_parent_class
)->dispose (object
);
343 /* Realize handler for canvas items */
345 foo_canvas_item_realize (FooCanvasItem
*item
)
347 if (item
->parent
&& !(item
->parent
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
))
348 (* FOO_CANVAS_ITEM_GET_CLASS (item
->parent
)->realize
) (item
->parent
);
350 if (item
->parent
== NULL
&& !gtk_widget_get_realized (GTK_WIDGET (item
->canvas
)))
351 gtk_widget_realize (GTK_WIDGET (item
->canvas
));
353 GTK_OBJECT_SET_FLAGS (item
, FOO_CANVAS_ITEM_REALIZED
);
355 foo_canvas_item_request_update (item
);
358 /* Unrealize handler for canvas items */
360 foo_canvas_item_unrealize (FooCanvasItem
*item
)
362 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
363 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
365 GTK_OBJECT_UNSET_FLAGS (item
, FOO_CANVAS_ITEM_REALIZED
);
368 /* Map handler for canvas items */
370 foo_canvas_item_map (FooCanvasItem
*item
)
372 GTK_OBJECT_SET_FLAGS (item
, FOO_CANVAS_ITEM_MAPPED
);
375 /* Unmap handler for canvas items */
377 foo_canvas_item_unmap (FooCanvasItem
*item
)
379 GTK_OBJECT_UNSET_FLAGS (item
, FOO_CANVAS_ITEM_MAPPED
);
382 /* Update handler for canvas items */
384 foo_canvas_item_update (FooCanvasItem
*item
, double i2w_dx
, double i2w_dy
, int flags
)
386 GTK_OBJECT_UNSET_FLAGS (item
, FOO_CANVAS_ITEM_NEED_UPDATE
);
387 GTK_OBJECT_UNSET_FLAGS (item
, FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
);
391 * This routine invokes the update method of the item
392 * Please notice, that we take parent to canvas pixel matrix as argument
393 * unlike virtual method ::update, whose argument is item 2 canvas pixel
396 * I will try to force somewhat meaningful naming for affines (Lauris)
397 * General naming rule is FROM2TO, where FROM and TO are abbreviations
398 * So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel
399 * I hope that this helps to keep track of what really happens
404 foo_canvas_item_invoke_update (FooCanvasItem
*item
,
413 /* apply object flags to child flags */
414 child_flags
&= ~FOO_CANVAS_UPDATE_REQUESTED
;
416 if (item
->object
.flags
& FOO_CANVAS_ITEM_NEED_UPDATE
)
417 child_flags
|= FOO_CANVAS_UPDATE_REQUESTED
;
419 if (item
->object
.flags
& FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
)
420 child_flags
|= FOO_CANVAS_UPDATE_DEEP
;
422 if (child_flags
& GCI_UPDATE_MASK
) {
423 if (FOO_CANVAS_ITEM_GET_CLASS (item
)->update
)
424 FOO_CANVAS_ITEM_GET_CLASS (item
)->update (item
, i2w_dx
, i2w_dy
, child_flags
);
427 /* If this fail you probably forgot to chain up to
428 * FooCanvasItem::update from a derived class */
429 g_return_if_fail (!(item
->object
.flags
& FOO_CANVAS_ITEM_NEED_UPDATE
));
433 * This routine invokes the point method of the item.
434 * The arguments x, y should be in the parent item local coordinates.
438 foo_canvas_item_invoke_point (FooCanvasItem
*item
, double x
, double y
, int cx
, int cy
, FooCanvasItem
**actual_item
)
440 /* Calculate x & y in item local coordinates */
442 if (FOO_CANVAS_ITEM_GET_CLASS (item
)->point
)
443 return FOO_CANVAS_ITEM_GET_CLASS (item
)->point (item
, x
, y
, cx
, cy
, actual_item
);
449 * foo_canvas_item_set:
450 * @item: A canvas item.
451 * @first_arg_name: The list of object argument name/value pairs used to configure the item.
454 * Configures a canvas item. The arguments in the item are set to the specified
455 * values, and the item is repainted as appropriate.
458 foo_canvas_item_set (FooCanvasItem
*item
, const gchar
*first_arg_name
, ...)
462 va_start (args
, first_arg_name
);
463 foo_canvas_item_set_valist (item
, first_arg_name
, args
);
469 * foo_canvas_item_set_valist:
470 * @item: A canvas item.
471 * @first_arg_name: The name of the first argument used to configure the item.
472 * @args: The list of object argument name/value pairs used to configure the item.
474 * Configures a canvas item. The arguments in the item are set to the specified
475 * values, and the item is repainted as appropriate.
478 foo_canvas_item_set_valist (FooCanvasItem
*item
, const gchar
*first_arg_name
, va_list args
)
480 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
482 g_object_set_valist (G_OBJECT (item
), first_arg_name
, args
);
485 /* I commented this out, because item implementations have to schedule update/redraw */
486 foo_canvas_item_request_redraw (item
);
489 item
->canvas
->need_repick
= TRUE
;
494 * foo_canvas_item_move:
495 * @item: A canvas item.
496 * @dx: Horizontal offset.
497 * @dy: Vertical offset.
499 * Moves a canvas item by creating an affine transformation matrix for
500 * translation by using the specified values. This happens in item
501 * local coordinate system, so if you have nontrivial transform, it
502 * most probably does not do, what you want.
505 foo_canvas_item_move (FooCanvasItem
*item
, double dx
, double dy
)
507 g_return_if_fail (item
!= NULL
);
508 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
510 if (!FOO_CANVAS_ITEM_GET_CLASS (item
)->translate
) {
511 g_warning ("Item type %s does not implement translate method.\n",
512 g_type_name (G_OBJECT_TYPE (item
)));
516 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->translate
) (item
, dx
, dy
);
518 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
519 item
->canvas
->need_repick
= TRUE
;
521 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
)) {
522 item
->object
.flags
|= FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
;
523 if (item
->parent
!= NULL
)
524 foo_canvas_item_request_update (item
->parent
);
526 foo_canvas_request_update (item
->canvas
);
531 /* Convenience function to reorder items in a group's child list. This puts the
532 * specified link after the "before" link. Returns TRUE if the list was changed.
535 put_item_after (GList
*link
, GList
*before
)
537 FooCanvasGroup
*parent
;
542 parent
= FOO_CANVAS_GROUP (FOO_CANVAS_ITEM (link
->data
)->parent
);
544 if (before
== NULL
) {
545 if (link
== parent
->item_list
)
548 link
->prev
->next
= link
->next
;
551 link
->next
->prev
= link
->prev
;
553 parent
->item_list_end
= link
->prev
;
556 link
->next
= parent
->item_list
;
557 link
->next
->prev
= link
;
558 parent
->item_list
= link
;
560 if ((link
== parent
->item_list_end
) && (before
== parent
->item_list_end
->prev
))
564 link
->next
->prev
= link
->prev
;
567 link
->prev
->next
= link
->next
;
569 parent
->item_list
= link
->next
;
570 parent
->item_list
->prev
= NULL
;
574 link
->next
= before
->next
;
576 link
->prev
->next
= link
;
579 link
->next
->prev
= link
;
581 parent
->item_list_end
= link
;
588 * foo_canvas_item_raise:
589 * @item: A canvas item.
590 * @positions: Number of steps to raise the item.
592 * Raises the item in its parent's stack by the specified number of positions.
593 * If the number of positions is greater than the distance to the top of the
594 * stack, then the item is put at the top.
597 foo_canvas_item_raise (FooCanvasItem
*item
, int positions
)
599 GList
*link
, *before
;
600 FooCanvasGroup
*parent
;
602 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
603 g_return_if_fail (positions
>= 0);
605 if (!item
->parent
|| positions
== 0)
608 parent
= FOO_CANVAS_GROUP (item
->parent
);
609 link
= g_list_find (parent
->item_list
, item
);
610 g_assert (link
!= NULL
);
612 for (before
= link
; positions
&& before
; positions
--)
613 before
= before
->next
;
616 before
= parent
->item_list_end
;
618 if (put_item_after (link
, before
)) {
619 redraw_and_repick_if_mapped (item
);
625 * foo_canvas_item_lower:
626 * @item: A canvas item.
627 * @positions: Number of steps to lower the item.
629 * Lowers the item in its parent's stack by the specified number of positions.
630 * If the number of positions is greater than the distance to the bottom of the
631 * stack, then the item is put at the bottom.
634 foo_canvas_item_lower (FooCanvasItem
*item
, int positions
)
636 GList
*link
, *before
;
637 FooCanvasGroup
*parent
;
639 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
640 g_return_if_fail (positions
>= 1);
642 if (!item
->parent
|| positions
== 0)
645 parent
= FOO_CANVAS_GROUP (item
->parent
);
646 link
= g_list_find (parent
->item_list
, item
);
647 g_assert (link
!= NULL
);
650 for (before
= link
->prev
; positions
&& before
; positions
--)
651 before
= before
->prev
;
655 if (put_item_after (link
, before
)) {
656 redraw_and_repick_if_mapped (item
);
662 * foo_canvas_item_raise_to_top:
663 * @item: A canvas item.
665 * Raises an item to the top of its parent's stack.
668 foo_canvas_item_raise_to_top (FooCanvasItem
*item
)
671 FooCanvasGroup
*parent
;
673 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
678 parent
= FOO_CANVAS_GROUP (item
->parent
);
679 link
= g_list_find (parent
->item_list
, item
);
680 g_assert (link
!= NULL
);
682 if (put_item_after (link
, parent
->item_list_end
)) {
683 redraw_and_repick_if_mapped (item
);
689 * foo_canvas_item_lower_to_bottom:
690 * @item: A canvas item.
692 * Lowers an item to the bottom of its parent's stack.
695 foo_canvas_item_lower_to_bottom (FooCanvasItem
*item
)
698 FooCanvasGroup
*parent
;
700 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
705 parent
= FOO_CANVAS_GROUP (item
->parent
);
706 link
= g_list_find (parent
->item_list
, item
);
707 g_assert (link
!= NULL
);
709 if (put_item_after (link
, NULL
)) {
710 redraw_and_repick_if_mapped (item
);
715 * foo_canvas_item_send_behind:
716 * @item: A canvas item.
717 * @behind_item: The canvas item to put item behind, or NULL
719 * Moves item to a in the position in the stacking order so that
720 * it is placed immediately below behind_item, or at the top if
721 * behind_item is NULL.
724 foo_canvas_item_send_behind (FooCanvasItem
*item
,
725 FooCanvasItem
*behind_item
)
728 int item_position
, behind_position
;
730 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
732 if (behind_item
== NULL
) {
733 foo_canvas_item_raise_to_top (item
);
737 g_return_if_fail (FOO_IS_CANVAS_ITEM (behind_item
));
738 g_return_if_fail (item
->parent
== behind_item
->parent
);
740 item_list
= FOO_CANVAS_GROUP (item
->parent
)->item_list
;
742 item_position
= g_list_index (item_list
, item
);
743 g_assert (item_position
!= -1);
744 behind_position
= g_list_index (item_list
, behind_item
);
745 g_assert (behind_position
!= -1);
746 g_assert (item_position
!= behind_position
);
748 if (item_position
== behind_position
- 1) {
752 if (item_position
< behind_position
) {
753 foo_canvas_item_raise (item
, (behind_position
- 1) - item_position
);
755 foo_canvas_item_lower (item
, item_position
- behind_position
);
760 * foo_canvas_item_show:
761 * @item: A canvas item.
763 * Shows a canvas item. If the item was already shown, then no action is taken.
766 foo_canvas_item_show (FooCanvasItem
*item
)
768 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
770 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
)) {
771 item
->object
.flags
|= FOO_CANVAS_ITEM_VISIBLE
;
773 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
))
774 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->realize
) (item
);
776 if (item
->parent
!= NULL
) {
777 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
) &&
778 item
->parent
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
779 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->map
) (item
);
781 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
) &&
782 gtk_widget_get_mapped (GTK_WIDGET (item
->canvas
)))
783 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->map
) (item
);
786 redraw_and_repick_if_mapped (item
);
792 * foo_canvas_item_hide:
793 * @item: A canvas item.
795 * Hides a canvas item. If the item was already hidden, then no action is
799 foo_canvas_item_hide (FooCanvasItem
*item
)
801 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
803 if (item
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
) {
804 item
->object
.flags
&= ~FOO_CANVAS_ITEM_VISIBLE
;
806 redraw_and_repick_if_mapped (item
);
808 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
809 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
811 /* No need to unrealize when we just want to hide */
817 * foo_canvas_item_grab:
818 * @item: A canvas item.
819 * @event_mask: Mask of events that will be sent to this item.
820 * @cursor: If non-NULL, the cursor that will be used while the grab is active.
821 * @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME.
823 * Specifies that all events that match the specified event mask should be sent
824 * to the specified item, and also grabs the mouse by calling
825 * gdk_pointer_grab(). The event mask is also used when grabbing the pointer.
826 * If @cursor is not NULL, then that cursor is used while the grab is active.
827 * The @etime parameter is the timestamp required for grabbing the mouse.
829 * Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED. If
830 * the specified item was hidden by calling foo_canvas_item_hide(), then it
831 * returns %GDK_GRAB_NOT_VIEWABLE. Else, it returns the result of calling
832 * gdk_pointer_grab().
835 foo_canvas_item_grab (FooCanvasItem
*item
, guint event_mask
, GdkCursor
*cursor
, guint32 etime
)
839 g_return_val_if_fail (FOO_IS_CANVAS_ITEM (item
), GDK_GRAB_NOT_VIEWABLE
);
840 g_return_val_if_fail (gtk_widget_get_mapped (GTK_WIDGET (item
->canvas
)), GDK_GRAB_NOT_VIEWABLE
);
842 if (item
->canvas
->grabbed_item
)
843 return GDK_GRAB_ALREADY_GRABBED
;
845 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
))
846 return GDK_GRAB_NOT_VIEWABLE
;
848 retval
= gdk_pointer_grab (item
->canvas
->layout
.bin_window
,
855 if (retval
!= GDK_GRAB_SUCCESS
)
858 item
->canvas
->grabbed_item
= item
;
859 item
->canvas
->grabbed_event_mask
= event_mask
;
860 item
->canvas
->current_item
= item
; /* So that events go to the grabbed item */
867 * foo_canvas_item_ungrab:
868 * @item: A canvas item that holds a grab.
869 * @etime: The timestamp for ungrabbing the mouse.
871 * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the
875 foo_canvas_item_ungrab (FooCanvasItem
*item
, guint32 etime
)
879 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
881 if (item
->canvas
->grabbed_item
!= item
)
884 display
= gtk_widget_get_display (GTK_WIDGET (item
->canvas
));
885 item
->canvas
->grabbed_item
= NULL
;
886 gdk_display_pointer_ungrab (display
, etime
);
891 * foo_canvas_item_w2i:
892 * @item: A canvas item.
893 * @x: X coordinate to convert (input/output value).
894 * @y: Y coordinate to convert (input/output value).
896 * Converts a coordinate pair from world coordinates to item-relative
900 foo_canvas_item_w2i (FooCanvasItem
*item
, double *x
, double *y
)
902 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
903 g_return_if_fail (x
!= NULL
);
904 g_return_if_fail (y
!= NULL
);
908 if (FOO_IS_CANVAS_GROUP (item
)) {
909 *x
-= FOO_CANVAS_GROUP (item
)->xpos
;
910 *y
-= FOO_CANVAS_GROUP (item
)->ypos
;
919 * foo_canvas_item_i2w:
920 * @item: A canvas item.
921 * @x: X coordinate to convert (input/output value).
922 * @y: Y coordinate to convert (input/output value).
924 * Converts a coordinate pair from item-relative coordinates to world
928 foo_canvas_item_i2w (FooCanvasItem
*item
, double *x
, double *y
)
930 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
931 g_return_if_fail (x
!= NULL
);
932 g_return_if_fail (y
!= NULL
);
936 if (FOO_IS_CANVAS_GROUP (item
)) {
937 *x
+= FOO_CANVAS_GROUP (item
)->xpos
;
938 *y
+= FOO_CANVAS_GROUP (item
)->ypos
;
945 /* Returns whether the item is an inferior of or is equal to the parent. */
947 is_descendant (FooCanvasItem
*item
, FooCanvasItem
*parent
)
949 for (; item
; item
= item
->parent
)
957 * foo_canvas_item_reparent:
958 * @item: A canvas item.
959 * @new_group: A canvas group.
961 * Changes the parent of the specified item to be the new group. The item keeps
962 * its group-relative coordinates as for its old parent, so the item may change
963 * its absolute position within the canvas.
966 foo_canvas_item_reparent (FooCanvasItem
*item
, FooCanvasGroup
*new_group
)
968 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
969 g_return_if_fail (FOO_IS_CANVAS_GROUP (new_group
));
971 /* Both items need to be in the same canvas */
972 g_return_if_fail (item
->canvas
== FOO_CANVAS_ITEM (new_group
)->canvas
);
974 /* The group cannot be an inferior of the item or be the item itself --
975 * this also takes care of the case where the item is the root item of
977 g_return_if_fail (!is_descendant (FOO_CANVAS_ITEM (new_group
), item
));
979 /* Everything is ok, now actually reparent the item */
981 g_object_ref (G_OBJECT (item
)); /* protect it from the unref in group_remove */
983 foo_canvas_item_request_redraw (item
);
985 group_remove (FOO_CANVAS_GROUP (item
->parent
), item
);
986 item
->parent
= FOO_CANVAS_ITEM (new_group
);
987 /* item->canvas is unchanged. */
988 group_add (new_group
, item
);
990 /* Redraw and repick */
992 redraw_and_repick_if_mapped (item
);
994 g_object_unref (G_OBJECT (item
));
998 * foo_canvas_item_grab_focus:
999 * @item: A canvas item.
1001 * Makes the specified item take the keyboard focus, so all keyboard events will
1002 * be sent to it. If the canvas widget itself did not have the focus, it grabs
1006 foo_canvas_item_grab_focus (FooCanvasItem
*item
)
1008 FooCanvasItem
*focused_item
;
1011 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
1012 g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item
->canvas
)));
1014 focused_item
= item
->canvas
->focused_item
;
1017 ev
.focus_change
.type
= GDK_FOCUS_CHANGE
;
1018 ev
.focus_change
.window
= GTK_LAYOUT (item
->canvas
)->bin_window
;
1019 ev
.focus_change
.send_event
= FALSE
;
1020 ev
.focus_change
.in
= FALSE
;
1022 emit_event (item
->canvas
, &ev
);
1025 item
->canvas
->focused_item
= item
;
1026 gtk_widget_grab_focus (GTK_WIDGET (item
->canvas
));
1029 ev
.focus_change
.type
= GDK_FOCUS_CHANGE
;
1030 ev
.focus_change
.window
= GTK_LAYOUT (item
->canvas
)->bin_window
;
1031 ev
.focus_change
.send_event
= FALSE
;
1032 ev
.focus_change
.in
= TRUE
;
1034 emit_event (item
->canvas
, &ev
);
1040 * foo_canvas_item_get_bounds:
1041 * @item: A canvas item.
1042 * @x1: Leftmost edge of the bounding box (return value).
1043 * @y1: Upper edge of the bounding box (return value).
1044 * @x2: Rightmost edge of the bounding box (return value).
1045 * @y2: Lower edge of the bounding box (return value).
1047 * Queries the bounding box of a canvas item. The bounds are returned in the
1048 * coordinate system of the item's parent.
1051 foo_canvas_item_get_bounds (FooCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
)
1053 double tx1
, ty1
, tx2
, ty2
;
1055 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
1057 tx1
= ty1
= tx2
= ty2
= 0.0;
1059 /* Get the item's bounds in its coordinate system */
1061 if (FOO_CANVAS_ITEM_GET_CLASS (item
)->bounds
)
1062 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->bounds
) (item
, &tx1
, &ty1
, &tx2
, &ty2
);
1064 /* Return the values */
1081 * foo_canvas_item_request_update
1082 * @item: A canvas item.
1084 * To be used only by item implementations. Requests that the canvas queue an
1085 * update for the specified item.
1088 foo_canvas_item_request_update (FooCanvasItem
*item
)
1090 if (NULL
== item
->canvas
)
1093 g_return_if_fail (!item
->canvas
->doing_update
);
1095 if (item
->object
.flags
& FOO_CANVAS_ITEM_NEED_UPDATE
)
1098 item
->object
.flags
|= FOO_CANVAS_ITEM_NEED_UPDATE
;
1100 if (item
->parent
!= NULL
) {
1101 /* Recurse up the tree */
1102 foo_canvas_item_request_update (item
->parent
);
1104 /* Have reached the top of the tree, make sure the update call gets scheduled. */
1105 foo_canvas_request_update (item
->canvas
);
1110 * foo_canvas_item_request_update
1111 * @item: A canvas item.
1113 * Convenience function that informs a canvas that the specified item needs
1114 * to be repainted. To be used by item implementations
1117 foo_canvas_item_request_redraw (FooCanvasItem
*item
)
1119 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
1120 foo_canvas_request_redraw (item
->canvas
,
1122 item
->x2
+ 1, item
->y2
+ 1);
1127 /*** FooCanvasGroup ***/
1137 static void foo_canvas_group_class_init (FooCanvasGroupClass
*klass
);
1138 static void foo_canvas_group_init (FooCanvasGroup
*group
);
1139 static void foo_canvas_group_set_property(GObject
*object
,
1141 const GValue
*value
,
1143 static void foo_canvas_group_get_property(GObject
*object
,
1148 static void foo_canvas_group_destroy (GtkObject
*object
);
1150 static void foo_canvas_group_update (FooCanvasItem
*item
,
1154 static void foo_canvas_group_unrealize (FooCanvasItem
*item
);
1155 static void foo_canvas_group_map (FooCanvasItem
*item
);
1156 static void foo_canvas_group_unmap (FooCanvasItem
*item
);
1157 static void foo_canvas_group_draw (FooCanvasItem
*item
, GdkDrawable
*drawable
,
1158 GdkEventExpose
*expose
);
1159 static double foo_canvas_group_point (FooCanvasItem
*item
, double x
, double y
,
1161 FooCanvasItem
**actual_item
);
1162 static void foo_canvas_group_translate (FooCanvasItem
*item
, double dx
, double dy
);
1163 static void foo_canvas_group_bounds (FooCanvasItem
*item
, double *x1
, double *y1
,
1164 double *x2
, double *y2
);
1167 static FooCanvasItemClass
*group_parent_class
;
1171 * foo_canvas_group_get_type:
1173 * Registers the &FooCanvasGroup class if necessary, and returns the type ID
1176 * Return value: The type ID of the &FooCanvasGroup class.
1179 foo_canvas_group_get_type (void)
1181 static GType group_type
= 0;
1184 static const GTypeInfo group_info
= {
1185 sizeof (FooCanvasGroupClass
),
1186 (GBaseInitFunc
) NULL
,
1187 (GBaseFinalizeFunc
) NULL
,
1188 (GClassInitFunc
) foo_canvas_group_class_init
,
1189 NULL
, /* class_finalize */
1190 NULL
, /* class_data */
1191 sizeof (FooCanvasGroup
),
1192 0, /* n_preallocs */
1193 (GInstanceInitFunc
) foo_canvas_group_init
1198 group_type
= g_type_register_static (foo_canvas_item_get_type (),
1207 /* Class initialization function for FooCanvasGroupClass */
1209 foo_canvas_group_class_init (FooCanvasGroupClass
*klass
)
1211 GObjectClass
*gobject_class
;
1212 GtkObjectClass
*object_class
;
1213 FooCanvasItemClass
*item_class
;
1215 gobject_class
= (GObjectClass
*) klass
;
1216 object_class
= (GtkObjectClass
*) klass
;
1217 item_class
= (FooCanvasItemClass
*) klass
;
1219 group_parent_class
= g_type_class_peek_parent (klass
);
1221 gobject_class
->set_property
= foo_canvas_group_set_property
;
1222 gobject_class
->get_property
= foo_canvas_group_get_property
;
1224 g_object_class_install_property
1225 (gobject_class
, GROUP_PROP_X
,
1226 g_param_spec_double ("x",
1229 -G_MAXDOUBLE
, G_MAXDOUBLE
, 0.0,
1230 G_PARAM_READWRITE
));
1231 g_object_class_install_property
1232 (gobject_class
, GROUP_PROP_Y
,
1233 g_param_spec_double ("y",
1236 -G_MAXDOUBLE
, G_MAXDOUBLE
, 0.0,
1237 G_PARAM_READWRITE
));
1239 object_class
->destroy
= foo_canvas_group_destroy
;
1241 item_class
->update
= foo_canvas_group_update
;
1242 item_class
->unrealize
= foo_canvas_group_unrealize
;
1243 item_class
->map
= foo_canvas_group_map
;
1244 item_class
->unmap
= foo_canvas_group_unmap
;
1245 item_class
->draw
= foo_canvas_group_draw
;
1246 item_class
->point
= foo_canvas_group_point
;
1247 item_class
->translate
= foo_canvas_group_translate
;
1248 item_class
->bounds
= foo_canvas_group_bounds
;
1251 /* Object initialization function for FooCanvasGroup */
1253 foo_canvas_group_init (FooCanvasGroup
*group
)
1259 /* Set_property handler for canvas groups */
1261 foo_canvas_group_set_property (GObject
*gobject
, guint param_id
,
1262 const GValue
*value
, GParamSpec
*pspec
)
1264 FooCanvasItem
*item
;
1265 FooCanvasGroup
*group
;
1269 g_return_if_fail (FOO_IS_CANVAS_GROUP (gobject
));
1271 item
= FOO_CANVAS_ITEM (gobject
);
1272 group
= FOO_CANVAS_GROUP (gobject
);
1278 group
->xpos
= g_value_get_double (value
);
1279 if (old
!= group
->xpos
)
1285 group
->ypos
= g_value_get_double (value
);
1286 if (old
!= group
->ypos
)
1291 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, param_id
, pspec
);
1296 item
->object
.flags
|= FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
;
1297 if (item
->parent
!= NULL
)
1298 foo_canvas_item_request_update (item
->parent
);
1300 foo_canvas_request_update (item
->canvas
);
1304 /* Get_property handler for canvas groups */
1306 foo_canvas_group_get_property (GObject
*gobject
, guint param_id
,
1307 GValue
*value
, GParamSpec
*pspec
)
1309 FooCanvasItem
*item
;
1310 FooCanvasGroup
*group
;
1312 g_return_if_fail (FOO_IS_CANVAS_GROUP (gobject
));
1314 item
= FOO_CANVAS_ITEM (gobject
);
1315 group
= FOO_CANVAS_GROUP (gobject
);
1319 g_value_set_double (value
, group
->xpos
);
1323 g_value_set_double (value
, group
->ypos
);
1327 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, param_id
, pspec
);
1332 /* Destroy handler for canvas groups */
1334 foo_canvas_group_destroy (GtkObject
*object
)
1336 FooCanvasGroup
*group
;
1337 FooCanvasItem
*child
;
1340 g_return_if_fail (FOO_IS_CANVAS_GROUP (object
));
1342 group
= FOO_CANVAS_GROUP (object
);
1344 list
= group
->item_list
;
1349 gtk_object_destroy (GTK_OBJECT (child
));
1352 if (GTK_OBJECT_CLASS (group_parent_class
)->destroy
)
1353 (* GTK_OBJECT_CLASS (group_parent_class
)->destroy
) (object
);
1356 /* Update handler for canvas groups */
1358 foo_canvas_group_update (FooCanvasItem
*item
, double i2w_dx
, double i2w_dy
, int flags
)
1360 FooCanvasGroup
*group
;
1363 double bbox_x0
, bbox_y0
, bbox_x1
, bbox_y1
;
1364 gboolean first
= TRUE
;
1366 group
= FOO_CANVAS_GROUP (item
);
1368 (* group_parent_class
->update
) (item
, i2w_dx
, i2w_dy
, flags
);
1375 for (list
= group
->item_list
; list
; list
= list
->next
) {
1378 foo_canvas_item_invoke_update (i
, i2w_dx
+ group
->xpos
, i2w_dy
+ group
->ypos
, flags
);
1387 bbox_x0
= MIN (bbox_x0
, i
->x1
);
1388 bbox_y0
= MIN (bbox_y0
, i
->y1
);
1389 bbox_x1
= MAX (bbox_x1
, i
->x2
);
1390 bbox_y1
= MAX (bbox_y1
, i
->y2
);
1399 /* Unrealize handler for canvas groups */
1401 foo_canvas_group_unrealize (FooCanvasItem
*item
)
1403 FooCanvasGroup
*group
;
1407 group
= FOO_CANVAS_GROUP (item
);
1409 /* Unmap group before children to avoid flash */
1410 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
1411 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
1413 for (list
= group
->item_list
; list
; list
= list
->next
) {
1416 if (i
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
)
1417 (* FOO_CANVAS_ITEM_GET_CLASS (i
)->unrealize
) (i
);
1420 (* group_parent_class
->unrealize
) (item
);
1423 /* Map handler for canvas groups */
1425 foo_canvas_group_map (FooCanvasItem
*item
)
1427 FooCanvasGroup
*group
;
1431 group
= FOO_CANVAS_GROUP (item
);
1433 for (list
= group
->item_list
; list
; list
= list
->next
) {
1436 if (i
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
&&
1437 !(i
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)) {
1438 if (!(i
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
))
1439 (* FOO_CANVAS_ITEM_GET_CLASS (i
)->realize
) (i
);
1441 (* FOO_CANVAS_ITEM_GET_CLASS (i
)->map
) (i
);
1445 (* group_parent_class
->map
) (item
);
1448 /* Unmap handler for canvas groups */
1450 foo_canvas_group_unmap (FooCanvasItem
*item
)
1452 FooCanvasGroup
*group
;
1456 group
= FOO_CANVAS_GROUP (item
);
1458 for (list
= group
->item_list
; list
; list
= list
->next
) {
1461 if (i
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
1462 (* FOO_CANVAS_ITEM_GET_CLASS (i
)->unmap
) (i
);
1465 (* group_parent_class
->unmap
) (item
);
1468 /* Draw handler for canvas groups */
1470 foo_canvas_group_draw (FooCanvasItem
*item
, GdkDrawable
*drawable
,
1471 GdkEventExpose
*expose
)
1473 FooCanvasGroup
*group
;
1475 FooCanvasItem
*child
= NULL
;
1477 group
= FOO_CANVAS_GROUP (item
);
1479 for (list
= group
->item_list
; list
; list
= list
->next
) {
1482 if ((child
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
) &&
1483 (FOO_CANVAS_ITEM_GET_CLASS (child
)->draw
)) {
1484 GdkRectangle child_rect
;
1486 child_rect
.x
= child
->x1
;
1487 child_rect
.y
= child
->y1
;
1488 child_rect
.width
= child
->x2
- child
->x1
+ 1;
1489 child_rect
.height
= child
->y2
- child
->y1
+ 1;
1491 if (gdk_region_rect_in (expose
->region
, &child_rect
) != GDK_OVERLAP_RECTANGLE_OUT
)
1492 (* FOO_CANVAS_ITEM_GET_CLASS (child
)->draw
) (child
, drawable
, expose
);
1497 /* Point handler for canvas groups */
1499 foo_canvas_group_point (FooCanvasItem
*item
, double x
, double y
, int cx
, int cy
,
1500 FooCanvasItem
**actual_item
)
1502 FooCanvasGroup
*group
;
1504 FooCanvasItem
*child
, *point_item
;
1510 group
= FOO_CANVAS_GROUP (item
);
1512 x1
= cx
- item
->canvas
->close_enough
;
1513 y1
= cy
- item
->canvas
->close_enough
;
1514 x2
= cx
+ item
->canvas
->close_enough
;
1515 y2
= cy
+ item
->canvas
->close_enough
;
1518 *actual_item
= NULL
;
1520 gx
= x
- group
->xpos
;
1521 gy
= y
- group
->ypos
;
1523 dist
= 0.0; /* keep gcc happy */
1525 for (list
= group
->item_list
; list
; list
= list
->next
) {
1528 if ((child
->x1
> x2
) || (child
->y1
> y2
) || (child
->x2
< x1
) || (child
->y2
< y1
))
1531 point_item
= NULL
; /* cater for incomplete item implementations */
1533 if ((child
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
1534 && FOO_CANVAS_ITEM_GET_CLASS (child
)->point
) {
1535 dist
= foo_canvas_item_invoke_point (child
, gx
, gy
, cx
, cy
, &point_item
);
1542 && ((int) (dist
* item
->canvas
->pixels_per_unit
+ 0.5)
1543 <= item
->canvas
->close_enough
)) {
1545 *actual_item
= point_item
;
1553 foo_canvas_group_translate (FooCanvasItem
*item
, double dx
, double dy
)
1555 FooCanvasGroup
*group
;
1557 group
= FOO_CANVAS_GROUP (item
);
1563 /* Bounds handler for canvas groups */
1565 foo_canvas_group_bounds (FooCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
)
1567 FooCanvasGroup
*group
;
1568 FooCanvasItem
*child
;
1570 double tx1
, ty1
, tx2
, ty2
;
1571 double minx
, miny
, maxx
, maxy
;
1574 group
= FOO_CANVAS_GROUP (item
);
1576 /* Get the bounds of the first visible item */
1578 child
= NULL
; /* Unnecessary but eliminates a warning. */
1582 for (list
= group
->item_list
; list
; list
= list
->next
) {
1585 if (child
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
) {
1587 foo_canvas_item_get_bounds (child
, &minx
, &miny
, &maxx
, &maxy
);
1592 /* If there were no visible items, return an empty bounding box */
1595 *x1
= *y1
= *x2
= *y2
= 0.0;
1599 /* Now we can grow the bounds using the rest of the items */
1603 for (; list
; list
= list
->next
) {
1606 if (!(child
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
))
1609 foo_canvas_item_get_bounds (child
, &tx1
, &ty1
, &tx2
, &ty2
);
1624 /* Make the bounds be relative to our parent's coordinate system */
1627 minx
+= group
->xpos
;
1628 miny
+= group
->ypos
;
1629 maxx
+= group
->xpos
;
1630 maxy
+= group
->ypos
;
1639 /* Adds an item to a group */
1641 group_add (FooCanvasGroup
*group
, FooCanvasItem
*item
)
1643 #if GLIB_CHECK_VERSION(2,10,0) && GTK_CHECK_VERSION(2,8,14)
1644 g_object_ref_sink (item
);
1646 g_object_ref (item
);
1647 gtk_object_sink (GTK_OBJECT (item
));
1650 if (!group
->item_list
) {
1651 group
->item_list
= g_list_append (group
->item_list
, item
);
1652 group
->item_list_end
= group
->item_list
;
1654 group
->item_list_end
= g_list_append (group
->item_list_end
, item
)->next
;
1656 if (item
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
&&
1657 group
->item
.object
.flags
& FOO_CANVAS_ITEM_MAPPED
) {
1658 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
))
1659 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->realize
) (item
);
1661 if (!(item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
))
1662 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->map
) (item
);
1666 /* Removes an item from a group */
1668 group_remove (FooCanvasGroup
*group
, FooCanvasItem
*item
)
1672 g_return_if_fail (FOO_IS_CANVAS_GROUP (group
));
1673 g_return_if_fail (FOO_IS_CANVAS_ITEM (item
));
1675 for (children
= group
->item_list
; children
; children
= children
->next
)
1676 if (children
->data
== item
) {
1677 if (item
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
1678 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
1680 if (item
->object
.flags
& FOO_CANVAS_ITEM_REALIZED
)
1681 (* FOO_CANVAS_ITEM_GET_CLASS (item
)->unrealize
) (item
);
1683 /* Unparent the child */
1685 item
->parent
= NULL
;
1686 /* item->canvas = NULL; */
1687 g_object_unref (G_OBJECT (item
));
1689 /* Remove it from the list */
1691 if (children
== group
->item_list_end
)
1692 group
->item_list_end
= children
->prev
;
1694 group
->item_list
= g_list_remove_link (group
->item_list
, children
);
1695 g_list_free (children
);
1709 static void foo_canvas_class_init (FooCanvasClass
*klass
);
1710 static void foo_canvas_init (FooCanvas
*canvas
);
1711 static void foo_canvas_destroy (GtkObject
*object
);
1712 static void foo_canvas_map (GtkWidget
*widget
);
1713 static void foo_canvas_unmap (GtkWidget
*widget
);
1714 static void foo_canvas_realize (GtkWidget
*widget
);
1715 static void foo_canvas_unrealize (GtkWidget
*widget
);
1716 static void foo_canvas_size_allocate (GtkWidget
*widget
,
1717 GtkAllocation
*allocation
);
1718 static gint
foo_canvas_button (GtkWidget
*widget
,
1719 GdkEventButton
*event
);
1720 static gint
foo_canvas_motion (GtkWidget
*widget
,
1721 GdkEventMotion
*event
);
1722 static gint
foo_canvas_expose (GtkWidget
*widget
,
1723 GdkEventExpose
*event
);
1724 static gint
foo_canvas_key (GtkWidget
*widget
,
1725 GdkEventKey
*event
);
1726 static gint
foo_canvas_crossing (GtkWidget
*widget
,
1727 GdkEventCrossing
*event
);
1728 static gint
foo_canvas_focus_in (GtkWidget
*widget
,
1729 GdkEventFocus
*event
);
1730 static gint
foo_canvas_focus_out (GtkWidget
*widget
,
1731 GdkEventFocus
*event
);
1732 static void foo_canvas_request_update_real (FooCanvas
*canvas
);
1733 static void foo_canvas_draw_background (FooCanvas
*canvas
,
1740 static GtkLayoutClass
*canvas_parent_class
;
1742 static guint canvas_signals
[LAST_SIGNAL
];
1745 * foo_canvas_get_type:
1747 * Registers the &FooCanvas class if necessary, and returns the type ID
1750 * Return value: The type ID of the &FooCanvas class.
1753 foo_canvas_get_type (void)
1755 static GType canvas_type
= 0;
1758 static const GTypeInfo canvas_info
= {
1759 sizeof (FooCanvasClass
),
1760 (GBaseInitFunc
) NULL
,
1761 (GBaseFinalizeFunc
) NULL
,
1762 (GClassInitFunc
) foo_canvas_class_init
,
1763 NULL
, /* class_finalize */
1764 NULL
, /* class_data */
1766 0, /* n_preallocs */
1767 (GInstanceInitFunc
) foo_canvas_init
1770 canvas_type
= g_type_register_static (gtk_layout_get_type (),
1780 foo_canvas_get_property (GObject
*object
,
1787 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1793 foo_canvas_set_property (GObject
*object
,
1795 const GValue
*value
,
1800 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1806 foo_canvas_accessible_adjustment_changed (GtkAdjustment
*adjustment
,
1811 /* The scrollbars have changed */
1812 atk_obj
= ATK_OBJECT (data
);
1814 g_signal_emit_by_name (atk_obj
, "visible_data_changed");
1818 foo_canvas_accessible_initialize (AtkObject
*obj
,
1823 if (ATK_OBJECT_CLASS (accessible_parent_class
)->initialize
!= NULL
)
1824 ATK_OBJECT_CLASS (accessible_parent_class
)->initialize (obj
, data
);
1826 canvas
= FOO_CANVAS (data
);
1827 g_signal_connect (canvas
->layout
.hadjustment
,
1829 G_CALLBACK (foo_canvas_accessible_adjustment_changed
),
1831 g_signal_connect (canvas
->layout
.vadjustment
,
1833 G_CALLBACK (foo_canvas_accessible_adjustment_changed
),
1836 obj
->role
= ATK_ROLE_LAYERED_PANE
;
1840 foo_canvas_accessible_get_n_children (AtkObject
* obj
)
1842 GtkAccessible
*accessible
;
1845 FooCanvasGroup
*root_group
;
1847 accessible
= GTK_ACCESSIBLE (obj
);
1848 widget
= accessible
->widget
;
1849 if (widget
== NULL
) {
1850 /* State is defunct */
1854 g_return_val_if_fail (FOO_IS_CANVAS (widget
), 0);
1856 canvas
= FOO_CANVAS (widget
);
1857 root_group
= foo_canvas_root (canvas
);
1858 g_return_val_if_fail (root_group
, 0);
1863 foo_canvas_accessible_ref_child (AtkObject
*obj
,
1866 GtkAccessible
*accessible
;
1869 FooCanvasGroup
*root_group
;
1870 AtkObject
*atk_object
;
1872 /* Canvas only has one child, so return NULL if index is non zero */
1877 accessible
= GTK_ACCESSIBLE (obj
);
1878 widget
= accessible
->widget
;
1879 if (widget
== NULL
) {
1880 /* State is defunct */
1884 canvas
= FOO_CANVAS (widget
);
1885 root_group
= foo_canvas_root (canvas
);
1886 g_return_val_if_fail (root_group
, NULL
);
1887 atk_object
= atk_gobject_accessible_for_object (G_OBJECT (root_group
));
1888 g_object_ref (atk_object
);
1890 g_warning ("Accessible support for FooGroup needs to be implemented");
1896 foo_canvas_accessible_class_init (AtkObjectClass
*klass
)
1898 accessible_parent_class
= g_type_class_peek_parent (klass
);
1900 klass
->initialize
= foo_canvas_accessible_initialize
;
1901 klass
->get_n_children
= foo_canvas_accessible_get_n_children
;
1902 klass
->ref_child
= foo_canvas_accessible_ref_child
;
1906 foo_canvas_accessible_get_type (void)
1908 static GType type
= 0;
1911 AtkObjectFactory
*factory
;
1912 GType parent_atk_type
;
1914 GTypeInfo tinfo
= { 0 };
1916 factory
= atk_registry_get_factory (atk_get_default_registry(),
1919 return G_TYPE_INVALID
;
1921 parent_atk_type
= atk_object_factory_get_accessible_type (factory
);
1922 if (!parent_atk_type
) {
1923 return G_TYPE_INVALID
;
1925 g_type_query (parent_atk_type
, &query
);
1926 tinfo
.class_init
= (GClassInitFunc
) foo_canvas_accessible_class_init
;
1927 tinfo
.class_size
= query
.class_size
;
1928 tinfo
.instance_size
= query
.instance_size
;
1929 type
= g_type_register_static (parent_atk_type
,
1930 "FooCanvasAccessibility",
1937 foo_canvas_accessible_create (GObject
*for_object
)
1940 AtkObject
*accessible
;
1943 canvas
= FOO_CANVAS (for_object
);
1944 g_return_val_if_fail (canvas
!= NULL
, NULL
);
1946 type
= foo_canvas_accessible_get_type ();
1948 if (type
== G_TYPE_INVALID
) {
1949 return atk_no_op_object_new (for_object
);
1952 accessible
= g_object_new (type
, NULL
);
1953 atk_object_initialize (accessible
, for_object
);
1958 foo_canvas_accessible_factory_get_accessible_type (void)
1960 return foo_canvas_accessible_get_type ();
1964 foo_canvas_accessible_factory_create_accessible (GObject
*obj
)
1966 AtkObject
*accessible
;
1968 g_return_val_if_fail (G_IS_OBJECT (obj
), NULL
);
1970 accessible
= foo_canvas_accessible_create (obj
);
1976 foo_canvas_accessible_factory_class_init (AtkObjectFactoryClass
*klass
)
1978 klass
->create_accessible
= foo_canvas_accessible_factory_create_accessible
;
1979 klass
->get_accessible_type
= foo_canvas_accessible_factory_get_accessible_type
;
1983 foo_canvas_accessible_factory_get_type (void)
1985 static GType type
= 0;
1988 static const GTypeInfo tinfo
= {
1989 sizeof (AtkObjectFactoryClass
),
1990 (GBaseInitFunc
) NULL
,
1991 (GBaseFinalizeFunc
) NULL
,
1992 (GClassInitFunc
) foo_canvas_accessible_factory_class_init
,
1993 NULL
, /* class_finalize */
1994 NULL
, /* class_data */
1995 sizeof (AtkObjectFactory
),
1996 0, /* n_preallocs */
1999 type
= g_type_register_static (ATK_TYPE_OBJECT_FACTORY
,
2000 "FooCanvasAccessibilityFactory",
2008 /* Class initialization function for FooCanvasClass */
2010 foo_canvas_class_init (FooCanvasClass
*klass
)
2012 GObjectClass
*gobject_class
;
2013 GtkObjectClass
*object_class
;
2014 GtkWidgetClass
*widget_class
;
2016 gobject_class
= (GObjectClass
*)klass
;
2017 object_class
= (GtkObjectClass
*) klass
;
2018 widget_class
= (GtkWidgetClass
*) klass
;
2020 canvas_parent_class
= g_type_class_peek_parent (klass
);
2022 gobject_class
->set_property
= foo_canvas_set_property
;
2023 gobject_class
->get_property
= foo_canvas_get_property
;
2025 object_class
->destroy
= foo_canvas_destroy
;
2027 widget_class
->map
= foo_canvas_map
;
2028 widget_class
->unmap
= foo_canvas_unmap
;
2029 widget_class
->realize
= foo_canvas_realize
;
2030 widget_class
->unrealize
= foo_canvas_unrealize
;
2031 widget_class
->size_allocate
= foo_canvas_size_allocate
;
2032 widget_class
->button_press_event
= foo_canvas_button
;
2033 widget_class
->button_release_event
= foo_canvas_button
;
2034 widget_class
->motion_notify_event
= foo_canvas_motion
;
2035 widget_class
->expose_event
= foo_canvas_expose
;
2036 widget_class
->key_press_event
= foo_canvas_key
;
2037 widget_class
->key_release_event
= foo_canvas_key
;
2038 widget_class
->enter_notify_event
= foo_canvas_crossing
;
2039 widget_class
->leave_notify_event
= foo_canvas_crossing
;
2040 widget_class
->focus_in_event
= foo_canvas_focus_in
;
2041 widget_class
->focus_out_event
= foo_canvas_focus_out
;
2043 klass
->draw_background
= foo_canvas_draw_background
;
2044 klass
->request_update
= foo_canvas_request_update_real
;
2046 canvas_signals
[DRAW_BACKGROUND
] =
2047 g_signal_new ("draw_background",
2048 G_TYPE_FROM_CLASS (object_class
),
2050 G_STRUCT_OFFSET (FooCanvasClass
, draw_background
),
2052 foo_canvas_marshal_VOID__INT_INT_INT_INT
,
2054 G_TYPE_INT
, G_TYPE_INT
, G_TYPE_INT
, G_TYPE_INT
);
2056 atk_registry_set_factory_type (atk_get_default_registry (),
2058 foo_canvas_accessible_factory_get_type ());
2061 /* Callback used when the root item of a canvas is destroyed. The user should
2062 * never ever do this, so we panic if this happens.
2065 panic_root_destroyed (GtkObject
*object
, gpointer data
)
2067 g_error ("Eeeek, root item %p of canvas %p was destroyed!", object
, data
);
2070 /* Object initialization function for FooCanvas */
2072 foo_canvas_init (FooCanvas
*canvas
)
2074 GTK_WIDGET_SET_FLAGS (canvas
, GTK_CAN_FOCUS
);
2076 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas
), FALSE
);
2078 canvas
->scroll_x1
= 0.0;
2079 canvas
->scroll_y1
= 0.0;
2080 canvas
->scroll_x2
= canvas
->layout
.width
;
2081 canvas
->scroll_y2
= canvas
->layout
.height
;
2083 canvas
->pixels_per_unit
= 1.0;
2085 canvas
->pick_event
.type
= GDK_LEAVE_NOTIFY
;
2086 canvas
->pick_event
.crossing
.x
= 0;
2087 canvas
->pick_event
.crossing
.y
= 0;
2089 gtk_layout_set_hadjustment (GTK_LAYOUT (canvas
), NULL
);
2090 gtk_layout_set_vadjustment (GTK_LAYOUT (canvas
), NULL
);
2092 /* Create the root item as a special case */
2094 canvas
->root
= FOO_CANVAS_ITEM (g_object_new (foo_canvas_group_get_type (), NULL
));
2095 canvas
->root
->canvas
= canvas
;
2097 #if GLIB_CHECK_VERSION(2,10,0) && GTK_CHECK_VERSION(2,8,14)
2098 g_object_ref_sink (canvas
->root
);
2100 g_object_ref (canvas
->root
);
2101 gtk_object_sink (GTK_OBJECT (canvas
->root
));
2104 canvas
->root_destroy_id
= g_signal_connect (G_OBJECT (canvas
->root
),
2105 "destroy", G_CALLBACK (panic_root_destroyed
), canvas
);
2107 canvas
->need_repick
= TRUE
;
2108 canvas
->doing_update
= FALSE
;
2111 /* Convenience function to remove the idle handler of a canvas */
2113 remove_idle (FooCanvas
*canvas
)
2115 if (canvas
->idle_id
== 0)
2118 g_source_remove (canvas
->idle_id
);
2119 canvas
->idle_id
= 0;
2122 /* Removes the transient state of the canvas (idle handler, grabs). */
2124 shutdown_transients (FooCanvas
*canvas
)
2126 /* We turn off the need_redraw flag, since if the canvas is mapped again
2127 * it will request a redraw anyways. We do not turn off the need_update
2128 * flag, though, because updates are not queued when the canvas remaps
2131 if (canvas
->need_redraw
) {
2132 canvas
->need_redraw
= FALSE
;
2135 if (canvas
->grabbed_item
) {
2136 GdkDisplay
*display
= gtk_widget_get_display (GTK_WIDGET (canvas
));
2137 canvas
->grabbed_item
= NULL
;
2138 gdk_display_pointer_ungrab (display
, GDK_CURRENT_TIME
);
2141 remove_idle (canvas
);
2144 /* Destroy handler for FooCanvas */
2146 foo_canvas_destroy (GtkObject
*object
)
2150 g_return_if_fail (FOO_IS_CANVAS (object
));
2152 /* remember, destroy can be run multiple times! */
2154 canvas
= FOO_CANVAS (object
);
2156 if (canvas
->root_destroy_id
) {
2157 g_signal_handler_disconnect (G_OBJECT (canvas
->root
), canvas
->root_destroy_id
);
2158 canvas
->root_destroy_id
= 0;
2161 FooCanvasItem
*root
= canvas
->root
;
2162 canvas
->root
= NULL
;
2163 gtk_object_destroy (GTK_OBJECT (root
));
2164 g_object_unref (root
);
2167 shutdown_transients (canvas
);
2169 if (GTK_OBJECT_CLASS (canvas_parent_class
)->destroy
)
2170 (* GTK_OBJECT_CLASS (canvas_parent_class
)->destroy
) (object
);
2177 * Creates a new empty canvas. If you wish to use the
2178 * &FooCanvasImage item inside this canvas, then you must push the gdk_imlib
2179 * visual and colormap before calling this function, and they can be popped
2182 * Return value: A newly-created canvas.
2185 foo_canvas_new (void)
2187 return GTK_WIDGET (g_object_new (foo_canvas_get_type (), NULL
));
2190 /* Map handler for the canvas */
2192 foo_canvas_map (GtkWidget
*widget
)
2196 g_return_if_fail (FOO_IS_CANVAS (widget
));
2198 /* Normal widget mapping stuff */
2200 if (GTK_WIDGET_CLASS (canvas_parent_class
)->map
)
2201 (* GTK_WIDGET_CLASS (canvas_parent_class
)->map
) (widget
);
2203 canvas
= FOO_CANVAS (widget
);
2207 if (canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
&&
2208 !(canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
) &&
2209 FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->map
)
2210 (* FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->map
) (canvas
->root
);
2213 /* Unmap handler for the canvas */
2215 foo_canvas_unmap (GtkWidget
*widget
)
2219 g_return_if_fail (FOO_IS_CANVAS (widget
));
2221 canvas
= FOO_CANVAS (widget
);
2223 shutdown_transients (canvas
);
2227 if (FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->unmap
)
2228 (* FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->unmap
) (canvas
->root
);
2230 /* Normal widget unmapping stuff */
2232 if (GTK_WIDGET_CLASS (canvas_parent_class
)->unmap
)
2233 (* GTK_WIDGET_CLASS (canvas_parent_class
)->unmap
) (widget
);
2236 /* Realize handler for the canvas */
2238 foo_canvas_realize (GtkWidget
*widget
)
2242 g_return_if_fail (FOO_IS_CANVAS (widget
));
2244 /* Normal widget realization stuff */
2246 if (GTK_WIDGET_CLASS (canvas_parent_class
)->realize
)
2247 (* GTK_WIDGET_CLASS (canvas_parent_class
)->realize
) (widget
);
2249 canvas
= FOO_CANVAS (widget
);
2251 gdk_window_set_events (canvas
->layout
.bin_window
,
2252 (gdk_window_get_events (canvas
->layout
.bin_window
)
2254 | GDK_BUTTON_PRESS_MASK
2255 | GDK_BUTTON_RELEASE_MASK
2256 | GDK_POINTER_MOTION_MASK
2257 | GDK_KEY_PRESS_MASK
2258 | GDK_KEY_RELEASE_MASK
2259 | GDK_ENTER_NOTIFY_MASK
2260 | GDK_LEAVE_NOTIFY_MASK
2261 | GDK_FOCUS_CHANGE_MASK
));
2263 (* FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->realize
) (canvas
->root
);
2266 /* Unrealize handler for the canvas */
2268 foo_canvas_unrealize (GtkWidget
*widget
)
2272 g_return_if_fail (FOO_IS_CANVAS (widget
));
2274 canvas
= FOO_CANVAS (widget
);
2276 shutdown_transients (canvas
);
2278 /* Unrealize items and parent widget */
2280 (* FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->unrealize
) (canvas
->root
);
2282 if (GTK_WIDGET_CLASS (canvas_parent_class
)->unrealize
)
2283 (* GTK_WIDGET_CLASS (canvas_parent_class
)->unrealize
) (widget
);
2286 /* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to
2287 * keep as much as possible of the canvas scrolling region in view.
2290 scroll_to (FooCanvas
*canvas
, int cx
, int cy
)
2292 int scroll_width
, scroll_height
;
2293 int right_limit
, bottom_limit
;
2294 int old_zoom_xofs
, old_zoom_yofs
;
2295 int changed_x
= FALSE
, changed_y
= FALSE
;
2296 int canvas_width
, canvas_height
;
2298 canvas_width
= GTK_WIDGET (canvas
)->allocation
.width
;
2299 canvas_height
= GTK_WIDGET (canvas
)->allocation
.height
;
2301 scroll_width
= floor ((canvas
->scroll_x2
- canvas
->scroll_x1
) * canvas
->pixels_per_unit
+ 0.5);
2302 scroll_height
= floor ((canvas
->scroll_y2
- canvas
->scroll_y1
) * canvas
->pixels_per_unit
+ 0.5);
2304 right_limit
= scroll_width
- canvas_width
;
2305 bottom_limit
= scroll_height
- canvas_height
;
2307 old_zoom_xofs
= canvas
->zoom_xofs
;
2308 old_zoom_yofs
= canvas
->zoom_yofs
;
2310 if (right_limit
< 0) {
2312 if (canvas
->center_scroll_region
) {
2313 canvas
->zoom_xofs
= (canvas_width
- scroll_width
) / 2;
2314 scroll_width
= canvas_width
;
2316 canvas
->zoom_xofs
= 0;
2318 } else if (cx
< 0) {
2320 canvas
->zoom_xofs
= 0;
2321 } else if (cx
> right_limit
) {
2323 canvas
->zoom_xofs
= 0;
2325 canvas
->zoom_xofs
= 0;
2327 if (bottom_limit
< 0) {
2329 if (canvas
->center_scroll_region
) {
2330 canvas
->zoom_yofs
= (canvas_height
- scroll_height
) / 2;
2331 scroll_height
= canvas_height
;
2333 canvas
->zoom_yofs
= 0;
2335 } else if (cy
< 0) {
2337 canvas
->zoom_yofs
= 0;
2338 } else if (cy
> bottom_limit
) {
2340 canvas
->zoom_yofs
= 0;
2342 canvas
->zoom_yofs
= 0;
2344 if ((canvas
->zoom_xofs
!= old_zoom_xofs
) || (canvas
->zoom_yofs
!= old_zoom_yofs
)) {
2345 /* This can only occur, if either canvas size or widget size changes */
2346 /* So I think we can request full redraw here */
2347 /* More stuff - we have to mark root as needing fresh affine (Lauris) */
2348 if (!(canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
)) {
2349 canvas
->root
->object
.flags
|= FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
;
2350 foo_canvas_request_update (canvas
);
2352 gtk_widget_queue_draw (GTK_WIDGET (canvas
));
2355 if (((int) canvas
->layout
.hadjustment
->value
) != cx
) {
2356 canvas
->layout
.hadjustment
->value
= cx
;
2360 if (((int) canvas
->layout
.vadjustment
->value
) != cy
) {
2361 canvas
->layout
.vadjustment
->value
= cy
;
2365 if ((scroll_width
!= (int) canvas
->layout
.width
) || (scroll_height
!= (int) canvas
->layout
.height
)) {
2366 gtk_layout_set_size (GTK_LAYOUT (canvas
), scroll_width
, scroll_height
);
2369 /* Signal GtkLayout that it should do a redraw. */
2371 g_signal_emit_by_name (G_OBJECT (canvas
->layout
.hadjustment
), "value_changed");
2373 g_signal_emit_by_name (G_OBJECT (canvas
->layout
.vadjustment
), "value_changed");
2376 /* Size allocation handler for the canvas */
2378 foo_canvas_size_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
)
2382 g_return_if_fail (FOO_IS_CANVAS (widget
));
2383 g_return_if_fail (allocation
!= NULL
);
2385 if (GTK_WIDGET_CLASS (canvas_parent_class
)->size_allocate
)
2386 (* GTK_WIDGET_CLASS (canvas_parent_class
)->size_allocate
) (widget
, allocation
);
2388 canvas
= FOO_CANVAS (widget
);
2390 /* Recenter the view, if appropriate */
2392 canvas
->layout
.hadjustment
->page_size
= allocation
->width
;
2393 canvas
->layout
.hadjustment
->page_increment
= allocation
->width
/ 2;
2395 canvas
->layout
.vadjustment
->page_size
= allocation
->height
;
2396 canvas
->layout
.vadjustment
->page_increment
= allocation
->height
/ 2;
2399 canvas
->layout
.hadjustment
->value
,
2400 canvas
->layout
.vadjustment
->value
);
2402 g_signal_emit_by_name (G_OBJECT (canvas
->layout
.hadjustment
), "changed");
2403 g_signal_emit_by_name (G_OBJECT (canvas
->layout
.vadjustment
), "changed");
2406 /* Emits an event for an item in the canvas, be it the current item, grabbed
2407 * item, or focused item, as appropriate.
2411 emit_event (FooCanvas
*canvas
, GdkEvent
*event
)
2415 FooCanvasItem
*item
;
2416 FooCanvasItem
*parent
;
2419 /* Could be an old pick event */
2420 if (!gtk_widget_get_realized (GTK_WIDGET (canvas
))) {
2424 /* Perform checks for grabbed items */
2426 if (canvas
->grabbed_item
&&
2427 !is_descendant (canvas
->current_item
, canvas
->grabbed_item
)) {
2431 if (canvas
->grabbed_item
) {
2432 switch (event
->type
) {
2433 case GDK_ENTER_NOTIFY
:
2434 mask
= GDK_ENTER_NOTIFY_MASK
;
2437 case GDK_LEAVE_NOTIFY
:
2438 mask
= GDK_LEAVE_NOTIFY_MASK
;
2441 case GDK_MOTION_NOTIFY
:
2442 mask
= GDK_POINTER_MOTION_MASK
;
2445 case GDK_BUTTON_PRESS
:
2446 case GDK_2BUTTON_PRESS
:
2447 case GDK_3BUTTON_PRESS
:
2448 mask
= GDK_BUTTON_PRESS_MASK
;
2451 case GDK_BUTTON_RELEASE
:
2452 mask
= GDK_BUTTON_RELEASE_MASK
;
2456 mask
= GDK_KEY_PRESS_MASK
;
2459 case GDK_KEY_RELEASE
:
2460 mask
= GDK_KEY_RELEASE_MASK
;
2468 if (!(mask
& canvas
->grabbed_event_mask
))
2472 /* Convert to world coordinates -- we have two cases because of diferent
2473 * offsets of the fields in the event structures.
2480 case GDK_ENTER_NOTIFY
:
2481 case GDK_LEAVE_NOTIFY
:
2482 foo_canvas_window_to_world (canvas
,
2483 ev
.crossing
.x
, ev
.crossing
.y
,
2484 &ev
.crossing
.x
, &ev
.crossing
.y
);
2487 case GDK_MOTION_NOTIFY
:
2488 foo_canvas_window_to_world (canvas
,
2489 ev
.motion
.x
, ev
.motion
.y
,
2490 &ev
.motion
.x
, &ev
.motion
.y
);
2493 case GDK_BUTTON_PRESS
:
2494 case GDK_2BUTTON_PRESS
:
2495 case GDK_3BUTTON_PRESS
:
2496 foo_canvas_window_to_world (canvas
,
2497 ev
.motion
.x
, ev
.motion
.y
,
2498 &ev
.motion
.x
, &ev
.motion
.y
);
2501 case GDK_BUTTON_RELEASE
:
2502 foo_canvas_window_to_world (canvas
,
2503 ev
.motion
.x
, ev
.motion
.y
,
2504 &ev
.motion
.x
, &ev
.motion
.y
);
2511 /* Choose where we send the event */
2513 item
= canvas
->current_item
;
2515 if (canvas
->focused_item
2516 && ((event
->type
== GDK_KEY_PRESS
) ||
2517 (event
->type
== GDK_KEY_RELEASE
) ||
2518 (event
->type
== GDK_FOCUS_CHANGE
)))
2519 item
= canvas
->focused_item
;
2521 /* The event is propagated up the hierarchy (for if someone connected to
2522 * a group instead of a leaf event), and emission is stopped if a
2523 * handler returns TRUE, just like for GtkWidget events.
2528 while (item
&& !finished
) {
2529 g_object_ref (GTK_OBJECT (item
));
2532 G_OBJECT (item
), item_signals
[ITEM_EVENT
], 0,
2535 parent
= item
->parent
;
2536 g_object_unref (GTK_OBJECT (item
));
2544 /* Re-picks the current item in the canvas, based on the event's coordinates.
2545 * Also emits enter/leave events for items as appropriate.
2548 pick_current_item (FooCanvas
*canvas
, GdkEvent
*event
)
2557 /* If a button is down, we'll perform enter and leave events on the
2558 * current item, but not enter on any other item. This is more or less
2559 * like X pointer grabbing for canvas items.
2561 button_down
= canvas
->state
& (GDK_BUTTON1_MASK
2565 | GDK_BUTTON5_MASK
);
2567 canvas
->left_grabbed_item
= FALSE
;
2569 /* Save the event in the canvas. This is used to synthesize enter and
2570 * leave events in case the current item changes. It is also used to
2571 * re-pick the current item if the current one gets deleted. Also,
2572 * synthesize an enter event.
2574 if (event
!= &canvas
->pick_event
) {
2575 if ((event
->type
== GDK_MOTION_NOTIFY
) || (event
->type
== GDK_BUTTON_RELEASE
)) {
2576 /* these fields have the same offsets in both types of events */
2578 canvas
->pick_event
.crossing
.type
= GDK_ENTER_NOTIFY
;
2579 canvas
->pick_event
.crossing
.window
= event
->motion
.window
;
2580 canvas
->pick_event
.crossing
.send_event
= event
->motion
.send_event
;
2581 canvas
->pick_event
.crossing
.subwindow
= NULL
;
2582 canvas
->pick_event
.crossing
.x
= event
->motion
.x
;
2583 canvas
->pick_event
.crossing
.y
= event
->motion
.y
;
2584 canvas
->pick_event
.crossing
.mode
= GDK_CROSSING_NORMAL
;
2585 canvas
->pick_event
.crossing
.detail
= GDK_NOTIFY_NONLINEAR
;
2586 canvas
->pick_event
.crossing
.focus
= FALSE
;
2587 canvas
->pick_event
.crossing
.state
= event
->motion
.state
;
2589 /* these fields don't have the same offsets in both types of events */
2591 if (event
->type
== GDK_MOTION_NOTIFY
) {
2592 canvas
->pick_event
.crossing
.x_root
= event
->motion
.x_root
;
2593 canvas
->pick_event
.crossing
.y_root
= event
->motion
.y_root
;
2595 canvas
->pick_event
.crossing
.x_root
= event
->button
.x_root
;
2596 canvas
->pick_event
.crossing
.y_root
= event
->button
.y_root
;
2599 canvas
->pick_event
= *event
;
2602 /* Don't do anything else if this is a recursive call */
2604 if (canvas
->in_repick
)
2607 /* LeaveNotify means that there is no current item, so we don't look for one */
2609 if (canvas
->pick_event
.type
!= GDK_LEAVE_NOTIFY
) {
2610 /* these fields don't have the same offsets in both types of events */
2612 if (canvas
->pick_event
.type
== GDK_ENTER_NOTIFY
) {
2613 x
= canvas
->pick_event
.crossing
.x
;
2614 y
= canvas
->pick_event
.crossing
.y
;
2616 x
= canvas
->pick_event
.motion
.x
;
2617 y
= canvas
->pick_event
.motion
.y
;
2620 /* canvas pixel coords */
2622 cx
= (int) (x
+ 0.5);
2623 cy
= (int) (y
+ 0.5);
2626 foo_canvas_c2w (canvas
, cx
, cy
, &x
, &y
);
2628 /* find the closest item */
2629 if (canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
2630 foo_canvas_item_invoke_point (canvas
->root
, x
, y
, cx
, cy
,
2631 &canvas
->new_current_item
);
2633 canvas
->new_current_item
= NULL
;
2635 canvas
->new_current_item
= NULL
;
2637 if ((canvas
->new_current_item
== canvas
->current_item
) && !canvas
->left_grabbed_item
)
2638 return retval
; /* current item did not change */
2640 /* Synthesize events for old and new current items */
2642 if ((canvas
->new_current_item
!= canvas
->current_item
)
2643 && (canvas
->current_item
!= NULL
)
2644 && !canvas
->left_grabbed_item
) {
2646 FooCanvasItem
*item
;
2648 item
= canvas
->current_item
;
2650 new_event
= canvas
->pick_event
;
2651 new_event
.type
= GDK_LEAVE_NOTIFY
;
2653 new_event
.crossing
.detail
= GDK_NOTIFY_ANCESTOR
;
2654 new_event
.crossing
.subwindow
= NULL
;
2655 canvas
->in_repick
= TRUE
;
2656 retval
= emit_event (canvas
, &new_event
);
2657 canvas
->in_repick
= FALSE
;
2660 /* new_current_item may have been set to NULL during the call to emit_event() above */
2662 if ((canvas
->new_current_item
!= canvas
->current_item
) && button_down
) {
2663 canvas
->left_grabbed_item
= TRUE
;
2667 /* Handle the rest of cases */
2669 canvas
->left_grabbed_item
= FALSE
;
2670 canvas
->current_item
= canvas
->new_current_item
;
2672 if (canvas
->current_item
!= NULL
) {
2675 new_event
= canvas
->pick_event
;
2676 new_event
.type
= GDK_ENTER_NOTIFY
;
2677 new_event
.crossing
.detail
= GDK_NOTIFY_ANCESTOR
;
2678 new_event
.crossing
.subwindow
= NULL
;
2679 retval
= emit_event (canvas
, &new_event
);
2685 /* Button event handler for the canvas */
2687 foo_canvas_button (GtkWidget
*widget
, GdkEventButton
*event
)
2693 g_return_val_if_fail (FOO_IS_CANVAS (widget
), FALSE
);
2694 g_return_val_if_fail (event
!= NULL
, FALSE
);
2698 canvas
= FOO_CANVAS (widget
);
2701 * dispatch normally regardless of the event's window if an item has
2702 * has a pointer grab in effect
2704 if (!canvas
->grabbed_item
&& event
->window
!= canvas
->layout
.bin_window
)
2707 switch (event
->button
) {
2709 mask
= GDK_BUTTON1_MASK
;
2712 mask
= GDK_BUTTON2_MASK
;
2715 mask
= GDK_BUTTON3_MASK
;
2718 mask
= GDK_BUTTON4_MASK
;
2721 mask
= GDK_BUTTON5_MASK
;
2727 switch (event
->type
) {
2728 case GDK_BUTTON_PRESS
:
2729 case GDK_2BUTTON_PRESS
:
2730 case GDK_3BUTTON_PRESS
:
2731 /* Pick the current item as if the button were not pressed, and
2732 * then process the event.
2734 canvas
->state
= event
->state
;
2735 pick_current_item (canvas
, (GdkEvent
*) event
);
2736 canvas
->state
^= mask
;
2737 retval
= emit_event (canvas
, (GdkEvent
*) event
);
2740 case GDK_BUTTON_RELEASE
:
2741 /* Process the event as if the button were pressed, then repick
2742 * after the button has been released
2744 canvas
->state
= event
->state
;
2745 retval
= emit_event (canvas
, (GdkEvent
*) event
);
2746 event
->state
^= mask
;
2747 canvas
->state
= event
->state
;
2748 pick_current_item (canvas
, (GdkEvent
*) event
);
2749 event
->state
^= mask
;
2753 g_assert_not_reached ();
2759 /* Motion event handler for the canvas */
2761 foo_canvas_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
2765 g_return_val_if_fail (FOO_IS_CANVAS (widget
), FALSE
);
2766 g_return_val_if_fail (event
!= NULL
, FALSE
);
2768 canvas
= FOO_CANVAS (widget
);
2770 if (event
->window
!= canvas
->layout
.bin_window
)
2773 canvas
->state
= event
->state
;
2774 pick_current_item (canvas
, (GdkEvent
*) event
);
2775 return emit_event (canvas
, (GdkEvent
*) event
);
2778 /* Key event handler for the canvas */
2780 foo_canvas_key (GtkWidget
*widget
, GdkEventKey
*event
)
2784 g_return_val_if_fail (FOO_IS_CANVAS (widget
), FALSE
);
2785 g_return_val_if_fail (event
!= NULL
, FALSE
);
2787 canvas
= FOO_CANVAS (widget
);
2789 if (emit_event (canvas
, (GdkEvent
*) event
))
2791 if (event
->type
== GDK_KEY_RELEASE
)
2792 return GTK_WIDGET_CLASS (canvas_parent_class
)->key_release_event (widget
, event
);
2794 return GTK_WIDGET_CLASS (canvas_parent_class
)->key_press_event (widget
, event
);
2798 /* Crossing event handler for the canvas */
2800 foo_canvas_crossing (GtkWidget
*widget
, GdkEventCrossing
*event
)
2804 g_return_val_if_fail (FOO_IS_CANVAS (widget
), FALSE
);
2805 g_return_val_if_fail (event
!= NULL
, FALSE
);
2807 canvas
= FOO_CANVAS (widget
);
2809 if (event
->window
!= canvas
->layout
.bin_window
)
2812 canvas
->state
= event
->state
;
2813 return pick_current_item (canvas
, (GdkEvent
*) event
);
2816 /* Focus in handler for the canvas */
2818 foo_canvas_focus_in (GtkWidget
*widget
, GdkEventFocus
*event
)
2822 GTK_WIDGET_SET_FLAGS (widget
, GTK_HAS_FOCUS
);
2824 canvas
= FOO_CANVAS (widget
);
2826 if (canvas
->focused_item
)
2827 return emit_event (canvas
, (GdkEvent
*) event
);
2832 /* Focus out handler for the canvas */
2834 foo_canvas_focus_out (GtkWidget
*widget
, GdkEventFocus
*event
)
2838 GTK_WIDGET_UNSET_FLAGS (widget
, GTK_HAS_FOCUS
);
2840 canvas
= FOO_CANVAS (widget
);
2842 if (canvas
->focused_item
)
2843 return emit_event (canvas
, (GdkEvent
*) event
);
2848 /* Expose handler for the canvas */
2850 foo_canvas_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
2854 canvas
= FOO_CANVAS (widget
);
2856 if (!gtk_widget_is_drawable (widget
) || (event
->window
!= canvas
->layout
.bin_window
)) return FALSE
;
2859 g_print ("Expose\n");
2861 /* If there are any outstanding items that need updating, do them now */
2862 if (canvas
->idle_id
) {
2863 g_source_remove (canvas
->idle_id
);
2864 canvas
->idle_id
= 0;
2866 if (canvas
->need_update
) {
2867 g_return_val_if_fail (!canvas
->doing_update
, FALSE
);
2869 canvas
->doing_update
= TRUE
;
2870 foo_canvas_item_invoke_update (canvas
->root
, 0, 0, 0);
2872 g_return_val_if_fail (canvas
->doing_update
, FALSE
);
2874 canvas
->doing_update
= FALSE
;
2876 canvas
->need_update
= FALSE
;
2879 /* Hmmm. Would like to queue antiexposes if the update marked
2880 anything that is gonna get redrawn as invalid */
2883 g_signal_emit (G_OBJECT (canvas
), canvas_signals
[DRAW_BACKGROUND
], 0,
2884 event
->area
.x
, event
->area
.y
,
2885 event
->area
.width
, event
->area
.height
);
2887 if (canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_MAPPED
)
2888 (* FOO_CANVAS_ITEM_GET_CLASS (canvas
->root
)->draw
) (canvas
->root
,
2889 canvas
->layout
.bin_window
,
2894 /* Chain up to get exposes on child widgets */
2895 GTK_WIDGET_CLASS (canvas_parent_class
)->expose_event (widget
, event
);
2901 foo_canvas_draw_background (FooCanvas
*canvas
,
2902 int x
, int y
, int width
, int height
)
2906 /* By default, we use the style background. */
2907 cr
= gdk_cairo_create (canvas
->layout
.bin_window
);
2908 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_NONE
);
2909 gdk_cairo_set_source_color (cr
, >K_WIDGET (canvas
)->style
->bg
[GTK_STATE_NORMAL
]);
2910 cairo_rectangle (cr
, x
, y
, width
, height
);
2916 do_update (FooCanvas
*canvas
)
2918 /* Cause the update if necessary */
2921 if (canvas
->need_update
) {
2922 g_return_if_fail (!canvas
->doing_update
);
2924 canvas
->doing_update
= TRUE
;
2925 foo_canvas_item_invoke_update (canvas
->root
, 0, 0, 0);
2927 g_return_if_fail (canvas
->doing_update
);
2929 canvas
->doing_update
= FALSE
;
2931 canvas
->need_update
= FALSE
;
2934 /* Pick new current item */
2936 while (canvas
->need_repick
) {
2937 canvas
->need_repick
= FALSE
;
2938 pick_current_item (canvas
, &canvas
->pick_event
);
2941 /* it is possible that during picking we emitted an event in which
2942 the user then called some function which then requested update
2943 of something. Without this we'd be left in a state where
2944 need_update would have been left TRUE and the canvas would have
2945 been left unpainted. */
2946 if (canvas
->need_update
) {
2951 /* Idle handler for the canvas. It deals with pending updates and redraws. */
2953 idle_handler (gpointer data
)
2957 GDK_THREADS_ENTER ();
2959 canvas
= FOO_CANVAS (data
);
2963 canvas
->idle_id
= 0;
2965 GDK_THREADS_LEAVE ();
2970 /* Convenience function to add an idle handler to a canvas */
2972 add_idle (FooCanvas
*canvas
)
2974 if (!canvas
->idle_id
) {
2975 /* We let the update idle handler have higher priority
2976 * than the redraw idle handler so the canvas state
2977 * will be updated during the expose event. canvas in
2980 canvas
->idle_id
= g_idle_add_full (GDK_PRIORITY_REDRAW
- 20,
2981 idle_handler
, canvas
, NULL
);
2987 * @canvas: A canvas.
2989 * Queries the root group of a canvas.
2991 * Return value: The root group of the specified canvas.
2994 foo_canvas_root (FooCanvas
*canvas
)
2996 g_return_val_if_fail (FOO_IS_CANVAS (canvas
), NULL
);
2998 return FOO_CANVAS_GROUP (canvas
->root
);
3003 * foo_canvas_set_scroll_region:
3004 * @canvas: A canvas.
3005 * @x1: Leftmost limit of the scrolling region.
3006 * @y1: Upper limit of the scrolling region.
3007 * @x2: Rightmost limit of the scrolling region.
3008 * @y2: Lower limit of the scrolling region.
3010 * Sets the scrolling region of a canvas to the specified rectangle. The canvas
3011 * will then be able to scroll only within this region. The view of the canvas
3012 * is adjusted as appropriate to display as much of the new region as possible.
3015 foo_canvas_set_scroll_region (FooCanvas
*canvas
, double x1
, double y1
, double x2
, double y2
)
3017 double wxofs
, wyofs
;
3020 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3022 if ((canvas
->scroll_x1
== x1
) && (canvas
->scroll_y1
== y1
) &&
3023 (canvas
->scroll_x2
== x2
) && (canvas
->scroll_y2
== y2
)) {
3028 * Set the new scrolling region. If possible, do not move the visible contents of the
3032 foo_canvas_c2w (canvas
,
3033 GTK_LAYOUT (canvas
)->hadjustment
->value
+ canvas
->zoom_xofs
,
3034 GTK_LAYOUT (canvas
)->vadjustment
->value
+ canvas
->zoom_yofs
,
3035 /*canvas->zoom_xofs,
3036 canvas->zoom_yofs,*/
3039 canvas
->scroll_x1
= x1
;
3040 canvas
->scroll_y1
= y1
;
3041 canvas
->scroll_x2
= x2
;
3042 canvas
->scroll_y2
= y2
;
3044 foo_canvas_w2c (canvas
, wxofs
, wyofs
, &xofs
, &yofs
);
3046 scroll_to (canvas
, xofs
, yofs
);
3048 canvas
->need_repick
= TRUE
;
3050 if (!(canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
)) {
3051 canvas
->root
->object
.flags
|= FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
;
3052 foo_canvas_request_update (canvas
);
3058 * foo_canvas_get_scroll_region:
3059 * @canvas: A canvas.
3060 * @x1: Leftmost limit of the scrolling region (return value).
3061 * @y1: Upper limit of the scrolling region (return value).
3062 * @x2: Rightmost limit of the scrolling region (return value).
3063 * @y2: Lower limit of the scrolling region (return value).
3065 * Queries the scrolling region of a canvas.
3068 foo_canvas_get_scroll_region (FooCanvas
*canvas
, double *x1
, double *y1
, double *x2
, double *y2
)
3070 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3073 *x1
= canvas
->scroll_x1
;
3076 *y1
= canvas
->scroll_y1
;
3079 *x2
= canvas
->scroll_x2
;
3082 *y2
= canvas
->scroll_y2
;
3086 foo_canvas_set_center_scroll_region (FooCanvas
*canvas
,
3087 gboolean center_scroll_region
)
3089 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3091 canvas
->center_scroll_region
= center_scroll_region
!= 0;
3094 canvas
->layout
.hadjustment
->value
,
3095 canvas
->layout
.vadjustment
->value
);
3100 * foo_canvas_set_pixels_per_unit:
3101 * @canvas: A canvas.
3102 * @n: The number of pixels that correspond to one canvas unit.
3104 * Sets the zooming factor of a canvas by specifying the number of pixels that
3105 * correspond to one canvas unit.
3108 foo_canvas_set_pixels_per_unit (FooCanvas
*canvas
, double n
)
3113 int center_x
, center_y
;
3115 GdkWindowAttr attributes
;
3116 gint attributes_mask
;
3118 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3119 g_return_if_fail (n
> FOO_CANVAS_EPSILON
);
3121 widget
= GTK_WIDGET (canvas
);
3123 center_x
= widget
->allocation
.width
/ 2;
3124 center_y
= widget
->allocation
.height
/ 2;
3126 /* Find the coordinates of the screen center in units. */
3127 cx
= (canvas
->layout
.hadjustment
->value
+ center_x
) / canvas
->pixels_per_unit
+ canvas
->scroll_x1
+ canvas
->zoom_xofs
;
3128 cy
= (canvas
->layout
.vadjustment
->value
+ center_y
) / canvas
->pixels_per_unit
+ canvas
->scroll_y1
+ canvas
->zoom_yofs
;
3130 /* Now calculate the new offset of the upper left corner. (round not truncate) */
3131 x1
= ((cx
- canvas
->scroll_x1
) * n
) - center_x
+ .5;
3132 y1
= ((cy
- canvas
->scroll_y1
) * n
) - center_y
+ .5;
3134 canvas
->pixels_per_unit
= n
;
3136 if (!(canvas
->root
->object
.flags
& FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
)) {
3137 canvas
->root
->object
.flags
|= FOO_CANVAS_ITEM_NEED_DEEP_UPDATE
;
3138 foo_canvas_request_update (canvas
);
3141 /* Map a background None window over the bin_window to avoid
3142 * scrolling the window scroll causing exposes.
3145 if (gtk_widget_get_mapped (widget
)) {
3146 attributes
.window_type
= GDK_WINDOW_CHILD
;
3147 attributes
.x
= widget
->allocation
.x
;
3148 attributes
.y
= widget
->allocation
.y
;
3149 attributes
.width
= widget
->allocation
.width
;
3150 attributes
.height
= widget
->allocation
.height
;
3151 attributes
.wclass
= GDK_INPUT_OUTPUT
;
3152 attributes
.visual
= gtk_widget_get_visual (widget
);
3153 attributes
.colormap
= gtk_widget_get_colormap (widget
);
3154 attributes
.event_mask
= GDK_VISIBILITY_NOTIFY_MASK
;
3156 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
3158 window
= gdk_window_new (gtk_widget_get_parent_window (widget
),
3159 &attributes
, attributes_mask
);
3160 gdk_window_set_back_pixmap (window
, NULL
, FALSE
);
3161 gdk_window_set_user_data (window
, widget
);
3163 gdk_window_show (window
);
3166 scroll_to (canvas
, x1
, y1
);
3168 /* If we created a an overlapping background None window, remove it how.
3170 * TODO: We would like to temporarily set the bin_window background to
3171 * None to avoid clearing the bin_window to the background, but gdk doesn't
3172 * expose enought to let us do this, so we get a flash-effect here. At least
3173 * it looks better than scroll + expose.
3175 if (window
!= NULL
) {
3176 gdk_window_hide (window
);
3177 gdk_window_set_user_data (window
, NULL
);
3178 gdk_window_destroy (window
);
3181 canvas
->need_repick
= TRUE
;
3185 * foo_canvas_scroll_to:
3186 * @canvas: A canvas.
3187 * @cx: Horizontal scrolling offset in canvas pixel units.
3188 * @cy: Vertical scrolling offset in canvas pixel units.
3190 * Makes a canvas scroll to the specified offsets, given in canvas pixel units.
3191 * The canvas will adjust the view so that it is not outside the scrolling
3192 * region. This function is typically not used, as it is better to hook
3193 * scrollbars to the canvas layout's scrolling adjusments.
3196 foo_canvas_scroll_to (FooCanvas
*canvas
, int cx
, int cy
)
3198 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3200 scroll_to (canvas
, cx
, cy
);
3204 * foo_canvas_get_scroll_offsets:
3205 * @canvas: A canvas.
3206 * @cx: Horizontal scrolling offset (return value).
3207 * @cy: Vertical scrolling offset (return value).
3209 * Queries the scrolling offsets of a canvas. The values are returned in canvas
3213 foo_canvas_get_scroll_offsets (FooCanvas
*canvas
, int *cx
, int *cy
)
3215 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3218 *cx
= canvas
->layout
.hadjustment
->value
;
3221 *cy
= canvas
->layout
.vadjustment
->value
;
3225 * foo_canvas_update_now:
3226 * @canvas: A canvas.
3228 * Forces an immediate update and redraw of a canvas. If the canvas does not
3229 * have any pending update or redraw requests, then no action is taken. This is
3230 * typically only used by applications that need explicit control of when the
3231 * display is updated, like games. It is not needed by normal applications.
3234 foo_canvas_update_now (FooCanvas
*canvas
)
3236 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3238 if (!(canvas
->need_update
|| canvas
->need_redraw
))
3240 remove_idle (canvas
);
3245 * foo_canvas_get_item_at:
3246 * @canvas: A canvas.
3247 * @x: X position in world coordinates.
3248 * @y: Y position in world coordinates.
3250 * Looks for the item that is under the specified position, which must be
3251 * specified in world coordinates.
3253 * Return value: The sought item, or NULL if no item is at the specified
3257 foo_canvas_get_item_at (FooCanvas
*canvas
, double x
, double y
)
3259 FooCanvasItem
*item
;
3263 g_return_val_if_fail (FOO_IS_CANVAS (canvas
), NULL
);
3265 foo_canvas_w2c (canvas
, x
, y
, &cx
, &cy
);
3267 dist
= foo_canvas_item_invoke_point (canvas
->root
, x
, y
, cx
, cy
, &item
);
3268 if ((int) (dist
* canvas
->pixels_per_unit
+ 0.5) <= canvas
->close_enough
)
3274 /* Queues an update of the canvas */
3276 foo_canvas_request_update (FooCanvas
*canvas
)
3278 FOO_CANVAS_GET_CLASS (canvas
)->request_update (canvas
);
3282 foo_canvas_request_update_real (FooCanvas
*canvas
)
3284 canvas
->need_update
= TRUE
;
3289 * foo_canvas_request_redraw:
3290 * @canvas: A canvas.
3291 * @x1: Leftmost coordinate of the rectangle to be redrawn.
3292 * @y1: Upper coordinate of the rectangle to be redrawn.
3293 * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1.
3294 * @y2: Lower coordinate of the rectangle to be redrawn, plus 1.
3296 * Convenience function that informs a canvas that the specified rectangle needs
3297 * to be repainted. The rectangle includes @x1 and @y1, but not @x2 and @y2.
3298 * To be used only by item implementations.
3301 foo_canvas_request_redraw (FooCanvas
*canvas
, int x1
, int y1
, int x2
, int y2
)
3305 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3307 if (!gtk_widget_is_drawable (GTK_WIDGET (canvas
)) || (x1
>= x2
) || (y1
>= y2
)) return;
3311 bbox
.width
= x2
- x1
;
3312 bbox
.height
= y2
- y1
;
3314 gdk_window_invalidate_rect (canvas
->layout
.bin_window
,
3320 * @canvas: A canvas.
3321 * @wx: World X coordinate.
3322 * @wy: World Y coordinate.
3323 * @cx: X pixel coordinate (return value).
3324 * @cy: Y pixel coordinate (return value).
3326 * Converts world coordinates into canvas pixel coordinates.
3329 foo_canvas_w2c (FooCanvas
*canvas
, double wx
, double wy
, int *cx
, int *cy
)
3333 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3335 zoom
= canvas
->pixels_per_unit
;
3338 *cx
= floor ((wx
- canvas
->scroll_x1
)*zoom
+ canvas
->zoom_xofs
+ 0.5);
3340 *cy
= floor ((wy
- canvas
->scroll_y1
)*zoom
+ canvas
->zoom_yofs
+ 0.5);
3345 * @canvas: A canvas.
3346 * @world: rectangle in world coordinates.
3347 * @canvas: rectangle in canvase coordinates.
3349 * Converts rectangles in world coordinates into canvas pixel coordinates.
3352 foo_canvas_w2c_rect_d (FooCanvas
*canvas
,
3353 double *x1
, double *y1
,
3354 double *x2
, double *y2
)
3356 foo_canvas_w2c_d (canvas
,
3359 foo_canvas_w2c_d (canvas
,
3368 * @canvas: A canvas.
3369 * @wx: World X coordinate.
3370 * @wy: World Y coordinate.
3371 * @cx: X pixel coordinate (return value).
3372 * @cy: Y pixel coordinate (return value).
3374 * Converts world coordinates into canvas pixel coordinates. This version
3375 * produces coordinates in floating point coordinates, for greater precision.
3378 foo_canvas_w2c_d (FooCanvas
*canvas
, double wx
, double wy
, double *cx
, double *cy
)
3382 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3384 zoom
= canvas
->pixels_per_unit
;
3387 *cx
= (wx
- canvas
->scroll_x1
)*zoom
+ canvas
->zoom_xofs
;
3389 *cy
= (wy
- canvas
->scroll_y1
)*zoom
+ canvas
->zoom_yofs
;
3395 * @canvas: A canvas.
3396 * @cx: Canvas pixel X coordinate.
3397 * @cy: Canvas pixel Y coordinate.
3398 * @wx: X world coordinate (return value).
3399 * @wy: Y world coordinate (return value).
3401 * Converts canvas pixel coordinates to world coordinates.
3404 foo_canvas_c2w (FooCanvas
*canvas
, int cx
, int cy
, double *wx
, double *wy
)
3408 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3410 zoom
= canvas
->pixels_per_unit
;
3413 *wx
= (cx
- canvas
->zoom_xofs
)/zoom
+ canvas
->scroll_x1
;
3415 *wy
= (cy
- canvas
->zoom_yofs
)/zoom
+ canvas
->scroll_y1
;
3420 * foo_canvas_window_to_world:
3421 * @canvas: A canvas.
3422 * @winx: Window-relative X coordinate.
3423 * @winy: Window-relative Y coordinate.
3424 * @worldx: X world coordinate (return value).
3425 * @worldy: Y world coordinate (return value).
3427 * Converts window-relative coordinates into world coordinates. You can use
3428 * this when you need to convert mouse coordinates into world coordinates, for
3430 * Window coordinates are really the same as canvas coordinates now, but this
3431 * function is here for backwards compatibility reasons.
3434 foo_canvas_window_to_world (FooCanvas
*canvas
, double winx
, double winy
,
3435 double *worldx
, double *worldy
)
3437 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3440 *worldx
= canvas
->scroll_x1
+ ((winx
- canvas
->zoom_xofs
)
3441 / canvas
->pixels_per_unit
);
3444 *worldy
= canvas
->scroll_y1
+ ((winy
- canvas
->zoom_yofs
)
3445 / canvas
->pixels_per_unit
);
3450 * foo_canvas_world_to_window:
3451 * @canvas: A canvas.
3452 * @worldx: World X coordinate.
3453 * @worldy: World Y coordinate.
3454 * @winx: X window-relative coordinate.
3455 * @winy: Y window-relative coordinate.
3457 * Converts world coordinates into window-relative coordinates.
3458 * Window coordinates are really the same as canvas coordinates now, but this
3459 * function is here for backwards compatibility reasons.
3462 foo_canvas_world_to_window (FooCanvas
*canvas
, double worldx
, double worldy
,
3463 double *winx
, double *winy
)
3465 g_return_if_fail (FOO_IS_CANVAS (canvas
));
3468 *winx
= (canvas
->pixels_per_unit
)*(worldx
- canvas
->scroll_x1
) + canvas
->zoom_xofs
;
3471 *winy
= (canvas
->pixels_per_unit
)*(worldy
- canvas
->scroll_y1
) + canvas
->zoom_yofs
;
3477 * foo_canvas_get_color:
3478 * @canvas: A canvas.
3479 * @spec: X color specification, or NULL for "transparent".
3480 * @color: Returns the allocated color.
3482 * Allocates a color based on the specified X color specification. As a
3483 * convenience to item implementations, it returns TRUE if the color was
3484 * allocated, or FALSE if the specification was NULL. A NULL color
3485 * specification is considered as "transparent" by the canvas.
3487 * Return value: TRUE if @spec is non-NULL and the color is allocated. If @spec
3488 * is NULL, then returns FALSE.
3491 foo_canvas_get_color (FooCanvas
*canvas
, const char *spec
, GdkColor
*color
)
3493 GdkColormap
*colormap
;
3495 g_return_val_if_fail (FOO_IS_CANVAS (canvas
), FALSE
);
3496 g_return_val_if_fail (color
!= NULL
, FALSE
);
3506 gdk_color_parse (spec
, color
);
3508 colormap
= gtk_widget_get_colormap (GTK_WIDGET (canvas
));
3510 gdk_rgb_find_color (colormap
, color
);
3516 * foo_canvas_get_color_pixel:
3517 * @canvas: A canvas.
3518 * @rgba: RGBA color specification.
3520 * Allocates a color from the RGBA value passed into this function. The alpha
3521 * opacity value is discarded, since normal X colors do not support it.
3523 * Return value: Allocated pixel value corresponding to the specified color.
3526 foo_canvas_get_color_pixel (FooCanvas
*canvas
, guint rgba
)
3528 GdkColormap
*colormap
;
3531 g_return_val_if_fail (FOO_IS_CANVAS (canvas
), 0);
3533 color
.red
= ((rgba
& 0xff000000) >> 16) + ((rgba
& 0xff000000) >> 24);
3534 color
.green
= ((rgba
& 0x00ff0000) >> 8) + ((rgba
& 0x00ff0000) >> 16);
3535 color
.blue
= (rgba
& 0x0000ff00) + ((rgba
& 0x0000ff00) >> 8);
3538 colormap
= gtk_widget_get_colormap (GTK_WIDGET (canvas
));
3540 gdk_rgb_find_color (colormap
, &color
);
3546 boolean_handled_accumulator (GSignalInvocationHint
*ihint
,
3547 GValue
*return_accu
,
3548 const GValue
*handler_return
,
3551 gboolean continue_emission
;
3552 gboolean signal_handled
;
3554 signal_handled
= g_value_get_boolean (handler_return
);
3555 g_value_set_boolean (return_accu
, signal_handled
);
3556 continue_emission
= !signal_handled
;
3558 return continue_emission
;
3562 foo_canvas_item_accessible_add_focus_handler (AtkComponent
*component
,
3563 AtkFocusHandler handler
)
3565 GSignalMatchType match_type
;
3568 match_type
= G_SIGNAL_MATCH_ID
| G_SIGNAL_MATCH_FUNC
;
3569 signal_id
= g_signal_lookup ("focus-event", ATK_TYPE_OBJECT
);
3571 if (!g_signal_handler_find (component
, match_type
, signal_id
, 0, NULL
,
3572 (gpointer
) handler
, NULL
)) {
3573 return g_signal_connect_closure_by_id (component
,
3576 G_CALLBACK (handler
), NULL
,
3577 (GClosureNotify
) NULL
),
3584 foo_canvas_item_accessible_get_item_extents (FooCanvasItem
*item
,
3587 double bx1
, bx2
, by1
, by2
;
3588 gint scroll_x
, scroll_y
;
3589 gint x1
, x2
, y1
, y2
;
3591 foo_canvas_item_get_bounds (item
, &bx1
, &by1
, &bx2
, &by2
);
3592 foo_canvas_w2c_rect_d (item
->canvas
, &bx1
, &by1
, &bx2
, &by2
);
3593 foo_canvas_get_scroll_offsets (item
->canvas
, &scroll_x
, &scroll_y
);
3594 x1
= floor (bx1
+ .5);
3595 y1
= floor (by1
+ .5);
3596 x2
= floor (bx2
+ .5);
3597 y2
= floor (by2
+ .5);
3598 rect
->x
= x1
- scroll_x
;
3599 rect
->y
= y1
- scroll_y
;
3600 rect
->width
= x2
- x1
;
3601 rect
->height
= y2
- y1
;
3605 foo_canvas_item_accessible_is_item_in_window (FooCanvasItem
*item
,
3611 widget
= GTK_WIDGET (item
->canvas
);
3612 if (widget
->window
) {
3613 int window_width
, window_height
;
3615 gdk_window_get_geometry (widget
->window
, NULL
, NULL
,
3616 &window_width
, &window_height
, NULL
);
3618 * Check whether rectangles intersect
3620 if (rect
->x
+ rect
->width
< 0 ||
3621 rect
->y
+ rect
->height
< 0 ||
3622 rect
->x
> window_width
||
3623 rect
->y
> window_height
) {
3636 foo_canvas_item_accessible_get_extents (AtkComponent
*component
,
3641 AtkCoordType coord_type
)
3643 AtkGObjectAccessible
*atk_gobj
;
3645 FooCanvasItem
*item
;
3646 gint window_x
, window_y
;
3647 gint toplevel_x
, toplevel_y
;
3652 atk_gobj
= ATK_GOBJECT_ACCESSIBLE (component
);
3653 obj
= atk_gobject_accessible_get_object (atk_gobj
);
3656 /* item is defunct */
3660 /* Get the CanvasItem */
3661 item
= FOO_CANVAS_ITEM (obj
);
3663 /* If this item has no parent canvas, something's broken */
3664 g_return_if_fail (GTK_IS_WIDGET (item
->canvas
));
3666 foo_canvas_item_accessible_get_item_extents (item
, &rect
);
3667 *width
= rect
.width
;
3668 *height
= rect
.height
;
3669 if (!foo_canvas_item_accessible_is_item_in_window (item
, &rect
)) {
3675 canvas
= GTK_WIDGET (item
->canvas
);
3676 window
= gtk_widget_get_parent_window (canvas
);
3677 gdk_window_get_origin (window
, &window_x
, &window_y
);
3678 *x
= rect
.x
+ window_x
;
3679 *y
= rect
.y
+ window_y
;
3680 if (coord_type
== ATK_XY_WINDOW
) {
3681 window
= gdk_window_get_toplevel (canvas
->window
);
3682 gdk_window_get_origin (window
, &toplevel_x
, &toplevel_y
);
3690 foo_canvas_item_accessible_get_mdi_zorder (AtkComponent
*component
)
3692 AtkGObjectAccessible
*atk_gobj
;
3694 FooCanvasItem
*item
;
3696 atk_gobj
= ATK_GOBJECT_ACCESSIBLE (component
);
3697 g_obj
= atk_gobject_accessible_get_object (atk_gobj
);
3698 if (g_obj
== NULL
) {
3699 /* Object is defunct */
3703 item
= FOO_CANVAS_ITEM (g_obj
);
3705 return g_list_index (FOO_CANVAS_GROUP (item
->parent
)->item_list
, item
);
3707 g_return_val_if_fail (item
->canvas
->root
== item
, -1);
3713 foo_canvas_item_accessible_grab_focus (AtkComponent
*component
)
3715 AtkGObjectAccessible
*atk_gobj
;
3717 FooCanvasItem
*item
;
3718 GtkWidget
*toplevel
;
3720 atk_gobj
= ATK_GOBJECT_ACCESSIBLE (component
);
3721 obj
= atk_gobject_accessible_get_object (atk_gobj
);
3723 item
= FOO_CANVAS_ITEM (obj
);
3725 /* item is defunct */
3729 foo_canvas_item_grab_focus (item
);
3730 toplevel
= gtk_widget_get_toplevel (GTK_WIDGET (item
->canvas
));
3731 if (gtk_widget_is_toplevel (toplevel
)) {
3732 gtk_window_present (GTK_WINDOW (toplevel
));
3739 foo_canvas_item_accessible_remove_focus_handler (AtkComponent
*component
,
3742 g_signal_handler_disconnect (component
, handler_id
);
3746 foo_canvas_item_accessible_component_interface_init (AtkComponentIface
*iface
)
3748 g_return_if_fail (iface
!= NULL
);
3750 iface
->add_focus_handler
= foo_canvas_item_accessible_add_focus_handler
;
3751 iface
->get_extents
= foo_canvas_item_accessible_get_extents
;
3752 iface
->get_mdi_zorder
= foo_canvas_item_accessible_get_mdi_zorder
;
3753 iface
->grab_focus
= foo_canvas_item_accessible_grab_focus
;
3754 iface
->remove_focus_handler
= foo_canvas_item_accessible_remove_focus_handler
;
3758 foo_canvas_item_accessible_is_item_on_screen (FooCanvasItem
*item
)
3762 foo_canvas_item_accessible_get_item_extents (item
, &rect
);
3763 return foo_canvas_item_accessible_is_item_in_window (item
, &rect
);
3767 foo_canvas_item_accessible_initialize (AtkObject
*obj
, gpointer data
)
3769 if (ATK_OBJECT_CLASS (accessible_item_parent_class
)->initialize
!= NULL
)
3770 ATK_OBJECT_CLASS (accessible_item_parent_class
)->initialize (obj
, data
);
3771 g_object_set_data (G_OBJECT (obj
), "atk-component-layer",
3772 GINT_TO_POINTER (ATK_LAYER_MDI
));
3776 foo_canvas_item_accessible_ref_state_set (AtkObject
*accessible
)
3778 AtkGObjectAccessible
*atk_gobj
;
3780 FooCanvasItem
*item
;
3781 AtkStateSet
*state_set
;
3783 state_set
= ATK_OBJECT_CLASS (accessible_item_parent_class
)->ref_state_set (accessible
);
3784 atk_gobj
= ATK_GOBJECT_ACCESSIBLE (accessible
);
3785 obj
= atk_gobject_accessible_get_object (atk_gobj
);
3787 item
= FOO_CANVAS_ITEM (obj
);
3789 atk_state_set_add_state (state_set
, ATK_STATE_DEFUNCT
);
3791 if (item
->object
.flags
& FOO_CANVAS_ITEM_VISIBLE
) {
3792 atk_state_set_add_state (state_set
, ATK_STATE_VISIBLE
);
3794 if (foo_canvas_item_accessible_is_item_on_screen (item
)) {
3795 atk_state_set_add_state (state_set
, ATK_STATE_SHOWING
);
3798 if (gtk_widget_get_can_focus (GTK_WIDGET (item
->canvas
))) {
3799 atk_state_set_add_state (state_set
, ATK_STATE_FOCUSABLE
);
3801 if (item
->canvas
->focused_item
== item
) {
3802 atk_state_set_add_state (state_set
, ATK_STATE_FOCUSED
);
3811 foo_canvas_item_accessible_class_init (AtkObjectClass
*klass
)
3813 accessible_item_parent_class
= g_type_class_peek_parent (klass
);
3815 klass
->initialize
= foo_canvas_item_accessible_initialize
;
3816 klass
->ref_state_set
= foo_canvas_item_accessible_ref_state_set
;
3820 foo_canvas_item_accessible_get_type (void)
3822 static GType type
= 0;
3825 static const GInterfaceInfo atk_component_info
= {
3826 (GInterfaceInitFunc
) foo_canvas_item_accessible_component_interface_init
,
3827 (GInterfaceFinalizeFunc
) NULL
,
3830 AtkObjectFactory
*factory
;
3831 GType parent_atk_type
;
3833 GTypeInfo tinfo
= { 0 };
3835 factory
= atk_registry_get_factory (atk_get_default_registry(),
3838 return G_TYPE_INVALID
;
3840 parent_atk_type
= atk_object_factory_get_accessible_type (factory
);
3841 if (!parent_atk_type
) {
3842 return G_TYPE_INVALID
;
3844 g_type_query (parent_atk_type
, &query
);
3845 tinfo
.class_init
= (GClassInitFunc
) foo_canvas_item_accessible_class_init
;
3846 tinfo
.class_size
= query
.class_size
;
3847 tinfo
.instance_size
= query
.instance_size
;
3848 type
= g_type_register_static (parent_atk_type
,
3849 "FooCanvasItemAccessibility",
3852 g_type_add_interface_static (type
, ATK_TYPE_COMPONENT
,
3853 &atk_component_info
);
3861 foo_canvas_item_accessible_create (GObject
*for_object
)
3864 AtkObject
*accessible
;
3865 FooCanvasItem
*item
;
3867 item
= FOO_CANVAS_ITEM (for_object
);
3868 g_return_val_if_fail (item
!= NULL
, NULL
);
3870 type
= foo_canvas_item_accessible_get_type ();
3871 if (type
== G_TYPE_INVALID
) {
3872 return atk_no_op_object_new (for_object
);
3875 accessible
= g_object_new (type
, NULL
);
3876 atk_object_initialize (accessible
, for_object
);
3881 foo_canvas_item_accessible_factory_get_accessible_type (void)
3883 return foo_canvas_item_accessible_get_type ();
3887 foo_canvas_item_accessible_factory_create_accessible (GObject
*obj
)
3889 AtkObject
*accessible
;
3891 g_return_val_if_fail (G_IS_OBJECT (obj
), NULL
);
3893 accessible
= foo_canvas_item_accessible_create (obj
);
3899 foo_canvas_item_accessible_factory_class_init (AtkObjectFactoryClass
*klass
)
3901 klass
->create_accessible
= foo_canvas_item_accessible_factory_create_accessible
;
3902 klass
->get_accessible_type
= foo_canvas_item_accessible_factory_get_accessible_type
;
3906 foo_canvas_item_accessible_factory_get_type (void)
3908 static GType type
= 0;
3911 static const GTypeInfo tinfo
= {
3912 sizeof (AtkObjectFactoryClass
),
3913 (GBaseInitFunc
) NULL
,
3914 (GBaseFinalizeFunc
) NULL
,
3915 (GClassInitFunc
) foo_canvas_item_accessible_factory_class_init
,
3916 NULL
, /* class_finalize */
3917 NULL
, /* class_data */
3918 sizeof (AtkObjectFactory
),
3919 0, /* n_preallocs */
3922 type
= g_type_register_static (ATK_TYPE_OBJECT_FACTORY
,
3923 "FooCanvasItemAccessibilityFactory",
3930 /* Class initialization function for FooCanvasItemClass */
3932 foo_canvas_item_class_init (FooCanvasItemClass
*klass
)
3934 GObjectClass
*gobject_class
= (GObjectClass
*) klass
;
3936 item_parent_class
= g_type_class_peek_parent (klass
);
3938 gobject_class
->set_property
= foo_canvas_item_set_property
;
3939 gobject_class
->get_property
= foo_canvas_item_get_property
;
3940 gobject_class
->dispose
= foo_canvas_item_dispose
;
3942 g_object_class_install_property
3943 (gobject_class
, ITEM_PROP_PARENT
,
3944 g_param_spec_object ("parent", NULL
, NULL
,
3945 FOO_TYPE_CANVAS_ITEM
,
3946 G_PARAM_READWRITE
));
3948 g_object_class_install_property
3949 (gobject_class
, ITEM_PROP_VISIBLE
,
3950 g_param_spec_boolean ("visible", NULL
, NULL
,
3952 G_PARAM_READWRITE
));
3954 item_signals
[ITEM_EVENT
] =
3955 g_signal_new ("event",
3956 G_TYPE_FROM_CLASS (klass
),
3958 G_STRUCT_OFFSET (FooCanvasItemClass
, event
),
3959 boolean_handled_accumulator
, NULL
,
3960 foo_canvas_marshal_BOOLEAN__BOXED
,
3962 GDK_TYPE_EVENT
| G_SIGNAL_TYPE_STATIC_SCOPE
);
3964 klass
->realize
= foo_canvas_item_realize
;
3965 klass
->unrealize
= foo_canvas_item_unrealize
;
3966 klass
->map
= foo_canvas_item_map
;
3967 klass
->unmap
= foo_canvas_item_unmap
;
3968 klass
->update
= foo_canvas_item_update
;
3970 atk_registry_set_factory_type (atk_get_default_registry (),
3971 FOO_TYPE_CANVAS_ITEM
,
3972 foo_canvas_item_accessible_factory_get_type ());