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
* EelCanvas widget - Tk-like canvas widget for Gnome
29
* EelCanvas 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 EelCanvasImage sizes are in units or pixels (scale or don't scale).
42
* - Implement a flag for eel_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 *eel_canvas_gimme_all_items_contained_in_this_area (EelCanvas *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 EelCanvasEllipse).
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 <glib/gi18n-lib.h>
72
#include <cairo-gobject.h>
73
#include "eel-canvas.h"
75
static void eel_canvas_request_update (EelCanvas *canvas);
76
static void group_add (EelCanvasGroup *group,
78
static void group_remove (EelCanvasGroup *group,
80
static void redraw_and_repick_if_mapped (EelCanvasItem *item);
82
/*** EelCanvasItem ***/
84
/* Some convenience stuff */
85
#define GCI_UPDATE_MASK (EEL_CANVAS_UPDATE_REQUESTED | EEL_CANVAS_UPDATE_DEEP)
86
#define GCI_EPSILON 1e-18
100
static void eel_canvas_item_class_init (EelCanvasItemClass *klass);
101
static void eel_canvas_item_init (EelCanvasItem *item);
102
static int emit_event (EelCanvas *canvas, GdkEvent *event);
104
static guint item_signals[ITEM_LAST_SIGNAL];
106
static GObjectClass *item_parent_class;
108
static gpointer accessible_item_parent_class;
109
static gpointer accessible_parent_class;
113
* eel_canvas_item_get_type:
115
* Registers the &EelCanvasItem class if necessary, and returns the type ID
118
* Return value: The type ID of the &EelCanvasItem class.
121
eel_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 (EelCanvasItemClass),
128
(GBaseInitFunc) NULL,
129
(GBaseFinalizeFunc) NULL,
130
(GClassInitFunc) eel_canvas_item_class_init,
131
NULL, /* class_finalize */
132
NULL, /* class_data */
133
sizeof (EelCanvasItem),
135
(GInstanceInitFunc) eel_canvas_item_init
138
canvas_item_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED,
144
return canvas_item_type;
147
/* Object initialization function for EelCanvasItem */
149
eel_canvas_item_init (EelCanvasItem *item)
151
item->flags |= EEL_CANVAS_ITEM_VISIBLE;
155
* eel_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
* eel_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
eel_canvas_item_new (EelCanvasGroup *parent, GType type, const gchar *first_arg_name, ...)
177
g_return_val_if_fail (EEL_IS_CANVAS_GROUP (parent), NULL);
178
g_return_val_if_fail (g_type_is_a (type, eel_canvas_item_get_type ()), NULL);
180
item = EEL_CANVAS_ITEM (g_object_new (type, NULL));
182
va_start (args, first_arg_name);
183
eel_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 (EelCanvasItem *item)
196
group_add (EEL_CANVAS_GROUP (item->parent), item);
198
redraw_and_repick_if_mapped (item);
201
/* Set_property handler for canvas items */
203
eel_canvas_item_set_property (GObject *gobject, guint param_id,
204
const GValue *value, GParamSpec *pspec)
208
g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject));
210
item = EEL_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 = EEL_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
eel_canvas_item_show (item);
227
eel_canvas_item_hide (item);
231
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
236
/* Get_property handler for canvas items */
238
eel_canvas_item_get_property (GObject *gobject, guint param_id,
239
GValue *value, GParamSpec *pspec)
243
g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject));
245
item = EEL_CANVAS_ITEM (gobject);
248
case ITEM_PROP_VISIBLE:
249
g_value_set_boolean (value, item->flags & EEL_CANVAS_ITEM_VISIBLE);
252
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
258
* eel_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
eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent,
268
const gchar *first_arg_name, va_list args)
270
g_return_if_fail (EEL_IS_CANVAS_GROUP (parent));
271
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
273
item->parent = EEL_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 (EelCanvasItem *item)
285
if (item->flags & EEL_CANVAS_ITEM_MAPPED) {
286
eel_canvas_item_request_redraw (item);
287
item->canvas->need_repick = TRUE;
291
/* Dispose handler for canvas items */
293
eel_canvas_item_dispose (GObject *object)
297
g_return_if_fail (EEL_IS_CANVAS_ITEM (object));
299
item = EEL_CANVAS_ITEM (object);
302
eel_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
eel_canvas_item_ungrab (item, GDK_CURRENT_TIME);
318
if (item == item->canvas->focused_item)
319
item->canvas->focused_item = NULL;
321
/* Normal destroy stuff */
323
if (item->flags & EEL_CANVAS_ITEM_MAPPED)
324
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
326
if (item->flags & EEL_CANVAS_ITEM_REALIZED)
327
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
330
group_remove (EEL_CANVAS_GROUP (item->parent), item);
335
g_object_set_data (object, "in-destruction", GINT_TO_POINTER (1));
336
g_signal_emit (object, item_signals[ITEM_DESTROY], 0);
338
g_object_set_data (object, "in-destruction", NULL);
340
G_OBJECT_CLASS (item_parent_class)->dispose (object);
344
eel_canvas_item_destroy (EelCanvasItem *item)
346
if (g_object_get_data (G_OBJECT (item), "in-destruction") == NULL) {
347
g_object_run_dispose (G_OBJECT (item));
351
/* Realize handler for canvas items */
353
eel_canvas_item_realize (EelCanvasItem *item)
355
if (item->parent && !(item->parent->flags & EEL_CANVAS_ITEM_REALIZED))
356
(* EEL_CANVAS_ITEM_GET_CLASS (item->parent)->realize) (item->parent);
358
if (item->parent == NULL && !gtk_widget_get_realized (GTK_WIDGET (item->canvas)))
359
gtk_widget_realize (GTK_WIDGET (item->canvas));
361
item->flags |= EEL_CANVAS_ITEM_REALIZED;
363
eel_canvas_item_request_update (item);
366
/* Unrealize handler for canvas items */
368
eel_canvas_item_unrealize (EelCanvasItem *item)
370
if (item->flags & EEL_CANVAS_ITEM_MAPPED)
371
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
373
item->flags &= ~(EEL_CANVAS_ITEM_REALIZED);
376
/* Map handler for canvas items */
378
eel_canvas_item_map (EelCanvasItem *item)
380
item->flags |= EEL_CANVAS_ITEM_MAPPED;
383
/* Unmap handler for canvas items */
385
eel_canvas_item_unmap (EelCanvasItem *item)
387
item->flags &= ~(EEL_CANVAS_ITEM_MAPPED);
390
/* Update handler for canvas items */
392
eel_canvas_item_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
394
item->flags &= ~(EEL_CANVAS_ITEM_NEED_UPDATE);
395
item->flags &= ~(EEL_CANVAS_ITEM_NEED_DEEP_UPDATE);
399
* This routine invokes the update method of the item
400
* Please notice, that we take parent to canvas pixel matrix as argument
401
* unlike virtual method ::update, whose argument is item 2 canvas pixel
404
* I will try to force somewhat meaningful naming for affines (Lauris)
405
* General naming rule is FROM2TO, where FROM and TO are abbreviations
406
* So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel
407
* I hope that this helps to keep track of what really happens
412
eel_canvas_item_invoke_update (EelCanvasItem *item,
421
/* apply object flags to child flags */
422
child_flags &= ~EEL_CANVAS_UPDATE_REQUESTED;
424
if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE)
425
child_flags |= EEL_CANVAS_UPDATE_REQUESTED;
427
if (item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)
428
child_flags |= EEL_CANVAS_UPDATE_DEEP;
430
if (child_flags & GCI_UPDATE_MASK) {
431
if (EEL_CANVAS_ITEM_GET_CLASS (item)->update)
432
EEL_CANVAS_ITEM_GET_CLASS (item)->update (item, i2w_dx, i2w_dy, child_flags);
435
/* If this fail you probably forgot to chain up to
436
* EelCanvasItem::update from a derived class */
437
g_return_if_fail (!(item->flags & EEL_CANVAS_ITEM_NEED_UPDATE));
441
* This routine invokes the point method of the item.
442
* The arguments x, y should be in the parent item local coordinates.
446
eel_canvas_item_invoke_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item)
448
/* Calculate x & y in item local coordinates */
450
if (EEL_CANVAS_ITEM_GET_CLASS (item)->point)
451
return EEL_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item);
457
* eel_canvas_item_set:
458
* @item: A canvas item.
459
* @first_arg_name: The list of object argument name/value pairs used to configure the item.
462
* Configures a canvas item. The arguments in the item are set to the specified
463
* values, and the item is repainted as appropriate.
466
eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...)
470
va_start (args, first_arg_name);
471
eel_canvas_item_set_valist (item, first_arg_name, args);
477
* eel_canvas_item_set_valist:
478
* @item: A canvas item.
479
* @first_arg_name: The name of the first argument used to configure the item.
480
* @args: The list of object argument name/value pairs used to configure the item.
482
* Configures a canvas item. The arguments in the item are set to the specified
483
* values, and the item is repainted as appropriate.
486
eel_canvas_item_set_valist (EelCanvasItem *item, const gchar *first_arg_name, va_list args)
488
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
490
g_object_set_valist (G_OBJECT (item), first_arg_name, args);
492
item->canvas->need_repick = TRUE;
497
* eel_canvas_item_move:
498
* @item: A canvas item.
499
* @dx: Horizontal offset.
500
* @dy: Vertical offset.
502
* Moves a canvas item by creating an affine transformation matrix for
503
* translation by using the specified values. This happens in item
504
* local coordinate system, so if you have nontrivial transform, it
505
* most probably does not do, what you want.
508
eel_canvas_item_move (EelCanvasItem *item, double dx, double dy)
510
g_return_if_fail (item != NULL);
511
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
513
if (!EEL_CANVAS_ITEM_GET_CLASS (item)->translate) {
514
g_warning ("Item type %s does not implement translate method.\n",
515
g_type_name (G_OBJECT_TYPE (item)));
519
(* EEL_CANVAS_ITEM_GET_CLASS (item)->translate) (item, dx, dy);
521
if (item->flags & EEL_CANVAS_ITEM_MAPPED)
522
item->canvas->need_repick = TRUE;
524
if (!(item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
525
item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
526
if (item->parent != NULL)
527
eel_canvas_item_request_update (item->parent);
529
eel_canvas_request_update (item->canvas);
535
eel_canvas_queue_resize (EelCanvas *canvas)
537
if (gtk_widget_is_drawable (GTK_WIDGET (canvas)))
538
gtk_widget_queue_resize (GTK_WIDGET (canvas));
541
/* Convenience function to reorder items in a group's child list. This puts the
542
* specified link after the "before" link. Returns TRUE if the list was changed.
545
put_item_after (GList *link, GList *before)
547
EelCanvasGroup *parent;
552
parent = EEL_CANVAS_GROUP (EEL_CANVAS_ITEM (link->data)->parent);
554
if (before == NULL) {
555
if (link == parent->item_list)
558
link->prev->next = link->next;
561
link->next->prev = link->prev;
563
parent->item_list_end = link->prev;
566
link->next = parent->item_list;
567
link->next->prev = link;
568
parent->item_list = link;
570
if ((link == parent->item_list_end) && (before == parent->item_list_end->prev))
574
link->next->prev = link->prev;
577
link->prev->next = link->next;
579
parent->item_list = link->next;
580
parent->item_list->prev = NULL;
584
link->next = before->next;
586
link->prev->next = link;
589
link->next->prev = link;
591
parent->item_list_end = link;
598
* eel_canvas_item_raise:
599
* @item: A canvas item.
600
* @positions: Number of steps to raise the item.
602
* Raises the item in its parent's stack by the specified number of positions.
603
* If the number of positions is greater than the distance to the top of the
604
* stack, then the item is put at the top.
607
eel_canvas_item_raise (EelCanvasItem *item, int positions)
609
GList *link, *before;
610
EelCanvasGroup *parent;
612
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
613
g_return_if_fail (positions >= 0);
615
if (!item->parent || positions == 0)
618
parent = EEL_CANVAS_GROUP (item->parent);
619
link = g_list_find (parent->item_list, item);
620
g_assert (link != NULL);
622
for (before = link; positions && before; positions--)
623
before = before->next;
626
before = parent->item_list_end;
628
if (put_item_after (link, before)) {
629
redraw_and_repick_if_mapped (item);
635
* eel_canvas_item_lower:
636
* @item: A canvas item.
637
* @positions: Number of steps to lower the item.
639
* Lowers the item in its parent's stack by the specified number of positions.
640
* If the number of positions is greater than the distance to the bottom of the
641
* stack, then the item is put at the bottom.
644
eel_canvas_item_lower (EelCanvasItem *item, int positions)
646
GList *link, *before;
647
EelCanvasGroup *parent;
649
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
650
g_return_if_fail (positions >= 1);
652
if (!item->parent || positions == 0)
655
parent = EEL_CANVAS_GROUP (item->parent);
656
link = g_list_find (parent->item_list, item);
657
g_assert (link != NULL);
660
for (before = link->prev; positions && before; positions--)
661
before = before->prev;
665
if (put_item_after (link, before)) {
666
redraw_and_repick_if_mapped (item);
672
* eel_canvas_item_raise_to_top:
673
* @item: A canvas item.
675
* Raises an item to the top of its parent's stack.
678
eel_canvas_item_raise_to_top (EelCanvasItem *item)
681
EelCanvasGroup *parent;
683
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
688
parent = EEL_CANVAS_GROUP (item->parent);
689
link = g_list_find (parent->item_list, item);
690
g_assert (link != NULL);
692
if (put_item_after (link, parent->item_list_end)) {
693
redraw_and_repick_if_mapped (item);
699
* eel_canvas_item_lower_to_bottom:
700
* @item: A canvas item.
702
* Lowers an item to the bottom of its parent's stack.
705
eel_canvas_item_lower_to_bottom (EelCanvasItem *item)
708
EelCanvasGroup *parent;
710
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
715
parent = EEL_CANVAS_GROUP (item->parent);
716
link = g_list_find (parent->item_list, item);
717
g_assert (link != NULL);
719
if (put_item_after (link, NULL)) {
720
redraw_and_repick_if_mapped (item);
725
* eel_canvas_item_send_behind:
726
* @item: A canvas item.
727
* @behind_item: The canvas item to put item behind, or NULL
729
* Moves item to a in the position in the stacking order so that
730
* it is placed immediately below behind_item, or at the top if
731
* behind_item is NULL.
734
eel_canvas_item_send_behind (EelCanvasItem *item,
735
EelCanvasItem *behind_item)
738
int item_position, behind_position;
740
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
742
if (behind_item == NULL) {
743
eel_canvas_item_raise_to_top (item);
747
g_return_if_fail (EEL_IS_CANVAS_ITEM (behind_item));
748
g_return_if_fail (item->parent == behind_item->parent);
750
item_list = EEL_CANVAS_GROUP (item->parent)->item_list;
752
item_position = g_list_index (item_list, item);
753
g_assert (item_position != -1);
754
behind_position = g_list_index (item_list, behind_item);
755
g_assert (behind_position != -1);
756
g_assert (item_position != behind_position);
758
if (item_position == behind_position - 1) {
762
if (item_position < behind_position) {
763
eel_canvas_item_raise (item, (behind_position - 1) - item_position);
765
eel_canvas_item_lower (item, item_position - behind_position);
770
* eel_canvas_item_show:
771
* @item: A canvas item.
773
* Shows a canvas item. If the item was already shown, then no action is taken.
776
eel_canvas_item_show (EelCanvasItem *item)
778
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
780
if (!(item->flags & EEL_CANVAS_ITEM_VISIBLE)) {
781
item->flags |= EEL_CANVAS_ITEM_VISIBLE;
783
if (!(item->flags & EEL_CANVAS_ITEM_REALIZED))
784
(* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
786
if (item->parent != NULL) {
787
if (!(item->flags & EEL_CANVAS_ITEM_MAPPED) &&
788
item->parent->flags & EEL_CANVAS_ITEM_MAPPED)
789
(* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item);
791
if (!(item->flags & EEL_CANVAS_ITEM_MAPPED) &&
792
gtk_widget_get_mapped (GTK_WIDGET (item->canvas)))
793
(* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item);
796
redraw_and_repick_if_mapped (item);
797
eel_canvas_queue_resize (item->canvas);
803
* eel_canvas_item_hide:
804
* @item: A canvas item.
806
* Hides a canvas item. If the item was already hidden, then no action is
810
eel_canvas_item_hide (EelCanvasItem *item)
812
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
814
if (item->flags & EEL_CANVAS_ITEM_VISIBLE) {
815
item->flags &= ~EEL_CANVAS_ITEM_VISIBLE;
817
redraw_and_repick_if_mapped (item);
819
if (item->flags & EEL_CANVAS_ITEM_MAPPED)
820
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
822
eel_canvas_queue_resize (item->canvas);
824
/* No need to unrealize when we just want to hide */
830
* eel_canvas_item_grab:
831
* @item: A canvas item.
832
* @event_mask: Mask of events that will be sent to this item.
833
* @cursor: If non-NULL, the cursor that will be used while the grab is active.
834
* @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME.
836
* Specifies that all events that match the specified event mask should be sent
837
* to the specified item, and also grabs the mouse by calling
838
* gdk_pointer_grab(). The event mask is also used when grabbing the pointer.
839
* If @cursor is not NULL, then that cursor is used while the grab is active.
840
* The @etime parameter is the timestamp required for grabbing the mouse.
842
* Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED. If
843
* the specified item was hidden by calling eel_canvas_item_hide(), then it
844
* returns %GDK_GRAB_NOT_VIEWABLE. Else, it returns the result of calling
845
* gdk_pointer_grab().
848
eel_canvas_item_grab (EelCanvasItem *item,
849
GdkEventMask event_mask,
853
GdkGrabStatus retval;
855
GdkDeviceManager *manager;
858
g_return_val_if_fail (EEL_IS_CANVAS_ITEM (item), GDK_GRAB_NOT_VIEWABLE);
859
g_return_val_if_fail (gtk_widget_get_mapped (GTK_WIDGET (item->canvas)),
860
GDK_GRAB_NOT_VIEWABLE);
862
if (item->canvas->grabbed_item)
863
return GDK_GRAB_ALREADY_GRABBED;
865
if (!(item->flags & EEL_CANVAS_ITEM_MAPPED))
866
return GDK_GRAB_NOT_VIEWABLE;
868
display = gtk_widget_get_display (GTK_WIDGET (item->canvas));
869
manager = gdk_display_get_device_manager (display);
870
device = gdk_device_manager_get_client_pointer (manager);
872
retval = gdk_device_grab (device,
873
gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)),
880
if (retval != GDK_GRAB_SUCCESS)
883
item->canvas->grabbed_item = item;
884
item->canvas->grabbed_event_mask = event_mask;
885
item->canvas->current_item = item; /* So that events go to the grabbed item */
892
* eel_canvas_item_ungrab:
893
* @item: A canvas item that holds a grab.
894
* @etime: The timestamp for ungrabbing the mouse.
896
* Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the
900
eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime)
903
GdkDeviceManager *manager;
906
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
908
if (item->canvas->grabbed_item != item)
911
display = gtk_widget_get_display (GTK_WIDGET (item->canvas));
912
manager = gdk_display_get_device_manager (display);
913
device = gdk_device_manager_get_client_pointer (manager);
915
item->canvas->grabbed_item = NULL;
916
gdk_device_ungrab (device, etime);
920
* eel_canvas_item_w2i:
921
* @item: A canvas item.
922
* @x: X coordinate to convert (input/output value).
923
* @y: Y coordinate to convert (input/output value).
925
* Converts a coordinate pair from world coordinates to item-relative
929
eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y)
931
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
932
g_return_if_fail (x != NULL);
933
g_return_if_fail (y != NULL);
937
if (EEL_IS_CANVAS_GROUP (item)) {
938
*x -= EEL_CANVAS_GROUP (item)->xpos;
939
*y -= EEL_CANVAS_GROUP (item)->ypos;
948
* eel_canvas_item_i2w:
949
* @item: A canvas item.
950
* @x: X coordinate to convert (input/output value).
951
* @y: Y coordinate to convert (input/output value).
953
* Converts a coordinate pair from item-relative coordinates to world
957
eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y)
959
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
960
g_return_if_fail (x != NULL);
961
g_return_if_fail (y != NULL);
965
if (EEL_IS_CANVAS_GROUP (item)) {
966
*x += EEL_CANVAS_GROUP (item)->xpos;
967
*y += EEL_CANVAS_GROUP (item)->ypos;
974
/* Returns whether the item is an inferior of or is equal to the parent. */
976
is_descendant (EelCanvasItem *item, EelCanvasItem *parent)
978
for (; item; item = item->parent)
986
* eel_canvas_item_reparent:
987
* @item: A canvas item.
988
* @new_group: A canvas group.
990
* Changes the parent of the specified item to be the new group. The item keeps
991
* its group-relative coordinates as for its old parent, so the item may change
992
* its absolute position within the canvas.
995
eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group)
997
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
998
g_return_if_fail (EEL_IS_CANVAS_GROUP (new_group));
1000
/* Both items need to be in the same canvas */
1001
g_return_if_fail (item->canvas == EEL_CANVAS_ITEM (new_group)->canvas);
1003
/* The group cannot be an inferior of the item or be the item itself --
1004
* this also takes care of the case where the item is the root item of
1006
g_return_if_fail (!is_descendant (EEL_CANVAS_ITEM (new_group), item));
1008
/* Everything is ok, now actually reparent the item */
1010
g_object_ref (G_OBJECT (item)); /* protect it from the unref in group_remove */
1012
eel_canvas_item_request_redraw (item);
1014
group_remove (EEL_CANVAS_GROUP (item->parent), item);
1015
item->parent = EEL_CANVAS_ITEM (new_group);
1016
/* item->canvas is unchanged. */
1017
group_add (new_group, item);
1019
/* Redraw and repick */
1021
redraw_and_repick_if_mapped (item);
1023
g_object_unref (G_OBJECT (item));
1027
* eel_canvas_item_grab_focus:
1028
* @item: A canvas item.
1030
* Makes the specified item take the keyboard focus, so all keyboard events will
1031
* be sent to it. If the canvas widget itself did not have the focus, it grabs
1035
eel_canvas_item_grab_focus (EelCanvasItem *item)
1037
EelCanvasItem *focused_item;
1040
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
1041
g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas)));
1043
focused_item = item->canvas->focused_item;
1046
ev.focus_change.type = GDK_FOCUS_CHANGE;
1047
ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas));
1048
ev.focus_change.send_event = FALSE;
1049
ev.focus_change.in = FALSE;
1051
emit_event (item->canvas, &ev);
1054
item->canvas->focused_item = item;
1055
gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
1058
ev.focus_change.type = GDK_FOCUS_CHANGE;
1059
ev.focus_change.window = gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas));
1060
ev.focus_change.send_event = FALSE;
1061
ev.focus_change.in = TRUE;
1063
emit_event (item->canvas, &ev);
1069
* eel_canvas_item_get_bounds:
1070
* @item: A canvas item.
1071
* @x1: Leftmost edge of the bounding box (return value).
1072
* @y1: Upper edge of the bounding box (return value).
1073
* @x2: Rightmost edge of the bounding box (return value).
1074
* @y2: Lower edge of the bounding box (return value).
1076
* Queries the bounding box of a canvas item. The bounds are returned in the
1077
* coordinate system of the item's parent.
1080
eel_canvas_item_get_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1082
double tx1, ty1, tx2, ty2;
1084
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
1086
tx1 = ty1 = tx2 = ty2 = 0.0;
1088
/* Get the item's bounds in its coordinate system */
1090
if (EEL_CANVAS_ITEM_GET_CLASS (item)->bounds)
1091
(* EEL_CANVAS_ITEM_GET_CLASS (item)->bounds) (item, &tx1, &ty1, &tx2, &ty2);
1093
/* Return the values */
1110
* eel_canvas_item_request_update
1111
* @item: A canvas item.
1113
* To be used only by item implementations. Requests that the canvas queue an
1114
* update for the specified item.
1117
eel_canvas_item_request_update (EelCanvasItem *item)
1119
if (NULL == item->canvas)
1122
g_return_if_fail (!item->canvas->doing_update);
1124
if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE)
1127
item->flags |= EEL_CANVAS_ITEM_NEED_UPDATE;
1129
if (item->parent != NULL) {
1130
/* Recurse up the tree */
1131
eel_canvas_item_request_update (item->parent);
1133
/* Have reached the top of the tree, make sure the update call gets scheduled. */
1134
eel_canvas_request_update (item->canvas);
1139
* eel_canvas_item_request_update
1140
* @item: A canvas item.
1142
* Convenience function that informs a canvas that the specified item needs
1143
* to be repainted. To be used by item implementations
1146
eel_canvas_item_request_redraw (EelCanvasItem *item)
1148
if (item->flags & EEL_CANVAS_ITEM_MAPPED)
1149
eel_canvas_request_redraw (item->canvas,
1151
item->x2 + 1, item->y2 + 1);
1156
/*** EelCanvasGroup ***/
1166
static void eel_canvas_group_class_init (EelCanvasGroupClass *klass);
1167
static void eel_canvas_group_init (EelCanvasGroup *group);
1168
static void eel_canvas_group_set_property(GObject *object,
1170
const GValue *value,
1172
static void eel_canvas_group_get_property(GObject *object,
1177
static void eel_canvas_group_destroy (EelCanvasItem *object);
1179
static void eel_canvas_group_update (EelCanvasItem *item,
1183
static void eel_canvas_group_unrealize (EelCanvasItem *item);
1184
static void eel_canvas_group_map (EelCanvasItem *item);
1185
static void eel_canvas_group_unmap (EelCanvasItem *item);
1186
static void eel_canvas_group_draw (EelCanvasItem *item,
1188
cairo_region_t *region);
1189
static double eel_canvas_group_point (EelCanvasItem *item, double x, double y,
1191
EelCanvasItem **actual_item);
1192
static void eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy);
1193
static void eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1,
1194
double *x2, double *y2);
1197
static EelCanvasItemClass *group_parent_class;
1201
* eel_canvas_group_get_type:
1203
* Registers the &EelCanvasGroup class if necessary, and returns the type ID
1206
* Return value: The type ID of the &EelCanvasGroup class.
1209
eel_canvas_group_get_type (void)
1211
static GType group_type = 0;
1214
static const GTypeInfo group_info = {
1215
sizeof (EelCanvasGroupClass),
1216
(GBaseInitFunc) NULL,
1217
(GBaseFinalizeFunc) NULL,
1218
(GClassInitFunc) eel_canvas_group_class_init,
1219
NULL, /* class_finalize */
1220
NULL, /* class_data */
1221
sizeof (EelCanvasGroup),
1222
0, /* n_preallocs */
1223
(GInstanceInitFunc) eel_canvas_group_init
1228
group_type = g_type_register_static (eel_canvas_item_get_type (),
1237
/* Class initialization function for EelCanvasGroupClass */
1239
eel_canvas_group_class_init (EelCanvasGroupClass *klass)
1241
GObjectClass *gobject_class;
1242
EelCanvasItemClass *item_class;
1244
gobject_class = (GObjectClass *) klass;
1245
item_class = (EelCanvasItemClass *) klass;
1247
group_parent_class = g_type_class_peek_parent (klass);
1249
gobject_class->set_property = eel_canvas_group_set_property;
1250
gobject_class->get_property = eel_canvas_group_get_property;
1252
g_object_class_install_property
1253
(gobject_class, GROUP_PROP_X,
1254
g_param_spec_double ("x",
1257
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
1258
G_PARAM_READWRITE));
1259
g_object_class_install_property
1260
(gobject_class, GROUP_PROP_Y,
1261
g_param_spec_double ("y",
1264
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
1265
G_PARAM_READWRITE));
1267
item_class->destroy = eel_canvas_group_destroy;
1268
item_class->update = eel_canvas_group_update;
1269
item_class->unrealize = eel_canvas_group_unrealize;
1270
item_class->map = eel_canvas_group_map;
1271
item_class->unmap = eel_canvas_group_unmap;
1272
item_class->draw = eel_canvas_group_draw;
1273
item_class->point = eel_canvas_group_point;
1274
item_class->translate = eel_canvas_group_translate;
1275
item_class->bounds = eel_canvas_group_bounds;
1278
/* Object initialization function for EelCanvasGroup */
1280
eel_canvas_group_init (EelCanvasGroup *group)
1286
/* Set_property handler for canvas groups */
1288
eel_canvas_group_set_property (GObject *gobject, guint param_id,
1289
const GValue *value, GParamSpec *pspec)
1291
EelCanvasItem *item;
1292
EelCanvasGroup *group;
1296
g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject));
1298
item = EEL_CANVAS_ITEM (gobject);
1299
group = EEL_CANVAS_GROUP (gobject);
1305
group->xpos = g_value_get_double (value);
1306
if (old != group->xpos)
1312
group->ypos = g_value_get_double (value);
1313
if (old != group->ypos)
1318
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
1323
item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
1324
if (item->parent != NULL)
1325
eel_canvas_item_request_update (item->parent);
1327
eel_canvas_request_update (item->canvas);
1331
/* Get_property handler for canvas groups */
1333
eel_canvas_group_get_property (GObject *gobject, guint param_id,
1334
GValue *value, GParamSpec *pspec)
1336
EelCanvasGroup *group;
1338
g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject));
1340
group = EEL_CANVAS_GROUP (gobject);
1344
g_value_set_double (value, group->xpos);
1348
g_value_set_double (value, group->ypos);
1352
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
1357
/* Destroy handler for canvas groups */
1359
eel_canvas_group_destroy (EelCanvasItem *object)
1361
EelCanvasGroup *group;
1362
EelCanvasItem *child;
1365
g_return_if_fail (EEL_IS_CANVAS_GROUP (object));
1367
group = EEL_CANVAS_GROUP (object);
1369
list = group->item_list;
1374
eel_canvas_item_destroy (child);
1377
if (EEL_CANVAS_ITEM_CLASS (group_parent_class)->destroy)
1378
(* EEL_CANVAS_ITEM_CLASS (group_parent_class)->destroy) (object);
1381
/* Update handler for canvas groups */
1383
eel_canvas_group_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
1385
EelCanvasGroup *group;
1388
double bbox_x0, bbox_y0, bbox_x1, bbox_y1;
1389
gboolean first = TRUE;
1391
group = EEL_CANVAS_GROUP (item);
1393
(* group_parent_class->update) (item, i2w_dx, i2w_dy, flags);
1400
for (list = group->item_list; list; list = list->next) {
1403
eel_canvas_item_invoke_update (i, i2w_dx + group->xpos, i2w_dy + group->ypos, flags);
1412
bbox_x0 = MIN (bbox_x0, i->x1);
1413
bbox_y0 = MIN (bbox_y0, i->y1);
1414
bbox_x1 = MAX (bbox_x1, i->x2);
1415
bbox_y1 = MAX (bbox_y1, i->y2);
1424
/* Unrealize handler for canvas groups */
1426
eel_canvas_group_unrealize (EelCanvasItem *item)
1428
EelCanvasGroup *group;
1432
group = EEL_CANVAS_GROUP (item);
1434
/* Unmap group before children to avoid flash */
1435
if (item->flags & EEL_CANVAS_ITEM_MAPPED)
1436
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
1438
for (list = group->item_list; list; list = list->next) {
1441
if (i->flags & EEL_CANVAS_ITEM_REALIZED)
1442
(* EEL_CANVAS_ITEM_GET_CLASS (i)->unrealize) (i);
1445
(* group_parent_class->unrealize) (item);
1448
/* Map handler for canvas groups */
1450
eel_canvas_group_map (EelCanvasItem *item)
1452
EelCanvasGroup *group;
1456
group = EEL_CANVAS_GROUP (item);
1458
for (list = group->item_list; list; list = list->next) {
1461
if (i->flags & EEL_CANVAS_ITEM_VISIBLE &&
1462
!(i->flags & EEL_CANVAS_ITEM_MAPPED)) {
1463
if (!(i->flags & EEL_CANVAS_ITEM_REALIZED))
1464
(* EEL_CANVAS_ITEM_GET_CLASS (i)->realize) (i);
1466
(* EEL_CANVAS_ITEM_GET_CLASS (i)->map) (i);
1470
(* group_parent_class->map) (item);
1473
/* Unmap handler for canvas groups */
1475
eel_canvas_group_unmap (EelCanvasItem *item)
1477
EelCanvasGroup *group;
1481
group = EEL_CANVAS_GROUP (item);
1483
for (list = group->item_list; list; list = list->next) {
1486
if (i->flags & EEL_CANVAS_ITEM_MAPPED)
1487
(* EEL_CANVAS_ITEM_GET_CLASS (i)->unmap) (i);
1490
(* group_parent_class->unmap) (item);
1493
/* Draw handler for canvas groups */
1495
eel_canvas_group_draw (EelCanvasItem *item,
1497
cairo_region_t *region)
1499
EelCanvasGroup *group;
1501
EelCanvasItem *child = NULL;
1503
group = EEL_CANVAS_GROUP (item);
1505
for (list = group->item_list; list; list = list->next) {
1508
if ((child->flags & EEL_CANVAS_ITEM_MAPPED) &&
1509
(EEL_CANVAS_ITEM_GET_CLASS (child)->draw)) {
1510
GdkRectangle child_rect;
1512
child_rect.x = child->x1;
1513
child_rect.y = child->y1;
1514
child_rect.width = child->x2 - child->x1 + 1;
1515
child_rect.height = child->y2 - child->y1 + 1;
1517
if (cairo_region_contains_rectangle (region, &child_rect) != CAIRO_REGION_OVERLAP_OUT)
1518
EEL_CANVAS_ITEM_GET_CLASS (child)->draw (child, cr, region);
1523
/* Point handler for canvas groups */
1525
eel_canvas_group_point (EelCanvasItem *item, double x, double y, int cx, int cy,
1526
EelCanvasItem **actual_item)
1528
EelCanvasGroup *group;
1530
EelCanvasItem *child, *point_item;
1536
group = EEL_CANVAS_GROUP (item);
1538
x1 = cx - item->canvas->close_enough;
1539
y1 = cy - item->canvas->close_enough;
1540
x2 = cx + item->canvas->close_enough;
1541
y2 = cy + item->canvas->close_enough;
1544
*actual_item = NULL;
1546
gx = x - group->xpos;
1547
gy = y - group->ypos;
1549
dist = 0.0; /* keep gcc happy */
1551
for (list = group->item_list; list; list = list->next) {
1554
if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1))
1557
point_item = NULL; /* cater for incomplete item implementations */
1559
if ((child->flags & EEL_CANVAS_ITEM_MAPPED)
1560
&& EEL_CANVAS_ITEM_GET_CLASS (child)->point) {
1561
dist = eel_canvas_item_invoke_point (child, gx, gy, cx, cy, &point_item);
1568
&& ((int) (dist * item->canvas->pixels_per_unit + 0.5)
1569
<= item->canvas->close_enough)) {
1571
*actual_item = point_item;
1579
eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy)
1581
EelCanvasGroup *group;
1583
group = EEL_CANVAS_GROUP (item);
1589
/* Bounds handler for canvas groups */
1591
eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1593
EelCanvasGroup *group;
1594
EelCanvasItem *child;
1596
double tx1, ty1, tx2, ty2;
1597
double minx, miny, maxx, maxy;
1600
group = EEL_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 & EEL_CANVAS_ITEM_MAPPED) {
1613
eel_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 & EEL_CANVAS_ITEM_MAPPED))
1635
eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2);
1650
/* Make the bounds be relative to our parent's coordinate system */
1653
minx += group->xpos;
1654
miny += group->ypos;
1655
maxx += group->xpos;
1656
maxy += group->ypos;
1665
/* Adds an item to a group */
1667
group_add (EelCanvasGroup *group, EelCanvasItem *item)
1669
g_object_ref_sink (item);
1671
if (!group->item_list) {
1672
group->item_list = g_list_append (group->item_list, item);
1673
group->item_list_end = group->item_list;
1675
group->item_list_end = g_list_append (group->item_list_end, item)->next;
1677
if (item->flags & EEL_CANVAS_ITEM_VISIBLE &&
1678
group->item.flags & EEL_CANVAS_ITEM_MAPPED) {
1679
if (!(item->flags & EEL_CANVAS_ITEM_REALIZED))
1680
(* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
1682
if (!(item->flags & EEL_CANVAS_ITEM_MAPPED))
1683
(* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item);
1686
if (item->flags & EEL_CANVAS_ITEM_VISIBLE)
1687
eel_canvas_queue_resize (EEL_CANVAS_ITEM (group)->canvas);
1690
/* Removes an item from a group */
1692
group_remove (EelCanvasGroup *group, EelCanvasItem *item)
1696
g_return_if_fail (EEL_IS_CANVAS_GROUP (group));
1697
g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
1699
for (children = group->item_list; children; children = children->next)
1700
if (children->data == item) {
1701
if (item->flags & EEL_CANVAS_ITEM_MAPPED) {
1702
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
1705
if (item->flags & EEL_CANVAS_ITEM_REALIZED)
1706
(* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
1708
if (item->flags & EEL_CANVAS_ITEM_VISIBLE)
1709
eel_canvas_queue_resize (item->canvas);
1711
/* Unparent the child */
1713
item->parent = NULL;
1714
/* item->canvas = NULL; */
1715
g_object_unref (G_OBJECT (item));
1717
/* Remove it from the list */
1719
if (children == group->item_list_end)
1720
group->item_list_end = children->prev;
1722
group->item_list = g_list_remove_link (group->item_list, children);
1723
g_list_free (children);
1737
static void eel_canvas_class_init (EelCanvasClass *klass);
1738
static void eel_canvas_init (EelCanvas *canvas);
1739
static void eel_canvas_destroy (GtkWidget *object);
1740
static void eel_canvas_map (GtkWidget *widget);
1741
static void eel_canvas_unmap (GtkWidget *widget);
1742
static void eel_canvas_realize (GtkWidget *widget);
1743
static void eel_canvas_unrealize (GtkWidget *widget);
1744
static void eel_canvas_size_allocate (GtkWidget *widget,
1745
GtkAllocation *allocation);
1746
static gint eel_canvas_button (GtkWidget *widget,
1747
GdkEventButton *event);
1748
static gint eel_canvas_motion (GtkWidget *widget,
1749
GdkEventMotion *event);
1750
static gint eel_canvas_draw (GtkWidget *widget,
1752
static gint eel_canvas_key (GtkWidget *widget,
1753
GdkEventKey *event);
1754
static gint eel_canvas_crossing (GtkWidget *widget,
1755
GdkEventCrossing *event);
1756
static gint eel_canvas_focus_in (GtkWidget *widget,
1757
GdkEventFocus *event);
1758
static gint eel_canvas_focus_out (GtkWidget *widget,
1759
GdkEventFocus *event);
1760
static void eel_canvas_request_update_real (EelCanvas *canvas);
1761
static void eel_canvas_draw_background (EelCanvas *canvas,
1763
static AtkObject *eel_canvas_get_accessible (GtkWidget *widget);
1766
static GtkLayoutClass *canvas_parent_class;
1768
static guint canvas_signals[LAST_SIGNAL];
1771
* eel_canvas_get_type:
1773
* Registers the &EelCanvas class if necessary, and returns the type ID
1776
* Return value: The type ID of the &EelCanvas class.
1779
eel_canvas_get_type (void)
1781
static GType canvas_type = 0;
1784
static const GTypeInfo canvas_info = {
1785
sizeof (EelCanvasClass),
1786
(GBaseInitFunc) NULL,
1787
(GBaseFinalizeFunc) NULL,
1788
(GClassInitFunc) eel_canvas_class_init,
1789
NULL, /* class_finalize */
1790
NULL, /* class_data */
1792
0, /* n_preallocs */
1793
(GInstanceInitFunc) eel_canvas_init
1796
canvas_type = g_type_register_static (gtk_layout_get_type (),
1806
eel_canvas_get_property (GObject *object,
1813
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1819
eel_canvas_set_property (GObject *object,
1821
const GValue *value,
1826
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1832
eel_canvas_accessible_adjustment_changed (GtkAdjustment *adjustment,
1837
/* The scrollbars have changed */
1838
atk_obj = ATK_OBJECT (data);
1840
g_signal_emit_by_name (atk_obj, "visible_data_changed");
1844
accessible_destroy_cb (GtkWidget *widget,
1845
GtkAccessible *accessible)
1847
gtk_accessible_set_widget (accessible, NULL);
1848
atk_object_notify_state_change (ATK_OBJECT (accessible), ATK_STATE_DEFUNCT, TRUE);
1852
accessible_focus_cb (GtkWidget *widget,
1853
GdkEventFocus *event)
1855
AtkObject* accessible = gtk_widget_get_accessible (widget);
1856
atk_object_notify_state_change (accessible, ATK_STATE_FOCUSED, event->in);
1862
accessible_notify_cb (GObject *obj,
1865
GtkWidget* widget = GTK_WIDGET (obj);
1866
AtkObject* atk_obj = gtk_widget_get_accessible (widget);
1870
if (strcmp (pspec->name, "visible") == 0) {
1871
state = ATK_STATE_VISIBLE;
1872
value = gtk_widget_get_visible (widget);
1873
} else if (strcmp (pspec->name, "sensitive") == 0) {
1874
state = ATK_STATE_SENSITIVE;
1875
value = gtk_widget_get_sensitive (widget);
1877
atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED, value);
1879
g_assert_not_reached ();
1882
atk_object_notify_state_change (atk_obj, state, value);
1885
/* Translate GtkWidget::size-allocate to AtkComponent::bounds-changed */
1887
accessible_size_allocate_cb (GtkWidget *widget,
1888
GtkAllocation *allocation)
1890
AtkObject* accessible = gtk_widget_get_accessible (widget);
1893
rect.x = allocation->x;
1894
rect.y = allocation->y;
1895
rect.width = allocation->width;
1896
rect.height = allocation->height;
1898
g_signal_emit_by_name (accessible, "bounds_changed", &rect);
1901
/* Translate GtkWidget mapped state into AtkObject showing */
1903
accessible_map_cb (GtkWidget *widget)
1905
AtkObject *accessible = gtk_widget_get_accessible (widget);
1906
atk_object_notify_state_change (accessible, ATK_STATE_SHOWING,
1907
gtk_widget_get_mapped (widget));
1911
eel_canvas_accessible_initialize (AtkObject *obj,
1914
EelCanvas *canvas = data;
1916
if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize != NULL) {
1917
ATK_OBJECT_CLASS (accessible_parent_class)->initialize (obj, data);
1920
gtk_accessible_set_widget (GTK_ACCESSIBLE (obj), GTK_WIDGET (data));
1921
g_signal_connect (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)),
1923
G_CALLBACK (eel_canvas_accessible_adjustment_changed),
1925
g_signal_connect (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)),
1927
G_CALLBACK (eel_canvas_accessible_adjustment_changed),
1930
obj->role = ATK_ROLE_LAYERED_PANE;
1932
/* below adapted from gtkwidgetaccessible.c */
1934
g_signal_connect_after (canvas, "destroy",
1935
G_CALLBACK (accessible_destroy_cb), obj);
1936
g_signal_connect_after (canvas, "focus-in-event",
1937
G_CALLBACK (accessible_focus_cb), NULL);
1938
g_signal_connect_after (canvas, "focus-out-event",
1939
G_CALLBACK (accessible_focus_cb), NULL);
1940
g_signal_connect (canvas, "notify::visible",
1941
G_CALLBACK (accessible_notify_cb), NULL);
1942
g_signal_connect (canvas, "notify::sensitive",
1943
G_CALLBACK (accessible_notify_cb), NULL);
1944
g_signal_connect (canvas, "size-allocate",
1945
G_CALLBACK (accessible_size_allocate_cb), NULL);
1946
g_signal_connect (canvas, "map",
1947
G_CALLBACK (accessible_map_cb), NULL);
1948
g_signal_connect (canvas, "unmap",
1949
G_CALLBACK (accessible_map_cb), NULL);
1953
eel_canvas_accessible_get_n_children (AtkObject* obj)
1955
GtkAccessible *accessible;
1958
EelCanvasGroup *root_group;
1960
accessible = GTK_ACCESSIBLE (obj);
1961
widget = gtk_accessible_get_widget (accessible);
1963
if (widget == NULL) {
1967
g_return_val_if_fail (EEL_IS_CANVAS (widget), 0);
1969
canvas = EEL_CANVAS (widget);
1970
root_group = eel_canvas_root (canvas);
1971
g_return_val_if_fail (root_group, 0);
1977
eel_canvas_accessible_ref_child (AtkObject *obj,
1980
GtkAccessible *accessible;
1983
EelCanvasGroup *root_group;
1984
AtkObject *atk_object;
1986
/* Canvas only has one child, so return NULL if index is non zero */
1991
accessible = GTK_ACCESSIBLE (obj);
1992
widget = gtk_accessible_get_widget (accessible);
1994
if (widget == NULL) {
1998
canvas = EEL_CANVAS (widget);
1999
root_group = eel_canvas_root (canvas);
2000
g_return_val_if_fail (root_group, NULL);
2002
atk_object = atk_gobject_accessible_for_object (G_OBJECT (root_group));
2004
return g_object_ref (atk_object);
2008
eel_canvas_accessible_all_parents_visible (GtkWidget *widget)
2010
GtkWidget *iter_parent = NULL;
2011
gboolean result = TRUE;
2013
for (iter_parent = gtk_widget_get_parent (widget); iter_parent != NULL;
2014
iter_parent = gtk_widget_get_parent (iter_parent)) {
2015
if (!gtk_widget_get_visible (iter_parent)) {
2025
eel_canvas_accessible_on_screen (GtkWidget *widget)
2027
GtkAllocation allocation;
2028
GtkWidget *viewport;
2029
gboolean return_value = TRUE;
2031
gtk_widget_get_allocation (widget, &allocation);
2033
viewport = gtk_widget_get_ancestor (widget, GTK_TYPE_VIEWPORT);
2036
GtkAllocation viewport_allocation;
2037
GtkAdjustment *adjustment;
2038
GdkRectangle visible_rect;
2040
gtk_widget_get_allocation (viewport, &viewport_allocation);
2042
adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (viewport));
2043
visible_rect.y = gtk_adjustment_get_value (adjustment);
2044
adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (viewport));
2045
visible_rect.x = gtk_adjustment_get_value (adjustment);
2046
visible_rect.width = viewport_allocation.width;
2047
visible_rect.height = viewport_allocation.height;
2049
if (((allocation.x + allocation.width) < visible_rect.x) ||
2050
((allocation.y + allocation.height) < visible_rect.y) ||
2051
(allocation.x > (visible_rect.x + visible_rect.width)) ||
2052
(allocation.y > (visible_rect.y + visible_rect.height))) {
2053
return_value = FALSE;
2056
/* Check whether the widget has been placed off the screen.
2057
* The widget may be MAPPED as when toolbar items do not
2058
* fit on the toolbar.
2060
if (allocation.x + allocation.width <= 0 &&
2061
allocation.y + allocation.height <= 0) {
2062
return_value = FALSE;
2066
return return_value;
2069
static AtkStateSet *
2070
eel_canvas_accessible_ref_state_set (AtkObject *accessible)
2073
AtkStateSet *state_set;
2075
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
2076
state_set = ATK_OBJECT_CLASS (accessible_parent_class)->ref_state_set (accessible);
2078
if (widget == NULL) {
2079
atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
2081
if (gtk_widget_is_sensitive (widget)) {
2082
atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
2083
atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
2086
if (gtk_widget_get_can_focus (widget)) {
2087
atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
2090
* We do not currently generate notifications when an ATK object
2091
* corresponding to a GtkWidget changes visibility by being scrolled
2092
* on or off the screen. The testcase for this is the main window
2093
* of the testgtk application in which a set of buttons in a GtkVBox
2094
* is in a scrolled window with a viewport.
2096
* To generate the notifications we would need to do the following:
2097
* 1) Find the GtkViewport among the ancestors of the objects
2098
* 2) Create an accessible for the viewport
2099
* 3) Connect to the value-changed signal on the viewport
2100
* 4) When the signal is received we need to traverse the children
2101
* of the viewport and check whether the children are visible or not
2102
* visible; we may want to restrict this to the widgets for which
2103
* accessible objects have been created.
2104
* 5) We probably need to store a variable on_screen in the
2105
* GtkWidgetAccessible data structure so we can determine whether
2106
* the value has changed.
2108
if (gtk_widget_get_visible (widget)) {
2109
atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
2111
if (eel_canvas_accessible_on_screen (widget) &&
2112
gtk_widget_get_mapped (widget) &&
2113
eel_canvas_accessible_all_parents_visible (widget)) {
2114
atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
2118
if (gtk_widget_has_focus (widget)) {
2119
AtkObject *focus_obj;
2121
focus_obj = g_object_get_data (G_OBJECT (accessible), "gail-focus-object");
2122
if (focus_obj == NULL) {
2123
atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
2127
if (gtk_widget_has_default (widget)) {
2128
atk_state_set_add_state (state_set, ATK_STATE_DEFAULT);
2135
eel_canvas_accessible_class_init (EelCanvasAccessibleClass *klass)
2137
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
2139
accessible_parent_class = g_type_class_peek_parent (klass);
2141
atk_class->initialize = eel_canvas_accessible_initialize;
2142
atk_class->get_n_children = eel_canvas_accessible_get_n_children;
2143
atk_class->ref_child = eel_canvas_accessible_ref_child;
2144
/* below adapted from gtkwidgetaccessible.c */
2145
atk_class->ref_state_set = eel_canvas_accessible_ref_state_set;
2149
eel_canvas_accessible_get_extents (AtkComponent *component,
2154
AtkCoordType coord_type)
2157
gint x_window, y_window;
2158
gint x_toplevel, y_toplevel;
2160
GtkAllocation allocation;
2162
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
2164
if (widget == NULL) {
2168
gtk_widget_get_allocation (widget, &allocation);
2169
*width = allocation.width;
2170
*height = allocation.height;
2172
if (!eel_canvas_accessible_on_screen (widget) ||
2173
!gtk_widget_is_drawable (widget)) {
2180
if (gtk_widget_get_parent (widget)) {
2183
window = gtk_widget_get_parent_window (widget);
2187
window = gtk_widget_get_window (widget);
2190
gdk_window_get_origin (window, &x_window, &y_window);
2194
if (coord_type == ATK_XY_WINDOW) {
2195
window = gdk_window_get_toplevel (gtk_widget_get_window (widget));
2196
gdk_window_get_origin (window, &x_toplevel, &y_toplevel);
2204
eel_canvas_accessible_get_size (AtkComponent *component,
2210
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
2212
if (widget == NULL) {
2216
*width = gtk_widget_get_allocated_width (widget);
2217
*height = gtk_widget_get_allocated_height (widget);
2221
eel_canvas_accessible_component_init(gpointer iface, gpointer data)
2223
AtkComponentIface *component;
2225
g_assert (G_TYPE_FROM_INTERFACE(iface) == ATK_TYPE_COMPONENT);
2228
component->get_extents = eel_canvas_accessible_get_extents;
2229
component->get_size = eel_canvas_accessible_get_size;
2233
eel_canvas_accessible_init (EelCanvasAccessible *accessible)
2237
G_DEFINE_TYPE_WITH_CODE (EelCanvasAccessible, eel_canvas_accessible, GTK_TYPE_ACCESSIBLE,
2238
G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, eel_canvas_accessible_component_init))
2241
eel_canvas_accessible_create (GObject *for_object)
2244
AtkObject *accessible;
2247
canvas = EEL_CANVAS (for_object);
2248
g_return_val_if_fail (canvas != NULL, NULL);
2250
type = eel_canvas_accessible_get_type ();
2252
if (type == G_TYPE_INVALID) {
2253
return atk_no_op_object_new (for_object);
2256
accessible = g_object_new (type, NULL);
2257
atk_object_initialize (accessible, for_object);
2262
eel_canvas_accessible_factory_get_accessible_type (void)
2264
return eel_canvas_accessible_get_type ();
2268
eel_canvas_accessible_factory_create_accessible (GObject *obj)
2270
AtkObject *accessible;
2272
g_return_val_if_fail (G_IS_OBJECT (obj), NULL);
2274
accessible = eel_canvas_accessible_create (obj);
2280
eel_canvas_accessible_factory_class_init (AtkObjectFactoryClass *klass)
2282
klass->create_accessible = eel_canvas_accessible_factory_create_accessible;
2283
klass->get_accessible_type = eel_canvas_accessible_factory_get_accessible_type;
2287
eel_canvas_accessible_factory_get_type (void)
2289
static GType type = 0;
2292
static const GTypeInfo tinfo = {
2293
sizeof (AtkObjectFactoryClass),
2294
(GBaseInitFunc) NULL,
2295
(GBaseFinalizeFunc) NULL,
2296
(GClassInitFunc) eel_canvas_accessible_factory_class_init,
2297
NULL, /* class_finalize */
2298
NULL, /* class_data */
2299
sizeof (AtkObjectFactory),
2300
0, /* n_preallocs */
2303
type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
2304
"EelCanvasAccessibilityFactory",
2312
/* Class initialization function for EelCanvasClass */
2314
eel_canvas_class_init (EelCanvasClass *klass)
2316
GObjectClass *gobject_class;
2317
GtkWidgetClass *widget_class;
2319
gobject_class = (GObjectClass *)klass;
2320
widget_class = (GtkWidgetClass *) klass;
2322
canvas_parent_class = g_type_class_peek_parent (klass);
2324
gobject_class->set_property = eel_canvas_set_property;
2325
gobject_class->get_property = eel_canvas_get_property;
2327
widget_class->destroy = eel_canvas_destroy;
2328
widget_class->map = eel_canvas_map;
2329
widget_class->unmap = eel_canvas_unmap;
2330
widget_class->realize = eel_canvas_realize;
2331
widget_class->unrealize = eel_canvas_unrealize;
2332
widget_class->size_allocate = eel_canvas_size_allocate;
2333
widget_class->button_press_event = eel_canvas_button;
2334
widget_class->button_release_event = eel_canvas_button;
2335
widget_class->motion_notify_event = eel_canvas_motion;
2336
widget_class->draw = eel_canvas_draw;
2337
widget_class->key_press_event = eel_canvas_key;
2338
widget_class->key_release_event = eel_canvas_key;
2339
widget_class->enter_notify_event = eel_canvas_crossing;
2340
widget_class->leave_notify_event = eel_canvas_crossing;
2341
widget_class->focus_in_event = eel_canvas_focus_in;
2342
widget_class->focus_out_event = eel_canvas_focus_out;
2343
widget_class->get_accessible = eel_canvas_get_accessible;
2345
klass->draw_background = eel_canvas_draw_background;
2346
klass->request_update = eel_canvas_request_update_real;
2348
canvas_signals[DRAW_BACKGROUND] =
2349
g_signal_new ("draw_background",
2350
G_TYPE_FROM_CLASS (klass),
2352
G_STRUCT_OFFSET (EelCanvasClass, draw_background),
2354
g_cclosure_marshal_VOID__BOXED,
2356
CAIRO_GOBJECT_TYPE_CONTEXT);
2358
atk_registry_set_factory_type (atk_get_default_registry (),
2360
eel_canvas_accessible_factory_get_type ());
2363
/* Callback used when the root item of a canvas is destroyed. The user should
2364
* never ever do this, so we panic if this happens.
2367
panic_root_destroyed (GtkWidget *object, gpointer data)
2369
g_error ("Eeeek, root item %p of canvas %p was destroyed!", object, data);
2372
/* Object initialization function for EelCanvas */
2374
eel_canvas_init (EelCanvas *canvas)
2376
guint width, height;
2377
gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE);
2379
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas), FALSE);
2381
canvas->scroll_x1 = 0.0;
2382
canvas->scroll_y1 = 0.0;
2383
gtk_layout_get_size (GTK_LAYOUT (canvas),
2385
canvas->scroll_x2 = width;
2386
canvas->scroll_y2 = height;
2388
canvas->pixels_per_unit = 1.0;
2390
canvas->pick_event.type = GDK_LEAVE_NOTIFY;
2391
canvas->pick_event.crossing.x = 0;
2392
canvas->pick_event.crossing.y = 0;
2394
gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (canvas), NULL);
2395
gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (canvas), NULL);
2397
/* Create the root item as a special case */
2399
canvas->root = EEL_CANVAS_ITEM (g_object_new (eel_canvas_group_get_type (), NULL));
2400
canvas->root->canvas = canvas;
2402
g_object_ref_sink (canvas->root);
2404
canvas->root_destroy_id = g_signal_connect (G_OBJECT (canvas->root),
2405
"destroy", G_CALLBACK (panic_root_destroyed), canvas);
2407
canvas->need_repick = TRUE;
2408
canvas->doing_update = FALSE;
2411
/* Convenience function to remove the idle handler of a canvas */
2413
remove_idle (EelCanvas *canvas)
2415
if (canvas->idle_id == 0)
2418
g_source_remove (canvas->idle_id);
2419
canvas->idle_id = 0;
2422
/* Removes the transient state of the canvas (idle handler, grabs). */
2424
shutdown_transients (EelCanvas *canvas)
2426
/* We turn off the need_redraw flag, since if the canvas is mapped again
2427
* it will request a redraw anyways. We do not turn off the need_update
2428
* flag, though, because updates are not queued when the canvas remaps
2431
if (canvas->need_redraw) {
2432
canvas->need_redraw = FALSE;
2435
if (canvas->grabbed_item) {
2436
eel_canvas_item_ungrab (canvas->grabbed_item, GDK_CURRENT_TIME);
2439
remove_idle (canvas);
2442
/* Destroy handler for EelCanvas */
2444
eel_canvas_destroy (GtkWidget *object)
2448
g_return_if_fail (EEL_IS_CANVAS (object));
2450
/* remember, destroy can be run multiple times! */
2452
canvas = EEL_CANVAS (object);
2454
if (canvas->root_destroy_id) {
2455
g_signal_handler_disconnect (G_OBJECT (canvas->root), canvas->root_destroy_id);
2456
canvas->root_destroy_id = 0;
2459
EelCanvasItem *root = canvas->root;
2460
canvas->root = NULL;
2461
eel_canvas_item_destroy (root);
2462
g_object_unref (root);
2465
shutdown_transients (canvas);
2467
if (GTK_WIDGET_CLASS (canvas_parent_class)->destroy)
2468
(* GTK_WIDGET_CLASS (canvas_parent_class)->destroy) (object);
2475
* Creates a new empty canvas. If you wish to use the
2476
* &EelCanvasImage item inside this canvas, then you must push the gdk_imlib
2477
* visual and colormap before calling this function, and they can be popped
2480
* Return value: A newly-created canvas.
2483
eel_canvas_new (void)
2485
return GTK_WIDGET (g_object_new (eel_canvas_get_type (), NULL));
2488
/* Map handler for the canvas */
2490
eel_canvas_map (GtkWidget *widget)
2494
g_return_if_fail (EEL_IS_CANVAS (widget));
2496
/* Normal widget mapping stuff */
2498
if (GTK_WIDGET_CLASS (canvas_parent_class)->map)
2499
(* GTK_WIDGET_CLASS (canvas_parent_class)->map) (widget);
2501
canvas = EEL_CANVAS (widget);
2505
if (canvas->root->flags & EEL_CANVAS_ITEM_VISIBLE &&
2506
!(canvas->root->flags & EEL_CANVAS_ITEM_MAPPED) &&
2507
EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->map)
2508
(* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->map) (canvas->root);
2511
/* Unmap handler for the canvas */
2513
eel_canvas_unmap (GtkWidget *widget)
2517
g_return_if_fail (EEL_IS_CANVAS (widget));
2519
canvas = EEL_CANVAS (widget);
2521
shutdown_transients (canvas);
2525
if (EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap)
2526
(* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (canvas->root);
2528
/* Normal widget unmapping stuff */
2530
if (GTK_WIDGET_CLASS (canvas_parent_class)->unmap)
2531
(* GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (widget);
2534
/* Realize handler for the canvas */
2536
eel_canvas_realize (GtkWidget *widget)
2540
g_return_if_fail (EEL_IS_CANVAS (widget));
2542
/* Normal widget realization stuff */
2544
if (GTK_WIDGET_CLASS (canvas_parent_class)->realize)
2545
(* GTK_WIDGET_CLASS (canvas_parent_class)->realize) (widget);
2547
canvas = EEL_CANVAS (widget);
2549
gdk_window_set_events (gtk_layout_get_bin_window (GTK_LAYOUT (canvas)),
2550
(gdk_window_get_events (gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
2552
| GDK_BUTTON_PRESS_MASK
2553
| GDK_BUTTON_RELEASE_MASK
2554
| GDK_POINTER_MOTION_MASK
2555
| GDK_KEY_PRESS_MASK
2556
| GDK_KEY_RELEASE_MASK
2557
| GDK_ENTER_NOTIFY_MASK
2558
| GDK_LEAVE_NOTIFY_MASK
2559
| GDK_FOCUS_CHANGE_MASK));
2561
/* Create our own temporary pixmap gc and realize all the items */
2563
(* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->realize) (canvas->root);
2566
/* Unrealize handler for the canvas */
2568
eel_canvas_unrealize (GtkWidget *widget)
2572
g_return_if_fail (EEL_IS_CANVAS (widget));
2574
canvas = EEL_CANVAS (widget);
2576
shutdown_transients (canvas);
2578
/* Unrealize items and parent widget */
2580
(* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unrealize) (canvas->root);
2582
if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize)
2583
(* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget);
2586
/* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to
2587
* keep as much as possible of the canvas scrolling region in view.
2590
scroll_to (EelCanvas *canvas, int cx, int cy)
2592
int scroll_width, scroll_height;
2593
int right_limit, bottom_limit;
2594
int old_zoom_xofs, old_zoom_yofs;
2595
int changed_x = FALSE, changed_y = FALSE;
2596
int canvas_width, canvas_height;
2597
GtkAllocation allocation;
2598
GtkAdjustment *vadjustment, *hadjustment;
2599
guint width, height;
2601
gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation);
2602
canvas_width = allocation.width;
2603
canvas_height = allocation.height;
2605
scroll_width = floor ((canvas->scroll_x2 - canvas->scroll_x1) * canvas->pixels_per_unit + 0.5);
2606
scroll_height = floor ((canvas->scroll_y2 - canvas->scroll_y1) * canvas->pixels_per_unit + 0.5);
2608
right_limit = scroll_width - canvas_width;
2609
bottom_limit = scroll_height - canvas_height;
2611
old_zoom_xofs = canvas->zoom_xofs;
2612
old_zoom_yofs = canvas->zoom_yofs;
2614
if (right_limit < 0) {
2616
if (canvas->center_scroll_region) {
2617
canvas->zoom_xofs = (canvas_width - scroll_width) / 2;
2618
scroll_width = canvas_width;
2620
canvas->zoom_xofs = 0;
2622
} else if (cx < 0) {
2624
canvas->zoom_xofs = 0;
2625
} else if (cx > right_limit) {
2627
canvas->zoom_xofs = 0;
2629
canvas->zoom_xofs = 0;
2631
if (bottom_limit < 0) {
2633
if (canvas->center_scroll_region) {
2634
canvas->zoom_yofs = (canvas_height - scroll_height) / 2;
2635
scroll_height = canvas_height;
2637
canvas->zoom_yofs = 0;
2639
} else if (cy < 0) {
2641
canvas->zoom_yofs = 0;
2642
} else if (cy > bottom_limit) {
2644
canvas->zoom_yofs = 0;
2646
canvas->zoom_yofs = 0;
2648
if ((canvas->zoom_xofs != old_zoom_xofs) || (canvas->zoom_yofs != old_zoom_yofs)) {
2649
/* This can only occur, if either canvas size or widget size changes */
2650
/* So I think we can request full redraw here */
2651
/* More stuff - we have to mark root as needing fresh affine (Lauris) */
2652
if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
2653
canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
2654
eel_canvas_request_update (canvas);
2656
gtk_widget_queue_draw (GTK_WIDGET (canvas));
2659
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
2660
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
2662
if (((int) gtk_adjustment_get_value (hadjustment)) != cx) {
2663
gtk_adjustment_set_value (hadjustment, cx);
2667
if (((int) gtk_adjustment_get_value (vadjustment)) != cy) {
2668
gtk_adjustment_set_value (vadjustment, cy);
2672
gtk_layout_get_size (&canvas->layout, &width, &height);
2673
if ((scroll_width != (int) width )|| (scroll_height != (int) height)) {
2674
gtk_layout_set_size (GTK_LAYOUT (canvas), scroll_width, scroll_height);
2677
/* Signal GtkLayout that it should do a redraw. */
2679
g_signal_emit_by_name (hadjustment, "value_changed");
2681
g_signal_emit_by_name (vadjustment, "value_changed");
2684
/* Size allocation handler for the canvas */
2686
eel_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
2689
GtkAdjustment *vadjustment, *hadjustment;
2691
g_return_if_fail (EEL_IS_CANVAS (widget));
2692
g_return_if_fail (allocation != NULL);
2694
if (GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate)
2695
(* GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (widget, allocation);
2697
canvas = EEL_CANVAS (widget);
2699
/* Recenter the view, if appropriate */
2701
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
2702
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
2704
gtk_adjustment_set_page_size (hadjustment, allocation->width);
2705
gtk_adjustment_set_page_increment (hadjustment, allocation->width / 2);
2707
gtk_adjustment_set_page_size (vadjustment, allocation->height);
2708
gtk_adjustment_set_page_increment (vadjustment, allocation->height / 2);
2711
gtk_adjustment_get_value (hadjustment),
2712
gtk_adjustment_get_value (vadjustment));
2714
g_signal_emit_by_name (hadjustment, "changed");
2715
g_signal_emit_by_name (vadjustment, "changed");
2718
/* Emits an event for an item in the canvas, be it the current item, grabbed
2719
* item, or focused item, as appropriate.
2723
emit_event (EelCanvas *canvas, GdkEvent *event)
2727
EelCanvasItem *item;
2728
EelCanvasItem *parent;
2731
/* Could be an old pick event */
2732
if (!gtk_widget_get_realized (GTK_WIDGET (canvas))) {
2736
/* Perform checks for grabbed items */
2738
if (canvas->grabbed_item &&
2739
!is_descendant (canvas->current_item, canvas->grabbed_item)) {
2743
if (canvas->grabbed_item) {
2744
switch (event->type) {
2745
case GDK_ENTER_NOTIFY:
2746
mask = GDK_ENTER_NOTIFY_MASK;
2749
case GDK_LEAVE_NOTIFY:
2750
mask = GDK_LEAVE_NOTIFY_MASK;
2753
case GDK_MOTION_NOTIFY:
2754
mask = GDK_POINTER_MOTION_MASK;
2757
case GDK_BUTTON_PRESS:
2758
case GDK_2BUTTON_PRESS:
2759
case GDK_3BUTTON_PRESS:
2760
mask = GDK_BUTTON_PRESS_MASK;
2763
case GDK_BUTTON_RELEASE:
2764
mask = GDK_BUTTON_RELEASE_MASK;
2768
mask = GDK_KEY_PRESS_MASK;
2771
case GDK_KEY_RELEASE:
2772
mask = GDK_KEY_RELEASE_MASK;
2780
if (!(mask & canvas->grabbed_event_mask))
2784
/* Convert to world coordinates -- we have two cases because of diferent
2785
* offsets of the fields in the event structures.
2792
case GDK_ENTER_NOTIFY:
2793
case GDK_LEAVE_NOTIFY:
2794
eel_canvas_window_to_world (canvas,
2795
ev.crossing.x, ev.crossing.y,
2796
&ev.crossing.x, &ev.crossing.y);
2799
case GDK_MOTION_NOTIFY:
2800
eel_canvas_window_to_world (canvas,
2801
ev.motion.x, ev.motion.y,
2802
&ev.motion.x, &ev.motion.y);
2805
case GDK_BUTTON_PRESS:
2806
case GDK_2BUTTON_PRESS:
2807
case GDK_3BUTTON_PRESS:
2808
eel_canvas_window_to_world (canvas,
2809
ev.motion.x, ev.motion.y,
2810
&ev.motion.x, &ev.motion.y);
2813
case GDK_BUTTON_RELEASE:
2814
eel_canvas_window_to_world (canvas,
2815
ev.motion.x, ev.motion.y,
2816
&ev.motion.x, &ev.motion.y);
2823
/* Choose where we send the event */
2825
item = canvas->current_item;
2827
if (canvas->focused_item
2828
&& ((event->type == GDK_KEY_PRESS) ||
2829
(event->type == GDK_KEY_RELEASE) ||
2830
(event->type == GDK_FOCUS_CHANGE)))
2831
item = canvas->focused_item;
2833
/* The event is propagated up the hierarchy (for if someone connected to
2834
* a group instead of a leaf event), and emission is stopped if a
2835
* handler returns TRUE, just like for GtkWidget events.
2840
while (item && !finished) {
2841
g_object_ref (item);
2844
G_OBJECT (item), item_signals[ITEM_EVENT], 0,
2847
parent = item->parent;
2848
g_object_unref (item);
2856
/* Re-picks the current item in the canvas, based on the event's coordinates.
2857
* Also emits enter/leave events for items as appropriate.
2860
pick_current_item (EelCanvas *canvas, GdkEvent *event)
2869
/* If a button is down, we'll perform enter and leave events on the
2870
* current item, but not enter on any other item. This is more or less
2871
* like X pointer grabbing for canvas items.
2873
button_down = canvas->state & (GDK_BUTTON1_MASK
2877
| GDK_BUTTON5_MASK);
2879
canvas->left_grabbed_item = FALSE;
2881
/* Save the event in the canvas. This is used to synthesize enter and
2882
* leave events in case the current item changes. It is also used to
2883
* re-pick the current item if the current one gets deleted. Also,
2884
* synthesize an enter event.
2886
if (event != &canvas->pick_event) {
2887
if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) {
2888
/* these fields have the same offsets in both types of events */
2890
canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY;
2891
canvas->pick_event.crossing.window = event->motion.window;
2892
canvas->pick_event.crossing.send_event = event->motion.send_event;
2893
canvas->pick_event.crossing.subwindow = NULL;
2894
canvas->pick_event.crossing.x = event->motion.x;
2895
canvas->pick_event.crossing.y = event->motion.y;
2896
canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL;
2897
canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR;
2898
canvas->pick_event.crossing.focus = FALSE;
2899
canvas->pick_event.crossing.state = event->motion.state;
2901
/* these fields don't have the same offsets in both types of events */
2903
if (event->type == GDK_MOTION_NOTIFY) {
2904
canvas->pick_event.crossing.x_root = event->motion.x_root;
2905
canvas->pick_event.crossing.y_root = event->motion.y_root;
2907
canvas->pick_event.crossing.x_root = event->button.x_root;
2908
canvas->pick_event.crossing.y_root = event->button.y_root;
2911
canvas->pick_event = *event;
2914
/* Don't do anything else if this is a recursive call */
2916
if (canvas->in_repick)
2919
/* LeaveNotify means that there is no current item, so we don't look for one */
2921
if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
2922
/* these fields don't have the same offsets in both types of events */
2924
if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
2925
x = canvas->pick_event.crossing.x;
2926
y = canvas->pick_event.crossing.y;
2928
x = canvas->pick_event.motion.x;
2929
y = canvas->pick_event.motion.y;
2932
/* canvas pixel coords */
2934
cx = (int) (x + 0.5);
2935
cy = (int) (y + 0.5);
2938
eel_canvas_c2w (canvas, cx, cy, &x, &y);
2940
/* find the closest item */
2941
if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED)
2942
eel_canvas_item_invoke_point (canvas->root, x, y, cx, cy,
2943
&canvas->new_current_item);
2945
canvas->new_current_item = NULL;
2947
canvas->new_current_item = NULL;
2949
if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item)
2950
return retval; /* current item did not change */
2952
/* Synthesize events for old and new current items */
2954
if ((canvas->new_current_item != canvas->current_item)
2955
&& (canvas->current_item != NULL)
2956
&& !canvas->left_grabbed_item) {
2959
new_event = canvas->pick_event;
2960
new_event.type = GDK_LEAVE_NOTIFY;
2962
new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
2963
new_event.crossing.subwindow = NULL;
2964
canvas->in_repick = TRUE;
2965
retval = emit_event (canvas, &new_event);
2966
canvas->in_repick = FALSE;
2969
/* new_current_item may have been set to NULL during the call to emit_event() above */
2971
if ((canvas->new_current_item != canvas->current_item) && button_down) {
2972
canvas->left_grabbed_item = TRUE;
2976
/* Handle the rest of cases */
2978
canvas->left_grabbed_item = FALSE;
2979
canvas->current_item = canvas->new_current_item;
2981
if (canvas->current_item != NULL) {
2984
new_event = canvas->pick_event;
2985
new_event.type = GDK_ENTER_NOTIFY;
2986
new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
2987
new_event.crossing.subwindow = NULL;
2988
retval = emit_event (canvas, &new_event);
2994
/* Button event handler for the canvas */
2996
eel_canvas_button (GtkWidget *widget, GdkEventButton *event)
3002
g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3003
g_return_val_if_fail (event != NULL, FALSE);
3007
canvas = EEL_CANVAS (widget);
3009
/* Don't handle extra mouse button events */
3010
if (event->button > 5)
3014
* dispatch normally regardless of the event's window if an item has
3015
* has a pointer grab in effect
3017
if (!canvas->grabbed_item && event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
3020
switch (event->button) {
3022
mask = GDK_BUTTON1_MASK;
3025
mask = GDK_BUTTON2_MASK;
3028
mask = GDK_BUTTON3_MASK;
3031
mask = GDK_BUTTON4_MASK;
3034
mask = GDK_BUTTON5_MASK;
3040
switch (event->type) {
3041
case GDK_BUTTON_PRESS:
3042
case GDK_2BUTTON_PRESS:
3043
case GDK_3BUTTON_PRESS:
3044
/* Pick the current item as if the button were not pressed, and
3045
* then process the event.
3047
canvas->state = event->state;
3048
pick_current_item (canvas, (GdkEvent *) event);
3049
canvas->state ^= mask;
3050
retval = emit_event (canvas, (GdkEvent *) event);
3053
case GDK_BUTTON_RELEASE:
3054
/* Process the event as if the button were pressed, then repick
3055
* after the button has been released
3057
canvas->state = event->state;
3058
retval = emit_event (canvas, (GdkEvent *) event);
3059
event->state ^= mask;
3060
canvas->state = event->state;
3061
pick_current_item (canvas, (GdkEvent *) event);
3062
event->state ^= mask;
3066
g_assert_not_reached ();
3072
/* Motion event handler for the canvas */
3074
eel_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
3078
g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3079
g_return_val_if_fail (event != NULL, FALSE);
3081
canvas = EEL_CANVAS (widget);
3083
if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
3086
canvas->state = event->state;
3087
pick_current_item (canvas, (GdkEvent *) event);
3088
return emit_event (canvas, (GdkEvent *) event);
3091
/* Key event handler for the canvas */
3093
eel_canvas_key (GtkWidget *widget, GdkEventKey *event)
3097
g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3098
g_return_val_if_fail (event != NULL, FALSE);
3100
canvas = EEL_CANVAS (widget);
3102
if (emit_event (canvas, (GdkEvent *) event))
3104
if (event->type == GDK_KEY_RELEASE)
3105
return GTK_WIDGET_CLASS (canvas_parent_class)->key_release_event (widget, event);
3107
return GTK_WIDGET_CLASS (canvas_parent_class)->key_press_event (widget, event);
3111
/* Crossing event handler for the canvas */
3113
eel_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event)
3117
g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3118
g_return_val_if_fail (event != NULL, FALSE);
3120
canvas = EEL_CANVAS (widget);
3122
if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
3125
canvas->state = event->state;
3126
return pick_current_item (canvas, (GdkEvent *) event);
3129
/* Focus in handler for the canvas */
3131
eel_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event)
3135
canvas = EEL_CANVAS (widget);
3137
if (canvas->focused_item)
3138
return emit_event (canvas, (GdkEvent *) event);
3144
eel_canvas_get_accessible (GtkWidget *widget)
3146
return atk_gobject_accessible_for_object (G_OBJECT (widget));
3149
/* Focus out handler for the canvas */
3151
eel_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event)
3155
canvas = EEL_CANVAS (widget);
3157
if (canvas->focused_item)
3158
return emit_event (canvas, (GdkEvent *) event);
3164
static cairo_region_t *
3165
eel_cairo_get_clip_region (cairo_t *cr)
3167
cairo_rectangle_list_t *list;
3168
cairo_region_t *region;
3171
list = cairo_copy_clip_rectangle_list (cr);
3172
if (list->status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) {
3173
cairo_rectangle_int_t clip_rect;
3175
cairo_rectangle_list_destroy (list);
3177
if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
3179
return cairo_region_create_rectangle (&clip_rect);
3183
region = cairo_region_create ();
3184
for (i = list->num_rectangles - 1; i >= 0; --i) {
3185
cairo_rectangle_t *rect = &list->rectangles[i];
3186
cairo_rectangle_int_t clip_rect;
3188
clip_rect.x = floor (rect->x);
3189
clip_rect.y = floor (rect->y);
3190
clip_rect.width = ceil (rect->x + rect->width) - clip_rect.x;
3191
clip_rect.height = ceil (rect->y + rect->height) - clip_rect.y;
3193
if (cairo_region_union_rectangle (region, &clip_rect) != CAIRO_STATUS_SUCCESS) {
3194
cairo_region_destroy (region);
3200
cairo_rectangle_list_destroy (list);
3204
/* Expose handler for the canvas */
3206
eel_canvas_draw (GtkWidget *widget, cairo_t *cr)
3208
EelCanvas *canvas = EEL_CANVAS (widget);
3209
GdkWindow *bin_window;
3210
cairo_region_t *region;
3212
if (!gdk_cairo_get_clip_rectangle (cr, NULL))
3215
bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (widget));
3216
gtk_cairo_transform_to_window (cr, widget, bin_window);
3218
region = eel_cairo_get_clip_region (cr);
3225
/* If there are any outstanding items that need updating, do them now */
3226
if (canvas->idle_id) {
3227
g_source_remove (canvas->idle_id);
3228
canvas->idle_id = 0;
3230
if (canvas->need_update) {
3231
g_return_val_if_fail (!canvas->doing_update, FALSE);
3233
canvas->doing_update = TRUE;
3234
eel_canvas_item_invoke_update (canvas->root, 0, 0, 0);
3236
g_return_val_if_fail (canvas->doing_update, FALSE);
3238
canvas->doing_update = FALSE;
3240
canvas->need_update = FALSE;
3243
/* Hmmm. Would like to queue antiexposes if the update marked
3244
anything that is gonna get redrawn as invalid */
3246
g_signal_emit (G_OBJECT (canvas), canvas_signals[DRAW_BACKGROUND], 0,
3249
if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED)
3250
EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->draw (canvas->root, cr, region);
3252
/* Chain up to get exposes on child widgets */
3253
if (GTK_WIDGET_CLASS (canvas_parent_class)->draw)
3254
GTK_WIDGET_CLASS (canvas_parent_class)->draw (widget, cr);
3256
cairo_region_destroy (region);
3261
eel_canvas_draw_background (EelCanvas *canvas,
3264
cairo_rectangle_int_t rect;
3265
GtkStyleContext *style_context;
3268
if (!gdk_cairo_get_clip_rectangle (cr, &rect))
3272
/* By default, we use the style background. */
3273
style_context = gtk_widget_get_style_context (GTK_WIDGET (canvas));
3274
gtk_style_context_get_background_color (style_context, GTK_STATE_FLAG_NORMAL, &color);
3275
gdk_cairo_set_source_rgba (cr, &color);
3276
gdk_cairo_rectangle (cr, &rect);
3282
do_update (EelCanvas *canvas)
3284
/* Cause the update if necessary */
3287
if (canvas->need_update) {
3288
g_return_if_fail (!canvas->doing_update);
3290
canvas->doing_update = TRUE;
3291
eel_canvas_item_invoke_update (canvas->root, 0, 0, 0);
3293
g_return_if_fail (canvas->doing_update);
3295
canvas->doing_update = FALSE;
3297
canvas->need_update = FALSE;
3300
/* Pick new current item */
3302
while (canvas->need_repick) {
3303
canvas->need_repick = FALSE;
3304
pick_current_item (canvas, &canvas->pick_event);
3307
/* it is possible that during picking we emitted an event in which
3308
the user then called some function which then requested update
3309
of something. Without this we'd be left in a state where
3310
need_update would have been left TRUE and the canvas would have
3311
been left unpainted. */
3312
if (canvas->need_update) {
3317
/* Idle handler for the canvas. It deals with pending updates and redraws. */
3319
idle_handler (gpointer data)
3323
canvas = EEL_CANVAS (data);
3327
canvas->idle_id = 0;
3332
/* Convenience function to add an idle handler to a canvas */
3334
add_idle (EelCanvas *canvas)
3336
if (!canvas->idle_id) {
3337
/* We let the update idle handler have higher priority
3338
* than the redraw idle handler so the canvas state
3339
* will be updated during the expose event. canvas in
3342
canvas->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW - 20,
3343
idle_handler, canvas, NULL);
3349
* @canvas: A canvas.
3351
* Queries the root group of a canvas.
3353
* Return value: The root group of the specified canvas.
3356
eel_canvas_root (EelCanvas *canvas)
3358
g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL);
3360
return EEL_CANVAS_GROUP (canvas->root);
3365
* eel_canvas_set_scroll_region:
3366
* @canvas: A canvas.
3367
* @x1: Leftmost limit of the scrolling region.
3368
* @y1: Upper limit of the scrolling region.
3369
* @x2: Rightmost limit of the scrolling region.
3370
* @y2: Lower limit of the scrolling region.
3372
* Sets the scrolling region of a canvas to the specified rectangle. The canvas
3373
* will then be able to scroll only within this region. The view of the canvas
3374
* is adjusted as appropriate to display as much of the new region as possible.
3377
eel_canvas_set_scroll_region (EelCanvas *canvas, double x1, double y1, double x2, double y2)
3379
double wxofs, wyofs;
3381
GtkAdjustment *vadjustment, *hadjustment;
3383
g_return_if_fail (EEL_IS_CANVAS (canvas));
3385
if ((canvas->scroll_x1 == x1) && (canvas->scroll_y1 == y1) &&
3386
(canvas->scroll_x2 == x2) && (canvas->scroll_y2 == y2)) {
3391
* Set the new scrolling region. If possible, do not move the visible contents of the
3394
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
3395
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
3397
eel_canvas_c2w (canvas,
3398
gtk_adjustment_get_value (hadjustment) + canvas->zoom_xofs,
3399
gtk_adjustment_get_value (vadjustment) + canvas->zoom_yofs,
3400
/*canvas->zoom_xofs,
3401
canvas->zoom_yofs,*/
3404
canvas->scroll_x1 = x1;
3405
canvas->scroll_y1 = y1;
3406
canvas->scroll_x2 = x2;
3407
canvas->scroll_y2 = y2;
3409
eel_canvas_w2c (canvas, wxofs, wyofs, &xofs, &yofs);
3411
scroll_to (canvas, xofs, yofs);
3413
canvas->need_repick = TRUE;
3415
if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
3416
canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
3417
eel_canvas_request_update (canvas);
3423
* eel_canvas_get_scroll_region:
3424
* @canvas: A canvas.
3425
* @x1: Leftmost limit of the scrolling region (return value).
3426
* @y1: Upper limit of the scrolling region (return value).
3427
* @x2: Rightmost limit of the scrolling region (return value).
3428
* @y2: Lower limit of the scrolling region (return value).
3430
* Queries the scrolling region of a canvas.
3433
eel_canvas_get_scroll_region (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2)
3435
g_return_if_fail (EEL_IS_CANVAS (canvas));
3438
*x1 = canvas->scroll_x1;
3441
*y1 = canvas->scroll_y1;
3444
*x2 = canvas->scroll_x2;
3447
*y2 = canvas->scroll_y2;
3451
eel_canvas_set_center_scroll_region (EelCanvas *canvas,
3452
gboolean center_scroll_region)
3454
GtkAdjustment *vadjustment, *hadjustment;
3456
g_return_if_fail (EEL_IS_CANVAS (canvas));
3458
canvas->center_scroll_region = center_scroll_region != 0;
3460
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (&canvas->layout));
3461
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (&canvas->layout));
3464
gtk_adjustment_get_value (hadjustment),
3465
gtk_adjustment_get_value (vadjustment));
3470
* eel_canvas_set_pixels_per_unit:
3471
* @canvas: A canvas.
3472
* @n: The number of pixels that correspond to one canvas unit.
3474
* Sets the zooming factor of a canvas by specifying the number of pixels that
3475
* correspond to one canvas unit.
3478
eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n)
3483
int center_x, center_y;
3485
GdkWindowAttr attributes;
3486
gint attributes_mask;
3487
GtkAllocation allocation;
3488
GtkAdjustment *vadjustment, *hadjustment;
3490
g_return_if_fail (EEL_IS_CANVAS (canvas));
3491
g_return_if_fail (n > EEL_CANVAS_EPSILON);
3493
widget = GTK_WIDGET (canvas);
3495
gtk_widget_get_allocation (widget, &allocation);
3496
center_x = allocation.width / 2;
3497
center_y = allocation.height / 2;
3499
/* Find the coordinates of the screen center in units. */
3500
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
3501
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
3502
cx = (gtk_adjustment_get_value (hadjustment) + center_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs;
3503
cy = (gtk_adjustment_get_value (vadjustment) + center_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs;
3505
/* Now calculate the new offset of the upper left corner. (round not truncate) */
3506
x1 = ((cx - canvas->scroll_x1) * n) - center_x + .5;
3507
y1 = ((cy - canvas->scroll_y1) * n) - center_y + .5;
3509
canvas->pixels_per_unit = n;
3511
if (!(canvas->root->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)) {
3512
canvas->root->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
3513
eel_canvas_request_update (canvas);
3516
/* Map a background None window over the bin_window to avoid
3517
* scrolling the window scroll causing exposes.
3520
if (gtk_widget_get_mapped (widget)) {
3521
GtkAllocation allocation;
3522
attributes.window_type = GDK_WINDOW_CHILD;
3523
gtk_widget_get_allocation (widget, &allocation);
3524
attributes.x = allocation.x;
3525
attributes.y = allocation.y;
3526
attributes.width = allocation.width;
3527
attributes.height = allocation.height;
3528
attributes.wclass = GDK_INPUT_OUTPUT;
3529
attributes.visual = gtk_widget_get_visual (widget);
3530
attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
3532
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3534
window = gdk_window_new (gtk_widget_get_parent_window (widget),
3535
&attributes, attributes_mask);
3536
gdk_window_set_user_data (window, widget);
3538
gdk_window_show (window);
3541
scroll_to (canvas, x1, y1);
3543
/* If we created a an overlapping background None window, remove it how.
3545
* TODO: We would like to temporarily set the bin_window background to
3546
* None to avoid clearing the bin_window to the background, but gdk doesn't
3547
* expose enought to let us do this, so we get a flash-effect here. At least
3548
* it looks better than scroll + expose.
3550
if (window != NULL) {
3551
gdk_window_hide (window);
3552
gdk_window_set_user_data (window, NULL);
3553
gdk_window_destroy (window);
3556
canvas->need_repick = TRUE;
3560
* eel_canvas_scroll_to:
3561
* @canvas: A canvas.
3562
* @cx: Horizontal scrolling offset in canvas pixel units.
3563
* @cy: Vertical scrolling offset in canvas pixel units.
3565
* Makes a canvas scroll to the specified offsets, given in canvas pixel units.
3566
* The canvas will adjust the view so that it is not outside the scrolling
3567
* region. This function is typically not used, as it is better to hook
3568
* scrollbars to the canvas layout's scrolling adjusments.
3571
eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy)
3573
g_return_if_fail (EEL_IS_CANVAS (canvas));
3575
scroll_to (canvas, cx, cy);
3579
* eel_canvas_get_scroll_offsets:
3580
* @canvas: A canvas.
3581
* @cx: Horizontal scrolling offset (return value).
3582
* @cy: Vertical scrolling offset (return value).
3584
* Queries the scrolling offsets of a canvas. The values are returned in canvas
3588
eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy)
3590
GtkAdjustment *vadjustment, *hadjustment;
3592
g_return_if_fail (EEL_IS_CANVAS (canvas));
3594
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
3595
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
3598
*cx = gtk_adjustment_get_value (hadjustment);
3601
*cy = gtk_adjustment_get_value (vadjustment);
3605
* eel_canvas_update_now:
3606
* @canvas: A canvas.
3608
* Forces an immediate update and redraw of a canvas. If the canvas does not
3609
* have any pending update or redraw requests, then no action is taken. This is
3610
* typically only used by applications that need explicit control of when the
3611
* display is updated, like games. It is not needed by normal applications.
3614
eel_canvas_update_now (EelCanvas *canvas)
3616
g_return_if_fail (EEL_IS_CANVAS (canvas));
3618
if (!(canvas->need_update || canvas->need_redraw))
3620
remove_idle (canvas);
3625
* eel_canvas_get_item_at:
3626
* @canvas: A canvas.
3627
* @x: X position in world coordinates.
3628
* @y: Y position in world coordinates.
3630
* Looks for the item that is under the specified position, which must be
3631
* specified in world coordinates.
3633
* Return value: The sought item, or NULL if no item is at the specified
3637
eel_canvas_get_item_at (EelCanvas *canvas, double x, double y)
3639
EelCanvasItem *item;
3643
g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL);
3645
eel_canvas_w2c (canvas, x, y, &cx, &cy);
3647
dist = eel_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &item);
3648
if ((int) (dist * canvas->pixels_per_unit + 0.5) <= canvas->close_enough)
3654
/* Queues an update of the canvas */
3656
eel_canvas_request_update (EelCanvas *canvas)
3658
EEL_CANVAS_GET_CLASS (canvas)->request_update (canvas);
3662
eel_canvas_request_update_real (EelCanvas *canvas)
3664
canvas->need_update = TRUE;
3669
* eel_canvas_request_redraw:
3670
* @canvas: A canvas.
3671
* @x1: Leftmost coordinate of the rectangle to be redrawn.
3672
* @y1: Upper coordinate of the rectangle to be redrawn.
3673
* @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1.
3674
* @y2: Lower coordinate of the rectangle to be redrawn, plus 1.
3676
* Convenience function that informs a canvas that the specified rectangle needs
3677
* to be repainted. The rectangle includes @x1 and @y1, but not @x2 and @y2.
3678
* To be used only by item implementations.
3681
eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2)
3685
g_return_if_fail (EEL_IS_CANVAS (canvas));
3687
if (!gtk_widget_is_drawable (GTK_WIDGET (canvas))
3688
|| (x1 >= x2) || (y1 >= y2)) return;
3692
bbox.width = x2 - x1;
3693
bbox.height = y2 - y1;
3695
gdk_window_invalidate_rect (gtk_layout_get_bin_window (GTK_LAYOUT (canvas)),
3701
* @canvas: A canvas.
3702
* @wx: World X coordinate.
3703
* @wy: World Y coordinate.
3704
* @cx: X pixel coordinate (return value).
3705
* @cy: Y pixel coordinate (return value).
3707
* Converts world coordinates into canvas pixel coordinates.
3710
eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy)
3714
g_return_if_fail (EEL_IS_CANVAS (canvas));
3716
zoom = canvas->pixels_per_unit;
3719
*cx = floor ((wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs + 0.5);
3721
*cy = floor ((wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs + 0.5);
3726
* @canvas: A canvas.
3727
* @world: rectangle in world coordinates.
3728
* @canvas: rectangle in canvase coordinates.
3730
* Converts rectangles in world coordinates into canvas pixel coordinates.
3733
eel_canvas_w2c_rect_d (EelCanvas *canvas,
3734
double *x1, double *y1,
3735
double *x2, double *y2)
3737
eel_canvas_w2c_d (canvas,
3740
eel_canvas_w2c_d (canvas,
3749
* @canvas: A canvas.
3750
* @wx: World X coordinate.
3751
* @wy: World Y coordinate.
3752
* @cx: X pixel coordinate (return value).
3753
* @cy: Y pixel coordinate (return value).
3755
* Converts world coordinates into canvas pixel coordinates. This version
3756
* produces coordinates in floating point coordinates, for greater precision.
3759
eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy)
3763
g_return_if_fail (EEL_IS_CANVAS (canvas));
3765
zoom = canvas->pixels_per_unit;
3768
*cx = (wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs;
3770
*cy = (wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs;
3776
* @canvas: A canvas.
3777
* @cx: Canvas pixel X coordinate.
3778
* @cy: Canvas pixel Y coordinate.
3779
* @wx: X world coordinate (return value).
3780
* @wy: Y world coordinate (return value).
3782
* Converts canvas pixel coordinates to world coordinates.
3785
eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy)
3789
g_return_if_fail (EEL_IS_CANVAS (canvas));
3791
zoom = canvas->pixels_per_unit;
3794
*wx = (cx - canvas->zoom_xofs)/zoom + canvas->scroll_x1;
3796
*wy = (cy - canvas->zoom_yofs)/zoom + canvas->scroll_y1;
3801
* eel_canvas_window_to_world:
3802
* @canvas: A canvas.
3803
* @winx: Window-relative X coordinate.
3804
* @winy: Window-relative Y coordinate.
3805
* @worldx: X world coordinate (return value).
3806
* @worldy: Y world coordinate (return value).
3808
* Converts window-relative coordinates into world coordinates. You can use
3809
* this when you need to convert mouse coordinates into world coordinates, for
3811
* Window coordinates are really the same as canvas coordinates now, but this
3812
* function is here for backwards compatibility reasons.
3815
eel_canvas_window_to_world (EelCanvas *canvas, double winx, double winy,
3816
double *worldx, double *worldy)
3818
g_return_if_fail (EEL_IS_CANVAS (canvas));
3821
*worldx = canvas->scroll_x1 + ((winx - canvas->zoom_xofs)
3822
/ canvas->pixels_per_unit);
3825
*worldy = canvas->scroll_y1 + ((winy - canvas->zoom_yofs)
3826
/ canvas->pixels_per_unit);
3831
* eel_canvas_world_to_window:
3832
* @canvas: A canvas.
3833
* @worldx: World X coordinate.
3834
* @worldy: World Y coordinate.
3835
* @winx: X window-relative coordinate.
3836
* @winy: Y window-relative coordinate.
3838
* Converts world coordinates into window-relative coordinates.
3839
* Window coordinates are really the same as canvas coordinates now, but this
3840
* function is here for backwards compatibility reasons.
3843
eel_canvas_world_to_window (EelCanvas *canvas, double worldx, double worldy,
3844
double *winx, double *winy)
3846
g_return_if_fail (EEL_IS_CANVAS (canvas));
3849
*winx = (canvas->pixels_per_unit)*(worldx - canvas->scroll_x1) + canvas->zoom_xofs;
3852
*winy = (canvas->pixels_per_unit)*(worldy - canvas->scroll_y1) + canvas->zoom_yofs;
3856
boolean_handled_accumulator (GSignalInvocationHint *ihint,
3857
GValue *return_accu,
3858
const GValue *handler_return,
3861
gboolean continue_emission;
3862
gboolean signal_handled;
3864
signal_handled = g_value_get_boolean (handler_return);
3865
g_value_set_boolean (return_accu, signal_handled);
3866
continue_emission = !signal_handled;
3868
return continue_emission;
3872
eel_canvas_item_accessible_add_focus_handler (AtkComponent *component,
3873
AtkFocusHandler handler)
3875
GSignalMatchType match_type;
3878
match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
3879
signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
3881
if (!g_signal_handler_find (component, match_type, signal_id, 0, NULL,
3882
(gpointer) handler, NULL)) {
3883
return g_signal_connect_closure_by_id (component,
3886
G_CALLBACK (handler), NULL,
3887
(GClosureNotify) NULL),
3894
eel_canvas_item_accessible_get_item_extents (EelCanvasItem *item,
3897
double bx1, bx2, by1, by2;
3898
gint scroll_x, scroll_y;
3899
gint x1, x2, y1, y2;
3901
eel_canvas_item_get_bounds (item, &bx1, &by1, &bx2, &by2);
3902
eel_canvas_w2c_rect_d (item->canvas, &bx1, &by1, &bx2, &by2);
3903
eel_canvas_get_scroll_offsets (item->canvas, &scroll_x, &scroll_y);
3904
x1 = floor (bx1 + .5);
3905
y1 = floor (by1 + .5);
3906
x2 = floor (bx2 + .5);
3907
y2 = floor (by2 + .5);
3908
rect->x = x1 - scroll_x;
3909
rect->y = y1 - scroll_y;
3910
rect->width = x2 - x1;
3911
rect->height = y2 - y1;
3915
eel_canvas_item_accessible_is_item_in_window (EelCanvasItem *item,
3921
widget = GTK_WIDGET (item->canvas);
3922
if (gtk_widget_get_window (widget)) {
3923
int window_width, window_height;
3925
gdk_window_get_geometry (gtk_widget_get_window (widget), NULL, NULL,
3926
&window_width, &window_height);
3928
* Check whether rectangles intersect
3930
if (rect->x + rect->width < 0 ||
3931
rect->y + rect->height < 0 ||
3932
rect->x > window_width ||
3933
rect->y > window_height) {
3946
eel_canvas_item_accessible_get_extents (AtkComponent *component,
3951
AtkCoordType coord_type)
3953
AtkGObjectAccessible *atk_gobj;
3955
EelCanvasItem *item;
3956
gint window_x, window_y;
3957
gint toplevel_x, toplevel_y;
3962
atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
3963
obj = atk_gobject_accessible_get_object (atk_gobj);
3966
/* item is defunct */
3970
/* Get the CanvasItem */
3971
item = EEL_CANVAS_ITEM (obj);
3973
/* If this item has no parent canvas, something's broken */
3974
g_return_if_fail (GTK_IS_WIDGET (item->canvas));
3976
eel_canvas_item_accessible_get_item_extents (item, &rect);
3977
*width = rect.width;
3978
*height = rect.height;
3979
if (!eel_canvas_item_accessible_is_item_in_window (item, &rect)) {
3985
canvas = GTK_WIDGET (item->canvas);
3986
window = gtk_widget_get_parent_window (canvas);
3987
gdk_window_get_origin (window, &window_x, &window_y);
3988
*x = rect.x + window_x;
3989
*y = rect.y + window_y;
3990
if (coord_type == ATK_XY_WINDOW) {
3991
window = gdk_window_get_toplevel (gtk_widget_get_window (canvas));
3992
gdk_window_get_origin (window, &toplevel_x, &toplevel_y);
4000
eel_canvas_item_accessible_get_mdi_zorder (AtkComponent *component)
4002
AtkGObjectAccessible *atk_gobj;
4004
EelCanvasItem *item;
4006
atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
4007
g_obj = atk_gobject_accessible_get_object (atk_gobj);
4008
if (g_obj == NULL) {
4009
/* Object is defunct */
4013
item = EEL_CANVAS_ITEM (g_obj);
4015
return g_list_index (EEL_CANVAS_GROUP (item->parent)->item_list, item);
4017
g_return_val_if_fail (item->canvas->root == item, -1);
4023
eel_canvas_item_accessible_grab_focus (AtkComponent *component)
4025
AtkGObjectAccessible *atk_gobj;
4027
EelCanvasItem *item;
4028
GtkWidget *toplevel;
4030
atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
4031
obj = atk_gobject_accessible_get_object (atk_gobj);
4033
item = EEL_CANVAS_ITEM (obj);
4035
/* item is defunct */
4039
eel_canvas_item_grab_focus (item);
4040
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->canvas));
4041
if (gtk_widget_is_toplevel (toplevel)) {
4042
gtk_window_present (GTK_WINDOW (toplevel));
4049
eel_canvas_item_accessible_remove_focus_handler (AtkComponent *component,
4052
g_signal_handler_disconnect (component, handler_id);
4056
eel_canvas_item_accessible_component_interface_init (AtkComponentIface *iface)
4058
g_return_if_fail (iface != NULL);
4060
iface->add_focus_handler = eel_canvas_item_accessible_add_focus_handler;
4061
iface->get_extents = eel_canvas_item_accessible_get_extents;
4062
iface->get_mdi_zorder = eel_canvas_item_accessible_get_mdi_zorder;
4063
iface->grab_focus = eel_canvas_item_accessible_grab_focus;
4064
iface->remove_focus_handler = eel_canvas_item_accessible_remove_focus_handler;
4068
eel_canvas_item_accessible_is_item_on_screen (EelCanvasItem *item)
4072
eel_canvas_item_accessible_get_item_extents (item, &rect);
4073
return eel_canvas_item_accessible_is_item_in_window (item, &rect);
4077
eel_canvas_item_accessible_initialize (AtkObject *obj, gpointer data)
4079
if (ATK_OBJECT_CLASS (accessible_item_parent_class)->initialize != NULL)
4080
ATK_OBJECT_CLASS (accessible_item_parent_class)->initialize (obj, data);
4081
g_object_set_data (G_OBJECT (obj), "atk-component-layer",
4082
GINT_TO_POINTER (ATK_LAYER_MDI));
4086
eel_canvas_item_accessible_ref_state_set (AtkObject *accessible)
4088
AtkGObjectAccessible *atk_gobj;
4090
EelCanvasItem *item;
4091
AtkStateSet *state_set;
4093
state_set = ATK_OBJECT_CLASS (accessible_item_parent_class)->ref_state_set (accessible);
4094
atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
4095
obj = atk_gobject_accessible_get_object (atk_gobj);
4097
item = EEL_CANVAS_ITEM (obj);
4099
atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
4101
if (item->flags & EEL_CANVAS_ITEM_VISIBLE) {
4102
atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
4104
if (eel_canvas_item_accessible_is_item_on_screen (item)) {
4105
atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
4108
if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))) {
4109
atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
4111
if (item->canvas->focused_item == item) {
4112
atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
4121
eel_canvas_item_accessible_class_init (EelCanvasItemAccessibleClass *klass)
4123
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
4125
accessible_item_parent_class = g_type_class_peek_parent (klass);
4127
atk_class->initialize = eel_canvas_item_accessible_initialize;
4128
atk_class->ref_state_set = eel_canvas_item_accessible_ref_state_set;
4132
eel_canvas_item_accessible_init (EelCanvasItemAccessible *self)
4137
G_DEFINE_TYPE_WITH_CODE (EelCanvasItemAccessible,
4138
eel_canvas_item_accessible,
4139
ATK_TYPE_GOBJECT_ACCESSIBLE,
4140
G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
4141
eel_canvas_item_accessible_component_interface_init));
4143
static GType eel_canvas_item_accessible_factory_get_type (void);
4145
typedef AtkObjectFactory EelCanvasItemAccessibleFactory;
4146
typedef AtkObjectFactoryClass EelCanvasItemAccessibleFactoryClass;
4147
G_DEFINE_TYPE (EelCanvasItemAccessibleFactory, eel_canvas_item_accessible_factory,
4148
ATK_TYPE_OBJECT_FACTORY)
4151
eel_canvas_item_accessible_factory_get_accessible_type (void)
4153
return eel_canvas_item_accessible_get_type ();
4157
eel_canvas_item_accessible_factory_create_accessible (GObject *for_object)
4159
AtkObject *accessible;
4161
accessible = g_object_new (eel_canvas_item_accessible_get_type (), NULL);
4162
atk_object_initialize (accessible, for_object);
4167
eel_canvas_item_accessible_factory_init (EelCanvasItemAccessibleFactory *self)
4173
eel_canvas_item_accessible_factory_class_init (AtkObjectFactoryClass *klass)
4175
klass->create_accessible = eel_canvas_item_accessible_factory_create_accessible;
4176
klass->get_accessible_type = eel_canvas_item_accessible_factory_get_accessible_type;
4179
/* Class initialization function for EelCanvasItemClass */
4181
eel_canvas_item_class_init (EelCanvasItemClass *klass)
4183
GObjectClass *gobject_class = (GObjectClass *) klass;
4185
item_parent_class = g_type_class_peek_parent (klass);
4187
gobject_class->set_property = eel_canvas_item_set_property;
4188
gobject_class->get_property = eel_canvas_item_get_property;
4189
gobject_class->dispose = eel_canvas_item_dispose;
4191
g_object_class_install_property
4192
(gobject_class, ITEM_PROP_PARENT,
4193
g_param_spec_object ("parent", NULL, NULL,
4194
EEL_TYPE_CANVAS_ITEM,
4195
G_PARAM_READWRITE));
4197
g_object_class_install_property
4198
(gobject_class, ITEM_PROP_VISIBLE,
4199
g_param_spec_boolean ("visible", NULL, NULL,
4201
G_PARAM_READWRITE));
4203
item_signals[ITEM_EVENT] =
4204
g_signal_new ("event",
4205
G_TYPE_FROM_CLASS (klass),
4207
G_STRUCT_OFFSET (EelCanvasItemClass, event),
4208
boolean_handled_accumulator, NULL,
4209
g_cclosure_marshal_generic,
4211
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
4213
item_signals[ITEM_DESTROY] =
4214
g_signal_new ("destroy",
4215
G_TYPE_FROM_CLASS (klass),
4216
G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
4217
G_STRUCT_OFFSET (EelCanvasItemClass, destroy),
4219
g_cclosure_marshal_VOID__VOID,
4222
klass->realize = eel_canvas_item_realize;
4223
klass->unrealize = eel_canvas_item_unrealize;
4224
klass->map = eel_canvas_item_map;
4225
klass->unmap = eel_canvas_item_unmap;
4226
klass->update = eel_canvas_item_update;
4228
atk_registry_set_factory_type (atk_get_default_registry (),
4229
EEL_TYPE_CANVAS_ITEM,
4230
eel_canvas_item_accessible_factory_get_type ());