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 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * published by the Free Software Foundation; either the
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU Lesser General Public License
18 * License along with the Gnome Library; see the file COPYING.LIB. If not,
24 * GnomeCanvas widget - Tk-like canvas widget for Gnome
26 * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
27 * widget. Tk is copyrighted by the Regents of the University of California,
28 * Sun Microsystems, and other parties.
31 * Authors: Federico Mena <federico@nuclecu.unam.mx>
32 * Raph Levien <raph@gimp.org>
36 * TO-DO list for the canvas:
38 * - Allow to specify whether GnomeCanvasImage sizes are in units or pixels
39 * (scale or don't scale).
41 * - Implement a flag for gnome_canvas_item_reparent() that tells the function
42 * to keep the item visually in the same place, that is, to keep it in the
43 * same place with respect to the canvas origin.
45 * - GC put functions for items.
47 * - Widget item (finish it).
50 * gnome_canvas_gimme_all_items_contained_in_this_area (GnomeCanvas *canvas,
53 * - Retrofit all the primitive items with microtile support.
55 * - Curve support for line item.
57 * - Arc item (Havoc has it; to be integrated in GnomeCanvasEllipse).
59 * - Sane font handling API.
61 * - Get_arg methods for items:
62 * - How to fetch the outline width and know whether it is in pixels or units?
66 * Raph's TODO list for the antialiased canvas integration:
68 * - ::point() method for text item not accurate when affine transformed.
70 * - Clip rectangle not implemented in aa renderer for text item.
72 * - Clip paths only partially implemented.
74 * - Add more image loading techniques to work around imlib deficiencies.
84 #include <gdk/gdkprivate.h>
86 #include <cairo-gobject.h>
87 #include "gailcanvas.h"
88 #include "gnome-canvas.h"
89 #include "gnome-canvas-i18n.h"
90 #include "gnome-canvas-util.h"
92 /* We must run our idle update handler *before* GDK wants to redraw. */
93 #define CANVAS_IDLE_PRIORITY (GDK_PRIORITY_REDRAW - 5)
95 static void gnome_canvas_request_update (GnomeCanvas
*canvas
);
96 static void group_add (GnomeCanvasGroup
*group
,
97 GnomeCanvasItem
*item
);
98 static void group_remove (GnomeCanvasGroup
*group
,
99 GnomeCanvasItem
*item
);
100 static void add_idle (GnomeCanvas
*canvas
);
102 /*** GnomeCanvasItem ***/
104 /* Some convenience stuff */
105 #define GCI_UPDATE_MASK \
106 (GNOME_CANVAS_UPDATE_REQUESTED | \
107 GNOME_CANVAS_UPDATE_AFFINE | \
108 GNOME_CANVAS_UPDATE_CLIP | \
109 GNOME_CANVAS_UPDATE_VISIBILITY)
110 #define GCI_EPSILON 1e-18
111 #define GCI_PRINT_MATRIX(s,a) \
112 g_print ("%s %g %g %g %g %g %g\n", \
113 s, (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5])
125 static gint
emit_event (GnomeCanvas
*canvas
, GdkEvent
*event
);
127 static guint item_signals
[ITEM_LAST_SIGNAL
];
132 G_TYPE_INITIALLY_UNOWNED
)
134 /* Object initialization function for GnomeCanvasItem */
136 gnome_canvas_item_init (GnomeCanvasItem
*item
)
138 item
->flags
|= GNOME_CANVAS_ITEM_VISIBLE
;
140 cairo_matrix_init_identity (&item
->matrix
);
144 * gnome_canvas_item_new:
145 * @parent: The parent group for the new item.
146 * @type: The object type of the item.
147 * @first_arg_name: A list of object argument name/value pairs, NULL-terminated,
148 * used to configure the item. For example, "fill_color", "black",
149 * "width_units", 5.0, NULL.
152 * Creates a new canvas item with @parent as its parent group. The item is
153 * created at the top of its parent's stack, and starts up as visible. The item
154 * is of the specified @type, for example, it can be
155 * gnome_canvas_rect_get_type(). The list of object arguments/value pairs is
156 * used to configure the item. If you need to pass construct time parameters, you
157 * should use g_object_new() to pass the parameters and
158 * gnome_canvas_item_construct() to set up the canvas item.
160 * Return value: The newly-created item.
163 gnome_canvas_item_new (GnomeCanvasGroup
*parent
,
165 const gchar
*first_arg_name
, ...)
167 GnomeCanvasItem
*item
;
170 g_return_val_if_fail (GNOME_IS_CANVAS_GROUP (parent
), NULL
);
171 g_return_val_if_fail (g_type_is_a (type
, gnome_canvas_item_get_type ()), NULL
);
173 item
= GNOME_CANVAS_ITEM (g_object_new (type
, NULL
));
175 va_start (args
, first_arg_name
);
176 gnome_canvas_item_construct (item
, parent
, first_arg_name
, args
);
182 /* Performs post-creation operations on a canvas item (adding it to its parent
186 item_post_create_setup (GnomeCanvasItem
*item
)
188 group_add (GNOME_CANVAS_GROUP (item
->parent
), item
);
190 gnome_canvas_request_redraw (
191 item
->canvas
, item
->x1
, item
->y1
, item
->x2
+ 1, item
->y2
+ 1);
192 item
->canvas
->need_repick
= TRUE
;
195 /* Set_property handler for canvas items */
197 gnome_canvas_item_set_property (GObject
*gobject
,
202 GnomeCanvasItem
*item
;
204 g_return_if_fail (GNOME_IS_CANVAS_ITEM (gobject
));
206 item
= GNOME_CANVAS_ITEM (gobject
);
208 switch (property_id
) {
209 case ITEM_PROP_PARENT
:
210 if (item
->parent
!= NULL
) {
211 g_warning ("Cannot set `parent' argument after item has "
212 "already been constructed.");
213 } else if (g_value_get_object (value
)) {
214 item
->parent
= GNOME_CANVAS_ITEM (g_value_get_object (value
));
215 item
->canvas
= item
->parent
->canvas
;
216 item_post_create_setup (item
);
220 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, property_id
, pspec
);
225 /* Get_property handler for canvas items */
227 gnome_canvas_item_get_property (GObject
*gobject
,
232 GnomeCanvasItem
*item
;
234 g_return_if_fail (GNOME_IS_CANVAS_ITEM (gobject
));
236 item
= GNOME_CANVAS_ITEM (gobject
);
238 switch (property_id
) {
239 case ITEM_PROP_PARENT
:
240 g_value_set_object (value
, item
->parent
);
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, property_id
, pspec
);
250 * gnome_canvas_item_construct:
251 * @item: An unconstructed canvas item.
252 * @parent: The parent group for the item.
253 * @first_arg_name: The name of the first argument for configuring the item.
254 * @args: The list of arguments used to configure the item.
256 * Constructs a canvas item; meant for use only by item implementations.
259 gnome_canvas_item_construct (GnomeCanvasItem
*item
,
260 GnomeCanvasGroup
*parent
,
261 const gchar
*first_arg_name
,
264 g_return_if_fail (GNOME_IS_CANVAS_GROUP (parent
));
265 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
267 item
->parent
= GNOME_CANVAS_ITEM (parent
);
268 item
->canvas
= item
->parent
->canvas
;
270 g_object_set_valist (G_OBJECT (item
), first_arg_name
, args
);
272 item_post_create_setup (item
);
275 /* If the item is visible, requests a redraw of it. */
277 redraw_if_visible (GnomeCanvasItem
*item
)
279 if (item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)
280 gnome_canvas_request_redraw (
281 item
->canvas
, item
->x1
, item
->y1
,
282 item
->x2
+ 1, item
->y2
+ 1);
285 /* Standard object dispose function for canvas items */
287 gnome_canvas_item_dispose (GObject
*object
)
289 GnomeCanvasItem
*item
;
291 g_return_if_fail (GNOME_IS_CANVAS_ITEM (object
));
293 item
= GNOME_CANVAS_ITEM (object
);
296 redraw_if_visible (item
);
298 /* Make the canvas forget about us */
300 if (item
->canvas
&& item
== item
->canvas
->current_item
) {
301 item
->canvas
->current_item
= NULL
;
302 item
->canvas
->need_repick
= TRUE
;
305 if (item
->canvas
&& item
== item
->canvas
->new_current_item
) {
306 item
->canvas
->new_current_item
= NULL
;
307 item
->canvas
->need_repick
= TRUE
;
310 if (item
->canvas
&& item
== item
->canvas
->grabbed_item
) {
311 item
->canvas
->grabbed_item
= NULL
;
314 item
->canvas
->grabbed_device
, GDK_CURRENT_TIME
);
315 g_object_unref (item
->canvas
->grabbed_device
);
316 item
->canvas
->grabbed_device
= NULL
;
319 if (item
->canvas
&& item
== item
->canvas
->focused_item
)
320 item
->canvas
->focused_item
= NULL
;
322 /* Normal dispose stuff */
324 if (item
->flags
& GNOME_CANVAS_ITEM_MAPPED
)
325 (* GNOME_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
327 if (item
->flags
& GNOME_CANVAS_ITEM_REALIZED
)
328 (* GNOME_CANVAS_ITEM_GET_CLASS (item
)->unrealize
) (item
);
331 group_remove (GNOME_CANVAS_GROUP (item
->parent
), item
);
333 if (GNOME_CANVAS_ITEM_GET_CLASS (item
)->dispose
)
334 GNOME_CANVAS_ITEM_GET_CLASS (item
)->dispose (item
);
336 G_OBJECT_CLASS (gnome_canvas_item_parent_class
)->dispose (object
);
337 /* items should remove any reference to item->canvas after the
342 /* Update handler for canvas items */
344 gnome_canvas_item_update (GnomeCanvasItem
*item
,
345 const cairo_matrix_t
*matrix
,
348 item
->flags
&= ~GNOME_CANVAS_ITEM_NEED_UPDATE
;
349 item
->flags
&= ~GNOME_CANVAS_ITEM_NEED_AFFINE
;
350 item
->flags
&= ~GNOME_CANVAS_ITEM_NEED_CLIP
;
351 item
->flags
&= ~GNOME_CANVAS_ITEM_NEED_VIS
;
354 /* Realize handler for canvas items */
356 gnome_canvas_item_realize (GnomeCanvasItem
*item
)
358 item
->flags
|= GNOME_CANVAS_ITEM_REALIZED
;
360 gnome_canvas_item_request_update (item
);
363 /* Unrealize handler for canvas items */
365 gnome_canvas_item_unrealize (GnomeCanvasItem
*item
)
367 item
->flags
&= ~GNOME_CANVAS_ITEM_REALIZED
;
370 /* Map handler for canvas items */
372 gnome_canvas_item_map (GnomeCanvasItem
*item
)
374 item
->flags
|= GNOME_CANVAS_ITEM_MAPPED
;
377 /* Unmap handler for canvas items */
379 gnome_canvas_item_unmap (GnomeCanvasItem
*item
)
381 item
->flags
&= ~GNOME_CANVAS_ITEM_MAPPED
;
384 /* Dispose handler for canvas items */
386 gnome_canvas_item_dispose_item (GnomeCanvasItem
*item
)
388 /* Placeholder so subclasses can safely chain up. */
392 gnome_canvas_item_draw (GnomeCanvasItem
*item
,
399 /* Placeholder so subclasses can safely chain up. */
402 static GnomeCanvasItem
*
403 gnome_canvas_item_point (GnomeCanvasItem
*item
,
409 /* Placeholder so subclasses can safely chain up. */
415 gnome_canvas_item_bounds (GnomeCanvasItem
*item
,
421 /* Placeholder so subclasses can safely chain up. */
425 gnome_canvas_item_event (GnomeCanvasItem
*item
,
428 /* Placeholder so subclasses can safely chain up. */
430 return FALSE
; /* event was not handled */
434 * This routine invokes the update method of the item
435 * Please notice, that we take parent to canvas pixel matrix as argument
436 * unlike virtual method ::update, whose argument is item 2 canvas pixel
439 * I will try to force somewhat meaningful naming for affines (Lauris)
440 * General naming rule is FROM2TO, where FROM and TO are abbreviations
441 * So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel
442 * I hope that this helps to keep track of what really happens
447 gnome_canvas_item_invoke_update (GnomeCanvasItem
*item
,
448 const cairo_matrix_t
*p2c
,
455 if (!(item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
))
456 child_flags
&= ~GNOME_CANVAS_UPDATE_IS_VISIBLE
;
458 /* Calculate actual item transformation matrix */
460 cairo_matrix_multiply (&i2c
, &item
->matrix
, p2c
);
462 /* apply object flags to child flags */
464 child_flags
&= ~GNOME_CANVAS_UPDATE_REQUESTED
;
466 if (item
->flags
& GNOME_CANVAS_ITEM_NEED_UPDATE
)
467 child_flags
|= GNOME_CANVAS_UPDATE_REQUESTED
;
469 if (item
->flags
& GNOME_CANVAS_ITEM_NEED_AFFINE
)
470 child_flags
|= GNOME_CANVAS_UPDATE_AFFINE
;
472 if (item
->flags
& GNOME_CANVAS_ITEM_NEED_CLIP
)
473 child_flags
|= GNOME_CANVAS_UPDATE_CLIP
;
475 if (item
->flags
& GNOME_CANVAS_ITEM_NEED_VIS
)
476 child_flags
|= GNOME_CANVAS_UPDATE_VISIBILITY
;
478 if (child_flags
& GCI_UPDATE_MASK
) {
479 if (GNOME_CANVAS_ITEM_GET_CLASS (item
)->update
)
480 GNOME_CANVAS_ITEM_GET_CLASS (item
)->update (item
, &i2c
, child_flags
);
485 * This routine invokes the point method of the item.
486 * The arguments x, y should be in the parent item local coordinates.
488 * This is potentially evil, as we are relying on matrix inversion (Lauris)
491 static GnomeCanvasItem
*
492 gnome_canvas_item_invoke_point (GnomeCanvasItem
*item
,
498 cairo_matrix_t inverse
;
500 /* Calculate x & y in item local coordinates */
501 inverse
= item
->matrix
;
502 if (cairo_matrix_invert (&inverse
) != CAIRO_STATUS_SUCCESS
)
505 cairo_matrix_transform_point (&inverse
, &x
, &y
);
507 if (GNOME_CANVAS_ITEM_GET_CLASS (item
)->point
)
508 return GNOME_CANVAS_ITEM_GET_CLASS (item
)->point (item
, x
, y
, cx
, cy
);
514 * gnome_canvas_item_set:
515 * @item: A canvas item.
516 * @first_arg_name: The list of object argument name/value pairs used to
517 * configure the item.
520 * Configures a canvas item. The arguments in the item are set to the
521 * specified values, and the item is repainted as appropriate.
524 gnome_canvas_item_set (GnomeCanvasItem
*item
,
525 const gchar
*first_arg_name
,
530 va_start (args
, first_arg_name
);
531 gnome_canvas_item_set_valist (item
, first_arg_name
, args
);
536 * gnome_canvas_item_set_valist:
537 * @item: A canvas item.
538 * @first_arg_name: The name of the first argument used to configure the item.
539 * @args: The list of object argument name/value pairs used to configure the item.
541 * Configures a canvas item. The arguments in the item are set to the specified
542 * values, and the item is repainted as appropriate.
545 gnome_canvas_item_set_valist (GnomeCanvasItem
*item
,
546 const gchar
*first_arg_name
,
549 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
551 g_object_set_valist (G_OBJECT (item
), first_arg_name
, args
);
553 item
->canvas
->need_repick
= TRUE
;
557 * gnome_canvas_item_transform:
558 * @item: A canvas item.
559 * @matrix: An affine transformation matrix.
561 * Combines the specified affine transformation matrix with the item's current
565 gnome_canvas_item_transform (GnomeCanvasItem
*item
,
566 const cairo_matrix_t
*matrix
)
570 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
571 g_return_if_fail (matrix
!= NULL
);
573 /* Calculate actual item transformation matrix */
574 cairo_matrix_multiply (&i2p
, matrix
, &item
->matrix
);
576 gnome_canvas_item_set_matrix (item
, &i2p
);
580 * gnome_canvas_item_set_matrix:
581 * @item: A canvas item.
582 * @matrix: An affine transformation matrix or %NULL for the identity matrix.
584 * Makes the item's affine transformation matrix be equal to the specified
585 * matrix. NULL is treated as identity.
588 gnome_canvas_item_set_matrix (GnomeCanvasItem
*item
,
589 const cairo_matrix_t
*matrix
)
591 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
594 item
->matrix
= *matrix
;
596 cairo_matrix_init_identity (&item
->matrix
);
599 if (!(item
->flags
& GNOME_CANVAS_ITEM_NEED_AFFINE
)) {
601 item
->flags
|= GNOME_CANVAS_ITEM_NEED_AFFINE
;
602 gnome_canvas_item_request_update (item
);
605 item
->canvas
->need_repick
= TRUE
;
609 * gnome_canvas_item_move:
610 * @item: A canvas item.
611 * @dx: Horizontal offset.
612 * @dy: Vertical offset.
614 * Moves a canvas item by creating an affine transformation matrix for
615 * translation by using the specified values. This happens in item
616 * local coordinate system, so if you have nontrivial transform, it
617 * most probably does not do, what you want.
620 gnome_canvas_item_move (GnomeCanvasItem
*item
,
624 cairo_matrix_t translate
;
626 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
628 cairo_matrix_init_translate (&translate
, dx
, dy
);
630 gnome_canvas_item_transform (item
, &translate
);
633 /* Convenience function to reorder items in a group's child list. This puts the
634 * specified link after the "before" link. Returns TRUE if the list was changed.
637 put_item_after (GList
*link
,
640 GnomeCanvasGroup
*parent
;
641 GList
*old_before
, *old_after
;
644 parent
= GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (link
->data
)->parent
);
647 after
= before
->next
;
649 after
= parent
->item_list
;
651 if (before
== link
|| after
== link
)
656 old_before
= link
->prev
;
657 old_after
= link
->next
;
660 old_before
->next
= old_after
;
662 parent
->item_list
= old_after
;
665 old_after
->prev
= old_before
;
667 parent
->item_list_end
= old_before
;
675 parent
->item_list
= link
;
681 parent
->item_list_end
= link
;
687 * gnome_canvas_item_raise:
688 * @item: A canvas item.
689 * @positions: Number of steps to raise the item.
691 * Raises the item in its parent's stack by the specified number of positions.
692 * If the number of positions is greater than the distance to the top of the
693 * stack, then the item is put at the top.
696 gnome_canvas_item_raise (GnomeCanvasItem
*item
,
699 GList
*link
, *before
;
700 GnomeCanvasGroup
*parent
;
702 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
703 g_return_if_fail (positions
>= 0);
705 if (!item
->parent
|| positions
== 0)
708 parent
= GNOME_CANVAS_GROUP (item
->parent
);
709 link
= g_list_find (parent
->item_list
, item
);
710 g_return_if_fail (link
!= NULL
);
712 for (before
= link
; positions
&& before
; positions
--)
713 before
= before
->next
;
716 before
= parent
->item_list_end
;
718 if (put_item_after (link
, before
)) {
719 redraw_if_visible (item
);
720 item
->canvas
->need_repick
= TRUE
;
725 * gnome_canvas_item_lower:
726 * @item: A canvas item.
727 * @positions: Number of steps to lower the item.
729 * Lowers the item in its parent's stack by the specified number of positions.
730 * If the number of positions is greater than the distance to the bottom of the
731 * stack, then the item is put at the bottom.
734 gnome_canvas_item_lower (GnomeCanvasItem
*item
,
737 GList
*link
, *before
;
738 GnomeCanvasGroup
*parent
;
740 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
741 g_return_if_fail (positions
>= 1);
743 if (!item
->parent
|| positions
== 0)
746 parent
= GNOME_CANVAS_GROUP (item
->parent
);
747 link
= g_list_find (parent
->item_list
, item
);
748 g_return_if_fail (link
!= NULL
);
751 for (before
= link
->prev
; positions
&& before
; positions
--)
752 before
= before
->prev
;
756 if (put_item_after (link
, before
)) {
757 redraw_if_visible (item
);
758 item
->canvas
->need_repick
= TRUE
;
763 * gnome_canvas_item_raise_to_top:
764 * @item: A canvas item.
766 * Raises an item to the top of its parent's stack.
769 gnome_canvas_item_raise_to_top (GnomeCanvasItem
*item
)
772 GnomeCanvasGroup
*parent
;
774 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
779 parent
= GNOME_CANVAS_GROUP (item
->parent
);
780 link
= g_list_find (parent
->item_list
, item
);
781 g_return_if_fail (link
!= NULL
);
783 if (put_item_after (link
, parent
->item_list_end
)) {
784 redraw_if_visible (item
);
785 item
->canvas
->need_repick
= TRUE
;
790 * gnome_canvas_item_lower_to_bottom:
791 * @item: A canvas item.
793 * Lowers an item to the bottom of its parent's stack.
796 gnome_canvas_item_lower_to_bottom (GnomeCanvasItem
*item
)
799 GnomeCanvasGroup
*parent
;
801 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
806 parent
= GNOME_CANVAS_GROUP (item
->parent
);
807 link
= g_list_find (parent
->item_list
, item
);
808 g_return_if_fail (link
!= NULL
);
810 if (put_item_after (link
, NULL
)) {
811 redraw_if_visible (item
);
812 item
->canvas
->need_repick
= TRUE
;
817 * gnome_canvas_item_show:
818 * @item: A canvas item.
820 * Shows a canvas item. If the item was already shown, then no action is taken.
823 gnome_canvas_item_show (GnomeCanvasItem
*item
)
825 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
827 if (!(item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)) {
828 item
->flags
|= GNOME_CANVAS_ITEM_VISIBLE
;
829 gnome_canvas_request_redraw (
830 item
->canvas
, item
->x1
, item
->y1
,
831 item
->x2
+ 1, item
->y2
+ 1);
832 item
->canvas
->need_repick
= TRUE
;
837 * gnome_canvas_item_hide:
838 * @item: A canvas item.
840 * Hides a canvas item. If the item was already hidden, then no action is
844 gnome_canvas_item_hide (GnomeCanvasItem
*item
)
846 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
848 if (item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
) {
849 item
->flags
&= ~GNOME_CANVAS_ITEM_VISIBLE
;
850 gnome_canvas_request_redraw (
851 item
->canvas
, item
->x1
, item
->y1
,
852 item
->x2
+ 1, item
->y2
+ 1);
853 item
->canvas
->need_repick
= TRUE
;
858 * gnome_canvas_item_grab:
859 * @item: A canvas item.
860 * @event_mask: Mask of events that will be sent to this item.
861 * @cursor: If non-NULL, the cursor that will be used while the grab is active.
862 * @device: The pointer device to grab.
863 * @etime: The timestamp required for grabbing @device, or GDK_CURRENT_TIME.
865 * Specifies that all events that match the specified event mask should be sent
866 * to the specified item, and also grabs @device by calling gdk_device_grab().
867 * The event mask is also used when grabbing the @device. If @cursor is not
868 * NULL, then that cursor is used while the grab is active. The @etime
869 * parameter is the timestamp required for grabbing the @device.
871 * Return value: If an item was already grabbed, it returns
872 * %GDK_GRAB_ALREADY_GRABBED. If the specified item was hidden by calling
873 * gnome_canvas_item_hide(), then it returns %GDK_GRAB_NOT_VIEWABLE. Else,
874 * it returns the result of calling gdk_device_grab().
877 gnome_canvas_item_grab (GnomeCanvasItem
*item
,
884 GdkWindow
*bin_window
;
887 g_return_val_if_fail (
888 GNOME_IS_CANVAS_ITEM (item
), GDK_GRAB_NOT_VIEWABLE
);
889 g_return_val_if_fail (
890 gtk_widget_get_mapped (GTK_WIDGET (item
->canvas
)),
891 GDK_GRAB_NOT_VIEWABLE
);
892 g_return_val_if_fail (
893 GDK_IS_DEVICE (device
), GDK_GRAB_NOT_VIEWABLE
);
895 if (item
->canvas
->grabbed_item
)
896 return GDK_GRAB_ALREADY_GRABBED
;
898 if (!(item
->flags
& GNOME_CANVAS_ITEM_VISIBLE
))
899 return GDK_GRAB_NOT_VIEWABLE
;
901 layout
= GTK_LAYOUT (item
->canvas
);
902 bin_window
= gtk_layout_get_bin_window (layout
);
904 retval
= gdk_device_grab (
905 device
, bin_window
, GDK_OWNERSHIP_NONE
,
906 FALSE
, event_mask
, cursor
, etime
);
908 if (retval
!= GDK_GRAB_SUCCESS
)
911 item
->canvas
->grabbed_item
= item
;
912 item
->canvas
->grabbed_device
= g_object_ref (device
);
913 item
->canvas
->grabbed_event_mask
= event_mask
;
914 item
->canvas
->current_item
= item
; /* So that events go to the grabbed item */
920 * gnome_canvas_item_ungrab:
921 * @item: A canvas item that holds a grab.
922 * @etime: The timestamp for ungrabbing the mouse.
924 * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the
928 gnome_canvas_item_ungrab (GnomeCanvasItem
*item
,
931 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
933 if (item
->canvas
->grabbed_item
!= item
)
936 item
->canvas
->grabbed_item
= NULL
;
938 g_return_if_fail (item
->canvas
->grabbed_device
!= NULL
);
939 gdk_device_ungrab (item
->canvas
->grabbed_device
, etime
);
941 g_object_unref (item
->canvas
->grabbed_device
);
942 item
->canvas
->grabbed_device
= NULL
;
946 gnome_canvas_item_i2w_matrix (GnomeCanvasItem
*item
,
947 cairo_matrix_t
*matrix
)
949 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
950 g_return_if_fail (matrix
!= NULL
);
952 cairo_matrix_init_identity (matrix
);
955 cairo_matrix_multiply (matrix
, matrix
, &item
->matrix
);
962 gnome_canvas_item_w2i_matrix (GnomeCanvasItem
*item
,
963 cairo_matrix_t
*matrix
)
965 cairo_status_t status
;
967 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
968 g_return_if_fail (matrix
!= NULL
);
970 gnome_canvas_item_i2w_matrix (item
, matrix
);
971 status
= cairo_matrix_invert (matrix
);
972 g_return_if_fail (status
== CAIRO_STATUS_SUCCESS
);
976 * gnome_canvas_item_w2i:
977 * @item: A canvas item.
978 * @x: X coordinate to convert (input/output value).
979 * @y: Y coordinate to convert (input/output value).
981 * Converts a coordinate pair from world coordinates to item-relative
985 gnome_canvas_item_w2i (GnomeCanvasItem
*item
,
989 cairo_matrix_t matrix
;
991 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
992 g_return_if_fail (x
!= NULL
);
993 g_return_if_fail (y
!= NULL
);
995 gnome_canvas_item_w2i_matrix (item
, &matrix
);
996 cairo_matrix_transform_point (&matrix
, x
, y
);
1000 * gnome_canvas_item_i2w:
1001 * @item: A canvas item.
1002 * @x: X coordinate to convert (input/output value).
1003 * @y: Y coordinate to convert (input/output value).
1005 * Converts a coordinate pair from item-relative coordinates to world
1009 gnome_canvas_item_i2w (GnomeCanvasItem
*item
,
1013 cairo_matrix_t matrix
;
1015 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
1016 g_return_if_fail (x
!= NULL
);
1017 g_return_if_fail (y
!= NULL
);
1019 gnome_canvas_item_i2w_matrix (item
, &matrix
);
1020 cairo_matrix_transform_point (&matrix
, x
, y
);
1024 * gnome_canvas_item_i2c_matrix:
1025 * @item: A canvas item.
1026 * @matrix: Matrix to take the resulting transformation matrix (return value).
1028 * Gets the affine transform that converts from item-relative coordinates to
1029 * canvas pixel coordinates.
1032 gnome_canvas_item_i2c_matrix (GnomeCanvasItem
*item
,
1033 cairo_matrix_t
*matrix
)
1035 cairo_matrix_t i2w
, w2c
;
1037 gnome_canvas_item_i2w_matrix (item
, &i2w
);
1038 gnome_canvas_w2c_matrix (item
->canvas
, &w2c
);
1039 cairo_matrix_multiply (matrix
, &i2w
, &w2c
);
1042 /* Returns whether the item is an inferior of or is equal to the parent. */
1044 is_descendant (GnomeCanvasItem
*item
,
1045 GnomeCanvasItem
*parent
)
1047 for (; item
; item
= item
->parent
)
1055 * gnome_canvas_item_reparent:
1056 * @item: A canvas item.
1057 * @new_group: A canvas group.
1059 * Changes the parent of the specified item to be the new group. The item keeps
1060 * its group-relative coordinates as for its old parent, so the item may change
1061 * its absolute position within the canvas.
1064 gnome_canvas_item_reparent (GnomeCanvasItem
*item
,
1065 GnomeCanvasGroup
*new_group
)
1067 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
1068 g_return_if_fail (GNOME_IS_CANVAS_GROUP (new_group
));
1070 /* Both items need to be in the same canvas */
1071 g_return_if_fail (item
->canvas
== GNOME_CANVAS_ITEM (new_group
)->canvas
);
1073 /* The group cannot be an inferior of the item or be the item itself --
1074 * this also takes care of the case where the item is the root item of
1076 g_return_if_fail (!is_descendant (GNOME_CANVAS_ITEM (new_group
), item
));
1078 /* Everything is ok, now actually reparent the item */
1080 g_object_ref (item
); /* protect it from the unref in group_remove */
1082 redraw_if_visible (item
);
1084 group_remove (GNOME_CANVAS_GROUP (item
->parent
), item
);
1085 item
->parent
= GNOME_CANVAS_ITEM (new_group
);
1086 group_add (new_group
, item
);
1088 /* Redraw and repick */
1090 redraw_if_visible (item
);
1091 item
->canvas
->need_repick
= TRUE
;
1093 g_object_unref (item
);
1097 * gnome_canvas_item_grab_focus:
1098 * @item: A canvas item.
1100 * Makes the specified item take the keyboard focus, so all keyboard events will
1101 * be sent to it. If the canvas widget itself did not have the focus, it grabs
1105 gnome_canvas_item_grab_focus (GnomeCanvasItem
*item
)
1107 GnomeCanvasItem
*focused_item
;
1110 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
1111 g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item
->canvas
)));
1113 focused_item
= item
->canvas
->focused_item
;
1117 GdkWindow
*bin_window
;
1119 layout
= GTK_LAYOUT (item
->canvas
);
1120 bin_window
= gtk_layout_get_bin_window (layout
);
1122 ev
.focus_change
.type
= GDK_FOCUS_CHANGE
;
1123 ev
.focus_change
.window
= bin_window
;
1124 ev
.focus_change
.send_event
= FALSE
;
1125 ev
.focus_change
.in
= FALSE
;
1127 emit_event (item
->canvas
, &ev
);
1130 item
->canvas
->focused_item
= item
;
1131 gtk_widget_grab_focus (GTK_WIDGET (item
->canvas
));
1135 GdkWindow
*bin_window
;
1137 layout
= GTK_LAYOUT (item
->canvas
);
1138 bin_window
= gtk_layout_get_bin_window (layout
);
1140 ev
.focus_change
.type
= GDK_FOCUS_CHANGE
;
1141 ev
.focus_change
.window
= bin_window
;
1142 ev
.focus_change
.send_event
= FALSE
;
1143 ev
.focus_change
.in
= TRUE
;
1145 emit_event (item
->canvas
, &ev
);
1150 * gnome_canvas_item_get_bounds:
1151 * @item: A canvas item.
1152 * @x1: Leftmost edge of the bounding box (return value).
1153 * @y1: Upper edge of the bounding box (return value).
1154 * @x2: Rightmost edge of the bounding box (return value).
1155 * @y2: Lower edge of the bounding box (return value).
1157 * Queries the bounding box of a canvas item. The bounds are returned in the
1158 * coordinate system of the item's parent.
1161 gnome_canvas_item_get_bounds (GnomeCanvasItem
*item
,
1167 gdouble tx1
, ty1
, tx2
, ty2
;
1169 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
1171 tx1
= ty1
= tx2
= ty2
= 0.0;
1173 /* Get the item's bounds in its coordinate system */
1175 if (GNOME_CANVAS_ITEM_GET_CLASS (item
)->bounds
)
1176 GNOME_CANVAS_ITEM_GET_CLASS (item
)->bounds (
1177 item
, &tx1
, &ty1
, &tx2
, &ty2
);
1179 /* Make the bounds relative to the item's parent coordinate system */
1180 gnome_canvas_matrix_transform_rect (&item
->matrix
, &tx1
, &ty1
, &tx2
, &ty2
);
1182 /* Return the values */
1198 * gnome_canvas_item_request_update
1199 * @item: A canvas item.
1201 * To be used only by item implementations. Requests that the canvas queue an
1202 * update for the specified item.
1205 gnome_canvas_item_request_update (GnomeCanvasItem
*item
)
1207 if (item
->flags
& GNOME_CANVAS_ITEM_NEED_UPDATE
)
1210 item
->flags
|= GNOME_CANVAS_ITEM_NEED_UPDATE
;
1212 if (item
->parent
!= NULL
) {
1213 /* Recurse up the tree */
1214 gnome_canvas_item_request_update (item
->parent
);
1216 /* Have reached the top of the tree, make
1217 * sure the update call gets scheduled. */
1218 gnome_canvas_request_update (item
->canvas
);
1222 /*** GnomeCanvasGroup ***/
1230 static void gnome_canvas_group_set_property (GObject
*object
,
1232 const GValue
*value
,
1234 static void gnome_canvas_group_get_property (GObject
*object
,
1239 static void gnome_canvas_group_dispose (GnomeCanvasItem
*object
);
1241 static void gnome_canvas_group_update (GnomeCanvasItem
*item
,
1242 const cairo_matrix_t
*matrix
,
1244 static void gnome_canvas_group_realize (GnomeCanvasItem
*item
);
1245 static void gnome_canvas_group_unrealize (GnomeCanvasItem
*item
);
1246 static void gnome_canvas_group_map (GnomeCanvasItem
*item
);
1247 static void gnome_canvas_group_unmap (GnomeCanvasItem
*item
);
1248 static void gnome_canvas_group_draw (GnomeCanvasItem
*item
,
1251 gint width
, gint height
);
1252 static GnomeCanvasItem
*gnome_canvas_group_point (GnomeCanvasItem
*item
,
1253 gdouble x
, gdouble y
,
1255 static void gnome_canvas_group_bounds (GnomeCanvasItem
*item
,
1256 gdouble
*x1
, gdouble
*y1
,
1257 gdouble
*x2
, gdouble
*y2
);
1262 GNOME_TYPE_CANVAS_ITEM
)
1264 /* Class initialization function for GnomeCanvasGroupClass */
1266 gnome_canvas_group_class_init (GnomeCanvasGroupClass
*class)
1268 GObjectClass
*object_class
;
1269 GnomeCanvasItemClass
*item_class
;
1271 object_class
= (GObjectClass
*) class;
1272 item_class
= (GnomeCanvasItemClass
*) class;
1274 object_class
->set_property
= gnome_canvas_group_set_property
;
1275 object_class
->get_property
= gnome_canvas_group_get_property
;
1277 g_object_class_install_property (
1280 g_param_spec_double (
1290 g_object_class_install_property (
1293 g_param_spec_double (
1303 item_class
->dispose
= gnome_canvas_group_dispose
;
1304 item_class
->update
= gnome_canvas_group_update
;
1305 item_class
->realize
= gnome_canvas_group_realize
;
1306 item_class
->unrealize
= gnome_canvas_group_unrealize
;
1307 item_class
->map
= gnome_canvas_group_map
;
1308 item_class
->unmap
= gnome_canvas_group_unmap
;
1309 item_class
->draw
= gnome_canvas_group_draw
;
1310 item_class
->point
= gnome_canvas_group_point
;
1311 item_class
->bounds
= gnome_canvas_group_bounds
;
1314 /* Object initialization function for GnomeCanvasGroup */
1316 gnome_canvas_group_init (GnomeCanvasGroup
*group
)
1320 /* Set_property handler for canvas groups */
1322 gnome_canvas_group_set_property (GObject
*gobject
,
1324 const GValue
*value
,
1327 GnomeCanvasItem
*item
;
1329 g_return_if_fail (GNOME_IS_CANVAS_GROUP (gobject
));
1331 item
= GNOME_CANVAS_ITEM (gobject
);
1333 switch (property_id
) {
1335 item
->matrix
.x0
= g_value_get_double (value
);
1339 item
->matrix
.y0
= g_value_get_double (value
);
1343 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, property_id
, pspec
);
1348 /* Get_property handler for canvas groups */
1350 gnome_canvas_group_get_property (GObject
*gobject
,
1355 GnomeCanvasItem
*item
;
1357 g_return_if_fail (GNOME_IS_CANVAS_GROUP (gobject
));
1359 item
= GNOME_CANVAS_ITEM (gobject
);
1361 switch (property_id
) {
1363 g_value_set_double (value
, item
->matrix
.x0
);
1367 g_value_set_double (value
, item
->matrix
.y0
);
1371 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject
, property_id
, pspec
);
1376 /* Dispose handler for canvas groups */
1378 gnome_canvas_group_dispose (GnomeCanvasItem
*object
)
1380 GnomeCanvasGroup
*group
;
1382 g_return_if_fail (GNOME_IS_CANVAS_GROUP (object
));
1384 group
= GNOME_CANVAS_GROUP (object
);
1386 while (group
->item_list
) {
1387 /* child is unref'ed by the child's group_remove (). */
1388 g_object_run_dispose (G_OBJECT (group
->item_list
->data
));
1391 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_group_parent_class
)->
1395 /* Update handler for canvas groups */
1397 gnome_canvas_group_update (GnomeCanvasItem
*item
,
1398 const cairo_matrix_t
*i2c
,
1401 GnomeCanvasGroup
*group
;
1404 gdouble x1
, y1
, x2
, y2
;
1406 group
= GNOME_CANVAS_GROUP (item
);
1408 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_group_parent_class
)->
1409 update (item
, i2c
, flags
);
1416 for (list
= group
->item_list
; list
; list
= list
->next
) {
1419 gnome_canvas_item_invoke_update (i
, i2c
, flags
);
1421 x1
= MIN (x1
, i
->x1
);
1422 x2
= MAX (x2
, i
->x2
);
1423 y1
= MIN (y1
, i
->y1
);
1424 y2
= MAX (y2
, i
->y2
);
1426 if (x1
>= x2
|| y1
>= y2
) {
1427 item
->x1
= item
->x2
= item
->y1
= item
->y2
= 0;
1436 /* Realize handler for canvas groups */
1438 gnome_canvas_group_realize (GnomeCanvasItem
*item
)
1440 GnomeCanvasGroup
*group
;
1444 group
= GNOME_CANVAS_GROUP (item
);
1446 for (list
= group
->item_list
; list
; list
= list
->next
) {
1449 if (!(i
->flags
& GNOME_CANVAS_ITEM_REALIZED
))
1450 (* GNOME_CANVAS_ITEM_GET_CLASS (i
)->realize
) (i
);
1453 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_group_parent_class
)->
1457 /* Unrealize handler for canvas groups */
1459 gnome_canvas_group_unrealize (GnomeCanvasItem
*item
)
1461 GnomeCanvasGroup
*group
;
1465 group
= GNOME_CANVAS_GROUP (item
);
1467 for (list
= group
->item_list
; list
; list
= list
->next
) {
1470 if (i
->flags
& GNOME_CANVAS_ITEM_REALIZED
)
1471 (* GNOME_CANVAS_ITEM_GET_CLASS (i
)->unrealize
) (i
);
1474 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_group_parent_class
)->
1478 /* Map handler for canvas groups */
1480 gnome_canvas_group_map (GnomeCanvasItem
*item
)
1482 GnomeCanvasGroup
*group
;
1486 group
= GNOME_CANVAS_GROUP (item
);
1488 for (list
= group
->item_list
; list
; list
= list
->next
) {
1491 if (!(i
->flags
& GNOME_CANVAS_ITEM_MAPPED
))
1492 (* GNOME_CANVAS_ITEM_GET_CLASS (i
)->map
) (i
);
1495 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_group_parent_class
)->map (item
);
1498 /* Unmap handler for canvas groups */
1500 gnome_canvas_group_unmap (GnomeCanvasItem
*item
)
1502 GnomeCanvasGroup
*group
;
1506 group
= GNOME_CANVAS_GROUP (item
);
1508 for (list
= group
->item_list
; list
; list
= list
->next
) {
1511 if (i
->flags
& GNOME_CANVAS_ITEM_MAPPED
)
1512 (* GNOME_CANVAS_ITEM_GET_CLASS (i
)->unmap
) (i
);
1515 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_group_parent_class
)->unmap (item
);
1518 /* Draw handler for canvas groups */
1520 gnome_canvas_group_draw (GnomeCanvasItem
*item
,
1527 GnomeCanvasGroup
*group
;
1529 GnomeCanvasItem
*child
= NULL
;
1531 group
= GNOME_CANVAS_GROUP (item
);
1533 for (list
= group
->item_list
; list
; list
= list
->next
) {
1536 if ((child
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)
1537 && ((child
->x1
< (x
+ width
))
1538 && (child
->y1
< (y
+ height
))
1540 && (child
->y2
> y
))) {
1543 GNOME_CANVAS_ITEM_GET_CLASS (child
)->draw (
1544 child
, cr
, x
, y
, width
, height
);
1551 /* Point handler for canvas groups */
1552 static GnomeCanvasItem
*
1553 gnome_canvas_group_point (GnomeCanvasItem
*item
,
1559 GnomeCanvasGroup
*group
;
1561 GnomeCanvasItem
*child
, *point_item
;
1563 group
= GNOME_CANVAS_GROUP (item
);
1565 for (list
= g_list_last (group
->item_list
); list
; list
= list
->prev
) {
1568 if ((child
->x1
> cx
) || (child
->y1
> cy
))
1571 if ((child
->x2
< cx
) || (child
->y2
< cy
))
1574 if (!(child
->flags
& GNOME_CANVAS_ITEM_VISIBLE
))
1577 point_item
= gnome_canvas_item_invoke_point (child
, x
, y
, cx
, cy
);
1585 /* Bounds handler for canvas groups */
1587 gnome_canvas_group_bounds (GnomeCanvasItem
*item
,
1593 GnomeCanvasGroup
*group
;
1594 GnomeCanvasItem
*child
;
1596 gdouble tx1
, ty1
, tx2
, ty2
;
1597 gdouble minx
, miny
, maxx
, maxy
;
1600 group
= GNOME_CANVAS_GROUP (item
);
1602 /* Get the bounds of the first visible item */
1604 child
= NULL
; /* Unnecessary but eliminates a warning. */
1608 for (list
= group
->item_list
; list
; list
= list
->next
) {
1611 if (child
->flags
& GNOME_CANVAS_ITEM_VISIBLE
) {
1613 gnome_canvas_item_get_bounds (child
, &minx
, &miny
, &maxx
, &maxy
);
1618 /* If there were no visible items, return an empty bounding box */
1621 *x1
= *y1
= *x2
= *y2
= 0.0;
1625 /* Now we can grow the bounds using the rest of the items */
1629 for (; list
; list
= list
->next
) {
1632 if (!(child
->flags
& GNOME_CANVAS_ITEM_VISIBLE
))
1635 gnome_canvas_item_get_bounds (child
, &tx1
, &ty1
, &tx2
, &ty2
);
1656 /* Adds an item to a group */
1658 group_add (GnomeCanvasGroup
*group
,
1659 GnomeCanvasItem
*item
)
1661 g_object_ref_sink (item
);
1663 if (!group
->item_list
) {
1664 group
->item_list
= g_list_append (group
->item_list
, item
);
1665 group
->item_list_end
= group
->item_list
;
1667 group
->item_list_end
= g_list_append (group
->item_list_end
, item
)->next
;
1669 if (group
->item
.flags
& GNOME_CANVAS_ITEM_REALIZED
)
1670 (* GNOME_CANVAS_ITEM_GET_CLASS (item
)->realize
) (item
);
1672 if (group
->item
.flags
& GNOME_CANVAS_ITEM_MAPPED
)
1673 (* GNOME_CANVAS_ITEM_GET_CLASS (item
)->map
) (item
);
1675 g_object_notify (G_OBJECT (item
), "parent");
1678 /* Removes an item from a group */
1680 group_remove (GnomeCanvasGroup
*group
,
1681 GnomeCanvasItem
*item
)
1685 g_return_if_fail (GNOME_IS_CANVAS_GROUP (group
));
1686 g_return_if_fail (GNOME_IS_CANVAS_ITEM (item
));
1688 for (children
= group
->item_list
; children
; children
= children
->next
)
1689 if (children
->data
== item
) {
1690 if (item
->flags
& GNOME_CANVAS_ITEM_MAPPED
)
1691 (* GNOME_CANVAS_ITEM_GET_CLASS (item
)->unmap
) (item
);
1693 if (item
->flags
& GNOME_CANVAS_ITEM_REALIZED
)
1694 (* GNOME_CANVAS_ITEM_GET_CLASS (item
)->unrealize
) (item
);
1696 /* Unparent the child */
1698 item
->parent
= NULL
;
1699 g_object_unref (item
);
1701 /* Remove it from the list */
1703 if (children
== group
->item_list_end
)
1704 group
->item_list_end
= children
->prev
;
1706 group
->item_list
= g_list_remove_link (group
->item_list
, children
);
1707 g_list_free (children
);
1712 /*** GnomeCanvas ***/
1719 static void gnome_canvas_dispose (GObject
*object
);
1720 static void gnome_canvas_map (GtkWidget
*widget
);
1721 static void gnome_canvas_unmap (GtkWidget
*widget
);
1722 static void gnome_canvas_realize (GtkWidget
*widget
);
1723 static void gnome_canvas_unrealize (GtkWidget
*widget
);
1724 static void gnome_canvas_size_allocate (GtkWidget
*widget
,
1725 GtkAllocation
*allocation
);
1726 static gint
gnome_canvas_draw (GtkWidget
*widget
,
1728 static void gnome_canvas_drag_end (GtkWidget
*widget
,
1729 GdkDragContext
*context
);
1730 static gint
gnome_canvas_button (GtkWidget
*widget
,
1731 GdkEventButton
*event
);
1732 static gint
gnome_canvas_motion (GtkWidget
*widget
,
1733 GdkEventMotion
*event
);
1734 static gboolean
gnome_canvas_key (GtkWidget
*widget
,
1735 GdkEventKey
*event
);
1736 static gint
gnome_canvas_crossing (GtkWidget
*widget
,
1737 GdkEventCrossing
*event
);
1738 static gint
gnome_canvas_focus_in (GtkWidget
*widget
,
1739 GdkEventFocus
*event
);
1740 static gint
gnome_canvas_focus_out (GtkWidget
*widget
,
1741 GdkEventFocus
*event
);
1742 static void gnome_canvas_request_update_real (GnomeCanvas
*canvas
);
1743 static void gnome_canvas_draw_background (GnomeCanvas
*canvas
,
1750 static guint canvas_signals
[LAST_SIGNAL
];
1763 gnome_canvas_paint_rect (GnomeCanvas
*canvas
,
1771 GtkAllocation allocation
;
1772 GtkScrollable
*scrollable
;
1773 GtkAdjustment
*hadjustment
;
1774 GtkAdjustment
*vadjustment
;
1775 gint draw_x1
, draw_y1
;
1776 gint draw_x2
, draw_y2
;
1777 gint draw_width
, draw_height
;
1778 gdouble hadjustment_value
;
1779 gdouble vadjustment_value
;
1781 g_return_if_fail (!canvas
->need_update
);
1783 widget
= GTK_WIDGET (canvas
);
1784 gtk_widget_get_allocation (widget
, &allocation
);
1786 scrollable
= GTK_SCROLLABLE (canvas
);
1787 hadjustment
= gtk_scrollable_get_hadjustment (scrollable
);
1788 vadjustment
= gtk_scrollable_get_vadjustment (scrollable
);
1790 hadjustment_value
= gtk_adjustment_get_value (hadjustment
);
1791 vadjustment_value
= gtk_adjustment_get_value (vadjustment
);
1793 draw_x1
= MAX (x0
, hadjustment_value
- canvas
->zoom_xofs
);
1794 draw_y1
= MAX (y0
, vadjustment_value
- canvas
->zoom_yofs
);
1795 draw_x2
= MIN (draw_x1
+ allocation
.width
, x1
);
1796 draw_y2
= MIN (draw_y1
+ allocation
.height
, y1
);
1798 draw_width
= draw_x2
- draw_x1
;
1799 draw_height
= draw_y2
- draw_y1
;
1801 if (draw_width
< 1 || draw_height
< 1)
1804 canvas
->draw_xofs
= draw_x1
;
1805 canvas
->draw_yofs
= draw_y1
;
1810 canvas
, canvas_signals
[DRAW_BACKGROUND
], 0, cr
,
1811 draw_x1
, draw_y1
, draw_width
, draw_height
);
1815 if (canvas
->root
->flags
& GNOME_CANVAS_ITEM_VISIBLE
) {
1818 (* GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->draw
) (
1821 draw_width
, draw_height
);
1828 gnome_canvas_get_property (GObject
*object
,
1833 switch (property_id
) {
1834 case PROP_FOCUSED_ITEM
:
1835 g_value_set_object (value
, GNOME_CANVAS (object
)->focused_item
);
1838 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1844 gnome_canvas_set_property (GObject
*object
,
1846 const GValue
*value
,
1849 switch (property_id
) {
1850 case PROP_FOCUSED_ITEM
:
1851 GNOME_CANVAS (object
)->focused_item
= g_value_get_object (value
);
1854 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1859 /* Class initialization function for GnomeCanvasClass */
1861 gnome_canvas_class_init (GnomeCanvasClass
*class)
1863 GObjectClass
*object_class
;
1864 GtkWidgetClass
*widget_class
;
1866 object_class
= (GObjectClass
*) class;
1867 widget_class
= (GtkWidgetClass
*) class;
1869 object_class
->set_property
= gnome_canvas_set_property
;
1870 object_class
->get_property
= gnome_canvas_get_property
;
1871 object_class
->dispose
= gnome_canvas_dispose
;
1873 widget_class
->map
= gnome_canvas_map
;
1874 widget_class
->unmap
= gnome_canvas_unmap
;
1875 widget_class
->realize
= gnome_canvas_realize
;
1876 widget_class
->unrealize
= gnome_canvas_unrealize
;
1877 widget_class
->size_allocate
= gnome_canvas_size_allocate
;
1878 widget_class
->draw
= gnome_canvas_draw
;
1879 widget_class
->drag_end
= gnome_canvas_drag_end
;
1880 widget_class
->button_press_event
= gnome_canvas_button
;
1881 widget_class
->button_release_event
= gnome_canvas_button
;
1882 widget_class
->motion_notify_event
= gnome_canvas_motion
;
1883 widget_class
->key_press_event
= gnome_canvas_key
;
1884 widget_class
->key_release_event
= gnome_canvas_key
;
1885 widget_class
->enter_notify_event
= gnome_canvas_crossing
;
1886 widget_class
->leave_notify_event
= gnome_canvas_crossing
;
1887 widget_class
->focus_in_event
= gnome_canvas_focus_in
;
1888 widget_class
->focus_out_event
= gnome_canvas_focus_out
;
1890 class->draw_background
= gnome_canvas_draw_background
;
1891 class->request_update
= gnome_canvas_request_update_real
;
1893 g_object_class_install_property (
1896 g_param_spec_object (
1900 GNOME_TYPE_CANVAS_ITEM
,
1904 canvas_signals
[DRAW_BACKGROUND
] = g_signal_new (
1906 G_TYPE_FROM_CLASS (object_class
),
1908 G_STRUCT_OFFSET (GnomeCanvasClass
, draw_background
),
1911 CAIRO_GOBJECT_TYPE_CONTEXT
,
1917 gtk_widget_class_set_accessible_type (widget_class
, GAIL_TYPE_CANVAS
);
1918 gail_canvas_a11y_init ();
1921 /* Callback used when the root item of a canvas is destroyed. The user should
1922 * never ever do this, so we panic if this happens.
1924 G_GNUC_NORETURN
static void
1925 panic_root_finalized (gpointer data
,
1926 GObject
*gone_object
)
1928 g_error ("Eeeek, root item %p of canvas %p was destroyed!", gone_object
, data
);
1931 /* Object initialization function for GnomeCanvas */
1933 gnome_canvas_init (GnomeCanvas
*canvas
)
1936 guint layout_width
, layout_height
;
1938 layout
= GTK_LAYOUT (canvas
);
1939 gtk_layout_get_size (layout
, &layout_width
, &layout_height
);
1941 gtk_widget_set_can_focus (GTK_WIDGET (canvas
), TRUE
);
1943 canvas
->need_update
= FALSE
;
1944 canvas
->idle_id
= 0;
1946 canvas
->scroll_x1
= 0.0;
1947 canvas
->scroll_y1
= 0.0;
1948 canvas
->scroll_x2
= layout_width
;
1949 canvas
->scroll_y2
= layout_height
;
1951 canvas
->pick_event
.type
= GDK_LEAVE_NOTIFY
;
1952 canvas
->pick_event
.crossing
.x
= 0;
1953 canvas
->pick_event
.crossing
.y
= 0;
1955 gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (canvas
), NULL
);
1956 gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (canvas
), NULL
);
1958 /* Create the root item as a special case */
1960 canvas
->root
= GNOME_CANVAS_ITEM (
1961 g_object_new (gnome_canvas_group_get_type (), NULL
));
1962 canvas
->root
->canvas
= canvas
;
1964 g_object_ref_sink (canvas
->root
);
1966 g_object_weak_ref (G_OBJECT (canvas
->root
), panic_root_finalized
, canvas
);
1968 canvas
->need_repick
= TRUE
;
1971 /* Convenience function to remove the idle handler of a canvas */
1973 remove_idle (GnomeCanvas
*canvas
)
1975 if (canvas
->idle_id
== 0)
1978 g_source_remove (canvas
->idle_id
);
1979 canvas
->idle_id
= 0;
1982 /* Removes the transient state of the canvas (idle handler, grabs). */
1984 shutdown_transients (GnomeCanvas
*canvas
)
1986 if (canvas
->grabbed_device
!= NULL
) {
1987 gdk_device_ungrab (canvas
->grabbed_device
, GDK_CURRENT_TIME
);
1988 g_object_unref (canvas
->grabbed_device
);
1989 canvas
->grabbed_device
= NULL
;
1992 canvas
->grabbed_item
= NULL
;
1994 remove_idle (canvas
);
1997 /* Dispose handler for GnomeCanvas */
1999 gnome_canvas_dispose (GObject
*object
)
2001 GnomeCanvas
*canvas
;
2003 g_return_if_fail (GNOME_IS_CANVAS (object
));
2005 /* remember, dispose can be run multiple times! */
2007 canvas
= GNOME_CANVAS (object
);
2010 g_object_weak_unref (G_OBJECT (canvas
->root
), panic_root_finalized
, canvas
);
2011 g_object_unref (canvas
->root
);
2012 canvas
->root
= NULL
;
2015 shutdown_transients (canvas
);
2017 /* Chain up to parent's dispose() method. */
2018 G_OBJECT_CLASS (gnome_canvas_parent_class
)->dispose (object
);
2024 * Creates a new empty canvas in non-antialiased mode.
2026 * Return value: A newly-created canvas.
2029 gnome_canvas_new (void)
2031 return GTK_WIDGET (g_object_new (gnome_canvas_get_type (), NULL
));
2034 /* Map handler for the canvas */
2036 gnome_canvas_map (GtkWidget
*widget
)
2038 GnomeCanvas
*canvas
;
2040 g_return_if_fail (GNOME_IS_CANVAS (widget
));
2042 /* Normal widget mapping stuff */
2044 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->map (widget
);
2046 canvas
= GNOME_CANVAS (widget
);
2048 if (canvas
->need_update
)
2053 if (GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->map
)
2054 (* GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->map
) (canvas
->root
);
2057 /* Unmap handler for the canvas */
2059 gnome_canvas_unmap (GtkWidget
*widget
)
2061 GnomeCanvas
*canvas
;
2063 g_return_if_fail (GNOME_IS_CANVAS (widget
));
2065 canvas
= GNOME_CANVAS (widget
);
2067 shutdown_transients (canvas
);
2071 if (GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->unmap
)
2072 (* GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->unmap
) (canvas
->root
);
2074 /* Normal widget unmapping stuff */
2076 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->unmap (widget
);
2079 /* Realize handler for the canvas */
2081 gnome_canvas_realize (GtkWidget
*widget
)
2083 GnomeCanvas
*canvas
;
2085 GdkWindow
*bin_window
;
2087 g_return_if_fail (GNOME_IS_CANVAS (widget
));
2089 /* Normal widget realization stuff */
2091 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->realize (widget
);
2093 canvas
= GNOME_CANVAS (widget
);
2095 layout
= GTK_LAYOUT (canvas
);
2096 bin_window
= gtk_layout_get_bin_window (layout
);
2098 gdk_window_set_events (
2100 (gdk_window_get_events (bin_window
)
2103 | GDK_BUTTON_PRESS_MASK
2104 | GDK_BUTTON_RELEASE_MASK
2105 | GDK_POINTER_MOTION_MASK
2106 | GDK_KEY_PRESS_MASK
2107 | GDK_KEY_RELEASE_MASK
2108 | GDK_ENTER_NOTIFY_MASK
2109 | GDK_LEAVE_NOTIFY_MASK
2110 | GDK_FOCUS_CHANGE_MASK
));
2112 /* Create our own temporary pixmap gc and realize all the items */
2114 (* GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->realize
) (canvas
->root
);
2117 /* Unrealize handler for the canvas */
2119 gnome_canvas_unrealize (GtkWidget
*widget
)
2121 GnomeCanvas
*canvas
;
2123 g_return_if_fail (GNOME_IS_CANVAS (widget
));
2125 canvas
= GNOME_CANVAS (widget
);
2127 shutdown_transients (canvas
);
2129 /* Unrealize items and parent widget */
2131 (* GNOME_CANVAS_ITEM_GET_CLASS (canvas
->root
)->unrealize
) (canvas
->root
);
2133 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->unrealize (widget
);
2136 /* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to
2137 * keep as much as possible of the canvas scrolling region in view.
2140 scroll_to (GnomeCanvas
*canvas
,
2145 GtkAllocation allocation
;
2146 GtkScrollable
*scrollable
;
2147 GtkAdjustment
*hadjustment
;
2148 GtkAdjustment
*vadjustment
;
2149 guint layout_width
, layout_height
;
2150 gint scroll_width
, scroll_height
;
2151 gint right_limit
, bottom_limit
;
2152 gint old_zoom_xofs
, old_zoom_yofs
;
2153 gint canvas_width
, canvas_height
;
2155 widget
= GTK_WIDGET (canvas
);
2156 gtk_widget_get_allocation (widget
, &allocation
);
2158 scrollable
= GTK_SCROLLABLE (canvas
);
2159 hadjustment
= gtk_scrollable_get_hadjustment (scrollable
);
2160 vadjustment
= gtk_scrollable_get_vadjustment (scrollable
);
2162 gtk_layout_get_size (GTK_LAYOUT (canvas
), &layout_width
, &layout_height
);
2164 canvas_width
= allocation
.width
;
2165 canvas_height
= allocation
.height
;
2168 floor ((canvas
->scroll_x2
- canvas
->scroll_x1
) + 0.5);
2170 floor ((canvas
->scroll_y2
- canvas
->scroll_y1
) + 0.5);
2172 right_limit
= scroll_width
- canvas_width
;
2173 bottom_limit
= scroll_height
- canvas_height
;
2175 old_zoom_xofs
= canvas
->zoom_xofs
;
2176 old_zoom_yofs
= canvas
->zoom_yofs
;
2178 if (right_limit
< 0) {
2180 canvas
->zoom_xofs
= (canvas_width
- scroll_width
) / 2;
2181 scroll_width
= canvas_width
;
2182 } else if (cx
< 0) {
2184 canvas
->zoom_xofs
= 0;
2185 } else if (cx
> right_limit
) {
2187 canvas
->zoom_xofs
= 0;
2189 canvas
->zoom_xofs
= 0;
2191 if (bottom_limit
< 0) {
2193 canvas
->zoom_yofs
= (canvas_height
- scroll_height
) / 2;
2194 scroll_height
= canvas_height
;
2195 } else if (cy
< 0) {
2197 canvas
->zoom_yofs
= 0;
2198 } else if (cy
> bottom_limit
) {
2200 canvas
->zoom_yofs
= 0;
2202 canvas
->zoom_yofs
= 0;
2204 if ((canvas
->zoom_xofs
!= old_zoom_xofs
) ||
2205 (canvas
->zoom_yofs
!= old_zoom_yofs
)) {
2206 /* This can only occur, if either canvas size or widget
2207 * size changes. So I think we can request full redraw
2208 * here. The reason is, that coverage UTA will be
2209 * invalidated by offset change. */
2210 /* FIXME Strictly this is not correct - we have to remove
2211 * our own idle (Lauris) */
2212 /* More stuff - we have to mark root as needing fresh affine
2214 if (!(canvas
->root
->flags
& GNOME_CANVAS_ITEM_NEED_AFFINE
)) {
2215 canvas
->root
->flags
|= GNOME_CANVAS_ITEM_NEED_AFFINE
;
2216 gnome_canvas_request_update (canvas
);
2218 gtk_widget_queue_draw (GTK_WIDGET (canvas
));
2222 gtk_adjustment_set_value (hadjustment
, cx
);
2225 gtk_adjustment_set_value (vadjustment
, cy
);
2227 if ((scroll_width
!= (gint
) layout_width
)
2228 || (scroll_height
!= (gint
) layout_height
))
2229 gtk_layout_set_size (GTK_LAYOUT (canvas
), scroll_width
, scroll_height
);
2232 /* Size allocation handler for the canvas */
2234 gnome_canvas_size_allocate (GtkWidget
*widget
,
2235 GtkAllocation
*allocation
)
2237 GtkScrollable
*scrollable
;
2238 GtkAdjustment
*hadjustment
;
2239 GtkAdjustment
*vadjustment
;
2241 g_return_if_fail (GNOME_IS_CANVAS (widget
));
2242 g_return_if_fail (allocation
!= NULL
);
2244 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->
2245 size_allocate (widget
, allocation
);
2247 scrollable
= GTK_SCROLLABLE (widget
);
2248 hadjustment
= gtk_scrollable_get_hadjustment (scrollable
);
2249 vadjustment
= gtk_scrollable_get_vadjustment (scrollable
);
2251 /* Recenter the view, if appropriate */
2253 g_object_freeze_notify (G_OBJECT (hadjustment
));
2254 g_object_freeze_notify (G_OBJECT (vadjustment
));
2256 gtk_adjustment_set_page_size (hadjustment
, allocation
->width
);
2257 gtk_adjustment_set_page_increment (hadjustment
, allocation
->width
/ 2);
2259 gtk_adjustment_set_page_size (vadjustment
, allocation
->height
);
2260 gtk_adjustment_set_page_increment (vadjustment
, allocation
->height
/ 2);
2263 GNOME_CANVAS (widget
),
2264 gtk_adjustment_get_value (hadjustment
),
2265 gtk_adjustment_get_value (vadjustment
));
2267 g_object_thaw_notify (G_OBJECT (hadjustment
));
2268 g_object_thaw_notify (G_OBJECT (vadjustment
));
2272 gnome_canvas_draw (GtkWidget
*widget
,
2275 GnomeCanvas
*canvas
= GNOME_CANVAS (widget
);
2276 cairo_rectangle_int_t rect
;
2278 GtkAdjustment
*hadjustment
;
2279 GtkAdjustment
*vadjustment
;
2280 gdouble hadjustment_value
;
2281 gdouble vadjustment_value
;
2283 layout
= GTK_LAYOUT (canvas
);
2284 hadjustment
= gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout
));
2285 vadjustment
= gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (layout
));
2287 hadjustment_value
= gtk_adjustment_get_value (hadjustment
);
2288 vadjustment_value
= gtk_adjustment_get_value (vadjustment
);
2290 gdk_cairo_get_clip_rectangle (cr
, &rect
);
2292 if (canvas
->need_update
) {
2295 /* We start updating root with w2c matrix */
2296 gnome_canvas_w2c_matrix (canvas
, &w2c
);
2298 gnome_canvas_item_invoke_update (canvas
->root
, &w2c
, 0);
2300 canvas
->need_update
= FALSE
;
2306 -canvas
->zoom_xofs
+ rect
.x
,
2307 -canvas
->zoom_yofs
+ rect
.y
);
2309 rect
.x
+= hadjustment_value
;
2310 rect
.y
+= vadjustment_value
;
2312 /* No pending updates, draw exposed area immediately */
2313 gnome_canvas_paint_rect (
2316 rect
.x
+ rect
.width
,
2317 rect
.y
+ rect
.height
);
2320 /* And call expose on parent container class */
2321 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->draw (widget
, cr
);
2327 gnome_canvas_drag_end (GtkWidget
*widget
,
2328 GdkDragContext
*context
)
2330 GnomeCanvas
*canvas
= GNOME_CANVAS (widget
);
2332 if (canvas
->grabbed_item
) {
2333 gnome_canvas_item_ungrab (canvas
->grabbed_item
, GDK_CURRENT_TIME
);
2336 if (GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->drag_end
)
2337 GTK_WIDGET_CLASS (gnome_canvas_parent_class
)->drag_end (widget
, context
);
2340 /* Emits an event for an item in the canvas, be it the current item, grabbed
2341 * item, or focused item, as appropriate.
2345 emit_event (GnomeCanvas
*canvas
,
2350 GnomeCanvasItem
*item
;
2351 GnomeCanvasItem
*parent
;
2354 /* Perform checks for grabbed items */
2356 if (canvas
->grabbed_item
&&
2357 !is_descendant (canvas
->current_item
, canvas
->grabbed_item
)) {
2358 /* I think this warning is annoying and I don't know what it's for
2359 * so I'll disable it for now.
2361 /* g_warning ("emit_event() returning FALSE!\n");*/
2365 if (canvas
->grabbed_item
) {
2366 switch (event
->type
) {
2367 case GDK_ENTER_NOTIFY
:
2368 mask
= GDK_ENTER_NOTIFY_MASK
;
2371 case GDK_LEAVE_NOTIFY
:
2372 mask
= GDK_LEAVE_NOTIFY_MASK
;
2375 case GDK_MOTION_NOTIFY
:
2376 mask
= GDK_POINTER_MOTION_MASK
;
2379 case GDK_BUTTON_PRESS
:
2380 case GDK_2BUTTON_PRESS
:
2381 case GDK_3BUTTON_PRESS
:
2382 mask
= GDK_BUTTON_PRESS_MASK
;
2385 case GDK_BUTTON_RELEASE
:
2386 mask
= GDK_BUTTON_RELEASE_MASK
;
2390 mask
= GDK_KEY_PRESS_MASK
;
2393 case GDK_KEY_RELEASE
:
2394 mask
= GDK_KEY_RELEASE_MASK
;
2398 mask
= GDK_SCROLL_MASK
;
2406 if (!(mask
& canvas
->grabbed_event_mask
))
2410 /* Convert to world coordinates -- we have two cases because of diferent
2411 * offsets of the fields in the event structures.
2414 ev
= gdk_event_copy (event
);
2418 case GDK_ENTER_NOTIFY
:
2419 case GDK_LEAVE_NOTIFY
:
2420 gnome_canvas_window_to_world (
2422 ev
->crossing
.x
, ev
->crossing
.y
,
2423 &ev
->crossing
.x
, &ev
->crossing
.y
);
2426 case GDK_MOTION_NOTIFY
:
2427 case GDK_BUTTON_PRESS
:
2428 case GDK_2BUTTON_PRESS
:
2429 case GDK_3BUTTON_PRESS
:
2430 case GDK_BUTTON_RELEASE
:
2431 gnome_canvas_window_to_world (
2433 ev
->motion
.x
, ev
->motion
.y
,
2434 &ev
->motion
.x
, &ev
->motion
.y
);
2441 /* Choose where we send the event */
2443 item
= canvas
->current_item
;
2445 if (canvas
->focused_item
2446 && ((event
->type
== GDK_KEY_PRESS
) ||
2447 (event
->type
== GDK_KEY_RELEASE
) ||
2448 (event
->type
== GDK_FOCUS_CHANGE
)))
2449 item
= canvas
->focused_item
;
2451 /* The event is propagated up the hierarchy (for if someone connected to
2452 * a group instead of a leaf event), and emission is stopped if a
2453 * handler returns TRUE, just like for GtkWidget events.
2458 while (item
&& !finished
) {
2459 g_object_ref (item
);
2462 item
, item_signals
[ITEM_EVENT
], 0,
2465 parent
= item
->parent
;
2466 g_object_unref (item
);
2471 gdk_event_free (ev
);
2476 /* Re-picks the current item in the canvas, based on the event's coordinates.
2477 * Also emits enter/leave events for items as appropriate.
2480 pick_current_item (GnomeCanvas
*canvas
,
2490 /* If a button is down, we'll perform enter and leave events on the
2491 * current item, but not enter on any other item. This is more or less
2492 * like X pointer grabbing for canvas items.
2494 button_down
= canvas
->state
& (GDK_BUTTON1_MASK
2498 | GDK_BUTTON5_MASK
);
2500 canvas
->left_grabbed_item
= FALSE
;
2502 /* Save the event in the canvas. This is used to synthesize enter and
2503 * leave events in case the current item changes. It is also used to
2504 * re-pick the current item if the current one gets deleted. Also,
2505 * synthesize an enter event.
2507 if (event
!= &canvas
->pick_event
) {
2508 if ((event
->type
== GDK_MOTION_NOTIFY
) ||
2509 (event
->type
== GDK_BUTTON_RELEASE
)) {
2510 /* these fields have the same offsets in both types of events */
2512 canvas
->pick_event
.crossing
.type
= GDK_ENTER_NOTIFY
;
2513 canvas
->pick_event
.crossing
.window
= event
->motion
.window
;
2514 canvas
->pick_event
.crossing
.send_event
= event
->motion
.send_event
;
2515 canvas
->pick_event
.crossing
.subwindow
= NULL
;
2516 canvas
->pick_event
.crossing
.x
= event
->motion
.x
;
2517 canvas
->pick_event
.crossing
.y
= event
->motion
.y
;
2518 canvas
->pick_event
.crossing
.mode
= GDK_CROSSING_NORMAL
;
2519 canvas
->pick_event
.crossing
.detail
= GDK_NOTIFY_NONLINEAR
;
2520 canvas
->pick_event
.crossing
.focus
= FALSE
;
2521 canvas
->pick_event
.crossing
.state
= event
->motion
.state
;
2523 /* these fields don't have the same offsets in both types of events */
2525 if (event
->type
== GDK_MOTION_NOTIFY
) {
2526 canvas
->pick_event
.crossing
.x_root
= event
->motion
.x_root
;
2527 canvas
->pick_event
.crossing
.y_root
= event
->motion
.y_root
;
2529 canvas
->pick_event
.crossing
.x_root
= event
->button
.x_root
;
2530 canvas
->pick_event
.crossing
.y_root
= event
->button
.y_root
;
2533 canvas
->pick_event
= *event
;
2536 /* Don't do anything else if this is a recursive call */
2538 if (canvas
->in_repick
)
2541 /* LeaveNotify means that there is no current item, so we don't look for one */
2543 if (canvas
->pick_event
.type
!= GDK_LEAVE_NOTIFY
) {
2544 /* these fields don't have the same offsets in both types of events */
2546 if (canvas
->pick_event
.type
== GDK_ENTER_NOTIFY
) {
2547 x
= canvas
->pick_event
.crossing
.x
- canvas
->zoom_xofs
;
2548 y
= canvas
->pick_event
.crossing
.y
- canvas
->zoom_yofs
;
2550 x
= canvas
->pick_event
.motion
.x
- canvas
->zoom_xofs
;
2551 y
= canvas
->pick_event
.motion
.y
- canvas
->zoom_yofs
;
2554 /* canvas pixel coords */
2556 cx
= (gint
) (x
+ 0.5);
2557 cy
= (gint
) (y
+ 0.5);
2561 x
= canvas
->scroll_x1
+ x
;
2562 y
= canvas
->scroll_y1
+ y
;
2564 /* find the closest item */
2566 if (canvas
->root
->flags
& GNOME_CANVAS_ITEM_VISIBLE
)
2567 canvas
->new_current_item
=
2568 gnome_canvas_item_invoke_point (
2569 canvas
->root
, x
, y
, cx
, cy
);
2571 canvas
->new_current_item
= NULL
;
2573 canvas
->new_current_item
= NULL
;
2575 if ((canvas
->new_current_item
== canvas
->current_item
)
2576 && !canvas
->left_grabbed_item
)
2577 return retval
; /* current item did not change */
2579 /* Synthesize events for old and new current items */
2581 if ((canvas
->new_current_item
!= canvas
->current_item
)
2582 && (canvas
->current_item
!= NULL
)
2583 && !canvas
->left_grabbed_item
) {
2586 new_event
= canvas
->pick_event
;
2587 new_event
.type
= GDK_LEAVE_NOTIFY
;
2589 new_event
.crossing
.detail
= GDK_NOTIFY_ANCESTOR
;
2590 new_event
.crossing
.subwindow
= NULL
;
2591 canvas
->in_repick
= TRUE
;
2592 retval
= emit_event (canvas
, &new_event
);
2593 canvas
->in_repick
= FALSE
;
2596 /* new_current_item may have been set to NULL during the
2597 * call to emit_event() above */
2599 if ((canvas
->new_current_item
!= canvas
->current_item
) && button_down
) {
2600 canvas
->left_grabbed_item
= TRUE
;
2604 /* Handle the rest of cases */
2606 canvas
->left_grabbed_item
= FALSE
;
2607 canvas
->current_item
= canvas
->new_current_item
;
2609 if (canvas
->current_item
!= NULL
) {
2612 new_event
= canvas
->pick_event
;
2613 new_event
.type
= GDK_ENTER_NOTIFY
;
2614 new_event
.crossing
.detail
= GDK_NOTIFY_ANCESTOR
;
2615 new_event
.crossing
.subwindow
= NULL
;
2616 retval
= emit_event (canvas
, &new_event
);
2622 /* Button event handler for the canvas */
2624 gnome_canvas_button (GtkWidget
*widget
,
2625 GdkEventButton
*event
)
2627 GnomeCanvas
*canvas
;
2629 GdkWindow
*bin_window
;
2633 g_return_val_if_fail (GNOME_IS_CANVAS (widget
), FALSE
);
2634 g_return_val_if_fail (event
!= NULL
, FALSE
);
2638 canvas
= GNOME_CANVAS (widget
);
2640 layout
= GTK_LAYOUT (canvas
);
2641 bin_window
= gtk_layout_get_bin_window (layout
);
2644 * dispatch normally regardless of the event's window if an item has
2645 * has a pointer grab in effect
2647 if (!canvas
->grabbed_item
&& event
->window
!= bin_window
)
2650 switch (event
->button
) {
2652 mask
= GDK_BUTTON1_MASK
;
2655 mask
= GDK_BUTTON2_MASK
;
2658 mask
= GDK_BUTTON3_MASK
;
2661 mask
= GDK_BUTTON4_MASK
;
2664 mask
= GDK_BUTTON5_MASK
;
2670 switch (event
->type
) {
2671 case GDK_BUTTON_PRESS
:
2672 case GDK_2BUTTON_PRESS
:
2673 case GDK_3BUTTON_PRESS
:
2674 /* Pick the current item as if the button were
2675 * not pressed, and then process the event. */
2676 canvas
->state
= event
->state
;
2677 pick_current_item (canvas
, (GdkEvent
*) event
);
2678 canvas
->state
^= mask
;
2679 retval
= emit_event (canvas
, (GdkEvent
*) event
);
2682 case GDK_BUTTON_RELEASE
:
2683 /* Process the event as if the button were pressed,
2684 * then repick after the button has been released. */
2685 canvas
->state
= event
->state
;
2686 retval
= emit_event (canvas
, (GdkEvent
*) event
);
2687 event
->state
^= mask
;
2688 canvas
->state
= event
->state
;
2689 pick_current_item (canvas
, (GdkEvent
*) event
);
2690 event
->state
^= mask
;
2694 g_warn_if_reached ();
2700 /* Motion event handler for the canvas */
2702 gnome_canvas_motion (GtkWidget
*widget
,
2703 GdkEventMotion
*event
)
2705 GnomeCanvas
*canvas
;
2707 GdkWindow
*bin_window
;
2709 g_return_val_if_fail (GNOME_IS_CANVAS (widget
), FALSE
);
2710 g_return_val_if_fail (event
!= NULL
, FALSE
);
2712 canvas
= GNOME_CANVAS (widget
);
2714 layout
= GTK_LAYOUT (widget
);
2715 bin_window
= gtk_layout_get_bin_window (layout
);
2717 if (event
->window
!= bin_window
)
2720 canvas
->state
= event
->state
;
2721 pick_current_item (canvas
, (GdkEvent
*) event
);
2722 return emit_event (canvas
, (GdkEvent
*) event
);
2725 /* Key event handler for the canvas */
2727 gnome_canvas_key (GtkWidget
*widget
,
2730 GnomeCanvas
*canvas
;
2732 g_return_val_if_fail (GNOME_IS_CANVAS (widget
), FALSE
);
2733 g_return_val_if_fail (event
!= NULL
, FALSE
);
2735 canvas
= GNOME_CANVAS (widget
);
2737 if (!emit_event (canvas
, (GdkEvent
*) event
)) {
2738 GtkWidgetClass
*widget_class
;
2740 widget_class
= GTK_WIDGET_CLASS (gnome_canvas_parent_class
);
2742 if (event
->type
== GDK_KEY_PRESS
) {
2743 if (widget_class
->key_press_event
)
2744 return (* widget_class
->key_press_event
) (widget
, event
);
2745 } else if (event
->type
== GDK_KEY_RELEASE
) {
2746 if (widget_class
->key_release_event
)
2747 return (* widget_class
->key_release_event
) (widget
, event
);
2749 g_warn_if_reached ();
2756 /* Crossing event handler for the canvas */
2758 gnome_canvas_crossing (GtkWidget
*widget
,
2759 GdkEventCrossing
*event
)
2761 GnomeCanvas
*canvas
;
2763 GdkWindow
*bin_window
;
2765 g_return_val_if_fail (GNOME_IS_CANVAS (widget
), FALSE
);
2766 g_return_val_if_fail (event
!= NULL
, FALSE
);
2768 canvas
= GNOME_CANVAS (widget
);
2770 layout
= GTK_LAYOUT (canvas
);
2771 bin_window
= gtk_layout_get_bin_window (layout
);
2773 if (event
->window
!= bin_window
)
2776 /* XXX Detect and disregard synthesized crossing events generated
2777 * by synth_crossing() in gtkwidget.c. The pointer coordinates
2778 * are invalid and pick_current_item() relies on them. */
2779 if (event
->x
== 0 && event
->y
== 0 &&
2780 event
->x_root
== 0 && event
->y_root
== 0)
2783 canvas
->state
= event
->state
;
2784 return pick_current_item (canvas
, (GdkEvent
*) event
);
2787 /* Focus in handler for the canvas */
2789 gnome_canvas_focus_in (GtkWidget
*widget
,
2790 GdkEventFocus
*event
)
2792 GnomeCanvas
*canvas
;
2794 /* XXX Can't access flags directly anymore, but is it really needed?
2795 * If so, could we call gtk_widget_send_focus_change() instead? */
2797 GTK_WIDGET_SET_FLAGS (widget
, GTK_HAS_FOCUS
);
2800 canvas
= GNOME_CANVAS (widget
);
2802 if (canvas
->focused_item
)
2803 return emit_event (canvas
, (GdkEvent
*) event
);
2808 /* Focus out handler for the canvas */
2810 gnome_canvas_focus_out (GtkWidget
*widget
,
2811 GdkEventFocus
*event
)
2813 GnomeCanvas
*canvas
;
2815 /* XXX Can't access flags directly anymore, but is it really needed?
2816 * If so, could we call gtk_widget_send_focus_change() instead? */
2818 GTK_WIDGET_UNSET_FLAGS (widget
, GTK_HAS_FOCUS
);
2821 canvas
= GNOME_CANVAS (widget
);
2823 if (canvas
->focused_item
)
2824 return emit_event (canvas
, (GdkEvent
*) event
);
2830 gnome_canvas_draw_background (GnomeCanvas
*canvas
,
2837 GtkStyleContext
*style_context
;
2840 style_context
= gtk_widget_get_style_context (GTK_WIDGET (canvas
));
2841 if (!gtk_style_context_lookup_color (style_context
, "theme_bg_color", &rgba
))
2842 gdk_rgba_parse (&rgba
, "#aaaaaa");
2845 gdk_cairo_set_source_rgba (cr
, &rgba
);
2851 do_update (GnomeCanvas
*canvas
)
2853 /* Cause the update if necessary */
2856 if (canvas
->need_update
) {
2859 /* We start updating root with w2c matrix */
2860 gnome_canvas_w2c_matrix (canvas
, &w2c
);
2862 gnome_canvas_item_invoke_update (canvas
->root
, &w2c
, 0);
2864 canvas
->need_update
= FALSE
;
2867 /* Pick new current item */
2869 while (canvas
->need_repick
) {
2870 canvas
->need_repick
= FALSE
;
2871 pick_current_item (canvas
, &canvas
->pick_event
);
2874 /* it is possible that during picking we emitted an event in which
2875 * the user then called some function which then requested update
2876 * of something. Without this we'd be left in a state where
2877 * need_update would have been left TRUE and the canvas would have
2878 * been left unpainted. */
2879 if (canvas
->need_update
) {
2884 /* Idle handler for the canvas. It deals with pending updates and redraws. */
2886 idle_handler (gpointer data
)
2888 GnomeCanvas
*canvas
;
2890 canvas
= GNOME_CANVAS (data
);
2895 canvas
->idle_id
= 0;
2900 /* Convenience function to add an idle handler to a canvas */
2902 add_idle (GnomeCanvas
*canvas
)
2904 g_return_if_fail (canvas
->need_update
);
2906 if (!canvas
->idle_id
)
2907 canvas
->idle_id
= g_idle_add_full (
2908 CANVAS_IDLE_PRIORITY
,
2913 /* canvas->idle_id = gtk_idle_add (idle_handler, canvas); */
2917 * gnome_canvas_root:
2918 * @canvas: A canvas.
2920 * Queries the root group of a canvas.
2922 * Return value: The root group of the specified canvas.
2925 gnome_canvas_root (GnomeCanvas
*canvas
)
2927 g_return_val_if_fail (GNOME_IS_CANVAS (canvas
), NULL
);
2929 return GNOME_CANVAS_GROUP (canvas
->root
);
2933 * gnome_canvas_set_scroll_region:
2934 * @canvas: A canvas.
2935 * @x1: Leftmost limit of the scrolling region.
2936 * @y1: Upper limit of the scrolling region.
2937 * @x2: Rightmost limit of the scrolling region.
2938 * @y2: Lower limit of the scrolling region.
2940 * Sets the scrolling region of a canvas to the specified rectangle. The canvas
2941 * will then be able to scroll only within this region. The view of the canvas
2942 * is adjusted as appropriate to display as much of the new region as possible.
2945 gnome_canvas_set_scroll_region (GnomeCanvas
*canvas
,
2951 GtkScrollable
*scrollable
;
2952 GtkAdjustment
*hadjustment
;
2953 GtkAdjustment
*vadjustment
;
2954 gdouble hadjustment_value
;
2955 gdouble vadjustment_value
;
2956 gdouble wxofs
, wyofs
;
2959 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
2961 scrollable
= GTK_SCROLLABLE (canvas
);
2962 hadjustment
= gtk_scrollable_get_hadjustment (scrollable
);
2963 vadjustment
= gtk_scrollable_get_vadjustment (scrollable
);
2965 hadjustment_value
= gtk_adjustment_get_value (hadjustment
);
2966 vadjustment_value
= gtk_adjustment_get_value (vadjustment
);
2969 * Set the new scrolling region. If possible, do not move the
2970 * visible contents of the canvas.
2975 hadjustment_value
+ canvas
->zoom_xofs
,
2976 vadjustment_value
+ canvas
->zoom_yofs
,
2979 canvas
->scroll_x1
= x1
;
2980 canvas
->scroll_y1
= y1
;
2981 canvas
->scroll_x2
= x2
;
2982 canvas
->scroll_y2
= y2
;
2984 gnome_canvas_w2c (canvas
, wxofs
, wyofs
, &xofs
, &yofs
);
2986 scroll_to (canvas
, xofs
, yofs
);
2988 canvas
->need_repick
= TRUE
;
2990 /* todo: should be requesting update */
2991 (* GNOME_CANVAS_ITEM_CLASS (canvas
->root
->object
.class)->update
) (
2992 canvas
->root
, NULL
, NULL
, 0);
2997 * gnome_canvas_get_scroll_region:
2998 * @canvas: A canvas.
2999 * @x1: Leftmost limit of the scrolling region (return value).
3000 * @y1: Upper limit of the scrolling region (return value).
3001 * @x2: Rightmost limit of the scrolling region (return value).
3002 * @y2: Lower limit of the scrolling region (return value).
3004 * Queries the scrolling region of a canvas.
3007 gnome_canvas_get_scroll_region (GnomeCanvas
*canvas
,
3013 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3016 *x1
= canvas
->scroll_x1
;
3019 *y1
= canvas
->scroll_y1
;
3022 *x2
= canvas
->scroll_x2
;
3025 *y2
= canvas
->scroll_y2
;
3029 * gnome_canvas_scroll_to:
3030 * @canvas: A canvas.
3031 * @cx: Horizontal scrolling offset in canvas pixel units.
3032 * @cy: Vertical scrolling offset in canvas pixel units.
3034 * Makes a canvas scroll to the specified offsets, given in canvas pixel units.
3035 * The canvas will adjust the view so that it is not outside the scrolling
3036 * region. This function is typically not used, as it is better to hook
3037 * scrollbars to the canvas layout's scrolling adjusments.
3040 gnome_canvas_scroll_to (GnomeCanvas
*canvas
,
3044 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3046 scroll_to (canvas
, cx
, cy
);
3050 * gnome_canvas_get_scroll_offsets:
3051 * @canvas: A canvas.
3052 * @cx: Horizontal scrolling offset (return value).
3053 * @cy: Vertical scrolling offset (return value).
3055 * Queries the scrolling offsets of a canvas. The values are returned in canvas
3059 gnome_canvas_get_scroll_offsets (GnomeCanvas
*canvas
,
3063 GtkAdjustment
*adjustment
;
3064 GtkScrollable
*scrollable
;
3066 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3068 scrollable
= GTK_SCROLLABLE (canvas
);
3071 adjustment
= gtk_scrollable_get_hadjustment (scrollable
);
3072 *cx
= (gint
) gtk_adjustment_get_value (adjustment
);
3076 adjustment
= gtk_scrollable_get_vadjustment (scrollable
);
3077 *cy
= (gint
) gtk_adjustment_get_value (adjustment
);
3082 * gnome_canvas_get_item_at:
3083 * @canvas: A canvas.
3084 * @x: X position in world coordinates.
3085 * @y: Y position in world coordinates.
3087 * Looks for the item that is under the specified position, which must be
3088 * specified in world coordinates.
3090 * Return value: The sought item, or NULL if no item is at the specified
3094 gnome_canvas_get_item_at (GnomeCanvas
*canvas
,
3100 g_return_val_if_fail (GNOME_IS_CANVAS (canvas
), NULL
);
3102 gnome_canvas_w2c (canvas
, x
, y
, &cx
, &cy
);
3104 return gnome_canvas_item_invoke_point (canvas
->root
, x
, y
, cx
, cy
);
3107 /* Queues an update of the canvas */
3109 gnome_canvas_request_update (GnomeCanvas
*canvas
)
3111 GNOME_CANVAS_GET_CLASS (canvas
)->request_update (canvas
);
3115 gnome_canvas_request_update_real (GnomeCanvas
*canvas
)
3117 if (canvas
->need_update
)
3120 canvas
->need_update
= TRUE
;
3121 if (gtk_widget_get_mapped ((GtkWidget
*) canvas
))
3126 get_visible_rect (GnomeCanvas
*canvas
,
3127 GdkRectangle
*visible
)
3129 GtkAllocation allocation
;
3130 GtkScrollable
*scrollable
;
3131 GtkAdjustment
*hadjustment
;
3132 GtkAdjustment
*vadjustment
;
3133 gdouble hadjustment_value
;
3134 gdouble vadjustment_value
;
3136 gtk_widget_get_allocation (GTK_WIDGET (canvas
), &allocation
);
3138 scrollable
= GTK_SCROLLABLE (canvas
);
3139 hadjustment
= gtk_scrollable_get_hadjustment (scrollable
);
3140 vadjustment
= gtk_scrollable_get_vadjustment (scrollable
);
3142 hadjustment_value
= gtk_adjustment_get_value (hadjustment
);
3143 vadjustment_value
= gtk_adjustment_get_value (vadjustment
);
3145 visible
->x
= hadjustment_value
- canvas
->zoom_xofs
;
3146 visible
->y
= vadjustment_value
- canvas
->zoom_yofs
;
3147 visible
->width
= allocation
.width
;
3148 visible
->height
= allocation
.height
;
3152 * gnome_canvas_request_redraw:
3153 * @canvas: A canvas.
3154 * @x1: Leftmost coordinate of the rectangle to be redrawn.
3155 * @y1: Upper coordinate of the rectangle to be redrawn.
3156 * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1.
3157 * @y2: Lower coordinate of the rectangle to be redrawn, plus 1.
3159 * Convenience function that informs a canvas that the specified rectangle needs
3160 * to be repainted. The rectangle includes @x1 and @y1, but not @x2 and @y2. To
3161 * be used only by item implementations.
3164 gnome_canvas_request_redraw (GnomeCanvas
*canvas
,
3170 GdkRectangle area
, clip
;
3172 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3174 if (!gtk_widget_is_drawable (GTK_WIDGET (canvas
)) || (x1
>= x2
) || (y1
>= y2
))
3179 area
.width
= x2
- x1
+ 1;
3180 area
.height
= y2
- y1
+ 1;
3182 get_visible_rect (canvas
, &clip
);
3183 if (!gdk_rectangle_intersect (&area
, &clip
, &area
))
3186 gdk_window_invalidate_rect (
3187 gtk_layout_get_bin_window (GTK_LAYOUT (canvas
)),
3192 * gnome_canvas_w2c_matrix:
3193 * @canvas: A canvas.
3194 * @matrix: (out): matrix to initialize
3196 * Gets the transformtion matrix that converts from world coordinates to canvas
3197 * pixel coordinates.
3200 gnome_canvas_w2c_matrix (GnomeCanvas
*canvas
,
3201 cairo_matrix_t
*matrix
)
3203 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3204 g_return_if_fail (matrix
!= NULL
);
3206 cairo_matrix_init_translate (
3207 matrix
, -canvas
->scroll_x1
, -canvas
->scroll_y1
);
3211 * gnome_canvas_c2w_matrix:
3212 * @canvas: A canvas.
3213 * @matrix: (out): matrix to initialize
3215 * Gets the transformtion matrix that converts from canvas pixel coordinates to
3216 * world coordinates.
3219 gnome_canvas_c2w_matrix (GnomeCanvas
*canvas
,
3220 cairo_matrix_t
*matrix
)
3222 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3223 g_return_if_fail (matrix
!= NULL
);
3225 cairo_matrix_init_translate (
3226 matrix
, canvas
->scroll_x1
, canvas
->scroll_y1
);
3231 * @canvas: A canvas.
3232 * @wx: World X coordinate.
3233 * @wy: World Y coordinate.
3234 * @cx: X pixel coordinate (return value).
3235 * @cy: Y pixel coordinate (return value).
3237 * Converts world coordinates into canvas pixel coordinates.
3240 gnome_canvas_w2c (GnomeCanvas
*canvas
,
3248 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3250 gnome_canvas_w2c_matrix (canvas
, &w2c
);
3251 cairo_matrix_transform_point (&w2c
, &wx
, &wy
);
3254 *cx
= floor (wx
+ 0.5);
3256 *cy
= floor (wy
+ 0.5);
3260 * gnome_canvas_w2c_d:
3261 * @canvas: A canvas.
3262 * @wx: World X coordinate.
3263 * @wy: World Y coordinate.
3264 * @cx: X pixel coordinate (return value).
3265 * @cy: Y pixel coordinate (return value).
3267 * Converts world coordinates into canvas pixel coordinates. This
3268 * version returns coordinates in floating point coordinates, for
3269 * greater precision.
3272 gnome_canvas_w2c_d (GnomeCanvas
*canvas
,
3280 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3282 gnome_canvas_w2c_matrix (canvas
, &w2c
);
3283 cairo_matrix_transform_point (&w2c
, &wx
, &wy
);
3293 * @canvas: A canvas.
3294 * @cx: Canvas pixel X coordinate.
3295 * @cy: Canvas pixel Y coordinate.
3296 * @wx: X world coordinate (return value).
3297 * @wy: Y world coordinate (return value).
3299 * Converts canvas pixel coordinates to world coordinates.
3302 gnome_canvas_c2w (GnomeCanvas
*canvas
,
3311 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3315 gnome_canvas_c2w_matrix (canvas
, &c2w
);
3316 cairo_matrix_transform_point (&c2w
, &x
, &y
);
3325 * gnome_canvas_window_to_world:
3326 * @canvas: A canvas.
3327 * @winx: Window-relative X coordinate.
3328 * @winy: Window-relative Y coordinate.
3329 * @worldx: X world coordinate (return value).
3330 * @worldy: Y world coordinate (return value).
3332 * Converts window-relative coordinates into world coordinates. You can use
3333 * this when you need to convert mouse coordinates into world coordinates, for
3337 gnome_canvas_window_to_world (GnomeCanvas
*canvas
,
3343 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3346 *worldx
= canvas
->scroll_x1
+ (winx
- canvas
->zoom_xofs
);
3349 *worldy
= canvas
->scroll_y1
+ (winy
- canvas
->zoom_yofs
);
3353 * gnome_canvas_world_to_window:
3354 * @canvas: A canvas.
3355 * @worldx: World X coordinate.
3356 * @worldy: World Y coordinate.
3357 * @winx: X window-relative coordinate.
3358 * @winy: Y window-relative coordinate.
3360 * Converts world coordinates into window-relative coordinates.
3363 gnome_canvas_world_to_window (GnomeCanvas
*canvas
,
3369 g_return_if_fail (GNOME_IS_CANVAS (canvas
));
3372 *winx
= (worldx
- canvas
->scroll_x1
) + canvas
->zoom_xofs
;
3375 *winy
= (worldy
- canvas
->scroll_y1
) + canvas
->zoom_yofs
;
3379 boolean_handled_accumulator (GSignalInvocationHint
*ihint
,
3380 GValue
*return_accu
,
3381 const GValue
*handler_return
,
3384 gboolean continue_emission
;
3385 gboolean signal_handled
;
3387 signal_handled
= g_value_get_boolean (handler_return
);
3388 g_value_set_boolean (return_accu
, signal_handled
);
3389 continue_emission
= !signal_handled
;
3391 return continue_emission
;
3394 /* Class initialization function for GnomeCanvasItemClass */
3396 gnome_canvas_item_class_init (GnomeCanvasItemClass
*class)
3398 GObjectClass
*gobject_class
;
3400 gobject_class
= (GObjectClass
*) class;
3402 gobject_class
->set_property
= gnome_canvas_item_set_property
;
3403 gobject_class
->get_property
= gnome_canvas_item_get_property
;
3405 g_object_class_install_property (
3408 g_param_spec_object (
3412 GNOME_TYPE_CANVAS_ITEM
,
3416 item_signals
[ITEM_EVENT
] = g_signal_new (
3418 G_TYPE_FROM_CLASS (class),
3420 G_STRUCT_OFFSET (GnomeCanvasItemClass
, event
),
3421 boolean_handled_accumulator
, NULL
, NULL
,
3423 GDK_TYPE_EVENT
| G_SIGNAL_TYPE_STATIC_SCOPE
);
3425 gobject_class
->dispose
= gnome_canvas_item_dispose
;
3427 class->update
= gnome_canvas_item_update
;
3428 class->realize
= gnome_canvas_item_realize
;
3429 class->unrealize
= gnome_canvas_item_unrealize
;
3430 class->map
= gnome_canvas_item_map
;
3431 class->unmap
= gnome_canvas_item_unmap
;
3432 class->dispose
= gnome_canvas_item_dispose_item
;
3433 class->draw
= gnome_canvas_item_draw
;
3434 class->point
= gnome_canvas_item_point
;
3435 class->bounds
= gnome_canvas_item_bounds
;
3436 class->event
= gnome_canvas_item_event
;