~ubuntu-branches/ubuntu/saucy/nautilus/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/git_fix_touch_double_click.patch/eel/eel-canvas.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Sebastien Bacher, Iain Lane, Jeremy Bicha, Robert Ancell, Rico Tzschichholz, Tim Lunn, Marco Trevisan (Treviño)
  • Date: 2013-06-21 17:10:06 UTC
  • mfrom: (1.17.42)
  • Revision ID: package-import@ubuntu.com-20130621171006-0vajxyu6ebhp1p9p
Tags: 1:3.8.2-0ubuntu1
[ Sebastien Bacher ]
* Bring the 3.8 update work from the gnome3 ppa to the distribution vcs
* debian/patches/16_unity_new_documents.patch: 
  - updated to work on 3.8 (by adding a revert of the commit that broke it)
* debian/patches/ubuntu_revert_no_wallpaper.patch:
  - revert upstream changes to use a rgba desktop view, until the other
    components are ready for that change, see lp #1159430 for details
* debian/patches/ubuntu_sync_background_to_accountsservice.patch:
  - restore that dropped patch since we keep display the wallpaper there

[ Iain Lane ]
* debian/patches/disconnect-extra-location-widgets.patch:
  - updated for the new nautilus codebase

[ Jeremy Bicha ]
* New upstream release (LP: #1130746)
  - Share the show-hidden-files setting with the GTK file chooser
    (LP: #1039014)
  - Limit folder size and content count to a single filesystem (LP: #585472)
* debian/nautilus.install:
  - Shell search provider doesn't need a separate library any more
* Drop git patches
* Refreshed patches

[ Robert Ancell ]
* debian/control:
  - Bump build-depends on libglib2.0-dev

[ Rico Tzschichholz ]
* New upstream release
* debian/control:
  - Bump build-depends on libgtk-3-dev (>= 3.7.7)
* debian/patches:
  - 09_no-initial-fade.patch:
  - 10_sync_background_to_accountsservice.patch:
    + Dropped, Nautilus doesn't draw the background itself any more
* Refreshed patches

[ Tim Lunn ]
* Add build-dep on gsettings-desktop-schemas

[ Marco Trevisan (Treviño) ]
* debian/patches:
  - 19_unity_open_location_xid.patch: updated to apply properly

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
2
 
/*
3
 
 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
4
 
 * All rights reserved.
5
 
 *
6
 
 * This file is part of the Gnome Library.
7
 
 *
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.
12
 
 *
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.
17
 
 *
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.
22
 
 */
23
 
/*
24
 
  @NOTATION@
25
 
 */
26
 
/*
27
 
 * EelCanvas widget - Tk-like canvas widget for Gnome
28
 
 *
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.
31
 
 *
32
 
 *
33
 
 * Authors: Federico Mena <federico@nuclecu.unam.mx>
34
 
 *          Raph Levien <raph@gimp.org>
35
 
 */
36
 
 
37
 
/*
38
 
 * TO-DO list for the canvas:
39
 
 *
40
 
 * - Allow to specify whether EelCanvasImage sizes are in units or pixels (scale or don't scale).
41
 
 *
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
44
 
 *   origin.
45
 
 *
46
 
 * - GC put functions for items.
47
 
 *
48
 
 * - Widget item (finish it).
49
 
 *
50
 
 * - GList *eel_canvas_gimme_all_items_contained_in_this_area (EelCanvas *canvas, Rectangle area);
51
 
 *
52
 
 * - Retrofit all the primitive items with microtile support.
53
 
 *
54
 
 * - Curve support for line item.
55
 
 *
56
 
 * - Arc item (Havoc has it; to be integrated in EelCanvasEllipse).
57
 
 *
58
 
 * - Sane font handling API.
59
 
 *
60
 
 * - Get_arg methods for items:
61
 
 *   - How to fetch the outline width and know whether it is in pixels or units?
62
 
 */
63
 
 
64
 
#include <config.h>
65
 
 
66
 
#include <math.h>
67
 
#include <string.h>
68
 
#include <stdio.h>
69
 
#include <gdk/gdkprivate.h>
70
 
#include <gtk/gtk.h>
71
 
#include <glib/gi18n-lib.h>
72
 
#include <cairo-gobject.h>
73
 
#include "eel-canvas.h"
74
 
 
75
 
static void eel_canvas_request_update (EelCanvas      *canvas);
76
 
static void group_add                   (EelCanvasGroup *group,
77
 
                                         EelCanvasItem  *item);
78
 
static void group_remove                (EelCanvasGroup *group,
79
 
                                         EelCanvasItem  *item);
80
 
static void redraw_and_repick_if_mapped (EelCanvasItem *item);
81
 
 
82
 
/*** EelCanvasItem ***/
83
 
 
84
 
/* Some convenience stuff */
85
 
#define GCI_UPDATE_MASK (EEL_CANVAS_UPDATE_REQUESTED | EEL_CANVAS_UPDATE_DEEP)
86
 
#define GCI_EPSILON 1e-18
87
 
 
88
 
enum {
89
 
        ITEM_PROP_0,
90
 
        ITEM_PROP_PARENT,
91
 
        ITEM_PROP_VISIBLE
92
 
};
93
 
 
94
 
enum {
95
 
        ITEM_DESTROY,
96
 
        ITEM_EVENT,
97
 
        ITEM_LAST_SIGNAL
98
 
};
99
 
 
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);
103
 
 
104
 
static guint item_signals[ITEM_LAST_SIGNAL];
105
 
 
106
 
static GObjectClass *item_parent_class;
107
 
 
108
 
static gpointer accessible_item_parent_class;
109
 
static gpointer accessible_parent_class;
110
 
 
111
 
 
112
 
/**
113
 
 * eel_canvas_item_get_type:
114
 
 *
115
 
 * Registers the &EelCanvasItem class if necessary, and returns the type ID
116
 
 * associated to it.
117
 
 *
118
 
 * Return value:  The type ID of the &EelCanvasItem class.
119
 
 **/
120
 
GType
121
 
eel_canvas_item_get_type (void)
122
 
{
123
 
        static GType canvas_item_type = 0;
124
 
 
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),
134
 
                        0,              /* n_preallocs */
135
 
                        (GInstanceInitFunc) eel_canvas_item_init
136
 
                };
137
 
 
138
 
                canvas_item_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED,
139
 
                                                           "EelCanvasItem",
140
 
                                                           &canvas_item_info,
141
 
                                                           0);
142
 
        }
143
 
 
144
 
        return canvas_item_type;
145
 
}
146
 
 
147
 
/* Object initialization function for EelCanvasItem */
148
 
static void
149
 
eel_canvas_item_init (EelCanvasItem *item)
150
 
{
151
 
        item->flags |= EEL_CANVAS_ITEM_VISIBLE;
152
 
}
153
 
 
154
 
/**
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.
161
 
 * @Varargs:
162
 
 *
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.
168
 
 *
169
 
 * Return value: The newly-created item.
170
 
 **/
171
 
EelCanvasItem *
172
 
eel_canvas_item_new (EelCanvasGroup *parent, GType type, const gchar *first_arg_name, ...)
173
 
{
174
 
        EelCanvasItem *item;
175
 
        va_list args;
176
 
 
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);
179
 
 
180
 
        item = EEL_CANVAS_ITEM (g_object_new (type, NULL));
181
 
 
182
 
        va_start (args, first_arg_name);
183
 
        eel_canvas_item_construct (item, parent, first_arg_name, args);
184
 
        va_end (args);
185
 
 
186
 
        return item;
187
 
}
188
 
 
189
 
 
190
 
/* Performs post-creation operations on a canvas item (adding it to its parent
191
 
 * group, etc.)
192
 
 */
193
 
static void
194
 
item_post_create_setup (EelCanvasItem *item)
195
 
{
196
 
        group_add (EEL_CANVAS_GROUP (item->parent), item);
197
 
 
198
 
        redraw_and_repick_if_mapped (item);
199
 
}
200
 
 
201
 
/* Set_property handler for canvas items */
202
 
static void
203
 
eel_canvas_item_set_property (GObject *gobject, guint param_id,
204
 
                              const GValue *value, GParamSpec *pspec)
205
 
{
206
 
        EelCanvasItem *item;
207
 
 
208
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject));
209
 
 
210
 
        item = EEL_CANVAS_ITEM (gobject);
211
 
 
212
 
        switch (param_id) {
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);
221
 
                }
222
 
                break;
223
 
        case ITEM_PROP_VISIBLE:
224
 
                if (g_value_get_boolean (value)) {
225
 
                        eel_canvas_item_show (item);
226
 
                } else {
227
 
                        eel_canvas_item_hide (item);
228
 
                }
229
 
                break;
230
 
        default:
231
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
232
 
                break;
233
 
        }
234
 
}
235
 
 
236
 
/* Get_property handler for canvas items */
237
 
static void
238
 
eel_canvas_item_get_property (GObject *gobject, guint param_id,
239
 
                              GValue *value, GParamSpec *pspec)
240
 
{
241
 
        EelCanvasItem *item;
242
 
 
243
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (gobject));
244
 
 
245
 
        item = EEL_CANVAS_ITEM (gobject);
246
 
 
247
 
        switch (param_id) {
248
 
        case ITEM_PROP_VISIBLE:
249
 
                g_value_set_boolean (value, item->flags & EEL_CANVAS_ITEM_VISIBLE);
250
 
                break;
251
 
        default:
252
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
253
 
                break;
254
 
        }
255
 
}
256
 
 
257
 
/**
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.
263
 
 *
264
 
 * Constructs a canvas item; meant for use only by item implementations.
265
 
 **/
266
 
void
267
 
eel_canvas_item_construct (EelCanvasItem *item, EelCanvasGroup *parent,
268
 
                           const gchar *first_arg_name, va_list args)
269
 
{
270
 
        g_return_if_fail (EEL_IS_CANVAS_GROUP (parent));
271
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
272
 
 
273
 
        item->parent = EEL_CANVAS_ITEM (parent);
274
 
        item->canvas = item->parent->canvas;
275
 
 
276
 
        g_object_set_valist (G_OBJECT (item), first_arg_name, args);
277
 
 
278
 
        item_post_create_setup (item);
279
 
}
280
 
 
281
 
 
282
 
static void
283
 
redraw_and_repick_if_mapped (EelCanvasItem *item)
284
 
{
285
 
        if (item->flags & EEL_CANVAS_ITEM_MAPPED) {
286
 
                eel_canvas_item_request_redraw (item);
287
 
                item->canvas->need_repick = TRUE;
288
 
        }
289
 
}
290
 
 
291
 
/* Dispose handler for canvas items */
292
 
static void
293
 
eel_canvas_item_dispose (GObject *object)
294
 
{
295
 
        EelCanvasItem *item;
296
 
 
297
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (object));
298
 
 
299
 
        item = EEL_CANVAS_ITEM (object);
300
 
 
301
 
        if (item->canvas) {
302
 
                eel_canvas_item_request_redraw (item);
303
 
 
304
 
                /* Make the canvas forget about us */
305
 
 
306
 
                if (item == item->canvas->current_item) {
307
 
                        item->canvas->current_item = NULL;
308
 
                        item->canvas->need_repick = TRUE;
309
 
                }
310
 
 
311
 
                if (item == item->canvas->new_current_item) {
312
 
                        item->canvas->new_current_item = NULL;
313
 
                        item->canvas->need_repick = TRUE;
314
 
                }
315
 
 
316
 
                eel_canvas_item_ungrab (item, GDK_CURRENT_TIME);
317
 
 
318
 
                if (item == item->canvas->focused_item)
319
 
                        item->canvas->focused_item = NULL;
320
 
 
321
 
                /* Normal destroy stuff */
322
 
 
323
 
                if (item->flags & EEL_CANVAS_ITEM_MAPPED)
324
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
325
 
 
326
 
                if (item->flags & EEL_CANVAS_ITEM_REALIZED)
327
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
328
 
 
329
 
                if (item->parent)
330
 
                        group_remove (EEL_CANVAS_GROUP (item->parent), item);
331
 
 
332
 
                item->canvas = NULL;
333
 
        }
334
 
 
335
 
        g_object_set_data (object, "in-destruction", GINT_TO_POINTER (1));
336
 
        g_signal_emit (object, item_signals[ITEM_DESTROY], 0);
337
 
 
338
 
        g_object_set_data (object, "in-destruction", NULL);
339
 
 
340
 
        G_OBJECT_CLASS (item_parent_class)->dispose (object);
341
 
}
342
 
 
343
 
void
344
 
eel_canvas_item_destroy (EelCanvasItem *item)
345
 
{
346
 
        if (g_object_get_data (G_OBJECT (item), "in-destruction") == NULL) {
347
 
                g_object_run_dispose (G_OBJECT (item));
348
 
        }
349
 
}
350
 
 
351
 
/* Realize handler for canvas items */
352
 
static void
353
 
eel_canvas_item_realize (EelCanvasItem *item)
354
 
{
355
 
        if (item->parent && !(item->parent->flags & EEL_CANVAS_ITEM_REALIZED))
356
 
                (* EEL_CANVAS_ITEM_GET_CLASS (item->parent)->realize) (item->parent);
357
 
        
358
 
        if (item->parent == NULL && !gtk_widget_get_realized (GTK_WIDGET (item->canvas)))
359
 
                gtk_widget_realize (GTK_WIDGET (item->canvas));
360
 
 
361
 
        item->flags |= EEL_CANVAS_ITEM_REALIZED;
362
 
 
363
 
        eel_canvas_item_request_update (item);
364
 
}
365
 
 
366
 
/* Unrealize handler for canvas items */
367
 
static void
368
 
eel_canvas_item_unrealize (EelCanvasItem *item)
369
 
{
370
 
        if (item->flags & EEL_CANVAS_ITEM_MAPPED)
371
 
                (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
372
 
 
373
 
        item->flags &= ~(EEL_CANVAS_ITEM_REALIZED);
374
 
}
375
 
 
376
 
/* Map handler for canvas items */
377
 
static void
378
 
eel_canvas_item_map (EelCanvasItem *item)
379
 
{
380
 
        item->flags |= EEL_CANVAS_ITEM_MAPPED;
381
 
}
382
 
 
383
 
/* Unmap handler for canvas items */
384
 
static void
385
 
eel_canvas_item_unmap (EelCanvasItem *item)
386
 
{
387
 
        item->flags &= ~(EEL_CANVAS_ITEM_MAPPED);
388
 
}
389
 
 
390
 
/* Update handler for canvas items */
391
 
static void
392
 
eel_canvas_item_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
393
 
{
394
 
        item->flags &= ~(EEL_CANVAS_ITEM_NEED_UPDATE);
395
 
        item->flags &= ~(EEL_CANVAS_ITEM_NEED_DEEP_UPDATE);
396
 
}
397
 
 
398
 
/*
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
402
 
 * matrix
403
 
 *
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
408
 
 *
409
 
 */
410
 
 
411
 
static void
412
 
eel_canvas_item_invoke_update (EelCanvasItem *item,
413
 
                               double i2w_dx,
414
 
                               double i2w_dy,
415
 
                               int flags)
416
 
{
417
 
        int child_flags;
418
 
 
419
 
        child_flags = flags;
420
 
 
421
 
        /* apply object flags to child flags */
422
 
        child_flags &= ~EEL_CANVAS_UPDATE_REQUESTED;
423
 
 
424
 
        if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE)
425
 
                child_flags |= EEL_CANVAS_UPDATE_REQUESTED;
426
 
 
427
 
        if (item->flags & EEL_CANVAS_ITEM_NEED_DEEP_UPDATE)
428
 
                child_flags |= EEL_CANVAS_UPDATE_DEEP;
429
 
 
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);
433
 
        }
434
 
 
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));
438
 
}
439
 
 
440
 
/*
441
 
 * This routine invokes the point method of the item.
442
 
 * The arguments x, y should be in the parent item local coordinates.
443
 
 */
444
 
 
445
 
static double
446
 
eel_canvas_item_invoke_point (EelCanvasItem *item, double x, double y, int cx, int cy, EelCanvasItem **actual_item)
447
 
{
448
 
        /* Calculate x & y in item local coordinates */
449
 
 
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);
452
 
 
453
 
        return 1e18;
454
 
}
455
 
 
456
 
/**
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.
460
 
 * @Varargs:
461
 
 *
462
 
 * Configures a canvas item.  The arguments in the item are set to the specified
463
 
 * values, and the item is repainted as appropriate.
464
 
 **/
465
 
void
466
 
eel_canvas_item_set (EelCanvasItem *item, const gchar *first_arg_name, ...)
467
 
{
468
 
        va_list args;
469
 
 
470
 
        va_start (args, first_arg_name);
471
 
        eel_canvas_item_set_valist (item, first_arg_name, args);
472
 
        va_end (args);
473
 
}
474
 
 
475
 
 
476
 
/**
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.
481
 
 *
482
 
 * Configures a canvas item.  The arguments in the item are set to the specified
483
 
 * values, and the item is repainted as appropriate.
484
 
 **/
485
 
void
486
 
eel_canvas_item_set_valist (EelCanvasItem *item, const gchar *first_arg_name, va_list args)
487
 
{
488
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
489
 
 
490
 
        g_object_set_valist (G_OBJECT (item), first_arg_name, args);
491
 
 
492
 
        item->canvas->need_repick = TRUE;
493
 
}
494
 
 
495
 
 
496
 
/**
497
 
 * eel_canvas_item_move:
498
 
 * @item: A canvas item.
499
 
 * @dx: Horizontal offset.
500
 
 * @dy: Vertical offset.
501
 
 *
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.
506
 
 **/
507
 
void
508
 
eel_canvas_item_move (EelCanvasItem *item, double dx, double dy)
509
 
{
510
 
        g_return_if_fail (item != NULL);
511
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
512
 
 
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)));
516
 
                return;
517
 
        }
518
 
 
519
 
        (* EEL_CANVAS_ITEM_GET_CLASS (item)->translate) (item, dx, dy);
520
 
 
521
 
        if (item->flags & EEL_CANVAS_ITEM_MAPPED) 
522
 
                item->canvas->need_repick = TRUE;
523
 
 
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);
528
 
                else
529
 
                        eel_canvas_request_update (item->canvas);
530
 
        }
531
 
 
532
 
}
533
 
 
534
 
static void
535
 
eel_canvas_queue_resize (EelCanvas *canvas)
536
 
{
537
 
        if (gtk_widget_is_drawable (GTK_WIDGET (canvas)))
538
 
                gtk_widget_queue_resize (GTK_WIDGET (canvas));
539
 
}
540
 
 
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.
543
 
 */
544
 
static gboolean
545
 
put_item_after (GList *link, GList *before)
546
 
{
547
 
        EelCanvasGroup *parent;
548
 
 
549
 
        if (link == before)
550
 
                return FALSE;
551
 
 
552
 
        parent = EEL_CANVAS_GROUP (EEL_CANVAS_ITEM (link->data)->parent);
553
 
 
554
 
        if (before == NULL) {
555
 
                if (link == parent->item_list)
556
 
                        return FALSE;
557
 
 
558
 
                link->prev->next = link->next;
559
 
 
560
 
                if (link->next)
561
 
                        link->next->prev = link->prev;
562
 
                else
563
 
                        parent->item_list_end = link->prev;
564
 
 
565
 
                link->prev = before;
566
 
                link->next = parent->item_list;
567
 
                link->next->prev = link;
568
 
                parent->item_list = link;
569
 
        } else {
570
 
                if ((link == parent->item_list_end) && (before == parent->item_list_end->prev))
571
 
                        return FALSE;
572
 
 
573
 
                if (link->next)
574
 
                        link->next->prev = link->prev;
575
 
 
576
 
                if (link->prev)
577
 
                        link->prev->next = link->next;
578
 
                else {
579
 
                        parent->item_list = link->next;
580
 
                        parent->item_list->prev = NULL;
581
 
                }
582
 
 
583
 
                link->prev = before;
584
 
                link->next = before->next;
585
 
 
586
 
                link->prev->next = link;
587
 
 
588
 
                if (link->next)
589
 
                        link->next->prev = link;
590
 
                else
591
 
                        parent->item_list_end = link;
592
 
        }
593
 
        return TRUE;
594
 
}
595
 
 
596
 
 
597
 
/**
598
 
 * eel_canvas_item_raise:
599
 
 * @item: A canvas item.
600
 
 * @positions: Number of steps to raise the item.
601
 
 *
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.
605
 
 **/
606
 
void
607
 
eel_canvas_item_raise (EelCanvasItem *item, int positions)
608
 
{
609
 
        GList *link, *before;
610
 
        EelCanvasGroup *parent;
611
 
 
612
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
613
 
        g_return_if_fail (positions >= 0);
614
 
 
615
 
        if (!item->parent || positions == 0)
616
 
                return;
617
 
 
618
 
        parent = EEL_CANVAS_GROUP (item->parent);
619
 
        link = g_list_find (parent->item_list, item);
620
 
        g_assert (link != NULL);
621
 
 
622
 
        for (before = link; positions && before; positions--)
623
 
                before = before->next;
624
 
 
625
 
        if (!before)
626
 
                before = parent->item_list_end;
627
 
 
628
 
        if (put_item_after (link, before)) {
629
 
                redraw_and_repick_if_mapped (item);
630
 
        }
631
 
}
632
 
 
633
 
 
634
 
/**
635
 
 * eel_canvas_item_lower:
636
 
 * @item: A canvas item.
637
 
 * @positions: Number of steps to lower the item.
638
 
 *
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.
642
 
 **/
643
 
void
644
 
eel_canvas_item_lower (EelCanvasItem *item, int positions)
645
 
{
646
 
        GList *link, *before;
647
 
        EelCanvasGroup *parent;
648
 
 
649
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
650
 
        g_return_if_fail (positions >= 1);
651
 
 
652
 
        if (!item->parent || positions == 0)
653
 
                return;
654
 
 
655
 
        parent = EEL_CANVAS_GROUP (item->parent);
656
 
        link = g_list_find (parent->item_list, item);
657
 
        g_assert (link != NULL);
658
 
 
659
 
        if (link->prev)
660
 
                for (before = link->prev; positions && before; positions--)
661
 
                        before = before->prev;
662
 
        else
663
 
                before = NULL;
664
 
 
665
 
        if (put_item_after (link, before)) {
666
 
                redraw_and_repick_if_mapped (item);
667
 
        }
668
 
}
669
 
 
670
 
 
671
 
/**
672
 
 * eel_canvas_item_raise_to_top:
673
 
 * @item: A canvas item.
674
 
 *
675
 
 * Raises an item to the top of its parent's stack.
676
 
 **/
677
 
void
678
 
eel_canvas_item_raise_to_top (EelCanvasItem *item)
679
 
{
680
 
        GList *link;
681
 
        EelCanvasGroup *parent;
682
 
 
683
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
684
 
 
685
 
        if (!item->parent)
686
 
                return;
687
 
 
688
 
        parent = EEL_CANVAS_GROUP (item->parent);
689
 
        link = g_list_find (parent->item_list, item);
690
 
        g_assert (link != NULL);
691
 
 
692
 
        if (put_item_after (link, parent->item_list_end)) {
693
 
                redraw_and_repick_if_mapped (item);
694
 
        }
695
 
}
696
 
 
697
 
 
698
 
/**
699
 
 * eel_canvas_item_lower_to_bottom:
700
 
 * @item: A canvas item.
701
 
 *
702
 
 * Lowers an item to the bottom of its parent's stack.
703
 
 **/
704
 
void
705
 
eel_canvas_item_lower_to_bottom (EelCanvasItem *item)
706
 
{
707
 
        GList *link;
708
 
        EelCanvasGroup *parent;
709
 
 
710
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
711
 
 
712
 
        if (!item->parent)
713
 
                return;
714
 
 
715
 
        parent = EEL_CANVAS_GROUP (item->parent);
716
 
        link = g_list_find (parent->item_list, item);
717
 
        g_assert (link != NULL);
718
 
 
719
 
        if (put_item_after (link, NULL)) {
720
 
                redraw_and_repick_if_mapped (item);
721
 
        }
722
 
}
723
 
 
724
 
/**
725
 
 * eel_canvas_item_send_behind:
726
 
 * @item: A canvas item.
727
 
 * @behind_item: The canvas item to put item behind, or NULL
728
 
 *
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.
732
 
 **/
733
 
void
734
 
eel_canvas_item_send_behind (EelCanvasItem *item,
735
 
                             EelCanvasItem *behind_item)
736
 
{
737
 
        GList *item_list;
738
 
        int item_position, behind_position;
739
 
 
740
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
741
 
 
742
 
        if (behind_item == NULL) {
743
 
                eel_canvas_item_raise_to_top (item);
744
 
                return;
745
 
        }
746
 
 
747
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (behind_item));
748
 
        g_return_if_fail (item->parent == behind_item->parent);
749
 
 
750
 
        item_list = EEL_CANVAS_GROUP (item->parent)->item_list;
751
 
 
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);
757
 
 
758
 
        if (item_position == behind_position - 1) {
759
 
                return;
760
 
        }
761
 
 
762
 
        if (item_position < behind_position) {
763
 
                eel_canvas_item_raise (item, (behind_position - 1) - item_position);
764
 
        } else {
765
 
                eel_canvas_item_lower (item, item_position - behind_position);
766
 
        }
767
 
}
768
 
 
769
 
/**
770
 
 * eel_canvas_item_show:
771
 
 * @item: A canvas item.
772
 
 *
773
 
 * Shows a canvas item.  If the item was already shown, then no action is taken.
774
 
 **/
775
 
void
776
 
eel_canvas_item_show (EelCanvasItem *item)
777
 
{
778
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
779
 
 
780
 
        if (!(item->flags & EEL_CANVAS_ITEM_VISIBLE)) {
781
 
                item->flags |= EEL_CANVAS_ITEM_VISIBLE;
782
 
                
783
 
                if (!(item->flags & EEL_CANVAS_ITEM_REALIZED))
784
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
785
 
 
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);
790
 
                } else {
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);
794
 
                }
795
 
 
796
 
                redraw_and_repick_if_mapped (item);
797
 
                eel_canvas_queue_resize (item->canvas);
798
 
        }
799
 
}
800
 
 
801
 
 
802
 
/**
803
 
 * eel_canvas_item_hide:
804
 
 * @item: A canvas item.
805
 
 *
806
 
 * Hides a canvas item.  If the item was already hidden, then no action is
807
 
 * taken.
808
 
 **/
809
 
void
810
 
eel_canvas_item_hide (EelCanvasItem *item)
811
 
{
812
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
813
 
 
814
 
        if (item->flags & EEL_CANVAS_ITEM_VISIBLE) {
815
 
                item->flags &= ~EEL_CANVAS_ITEM_VISIBLE;
816
 
 
817
 
                redraw_and_repick_if_mapped (item);
818
 
 
819
 
                if (item->flags & EEL_CANVAS_ITEM_MAPPED)
820
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
821
 
 
822
 
                eel_canvas_queue_resize (item->canvas);
823
 
 
824
 
                /* No need to unrealize when we just want to hide */
825
 
        }
826
 
}
827
 
 
828
 
 
829
 
/**
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.
835
 
 *
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.
841
 
 *
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().
846
 
 **/
847
 
GdkGrabStatus
848
 
eel_canvas_item_grab (EelCanvasItem *item,
849
 
                      GdkEventMask event_mask,
850
 
                      GdkCursor *cursor,
851
 
                      guint32 timestamp)
852
 
{
853
 
        GdkGrabStatus retval;
854
 
        GdkDisplay *display;
855
 
        GdkDeviceManager *manager;
856
 
        GdkDevice *device;
857
 
 
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);
861
 
 
862
 
        if (item->canvas->grabbed_item)
863
 
                return GDK_GRAB_ALREADY_GRABBED;
864
 
 
865
 
        if (!(item->flags & EEL_CANVAS_ITEM_MAPPED))
866
 
                return GDK_GRAB_NOT_VIEWABLE;
867
 
 
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);
871
 
 
872
 
        retval = gdk_device_grab (device,
873
 
                                  gtk_layout_get_bin_window (GTK_LAYOUT (item->canvas)),
874
 
                                  GDK_OWNERSHIP_NONE,
875
 
                                  FALSE,
876
 
                                  event_mask,
877
 
                                  cursor,
878
 
                                  timestamp);
879
 
 
880
 
        if (retval != GDK_GRAB_SUCCESS)
881
 
                return retval;
882
 
 
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 */
886
 
 
887
 
        return retval;
888
 
}
889
 
 
890
 
 
891
 
/**
892
 
 * eel_canvas_item_ungrab:
893
 
 * @item: A canvas item that holds a grab.
894
 
 * @etime: The timestamp for ungrabbing the mouse.
895
 
 *
896
 
 * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the
897
 
 * mouse.
898
 
 **/
899
 
void
900
 
eel_canvas_item_ungrab (EelCanvasItem *item, guint32 etime)
901
 
{
902
 
        GdkDisplay *display;
903
 
        GdkDeviceManager *manager;
904
 
        GdkDevice *device;
905
 
 
906
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
907
 
 
908
 
        if (item->canvas->grabbed_item != item)
909
 
                return;
910
 
 
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);
914
 
 
915
 
        item->canvas->grabbed_item = NULL;
916
 
        gdk_device_ungrab (device, etime);
917
 
}
918
 
 
919
 
/**
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).
924
 
 *
925
 
 * Converts a coordinate pair from world coordinates to item-relative
926
 
 * coordinates.
927
 
 **/
928
 
void
929
 
eel_canvas_item_w2i (EelCanvasItem *item, double *x, double *y)
930
 
{
931
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
932
 
        g_return_if_fail (x != NULL);
933
 
        g_return_if_fail (y != NULL);
934
 
 
935
 
        item = item->parent;
936
 
        while (item) {
937
 
                if (EEL_IS_CANVAS_GROUP (item)) {
938
 
                        *x -= EEL_CANVAS_GROUP (item)->xpos;
939
 
                        *y -= EEL_CANVAS_GROUP (item)->ypos;
940
 
                }
941
 
 
942
 
                item = item->parent;
943
 
        }
944
 
}
945
 
 
946
 
 
947
 
/**
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).
952
 
 *
953
 
 * Converts a coordinate pair from item-relative coordinates to world
954
 
 * coordinates.
955
 
 **/
956
 
void
957
 
eel_canvas_item_i2w (EelCanvasItem *item, double *x, double *y)
958
 
{
959
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
960
 
        g_return_if_fail (x != NULL);
961
 
        g_return_if_fail (y != NULL);
962
 
 
963
 
        item = item->parent;
964
 
        while (item) {
965
 
                if (EEL_IS_CANVAS_GROUP (item)) {
966
 
                        *x += EEL_CANVAS_GROUP (item)->xpos;
967
 
                        *y += EEL_CANVAS_GROUP (item)->ypos;
968
 
                }
969
 
 
970
 
                item = item->parent;
971
 
        }
972
 
}
973
 
 
974
 
/* Returns whether the item is an inferior of or is equal to the parent. */
975
 
static int
976
 
is_descendant (EelCanvasItem *item, EelCanvasItem *parent)
977
 
{
978
 
        for (; item; item = item->parent)
979
 
                if (item == parent)
980
 
                        return TRUE;
981
 
 
982
 
        return FALSE;
983
 
}
984
 
 
985
 
/**
986
 
 * eel_canvas_item_reparent:
987
 
 * @item: A canvas item.
988
 
 * @new_group: A canvas group.
989
 
 *
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.
993
 
 **/
994
 
void
995
 
eel_canvas_item_reparent (EelCanvasItem *item, EelCanvasGroup *new_group)
996
 
{
997
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
998
 
        g_return_if_fail (EEL_IS_CANVAS_GROUP (new_group));
999
 
 
1000
 
        /* Both items need to be in the same canvas */
1001
 
        g_return_if_fail (item->canvas == EEL_CANVAS_ITEM (new_group)->canvas);
1002
 
 
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
1005
 
         * the canvas.  */
1006
 
        g_return_if_fail (!is_descendant (EEL_CANVAS_ITEM (new_group), item));
1007
 
 
1008
 
        /* Everything is ok, now actually reparent the item */
1009
 
 
1010
 
        g_object_ref (G_OBJECT (item)); /* protect it from the unref in group_remove */
1011
 
 
1012
 
        eel_canvas_item_request_redraw (item);
1013
 
 
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);
1018
 
 
1019
 
        /* Redraw and repick */
1020
 
 
1021
 
        redraw_and_repick_if_mapped (item);
1022
 
 
1023
 
        g_object_unref (G_OBJECT (item));
1024
 
}
1025
 
 
1026
 
/**
1027
 
 * eel_canvas_item_grab_focus:
1028
 
 * @item: A canvas item.
1029
 
 *
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
1032
 
 * it as well.
1033
 
 **/
1034
 
void
1035
 
eel_canvas_item_grab_focus (EelCanvasItem *item)
1036
 
{
1037
 
        EelCanvasItem *focused_item;
1038
 
        GdkEvent ev;
1039
 
 
1040
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
1041
 
        g_return_if_fail (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas)));
1042
 
 
1043
 
        focused_item = item->canvas->focused_item;
1044
 
 
1045
 
        if (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;
1050
 
 
1051
 
                emit_event (item->canvas, &ev);
1052
 
        }
1053
 
 
1054
 
        item->canvas->focused_item = item;
1055
 
        gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
1056
 
 
1057
 
        if (focused_item) {                                                     
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;                                      
1062
 
 
1063
 
                emit_event (item->canvas, &ev);                          
1064
 
        }                               
1065
 
}
1066
 
 
1067
 
 
1068
 
/**
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).
1075
 
 *
1076
 
 * Queries the bounding box of a canvas item.  The bounds are returned in the
1077
 
 * coordinate system of the item's parent.
1078
 
 **/
1079
 
void
1080
 
eel_canvas_item_get_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1081
 
{
1082
 
        double tx1, ty1, tx2, ty2;
1083
 
 
1084
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
1085
 
 
1086
 
        tx1 = ty1 = tx2 = ty2 = 0.0;
1087
 
 
1088
 
        /* Get the item's bounds in its coordinate system */
1089
 
 
1090
 
        if (EEL_CANVAS_ITEM_GET_CLASS (item)->bounds)
1091
 
                (* EEL_CANVAS_ITEM_GET_CLASS (item)->bounds) (item, &tx1, &ty1, &tx2, &ty2);
1092
 
 
1093
 
        /* Return the values */
1094
 
 
1095
 
        if (x1)
1096
 
                *x1 = tx1;
1097
 
 
1098
 
        if (y1)
1099
 
                *y1 = ty1;
1100
 
 
1101
 
        if (x2)
1102
 
                *x2 = tx2;
1103
 
 
1104
 
        if (y2)
1105
 
                *y2 = ty2;
1106
 
}
1107
 
 
1108
 
 
1109
 
/**
1110
 
 * eel_canvas_item_request_update
1111
 
 * @item: A canvas item.
1112
 
 *
1113
 
 * To be used only by item implementations.  Requests that the canvas queue an
1114
 
 * update for the specified item.
1115
 
 **/
1116
 
void
1117
 
eel_canvas_item_request_update (EelCanvasItem *item)
1118
 
{
1119
 
        if (NULL == item->canvas)
1120
 
                return;
1121
 
 
1122
 
        g_return_if_fail (!item->canvas->doing_update);
1123
 
 
1124
 
        if (item->flags & EEL_CANVAS_ITEM_NEED_UPDATE)
1125
 
                return;
1126
 
 
1127
 
        item->flags |= EEL_CANVAS_ITEM_NEED_UPDATE;
1128
 
 
1129
 
        if (item->parent != NULL) {
1130
 
                /* Recurse up the tree */
1131
 
                eel_canvas_item_request_update (item->parent);
1132
 
        } else {
1133
 
                /* Have reached the top of the tree, make sure the update call gets scheduled. */
1134
 
                eel_canvas_request_update (item->canvas);
1135
 
        }
1136
 
}
1137
 
 
1138
 
/**
1139
 
 * eel_canvas_item_request_update
1140
 
 * @item: A canvas item.
1141
 
 *
1142
 
 * Convenience function that informs a canvas that the specified item needs
1143
 
 * to be repainted. To be used by item implementations
1144
 
 **/
1145
 
void
1146
 
eel_canvas_item_request_redraw (EelCanvasItem *item)
1147
 
{
1148
 
        if (item->flags & EEL_CANVAS_ITEM_MAPPED)
1149
 
                eel_canvas_request_redraw (item->canvas,
1150
 
                                           item->x1, item->y1,
1151
 
                                           item->x2 + 1, item->y2 + 1);
1152
 
}
1153
 
 
1154
 
 
1155
 
 
1156
 
/*** EelCanvasGroup ***/
1157
 
 
1158
 
 
1159
 
enum {
1160
 
        GROUP_PROP_0,
1161
 
        GROUP_PROP_X,
1162
 
        GROUP_PROP_Y
1163
 
};
1164
 
 
1165
 
 
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, 
1169
 
                                            guint                  param_id,
1170
 
                                            const GValue          *value,
1171
 
                                            GParamSpec            *pspec);
1172
 
static void eel_canvas_group_get_property(GObject               *object,
1173
 
                                            guint                  param_id,
1174
 
                                            GValue                *value,
1175
 
                                            GParamSpec            *pspec);
1176
 
 
1177
 
static void eel_canvas_group_destroy     (EelCanvasItem           *object);
1178
 
 
1179
 
static void   eel_canvas_group_update      (EelCanvasItem *item,
1180
 
                                              double           i2w_dx,
1181
 
                                              double           i2w_dy,
1182
 
                                              int              flags);
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,
1187
 
                                            cairo_t        *cr,
1188
 
                                            cairo_region_t *region);
1189
 
static double eel_canvas_group_point       (EelCanvasItem *item, double x, double y,
1190
 
                                              int cx, int cy,
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);
1195
 
 
1196
 
 
1197
 
static EelCanvasItemClass *group_parent_class;
1198
 
 
1199
 
 
1200
 
/**
1201
 
 * eel_canvas_group_get_type:
1202
 
 *
1203
 
 * Registers the &EelCanvasGroup class if necessary, and returns the type ID
1204
 
 * associated to it.
1205
 
 *
1206
 
 * Return value:  The type ID of the &EelCanvasGroup class.
1207
 
 **/
1208
 
GType
1209
 
eel_canvas_group_get_type (void)
1210
 
{
1211
 
        static GType group_type = 0;
1212
 
 
1213
 
        if (!group_type) {
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
1224
 
 
1225
 
        
1226
 
                };
1227
 
 
1228
 
                group_type = g_type_register_static (eel_canvas_item_get_type (),
1229
 
                                                     "EelCanvasGroup",
1230
 
                                                     &group_info,
1231
 
                                                     0);
1232
 
        }
1233
 
 
1234
 
        return group_type;
1235
 
}
1236
 
 
1237
 
/* Class initialization function for EelCanvasGroupClass */
1238
 
static void
1239
 
eel_canvas_group_class_init (EelCanvasGroupClass *klass)
1240
 
{
1241
 
        GObjectClass *gobject_class;
1242
 
        EelCanvasItemClass *item_class;
1243
 
 
1244
 
        gobject_class = (GObjectClass *) klass;
1245
 
        item_class = (EelCanvasItemClass *) klass;
1246
 
 
1247
 
        group_parent_class = g_type_class_peek_parent (klass);
1248
 
 
1249
 
        gobject_class->set_property = eel_canvas_group_set_property;
1250
 
        gobject_class->get_property = eel_canvas_group_get_property;
1251
 
 
1252
 
        g_object_class_install_property
1253
 
                (gobject_class, GROUP_PROP_X,
1254
 
                 g_param_spec_double ("x",
1255
 
                                      _("X"),
1256
 
                                      _("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",
1262
 
                                      _("Y"),
1263
 
                                      _("Y"),
1264
 
                                      -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
1265
 
                                      G_PARAM_READWRITE));
1266
 
 
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;
1276
 
}
1277
 
 
1278
 
/* Object initialization function for EelCanvasGroup */
1279
 
static void
1280
 
eel_canvas_group_init (EelCanvasGroup *group)
1281
 
{
1282
 
        group->xpos = 0.0;
1283
 
        group->ypos = 0.0;
1284
 
}
1285
 
 
1286
 
/* Set_property handler for canvas groups */
1287
 
static void
1288
 
eel_canvas_group_set_property (GObject *gobject, guint param_id,
1289
 
                               const GValue *value, GParamSpec *pspec)
1290
 
{
1291
 
        EelCanvasItem *item;
1292
 
        EelCanvasGroup *group;
1293
 
        double old;
1294
 
        gboolean moved;
1295
 
 
1296
 
        g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject));
1297
 
 
1298
 
        item = EEL_CANVAS_ITEM (gobject);
1299
 
        group = EEL_CANVAS_GROUP (gobject);
1300
 
 
1301
 
        moved = FALSE;
1302
 
        switch (param_id) {
1303
 
        case GROUP_PROP_X:
1304
 
                old = group->xpos;
1305
 
                group->xpos = g_value_get_double (value);
1306
 
                if (old != group->xpos)
1307
 
                        moved = TRUE;
1308
 
                break;
1309
 
 
1310
 
        case GROUP_PROP_Y:
1311
 
                old = group->ypos;
1312
 
                group->ypos = g_value_get_double (value);
1313
 
                if (old != group->ypos)
1314
 
                        moved = TRUE;
1315
 
                break;
1316
 
 
1317
 
        default:
1318
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
1319
 
                break;
1320
 
        }
1321
 
 
1322
 
        if (moved) {
1323
 
                item->flags |= EEL_CANVAS_ITEM_NEED_DEEP_UPDATE;
1324
 
                if (item->parent != NULL)
1325
 
                        eel_canvas_item_request_update (item->parent);
1326
 
                else
1327
 
                        eel_canvas_request_update (item->canvas);
1328
 
        }
1329
 
}
1330
 
 
1331
 
/* Get_property handler for canvas groups */
1332
 
static void
1333
 
eel_canvas_group_get_property (GObject *gobject, guint param_id,
1334
 
                                 GValue *value, GParamSpec *pspec)
1335
 
{
1336
 
        EelCanvasGroup *group;
1337
 
 
1338
 
        g_return_if_fail (EEL_IS_CANVAS_GROUP (gobject));
1339
 
 
1340
 
        group = EEL_CANVAS_GROUP (gobject);
1341
 
 
1342
 
        switch (param_id) {
1343
 
        case GROUP_PROP_X:
1344
 
                g_value_set_double (value, group->xpos);
1345
 
                break;
1346
 
 
1347
 
        case GROUP_PROP_Y:
1348
 
                g_value_set_double (value, group->ypos);
1349
 
                break;
1350
 
 
1351
 
        default:
1352
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
1353
 
                break;
1354
 
        }
1355
 
}
1356
 
 
1357
 
/* Destroy handler for canvas groups */
1358
 
static void
1359
 
eel_canvas_group_destroy (EelCanvasItem *object)
1360
 
{
1361
 
        EelCanvasGroup *group;
1362
 
        EelCanvasItem *child;
1363
 
        GList *list;
1364
 
 
1365
 
        g_return_if_fail (EEL_IS_CANVAS_GROUP (object));
1366
 
 
1367
 
        group = EEL_CANVAS_GROUP (object);
1368
 
 
1369
 
        list = group->item_list;
1370
 
        while (list) {
1371
 
                child = list->data;
1372
 
                list = list->next;
1373
 
 
1374
 
                eel_canvas_item_destroy (child);
1375
 
        }
1376
 
 
1377
 
        if (EEL_CANVAS_ITEM_CLASS (group_parent_class)->destroy)
1378
 
                (* EEL_CANVAS_ITEM_CLASS (group_parent_class)->destroy) (object);
1379
 
}
1380
 
 
1381
 
/* Update handler for canvas groups */
1382
 
static void
1383
 
eel_canvas_group_update (EelCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
1384
 
{
1385
 
        EelCanvasGroup *group;
1386
 
        GList *list;
1387
 
        EelCanvasItem *i;
1388
 
        double bbox_x0, bbox_y0, bbox_x1, bbox_y1;
1389
 
        gboolean first = TRUE;
1390
 
 
1391
 
        group = EEL_CANVAS_GROUP (item);
1392
 
 
1393
 
        (* group_parent_class->update) (item, i2w_dx, i2w_dy, flags);
1394
 
 
1395
 
        bbox_x0 = 0;
1396
 
        bbox_y0 = 0;
1397
 
        bbox_x1 = 0;
1398
 
        bbox_y1 = 0;
1399
 
 
1400
 
        for (list = group->item_list; list; list = list->next) {
1401
 
                i = list->data;
1402
 
 
1403
 
                eel_canvas_item_invoke_update (i, i2w_dx + group->xpos, i2w_dy + group->ypos, flags);
1404
 
 
1405
 
                if (first) {
1406
 
                        first = FALSE;
1407
 
                        bbox_x0 = i->x1;
1408
 
                        bbox_y0 = i->y1;
1409
 
                        bbox_x1 = i->x2;
1410
 
                        bbox_y1 = i->y2;
1411
 
                } else {
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);
1416
 
                }
1417
 
        }
1418
 
        item->x1 = bbox_x0;
1419
 
        item->y1 = bbox_y0;
1420
 
        item->x2 = bbox_x1;
1421
 
        item->y2 = bbox_y1;
1422
 
}
1423
 
 
1424
 
/* Unrealize handler for canvas groups */
1425
 
static void
1426
 
eel_canvas_group_unrealize (EelCanvasItem *item)
1427
 
{
1428
 
        EelCanvasGroup *group;
1429
 
        GList *list;
1430
 
        EelCanvasItem *i;
1431
 
 
1432
 
        group = EEL_CANVAS_GROUP (item);
1433
 
 
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);
1437
 
 
1438
 
        for (list = group->item_list; list; list = list->next) {
1439
 
                i = list->data;
1440
 
 
1441
 
                if (i->flags & EEL_CANVAS_ITEM_REALIZED)
1442
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (i)->unrealize) (i);
1443
 
        }
1444
 
 
1445
 
        (* group_parent_class->unrealize) (item);
1446
 
}
1447
 
 
1448
 
/* Map handler for canvas groups */
1449
 
static void
1450
 
eel_canvas_group_map (EelCanvasItem *item)
1451
 
{
1452
 
        EelCanvasGroup *group;
1453
 
        GList *list;
1454
 
        EelCanvasItem *i;
1455
 
 
1456
 
        group = EEL_CANVAS_GROUP (item);
1457
 
 
1458
 
        for (list = group->item_list; list; list = list->next) {
1459
 
                i = list->data;
1460
 
 
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);
1465
 
                                
1466
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (i)->map) (i);
1467
 
                }
1468
 
        }
1469
 
 
1470
 
        (* group_parent_class->map) (item);
1471
 
}
1472
 
 
1473
 
/* Unmap handler for canvas groups */
1474
 
static void
1475
 
eel_canvas_group_unmap (EelCanvasItem *item)
1476
 
{
1477
 
        EelCanvasGroup *group;
1478
 
        GList *list;
1479
 
        EelCanvasItem *i;
1480
 
 
1481
 
        group = EEL_CANVAS_GROUP (item);
1482
 
 
1483
 
        for (list = group->item_list; list; list = list->next) {
1484
 
                i = list->data;
1485
 
 
1486
 
                if (i->flags & EEL_CANVAS_ITEM_MAPPED)
1487
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (i)->unmap) (i);
1488
 
        }
1489
 
 
1490
 
        (* group_parent_class->unmap) (item);
1491
 
}
1492
 
 
1493
 
/* Draw handler for canvas groups */
1494
 
static void
1495
 
eel_canvas_group_draw (EelCanvasItem  *item,
1496
 
                       cairo_t        *cr,
1497
 
                       cairo_region_t *region)
1498
 
{
1499
 
        EelCanvasGroup *group;
1500
 
        GList *list;
1501
 
        EelCanvasItem *child = NULL;
1502
 
 
1503
 
        group = EEL_CANVAS_GROUP (item);
1504
 
 
1505
 
        for (list = group->item_list; list; list = list->next) {
1506
 
                child = list->data;
1507
 
 
1508
 
                if ((child->flags & EEL_CANVAS_ITEM_MAPPED) &&
1509
 
                    (EEL_CANVAS_ITEM_GET_CLASS (child)->draw)) {
1510
 
                        GdkRectangle child_rect;
1511
 
 
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;
1516
 
 
1517
 
                        if (cairo_region_contains_rectangle (region, &child_rect) != CAIRO_REGION_OVERLAP_OUT)
1518
 
                                EEL_CANVAS_ITEM_GET_CLASS (child)->draw (child, cr, region);
1519
 
                }
1520
 
        }
1521
 
}
1522
 
 
1523
 
/* Point handler for canvas groups */
1524
 
static double
1525
 
eel_canvas_group_point (EelCanvasItem *item, double x, double y, int cx, int cy,
1526
 
                        EelCanvasItem **actual_item)
1527
 
{
1528
 
        EelCanvasGroup *group;
1529
 
        GList *list;
1530
 
        EelCanvasItem *child, *point_item;
1531
 
        int x1, y1, x2, y2;
1532
 
        double gx, gy;
1533
 
        double dist, best;
1534
 
        int has_point;
1535
 
 
1536
 
        group = EEL_CANVAS_GROUP (item);
1537
 
 
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;
1542
 
 
1543
 
        best = 0.0;
1544
 
        *actual_item = NULL;
1545
 
 
1546
 
        gx = x - group->xpos;
1547
 
        gy = y - group->ypos;
1548
 
 
1549
 
        dist = 0.0; /* keep gcc happy */
1550
 
 
1551
 
        for (list = group->item_list; list; list = list->next) {
1552
 
                child = list->data;
1553
 
 
1554
 
                if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1))
1555
 
                        continue;
1556
 
 
1557
 
                point_item = NULL; /* cater for incomplete item implementations */
1558
 
 
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);
1562
 
                        has_point = TRUE;
1563
 
                } else
1564
 
                        has_point = FALSE;
1565
 
 
1566
 
                if (has_point
1567
 
                    && point_item
1568
 
                    && ((int) (dist * item->canvas->pixels_per_unit + 0.5)
1569
 
                        <= item->canvas->close_enough)) {
1570
 
                        best = dist;
1571
 
                        *actual_item = point_item;
1572
 
                }
1573
 
        }
1574
 
 
1575
 
        return best;
1576
 
}
1577
 
 
1578
 
void
1579
 
eel_canvas_group_translate (EelCanvasItem *item, double dx, double dy)
1580
 
{
1581
 
        EelCanvasGroup *group;
1582
 
 
1583
 
        group = EEL_CANVAS_GROUP (item);
1584
 
 
1585
 
        group->xpos += dx;
1586
 
        group->ypos += dy;
1587
 
}
1588
 
 
1589
 
/* Bounds handler for canvas groups */
1590
 
static void
1591
 
eel_canvas_group_bounds (EelCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1592
 
{
1593
 
        EelCanvasGroup *group;
1594
 
        EelCanvasItem *child;
1595
 
        GList *list;
1596
 
        double tx1, ty1, tx2, ty2;
1597
 
        double minx, miny, maxx, maxy;
1598
 
        int set;
1599
 
 
1600
 
        group = EEL_CANVAS_GROUP (item);
1601
 
 
1602
 
        /* Get the bounds of the first visible item */
1603
 
 
1604
 
        child = NULL; /* Unnecessary but eliminates a warning. */
1605
 
 
1606
 
        set = FALSE;
1607
 
 
1608
 
        for (list = group->item_list; list; list = list->next) {
1609
 
                child = list->data;
1610
 
 
1611
 
                if (child->flags & EEL_CANVAS_ITEM_MAPPED) {
1612
 
                        set = TRUE;
1613
 
                        eel_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy);
1614
 
                        break;
1615
 
                }
1616
 
        }
1617
 
 
1618
 
        /* If there were no visible items, return an empty bounding box */
1619
 
 
1620
 
        if (!set) {
1621
 
                *x1 = *y1 = *x2 = *y2 = 0.0;
1622
 
                return;
1623
 
        }
1624
 
 
1625
 
        /* Now we can grow the bounds using the rest of the items */
1626
 
 
1627
 
        list = list->next;
1628
 
 
1629
 
        for (; list; list = list->next) {
1630
 
                child = list->data;
1631
 
 
1632
 
                if (!(child->flags & EEL_CANVAS_ITEM_MAPPED))
1633
 
                        continue;
1634
 
 
1635
 
                eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2);
1636
 
 
1637
 
                if (tx1 < minx)
1638
 
                        minx = tx1;
1639
 
 
1640
 
                if (ty1 < miny)
1641
 
                        miny = ty1;
1642
 
 
1643
 
                if (tx2 > maxx)
1644
 
                        maxx = tx2;
1645
 
 
1646
 
                if (ty2 > maxy)
1647
 
                        maxy = ty2;
1648
 
        }
1649
 
 
1650
 
        /* Make the bounds be relative to our parent's coordinate system */
1651
 
 
1652
 
        if (item->parent) {
1653
 
                minx += group->xpos;
1654
 
                miny += group->ypos;
1655
 
                maxx += group->xpos;
1656
 
                maxy += group->ypos;
1657
 
        }
1658
 
        
1659
 
        *x1 = minx;
1660
 
        *y1 = miny;
1661
 
        *x2 = maxx;
1662
 
        *y2 = maxy;
1663
 
}
1664
 
 
1665
 
/* Adds an item to a group */
1666
 
static void
1667
 
group_add (EelCanvasGroup *group, EelCanvasItem *item)
1668
 
{
1669
 
        g_object_ref_sink (item);
1670
 
 
1671
 
        if (!group->item_list) {
1672
 
                group->item_list = g_list_append (group->item_list, item);
1673
 
                group->item_list_end = group->item_list;
1674
 
        } else
1675
 
                group->item_list_end = g_list_append (group->item_list_end, item)->next;
1676
 
 
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);
1681
 
                
1682
 
                if (!(item->flags & EEL_CANVAS_ITEM_MAPPED))
1683
 
                        (* EEL_CANVAS_ITEM_GET_CLASS (item)->map) (item);
1684
 
        }
1685
 
 
1686
 
        if (item->flags & EEL_CANVAS_ITEM_VISIBLE)
1687
 
                eel_canvas_queue_resize (EEL_CANVAS_ITEM (group)->canvas);
1688
 
}
1689
 
 
1690
 
/* Removes an item from a group */
1691
 
static void
1692
 
group_remove (EelCanvasGroup *group, EelCanvasItem *item)
1693
 
{
1694
 
        GList *children;
1695
 
 
1696
 
        g_return_if_fail (EEL_IS_CANVAS_GROUP (group));
1697
 
        g_return_if_fail (EEL_IS_CANVAS_ITEM (item));
1698
 
 
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);
1703
 
                        }
1704
 
 
1705
 
                        if (item->flags & EEL_CANVAS_ITEM_REALIZED)
1706
 
                                (* EEL_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
1707
 
 
1708
 
                        if (item->flags & EEL_CANVAS_ITEM_VISIBLE)
1709
 
                                eel_canvas_queue_resize (item->canvas);
1710
 
 
1711
 
                        /* Unparent the child */
1712
 
 
1713
 
                        item->parent = NULL;
1714
 
                        /* item->canvas = NULL; */
1715
 
                        g_object_unref (G_OBJECT (item));
1716
 
 
1717
 
                        /* Remove it from the list */
1718
 
 
1719
 
                        if (children == group->item_list_end)
1720
 
                                group->item_list_end = children->prev;
1721
 
 
1722
 
                        group->item_list = g_list_remove_link (group->item_list, children);
1723
 
                        g_list_free (children);
1724
 
                        break;
1725
 
                }
1726
 
}
1727
 
 
1728
 
 
1729
 
/*** EelCanvas ***/
1730
 
 
1731
 
 
1732
 
enum {
1733
 
        DRAW_BACKGROUND,
1734
 
        LAST_SIGNAL
1735
 
};
1736
 
 
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,
1751
 
                                            cairo_t          *cr);
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,
1762
 
                                            cairo_t        *cr);
1763
 
static AtkObject *eel_canvas_get_accessible (GtkWidget       *widget);
1764
 
 
1765
 
 
1766
 
static GtkLayoutClass *canvas_parent_class;
1767
 
 
1768
 
static guint canvas_signals[LAST_SIGNAL];
1769
 
 
1770
 
/**
1771
 
 * eel_canvas_get_type:
1772
 
 *
1773
 
 * Registers the &EelCanvas class if necessary, and returns the type ID
1774
 
 * associated to it.
1775
 
 *
1776
 
 * Return value:  The type ID of the &EelCanvas class.
1777
 
 **/
1778
 
GType
1779
 
eel_canvas_get_type (void)
1780
 
{
1781
 
        static GType canvas_type = 0;
1782
 
 
1783
 
        if (!canvas_type) {
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 */
1791
 
                        sizeof (EelCanvas),
1792
 
                        0,              /* n_preallocs */
1793
 
                        (GInstanceInitFunc) eel_canvas_init
1794
 
                };
1795
 
 
1796
 
                canvas_type = g_type_register_static (gtk_layout_get_type (),
1797
 
                                                      "EelCanvas",
1798
 
                                                      &canvas_info,
1799
 
                                                      0);
1800
 
        }
1801
 
 
1802
 
        return canvas_type;
1803
 
}
1804
 
 
1805
 
static void
1806
 
eel_canvas_get_property (GObject    *object, 
1807
 
                           guint       prop_id,
1808
 
                           GValue     *value,
1809
 
                           GParamSpec *pspec)
1810
 
{
1811
 
        switch (prop_id) {
1812
 
        default:
1813
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1814
 
                break;
1815
 
        }
1816
 
}
1817
 
 
1818
 
static void
1819
 
eel_canvas_set_property (GObject      *object, 
1820
 
                           guint         prop_id,
1821
 
                           const GValue *value,
1822
 
                           GParamSpec   *pspec)
1823
 
{
1824
 
        switch (prop_id) {
1825
 
        default:
1826
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1827
 
                break;
1828
 
        }
1829
 
}
1830
 
 
1831
 
static void
1832
 
eel_canvas_accessible_adjustment_changed (GtkAdjustment *adjustment,
1833
 
                                          gpointer       data)
1834
 
{
1835
 
        AtkObject *atk_obj;
1836
 
 
1837
 
        /* The scrollbars have changed */
1838
 
        atk_obj = ATK_OBJECT (data);
1839
 
 
1840
 
        g_signal_emit_by_name (atk_obj, "visible_data_changed");
1841
 
}
1842
 
 
1843
 
static void
1844
 
accessible_destroy_cb (GtkWidget     *widget,
1845
 
                       GtkAccessible *accessible)
1846
 
{
1847
 
        gtk_accessible_set_widget (accessible, NULL);
1848
 
        atk_object_notify_state_change (ATK_OBJECT (accessible), ATK_STATE_DEFUNCT, TRUE);
1849
 
}
1850
 
 
1851
 
static gboolean
1852
 
accessible_focus_cb (GtkWidget     *widget,
1853
 
                     GdkEventFocus *event)
1854
 
{
1855
 
        AtkObject* accessible = gtk_widget_get_accessible (widget);
1856
 
        atk_object_notify_state_change (accessible, ATK_STATE_FOCUSED, event->in);
1857
 
 
1858
 
        return FALSE;
1859
 
}
1860
 
 
1861
 
static void
1862
 
accessible_notify_cb (GObject    *obj,
1863
 
                      GParamSpec *pspec)
1864
 
{
1865
 
        GtkWidget* widget = GTK_WIDGET (obj);
1866
 
        AtkObject* atk_obj = gtk_widget_get_accessible (widget);
1867
 
        AtkState state;
1868
 
        gboolean value;
1869
 
 
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);
1876
 
 
1877
 
                atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED, value);
1878
 
        } else {
1879
 
                g_assert_not_reached ();
1880
 
        }
1881
 
 
1882
 
        atk_object_notify_state_change (atk_obj, state, value);
1883
 
}
1884
 
 
1885
 
/* Translate GtkWidget::size-allocate to AtkComponent::bounds-changed */
1886
 
static void
1887
 
accessible_size_allocate_cb (GtkWidget     *widget,
1888
 
                             GtkAllocation *allocation)
1889
 
{
1890
 
        AtkObject* accessible = gtk_widget_get_accessible (widget);
1891
 
        AtkRectangle rect;
1892
 
 
1893
 
        rect.x = allocation->x;
1894
 
        rect.y = allocation->y;
1895
 
        rect.width = allocation->width;
1896
 
        rect.height = allocation->height;
1897
 
 
1898
 
        g_signal_emit_by_name (accessible, "bounds_changed", &rect);
1899
 
}
1900
 
 
1901
 
/* Translate GtkWidget mapped state into AtkObject showing */
1902
 
static void
1903
 
accessible_map_cb (GtkWidget *widget)
1904
 
{
1905
 
        AtkObject *accessible = gtk_widget_get_accessible (widget);
1906
 
        atk_object_notify_state_change (accessible, ATK_STATE_SHOWING,
1907
 
                                        gtk_widget_get_mapped (widget));
1908
 
}
1909
 
 
1910
 
static void
1911
 
eel_canvas_accessible_initialize (AtkObject *obj, 
1912
 
                                  gpointer   data)
1913
 
{
1914
 
        EelCanvas *canvas = data;
1915
 
 
1916
 
        if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize != NULL) {
1917
 
                ATK_OBJECT_CLASS (accessible_parent_class)->initialize (obj, data);
1918
 
        }
1919
 
 
1920
 
        gtk_accessible_set_widget (GTK_ACCESSIBLE (obj), GTK_WIDGET (data));
1921
 
        g_signal_connect (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)),
1922
 
                          "value_changed",
1923
 
                          G_CALLBACK (eel_canvas_accessible_adjustment_changed),
1924
 
                          obj);
1925
 
        g_signal_connect (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)),
1926
 
                          "value_changed",
1927
 
                          G_CALLBACK (eel_canvas_accessible_adjustment_changed),
1928
 
                          obj);
1929
 
        
1930
 
        obj->role = ATK_ROLE_LAYERED_PANE;
1931
 
 
1932
 
        /* below adapted from gtkwidgetaccessible.c */
1933
 
 
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);
1950
 
}
1951
 
 
1952
 
static gint
1953
 
eel_canvas_accessible_get_n_children (AtkObject* obj)
1954
 
{
1955
 
        GtkAccessible *accessible;
1956
 
        GtkWidget *widget;
1957
 
        EelCanvas *canvas;
1958
 
        EelCanvasGroup *root_group;
1959
 
 
1960
 
        accessible = GTK_ACCESSIBLE (obj);
1961
 
        widget = gtk_accessible_get_widget (accessible);
1962
 
 
1963
 
        if (widget == NULL) {
1964
 
                return 0;
1965
 
        }
1966
 
 
1967
 
        g_return_val_if_fail (EEL_IS_CANVAS (widget), 0);
1968
 
 
1969
 
        canvas = EEL_CANVAS (widget);
1970
 
        root_group = eel_canvas_root (canvas);
1971
 
        g_return_val_if_fail (root_group, 0);
1972
 
 
1973
 
        return 1;
1974
 
}
1975
 
 
1976
 
static AtkObject*
1977
 
eel_canvas_accessible_ref_child (AtkObject *obj,
1978
 
                                 gint       i)
1979
 
{
1980
 
        GtkAccessible *accessible;
1981
 
        GtkWidget *widget;
1982
 
        EelCanvas *canvas;
1983
 
        EelCanvasGroup *root_group;
1984
 
        AtkObject *atk_object;
1985
 
 
1986
 
        /* Canvas only has one child, so return NULL if index is non zero */
1987
 
        if (i != 0) {
1988
 
                return NULL;
1989
 
        }
1990
 
 
1991
 
        accessible = GTK_ACCESSIBLE (obj);
1992
 
        widget = gtk_accessible_get_widget (accessible);
1993
 
 
1994
 
        if (widget == NULL) {
1995
 
                return NULL;
1996
 
        }
1997
 
 
1998
 
        canvas = EEL_CANVAS (widget);
1999
 
        root_group = eel_canvas_root (canvas);
2000
 
        g_return_val_if_fail (root_group, NULL);
2001
 
 
2002
 
        atk_object = atk_gobject_accessible_for_object (G_OBJECT (root_group));
2003
 
        
2004
 
        return g_object_ref (atk_object);
2005
 
}
2006
 
 
2007
 
static gboolean
2008
 
eel_canvas_accessible_all_parents_visible (GtkWidget *widget)
2009
 
{
2010
 
        GtkWidget *iter_parent = NULL;
2011
 
        gboolean result = TRUE;
2012
 
 
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)) {
2016
 
                        result = FALSE;
2017
 
                        break;
2018
 
                }
2019
 
        }
2020
 
 
2021
 
        return result;
2022
 
}
2023
 
 
2024
 
static gboolean
2025
 
eel_canvas_accessible_on_screen (GtkWidget *widget)
2026
 
{
2027
 
        GtkAllocation allocation;
2028
 
        GtkWidget *viewport;
2029
 
        gboolean return_value = TRUE;
2030
 
 
2031
 
        gtk_widget_get_allocation (widget, &allocation);
2032
 
 
2033
 
        viewport = gtk_widget_get_ancestor (widget, GTK_TYPE_VIEWPORT);
2034
 
 
2035
 
        if (viewport) {
2036
 
                GtkAllocation viewport_allocation;
2037
 
                GtkAdjustment *adjustment;
2038
 
                GdkRectangle visible_rect;
2039
 
 
2040
 
                gtk_widget_get_allocation (viewport, &viewport_allocation);
2041
 
 
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;
2048
 
 
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;
2054
 
                }
2055
 
        } else {
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.
2059
 
                 */
2060
 
                if (allocation.x + allocation.width <= 0 &&
2061
 
                    allocation.y + allocation.height <= 0) {
2062
 
                        return_value = FALSE;
2063
 
                }
2064
 
        }
2065
 
 
2066
 
        return return_value;
2067
 
}
2068
 
 
2069
 
static AtkStateSet *
2070
 
eel_canvas_accessible_ref_state_set (AtkObject *accessible)
2071
 
{
2072
 
        GtkWidget *widget;
2073
 
        AtkStateSet *state_set;
2074
 
 
2075
 
        widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
2076
 
        state_set = ATK_OBJECT_CLASS (accessible_parent_class)->ref_state_set (accessible);
2077
 
 
2078
 
        if (widget == NULL) {
2079
 
                atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
2080
 
        } else {
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);
2084
 
                }
2085
 
 
2086
 
                if (gtk_widget_get_can_focus (widget)) {
2087
 
                        atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
2088
 
                }
2089
 
                /*
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.
2095
 
                 *
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.
2107
 
                 */
2108
 
                if (gtk_widget_get_visible (widget)) {
2109
 
                        atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
2110
 
 
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);
2115
 
                        }
2116
 
                }
2117
 
 
2118
 
                if (gtk_widget_has_focus (widget)) {
2119
 
                        AtkObject *focus_obj;
2120
 
 
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);
2124
 
                        }
2125
 
                }
2126
 
 
2127
 
                if (gtk_widget_has_default (widget)) {
2128
 
                        atk_state_set_add_state (state_set, ATK_STATE_DEFAULT);
2129
 
                }
2130
 
        }
2131
 
        return state_set;
2132
 
}
2133
 
 
2134
 
static void
2135
 
eel_canvas_accessible_class_init (EelCanvasAccessibleClass *klass)
2136
 
{
2137
 
        AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
2138
 
 
2139
 
        accessible_parent_class = g_type_class_peek_parent (klass);
2140
 
 
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;
2146
 
}
2147
 
 
2148
 
static void
2149
 
eel_canvas_accessible_get_extents (AtkComponent   *component,
2150
 
                                   gint           *x,
2151
 
                                   gint           *y,
2152
 
                                   gint           *width,
2153
 
                                   gint           *height,
2154
 
                                   AtkCoordType    coord_type)
2155
 
{
2156
 
        GdkWindow *window;
2157
 
        gint x_window, y_window;
2158
 
        gint x_toplevel, y_toplevel;
2159
 
        GtkWidget *widget;
2160
 
        GtkAllocation allocation;
2161
 
 
2162
 
        widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
2163
 
 
2164
 
        if (widget == NULL) {
2165
 
                return;
2166
 
        }
2167
 
 
2168
 
        gtk_widget_get_allocation (widget, &allocation);
2169
 
        *width = allocation.width;
2170
 
        *height = allocation.height;
2171
 
 
2172
 
        if (!eel_canvas_accessible_on_screen (widget) ||
2173
 
            !gtk_widget_is_drawable (widget)) {
2174
 
                *x = G_MININT;
2175
 
                *y = G_MININT;
2176
 
 
2177
 
                return;
2178
 
        }
2179
 
 
2180
 
        if (gtk_widget_get_parent (widget)) {
2181
 
                *x = allocation.x;
2182
 
                *y = allocation.y;
2183
 
                window = gtk_widget_get_parent_window (widget);
2184
 
        } else {
2185
 
                *x = 0;
2186
 
                *y = 0;
2187
 
                window = gtk_widget_get_window (widget);
2188
 
        }
2189
 
 
2190
 
        gdk_window_get_origin (window, &x_window, &y_window);
2191
 
        *x += x_window;
2192
 
        *y += y_window;
2193
 
 
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);
2197
 
 
2198
 
                *x -= x_toplevel;
2199
 
                *y -= y_toplevel;
2200
 
        }
2201
 
}
2202
 
 
2203
 
static void
2204
 
eel_canvas_accessible_get_size (AtkComponent *component,
2205
 
                                gint         *width,
2206
 
                                gint         *height)
2207
 
{
2208
 
        GtkWidget *widget;
2209
 
 
2210
 
        widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
2211
 
 
2212
 
        if (widget == NULL) {
2213
 
          return;
2214
 
        }
2215
 
 
2216
 
        *width = gtk_widget_get_allocated_width (widget);
2217
 
        *height = gtk_widget_get_allocated_height (widget);
2218
 
}
2219
 
 
2220
 
static void
2221
 
eel_canvas_accessible_component_init(gpointer iface, gpointer data)
2222
 
{
2223
 
        AtkComponentIface *component;
2224
 
 
2225
 
        g_assert (G_TYPE_FROM_INTERFACE(iface) == ATK_TYPE_COMPONENT);
2226
 
 
2227
 
        component = iface;
2228
 
        component->get_extents = eel_canvas_accessible_get_extents;
2229
 
        component->get_size = eel_canvas_accessible_get_size;
2230
 
}
2231
 
 
2232
 
static void
2233
 
eel_canvas_accessible_init (EelCanvasAccessible *accessible)
2234
 
{
2235
 
}
2236
 
 
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))
2239
 
 
2240
 
static AtkObject *
2241
 
eel_canvas_accessible_create (GObject *for_object)
2242
 
{
2243
 
        GType type;
2244
 
        AtkObject *accessible;
2245
 
        EelCanvas *canvas;
2246
 
 
2247
 
        canvas = EEL_CANVAS (for_object);
2248
 
        g_return_val_if_fail (canvas != NULL, NULL);
2249
 
 
2250
 
        type = eel_canvas_accessible_get_type ();
2251
 
 
2252
 
        if (type == G_TYPE_INVALID) {
2253
 
                return atk_no_op_object_new (for_object);
2254
 
        }
2255
 
 
2256
 
        accessible = g_object_new (type, NULL);
2257
 
        atk_object_initialize (accessible, for_object);
2258
 
        return accessible;
2259
 
}
2260
 
 
2261
 
static GType
2262
 
eel_canvas_accessible_factory_get_accessible_type (void)
2263
 
{
2264
 
        return eel_canvas_accessible_get_type ();
2265
 
}
2266
 
 
2267
 
static AtkObject*
2268
 
eel_canvas_accessible_factory_create_accessible (GObject *obj)
2269
 
{
2270
 
        AtkObject *accessible;
2271
 
 
2272
 
        g_return_val_if_fail (G_IS_OBJECT (obj), NULL);
2273
 
 
2274
 
        accessible = eel_canvas_accessible_create (obj);
2275
 
 
2276
 
        return accessible;
2277
 
}
2278
 
 
2279
 
static void
2280
 
eel_canvas_accessible_factory_class_init (AtkObjectFactoryClass *klass)
2281
 
{
2282
 
        klass->create_accessible = eel_canvas_accessible_factory_create_accessible;
2283
 
        klass->get_accessible_type = eel_canvas_accessible_factory_get_accessible_type;
2284
 
}
2285
 
 
2286
 
static GType
2287
 
eel_canvas_accessible_factory_get_type (void)
2288
 
{
2289
 
        static GType type = 0;
2290
 
 
2291
 
        if (!type) {
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 */
2301
 
                        NULL
2302
 
                };
2303
 
                type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
2304
 
                                               "EelCanvasAccessibilityFactory",
2305
 
                                               &tinfo, 0);
2306
 
        }
2307
 
 
2308
 
        return type;
2309
 
}
2310
 
 
2311
 
 
2312
 
/* Class initialization function for EelCanvasClass */
2313
 
static void
2314
 
eel_canvas_class_init (EelCanvasClass *klass)
2315
 
{
2316
 
        GObjectClass   *gobject_class;
2317
 
        GtkWidgetClass *widget_class;
2318
 
 
2319
 
        gobject_class = (GObjectClass *)klass;
2320
 
        widget_class  = (GtkWidgetClass *) klass;
2321
 
 
2322
 
        canvas_parent_class = g_type_class_peek_parent (klass);
2323
 
 
2324
 
        gobject_class->set_property = eel_canvas_set_property;
2325
 
        gobject_class->get_property = eel_canvas_get_property;
2326
 
 
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;
2344
 
 
2345
 
        klass->draw_background = eel_canvas_draw_background;
2346
 
        klass->request_update = eel_canvas_request_update_real;
2347
 
 
2348
 
        canvas_signals[DRAW_BACKGROUND] =
2349
 
                g_signal_new ("draw_background",
2350
 
                              G_TYPE_FROM_CLASS (klass),
2351
 
                              G_SIGNAL_RUN_LAST,
2352
 
                              G_STRUCT_OFFSET (EelCanvasClass, draw_background),
2353
 
                              NULL, NULL,
2354
 
                              g_cclosure_marshal_VOID__BOXED,
2355
 
                              G_TYPE_NONE, 1,
2356
 
                              CAIRO_GOBJECT_TYPE_CONTEXT);
2357
 
 
2358
 
        atk_registry_set_factory_type (atk_get_default_registry (),
2359
 
                                       EEL_TYPE_CANVAS,
2360
 
                                       eel_canvas_accessible_factory_get_type ());
2361
 
}
2362
 
 
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.
2365
 
 */
2366
 
static void
2367
 
panic_root_destroyed (GtkWidget *object, gpointer data)
2368
 
{
2369
 
        g_error ("Eeeek, root item %p of canvas %p was destroyed!", object, data);
2370
 
}
2371
 
 
2372
 
/* Object initialization function for EelCanvas */
2373
 
static void
2374
 
eel_canvas_init (EelCanvas *canvas)
2375
 
{
2376
 
        guint width, height;
2377
 
        gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE);
2378
 
 
2379
 
        gtk_widget_set_redraw_on_allocate (GTK_WIDGET (canvas), FALSE);
2380
 
 
2381
 
        canvas->scroll_x1 = 0.0;
2382
 
        canvas->scroll_y1 = 0.0;
2383
 
        gtk_layout_get_size (GTK_LAYOUT (canvas),
2384
 
                             &width, &height);
2385
 
        canvas->scroll_x2 = width;
2386
 
        canvas->scroll_y2 = height;
2387
 
 
2388
 
        canvas->pixels_per_unit = 1.0;
2389
 
 
2390
 
        canvas->pick_event.type = GDK_LEAVE_NOTIFY;
2391
 
        canvas->pick_event.crossing.x = 0;
2392
 
        canvas->pick_event.crossing.y = 0;
2393
 
 
2394
 
        gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (canvas), NULL);
2395
 
        gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (canvas), NULL);
2396
 
 
2397
 
        /* Create the root item as a special case */
2398
 
 
2399
 
        canvas->root = EEL_CANVAS_ITEM (g_object_new (eel_canvas_group_get_type (), NULL));
2400
 
        canvas->root->canvas = canvas;
2401
 
 
2402
 
        g_object_ref_sink (canvas->root);
2403
 
 
2404
 
        canvas->root_destroy_id = g_signal_connect (G_OBJECT (canvas->root),
2405
 
                "destroy", G_CALLBACK (panic_root_destroyed), canvas);
2406
 
 
2407
 
        canvas->need_repick = TRUE;
2408
 
        canvas->doing_update = FALSE;
2409
 
}
2410
 
 
2411
 
/* Convenience function to remove the idle handler of a canvas */
2412
 
static void
2413
 
remove_idle (EelCanvas *canvas)
2414
 
{
2415
 
        if (canvas->idle_id == 0)
2416
 
                return;
2417
 
 
2418
 
        g_source_remove (canvas->idle_id);
2419
 
        canvas->idle_id = 0;
2420
 
}
2421
 
 
2422
 
/* Removes the transient state of the canvas (idle handler, grabs). */
2423
 
static void
2424
 
shutdown_transients (EelCanvas *canvas)
2425
 
{
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
2429
 
         * itself.
2430
 
         */
2431
 
        if (canvas->need_redraw) {
2432
 
                canvas->need_redraw = FALSE;
2433
 
        }
2434
 
 
2435
 
        if (canvas->grabbed_item) {
2436
 
                eel_canvas_item_ungrab (canvas->grabbed_item, GDK_CURRENT_TIME);
2437
 
        }
2438
 
 
2439
 
        remove_idle (canvas);
2440
 
}
2441
 
 
2442
 
/* Destroy handler for EelCanvas */
2443
 
static void
2444
 
eel_canvas_destroy (GtkWidget *object)
2445
 
{
2446
 
        EelCanvas *canvas;
2447
 
 
2448
 
        g_return_if_fail (EEL_IS_CANVAS (object));
2449
 
 
2450
 
        /* remember, destroy can be run multiple times! */
2451
 
 
2452
 
        canvas = EEL_CANVAS (object);
2453
 
 
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;
2457
 
        }
2458
 
        if (canvas->root) {
2459
 
                EelCanvasItem *root = canvas->root;
2460
 
                canvas->root = NULL;
2461
 
                eel_canvas_item_destroy (root);
2462
 
                g_object_unref (root);
2463
 
        }
2464
 
 
2465
 
        shutdown_transients (canvas);
2466
 
 
2467
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->destroy)
2468
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->destroy) (object);
2469
 
}
2470
 
 
2471
 
/**
2472
 
 * eel_canvas_new:
2473
 
 * @void:
2474
 
 *
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
2478
 
 * afterwards.
2479
 
 *
2480
 
 * Return value: A newly-created canvas.
2481
 
 **/
2482
 
GtkWidget *
2483
 
eel_canvas_new (void)
2484
 
{
2485
 
        return GTK_WIDGET (g_object_new (eel_canvas_get_type (), NULL));
2486
 
}
2487
 
 
2488
 
/* Map handler for the canvas */
2489
 
static void
2490
 
eel_canvas_map (GtkWidget *widget)
2491
 
{
2492
 
        EelCanvas *canvas;
2493
 
 
2494
 
        g_return_if_fail (EEL_IS_CANVAS (widget));
2495
 
 
2496
 
        /* Normal widget mapping stuff */
2497
 
 
2498
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->map)
2499
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->map) (widget);
2500
 
 
2501
 
        canvas = EEL_CANVAS (widget);
2502
 
 
2503
 
        /* Map items */
2504
 
 
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);
2509
 
}
2510
 
 
2511
 
/* Unmap handler for the canvas */
2512
 
static void
2513
 
eel_canvas_unmap (GtkWidget *widget)
2514
 
{
2515
 
        EelCanvas *canvas;
2516
 
 
2517
 
        g_return_if_fail (EEL_IS_CANVAS (widget));
2518
 
 
2519
 
        canvas = EEL_CANVAS (widget);
2520
 
 
2521
 
        shutdown_transients (canvas);
2522
 
 
2523
 
        /* Unmap items */
2524
 
 
2525
 
        if (EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap)
2526
 
                (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (canvas->root);
2527
 
 
2528
 
        /* Normal widget unmapping stuff */
2529
 
 
2530
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->unmap)
2531
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (widget);
2532
 
}
2533
 
 
2534
 
/* Realize handler for the canvas */
2535
 
static void
2536
 
eel_canvas_realize (GtkWidget *widget)
2537
 
{
2538
 
        EelCanvas *canvas;
2539
 
 
2540
 
        g_return_if_fail (EEL_IS_CANVAS (widget));
2541
 
 
2542
 
        /* Normal widget realization stuff */
2543
 
 
2544
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->realize)
2545
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->realize) (widget);
2546
 
 
2547
 
        canvas = EEL_CANVAS (widget);
2548
 
 
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)))
2551
 
                                 | GDK_EXPOSURE_MASK
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));
2560
 
 
2561
 
        /* Create our own temporary pixmap gc and realize all the items */
2562
 
 
2563
 
        (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->realize) (canvas->root);
2564
 
}
2565
 
 
2566
 
/* Unrealize handler for the canvas */
2567
 
static void
2568
 
eel_canvas_unrealize (GtkWidget *widget)
2569
 
{
2570
 
        EelCanvas *canvas;
2571
 
 
2572
 
        g_return_if_fail (EEL_IS_CANVAS (widget));
2573
 
 
2574
 
        canvas = EEL_CANVAS (widget);
2575
 
 
2576
 
        shutdown_transients (canvas);
2577
 
 
2578
 
        /* Unrealize items and parent widget */
2579
 
 
2580
 
        (* EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->unrealize) (canvas->root);
2581
 
 
2582
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize)
2583
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget);
2584
 
}
2585
 
 
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.
2588
 
 */
2589
 
static void
2590
 
scroll_to (EelCanvas *canvas, int cx, int cy)
2591
 
{
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;
2600
 
 
2601
 
        gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation);
2602
 
        canvas_width = allocation.width;
2603
 
        canvas_height = allocation.height;
2604
 
 
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);
2607
 
 
2608
 
        right_limit = scroll_width - canvas_width;
2609
 
        bottom_limit = scroll_height - canvas_height;
2610
 
 
2611
 
        old_zoom_xofs = canvas->zoom_xofs;
2612
 
        old_zoom_yofs = canvas->zoom_yofs;
2613
 
 
2614
 
        if (right_limit < 0) {
2615
 
                cx = 0;
2616
 
                if (canvas->center_scroll_region) {
2617
 
                        canvas->zoom_xofs = (canvas_width - scroll_width) / 2;
2618
 
                        scroll_width = canvas_width;
2619
 
                } else {
2620
 
                        canvas->zoom_xofs = 0;
2621
 
                }
2622
 
        } else if (cx < 0) {
2623
 
                cx = 0;
2624
 
                canvas->zoom_xofs = 0;
2625
 
        } else if (cx > right_limit) {
2626
 
                cx = right_limit;
2627
 
                canvas->zoom_xofs = 0;
2628
 
        } else
2629
 
                canvas->zoom_xofs = 0;
2630
 
 
2631
 
        if (bottom_limit < 0) {
2632
 
                cy = 0;
2633
 
                if (canvas->center_scroll_region) {
2634
 
                        canvas->zoom_yofs = (canvas_height - scroll_height) / 2;
2635
 
                        scroll_height = canvas_height;
2636
 
                } else {
2637
 
                        canvas->zoom_yofs = 0;
2638
 
                }
2639
 
        } else if (cy < 0) {
2640
 
                cy = 0;
2641
 
                canvas->zoom_yofs = 0;
2642
 
        } else if (cy > bottom_limit) {
2643
 
                cy = bottom_limit;
2644
 
                canvas->zoom_yofs = 0;
2645
 
        } else
2646
 
                canvas->zoom_yofs = 0;
2647
 
 
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);
2655
 
                }
2656
 
                gtk_widget_queue_draw (GTK_WIDGET (canvas));
2657
 
        }
2658
 
 
2659
 
        hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
2660
 
        vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
2661
 
 
2662
 
        if (((int) gtk_adjustment_get_value (hadjustment)) != cx) {
2663
 
                gtk_adjustment_set_value (hadjustment, cx);
2664
 
                changed_x = TRUE;
2665
 
        }
2666
 
 
2667
 
        if (((int) gtk_adjustment_get_value (vadjustment)) != cy) {
2668
 
                gtk_adjustment_set_value (vadjustment, cy);
2669
 
                changed_y = TRUE;
2670
 
        }
2671
 
 
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);
2675
 
        }
2676
 
        
2677
 
        /* Signal GtkLayout that it should do a redraw. */
2678
 
        if (changed_x)
2679
 
                g_signal_emit_by_name (hadjustment, "value_changed");
2680
 
        if (changed_y)
2681
 
                g_signal_emit_by_name (vadjustment, "value_changed");
2682
 
}
2683
 
 
2684
 
/* Size allocation handler for the canvas */
2685
 
static void
2686
 
eel_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
2687
 
{
2688
 
        EelCanvas *canvas;
2689
 
        GtkAdjustment *vadjustment, *hadjustment;
2690
 
 
2691
 
        g_return_if_fail (EEL_IS_CANVAS (widget));
2692
 
        g_return_if_fail (allocation != NULL);
2693
 
 
2694
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate)
2695
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (widget, allocation);
2696
 
 
2697
 
        canvas = EEL_CANVAS (widget);
2698
 
 
2699
 
        /* Recenter the view, if appropriate */
2700
 
 
2701
 
        hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
2702
 
        vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
2703
 
 
2704
 
        gtk_adjustment_set_page_size (hadjustment, allocation->width);
2705
 
        gtk_adjustment_set_page_increment (hadjustment, allocation->width / 2);
2706
 
 
2707
 
        gtk_adjustment_set_page_size (vadjustment, allocation->height);
2708
 
        gtk_adjustment_set_page_increment (vadjustment, allocation->height / 2);
2709
 
 
2710
 
        scroll_to (canvas,
2711
 
                   gtk_adjustment_get_value (hadjustment),
2712
 
                   gtk_adjustment_get_value (vadjustment));
2713
 
 
2714
 
        g_signal_emit_by_name (hadjustment, "changed");
2715
 
        g_signal_emit_by_name (vadjustment, "changed");
2716
 
}
2717
 
 
2718
 
/* Emits an event for an item in the canvas, be it the current item, grabbed
2719
 
 * item, or focused item, as appropriate.
2720
 
 */
2721
 
 
2722
 
static int
2723
 
emit_event (EelCanvas *canvas, GdkEvent *event)
2724
 
{
2725
 
        GdkEvent ev;
2726
 
        gint finished;
2727
 
        EelCanvasItem *item;
2728
 
        EelCanvasItem *parent;
2729
 
        guint mask;
2730
 
 
2731
 
        /* Could be an old pick event */
2732
 
        if (!gtk_widget_get_realized (GTK_WIDGET (canvas))) {
2733
 
                return FALSE;
2734
 
        }
2735
 
 
2736
 
        /* Perform checks for grabbed items */
2737
 
 
2738
 
        if (canvas->grabbed_item &&
2739
 
            !is_descendant (canvas->current_item, canvas->grabbed_item)) {
2740
 
                return FALSE;
2741
 
        }
2742
 
 
2743
 
        if (canvas->grabbed_item) {
2744
 
                switch (event->type) {
2745
 
                case GDK_ENTER_NOTIFY:
2746
 
                        mask = GDK_ENTER_NOTIFY_MASK;
2747
 
                        break;
2748
 
 
2749
 
                case GDK_LEAVE_NOTIFY:
2750
 
                        mask = GDK_LEAVE_NOTIFY_MASK;
2751
 
                        break;
2752
 
 
2753
 
                case GDK_MOTION_NOTIFY:
2754
 
                        mask = GDK_POINTER_MOTION_MASK;
2755
 
                        break;
2756
 
 
2757
 
                case GDK_BUTTON_PRESS:
2758
 
                case GDK_2BUTTON_PRESS:
2759
 
                case GDK_3BUTTON_PRESS:
2760
 
                        mask = GDK_BUTTON_PRESS_MASK;
2761
 
                        break;
2762
 
 
2763
 
                case GDK_BUTTON_RELEASE:
2764
 
                        mask = GDK_BUTTON_RELEASE_MASK;
2765
 
                        break;
2766
 
 
2767
 
                case GDK_KEY_PRESS:
2768
 
                        mask = GDK_KEY_PRESS_MASK;
2769
 
                        break;
2770
 
 
2771
 
                case GDK_KEY_RELEASE:
2772
 
                        mask = GDK_KEY_RELEASE_MASK;
2773
 
                        break;
2774
 
 
2775
 
                default:
2776
 
                        mask = 0;
2777
 
                        break;
2778
 
                }
2779
 
 
2780
 
                if (!(mask & canvas->grabbed_event_mask))
2781
 
                        return FALSE;
2782
 
        }
2783
 
 
2784
 
        /* Convert to world coordinates -- we have two cases because of diferent
2785
 
         * offsets of the fields in the event structures.
2786
 
         */
2787
 
 
2788
 
        ev = *event;
2789
 
 
2790
 
        switch (ev.type)
2791
 
        {
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);
2797
 
                break;
2798
 
 
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);
2803
 
                break;
2804
 
 
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);
2811
 
                break;
2812
 
 
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);
2817
 
                break;
2818
 
 
2819
 
        default:
2820
 
                break;
2821
 
        }
2822
 
 
2823
 
        /* Choose where we send the event */
2824
 
 
2825
 
        item = canvas->current_item;
2826
 
 
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;
2832
 
 
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.
2836
 
         */
2837
 
 
2838
 
        finished = FALSE;
2839
 
 
2840
 
        while (item && !finished) {
2841
 
                g_object_ref (item);
2842
 
 
2843
 
                g_signal_emit (
2844
 
                       G_OBJECT (item), item_signals[ITEM_EVENT], 0,
2845
 
                        &ev, &finished);
2846
 
                
2847
 
                parent = item->parent;
2848
 
                g_object_unref (item);
2849
 
 
2850
 
                item = parent;
2851
 
        }
2852
 
 
2853
 
        return finished;
2854
 
}
2855
 
 
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.
2858
 
 */
2859
 
static int
2860
 
pick_current_item (EelCanvas *canvas, GdkEvent *event)
2861
 
{
2862
 
        int button_down;
2863
 
        double x, y;
2864
 
        int cx, cy;
2865
 
        int retval;
2866
 
 
2867
 
        retval = FALSE;
2868
 
 
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.
2872
 
         */
2873
 
        button_down = canvas->state & (GDK_BUTTON1_MASK
2874
 
                                       | GDK_BUTTON2_MASK
2875
 
                                       | GDK_BUTTON3_MASK
2876
 
                                       | GDK_BUTTON4_MASK
2877
 
                                       | GDK_BUTTON5_MASK);
2878
 
        if (!button_down)
2879
 
                canvas->left_grabbed_item = FALSE;
2880
 
 
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.
2885
 
         */
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 */
2889
 
 
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;
2900
 
 
2901
 
                        /* these fields don't have the same offsets in both types of events */
2902
 
 
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;
2906
 
                        } else {
2907
 
                                canvas->pick_event.crossing.x_root = event->button.x_root;
2908
 
                                canvas->pick_event.crossing.y_root = event->button.y_root;
2909
 
                        }
2910
 
                } else
2911
 
                        canvas->pick_event = *event;
2912
 
        }
2913
 
 
2914
 
        /* Don't do anything else if this is a recursive call */
2915
 
 
2916
 
        if (canvas->in_repick)
2917
 
                return retval;
2918
 
 
2919
 
        /* LeaveNotify means that there is no current item, so we don't look for one */
2920
 
 
2921
 
        if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
2922
 
                /* these fields don't have the same offsets in both types of events */
2923
 
 
2924
 
                if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
2925
 
                        x = canvas->pick_event.crossing.x;
2926
 
                        y = canvas->pick_event.crossing.y;
2927
 
                } else {
2928
 
                        x = canvas->pick_event.motion.x;
2929
 
                        y = canvas->pick_event.motion.y;
2930
 
                }
2931
 
 
2932
 
                /* canvas pixel coords */
2933
 
 
2934
 
                cx = (int) (x + 0.5);
2935
 
                cy = (int) (y + 0.5);
2936
 
 
2937
 
                /* world coords */
2938
 
                eel_canvas_c2w (canvas, cx, cy, &x, &y);
2939
 
 
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);
2944
 
                else
2945
 
                        canvas->new_current_item = NULL;
2946
 
        } else
2947
 
                canvas->new_current_item = NULL;
2948
 
 
2949
 
        if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item)
2950
 
                return retval; /* current item did not change */
2951
 
 
2952
 
        /* Synthesize events for old and new current items */
2953
 
 
2954
 
        if ((canvas->new_current_item != canvas->current_item)
2955
 
            && (canvas->current_item != NULL)
2956
 
            && !canvas->left_grabbed_item) {
2957
 
                GdkEvent new_event;
2958
 
 
2959
 
                new_event = canvas->pick_event;
2960
 
                new_event.type = GDK_LEAVE_NOTIFY;
2961
 
 
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;
2967
 
        }
2968
 
 
2969
 
        /* new_current_item may have been set to NULL during the call to emit_event() above */
2970
 
 
2971
 
        if ((canvas->new_current_item != canvas->current_item) && button_down) {
2972
 
                canvas->left_grabbed_item = TRUE;
2973
 
                return retval;
2974
 
        }
2975
 
 
2976
 
        /* Handle the rest of cases */
2977
 
 
2978
 
        canvas->left_grabbed_item = FALSE;
2979
 
        canvas->current_item = canvas->new_current_item;
2980
 
 
2981
 
        if (canvas->current_item != NULL) {
2982
 
                GdkEvent new_event;
2983
 
 
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);
2989
 
        }
2990
 
 
2991
 
        return retval;
2992
 
}
2993
 
 
2994
 
/* Button event handler for the canvas */
2995
 
static gint
2996
 
eel_canvas_button (GtkWidget *widget, GdkEventButton *event)
2997
 
{
2998
 
        EelCanvas *canvas;
2999
 
        int mask;
3000
 
        int retval;
3001
 
 
3002
 
        g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3003
 
        g_return_val_if_fail (event != NULL, FALSE);
3004
 
 
3005
 
        retval = FALSE;
3006
 
 
3007
 
        canvas = EEL_CANVAS (widget);
3008
 
 
3009
 
        /* Don't handle extra mouse button events */
3010
 
        if (event->button > 5)
3011
 
                return FALSE;
3012
 
 
3013
 
        /*
3014
 
         * dispatch normally regardless of the event's window if an item has
3015
 
         * has a pointer grab in effect
3016
 
         */
3017
 
        if (!canvas->grabbed_item && event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
3018
 
                return retval;
3019
 
 
3020
 
        switch (event->button) {
3021
 
        case 1:
3022
 
                mask = GDK_BUTTON1_MASK;
3023
 
                break;
3024
 
        case 2:
3025
 
                mask = GDK_BUTTON2_MASK;
3026
 
                break;
3027
 
        case 3:
3028
 
                mask = GDK_BUTTON3_MASK;
3029
 
                break;
3030
 
        case 4:
3031
 
                mask = GDK_BUTTON4_MASK;
3032
 
                break;
3033
 
        case 5:
3034
 
                mask = GDK_BUTTON5_MASK;
3035
 
                break;
3036
 
        default:
3037
 
                mask = 0;
3038
 
        }
3039
 
 
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.
3046
 
                 */
3047
 
                canvas->state = event->state;
3048
 
                pick_current_item (canvas, (GdkEvent *) event);
3049
 
                canvas->state ^= mask;
3050
 
                retval = emit_event (canvas, (GdkEvent *) event);
3051
 
                break;
3052
 
 
3053
 
        case GDK_BUTTON_RELEASE:
3054
 
                /* Process the event as if the button were pressed, then repick
3055
 
                 * after the button has been released
3056
 
                 */
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;
3063
 
                break;
3064
 
 
3065
 
        default:
3066
 
                g_assert_not_reached ();
3067
 
        }
3068
 
 
3069
 
        return retval;
3070
 
}
3071
 
 
3072
 
/* Motion event handler for the canvas */
3073
 
static gint
3074
 
eel_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
3075
 
{
3076
 
        EelCanvas *canvas;
3077
 
 
3078
 
        g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3079
 
        g_return_val_if_fail (event != NULL, FALSE);
3080
 
 
3081
 
        canvas = EEL_CANVAS (widget);
3082
 
 
3083
 
        if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
3084
 
                return FALSE;
3085
 
 
3086
 
        canvas->state = event->state;
3087
 
        pick_current_item (canvas, (GdkEvent *) event);
3088
 
        return emit_event (canvas, (GdkEvent *) event);
3089
 
}
3090
 
 
3091
 
/* Key event handler for the canvas */
3092
 
static gint
3093
 
eel_canvas_key (GtkWidget *widget, GdkEventKey *event)
3094
 
{
3095
 
        EelCanvas *canvas;
3096
 
        
3097
 
        g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3098
 
        g_return_val_if_fail (event != NULL, FALSE);
3099
 
 
3100
 
        canvas = EEL_CANVAS (widget);
3101
 
        
3102
 
        if (emit_event (canvas, (GdkEvent *) event))
3103
 
                return TRUE;
3104
 
        if (event->type == GDK_KEY_RELEASE)
3105
 
                return GTK_WIDGET_CLASS (canvas_parent_class)->key_release_event (widget, event);
3106
 
        else
3107
 
                return GTK_WIDGET_CLASS (canvas_parent_class)->key_press_event (widget, event);
3108
 
}
3109
 
 
3110
 
 
3111
 
/* Crossing event handler for the canvas */
3112
 
static gint
3113
 
eel_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event)
3114
 
{
3115
 
        EelCanvas *canvas;
3116
 
 
3117
 
        g_return_val_if_fail (EEL_IS_CANVAS (widget), FALSE);
3118
 
        g_return_val_if_fail (event != NULL, FALSE);
3119
 
 
3120
 
        canvas = EEL_CANVAS (widget);
3121
 
 
3122
 
        if (event->window != gtk_layout_get_bin_window (GTK_LAYOUT (canvas)))
3123
 
                return FALSE;
3124
 
 
3125
 
        canvas->state = event->state;
3126
 
        return pick_current_item (canvas, (GdkEvent *) event);
3127
 
}
3128
 
 
3129
 
/* Focus in handler for the canvas */
3130
 
static gint
3131
 
eel_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event)
3132
 
{
3133
 
        EelCanvas *canvas;
3134
 
 
3135
 
        canvas = EEL_CANVAS (widget);
3136
 
 
3137
 
        if (canvas->focused_item)
3138
 
                return emit_event (canvas, (GdkEvent *) event);
3139
 
        else
3140
 
                return FALSE;
3141
 
}
3142
 
 
3143
 
static AtkObject *
3144
 
eel_canvas_get_accessible (GtkWidget *widget)
3145
 
{
3146
 
        return atk_gobject_accessible_for_object (G_OBJECT (widget));
3147
 
}
3148
 
 
3149
 
/* Focus out handler for the canvas */
3150
 
static gint
3151
 
eel_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event)
3152
 
{
3153
 
        EelCanvas *canvas;
3154
 
 
3155
 
        canvas = EEL_CANVAS (widget);
3156
 
 
3157
 
        if (canvas->focused_item)
3158
 
                return emit_event (canvas, (GdkEvent *) event);
3159
 
        else
3160
 
                return FALSE;
3161
 
}
3162
 
 
3163
 
 
3164
 
static cairo_region_t *
3165
 
eel_cairo_get_clip_region (cairo_t *cr)
3166
 
{
3167
 
        cairo_rectangle_list_t *list;
3168
 
        cairo_region_t *region;
3169
 
        int i;
3170
 
 
3171
 
        list = cairo_copy_clip_rectangle_list (cr);
3172
 
        if (list->status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) {
3173
 
                cairo_rectangle_int_t clip_rect;
3174
 
 
3175
 
                cairo_rectangle_list_destroy (list);
3176
 
 
3177
 
                if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect))
3178
 
                        return NULL;
3179
 
                return cairo_region_create_rectangle (&clip_rect);
3180
 
        }
3181
 
 
3182
 
 
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;
3187
 
 
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;
3192
 
 
3193
 
                if (cairo_region_union_rectangle (region, &clip_rect) != CAIRO_STATUS_SUCCESS) {
3194
 
                        cairo_region_destroy (region);
3195
 
                        region = NULL;
3196
 
                        break;
3197
 
                }
3198
 
        }
3199
 
 
3200
 
        cairo_rectangle_list_destroy (list);
3201
 
        return region;
3202
 
}
3203
 
 
3204
 
/* Expose handler for the canvas */
3205
 
static gboolean
3206
 
eel_canvas_draw (GtkWidget *widget, cairo_t *cr)
3207
 
{
3208
 
        EelCanvas *canvas = EEL_CANVAS (widget);
3209
 
        GdkWindow *bin_window;
3210
 
        cairo_region_t *region;
3211
 
 
3212
 
        if (!gdk_cairo_get_clip_rectangle (cr, NULL))
3213
 
                return FALSE;
3214
 
 
3215
 
        bin_window = gtk_layout_get_bin_window (GTK_LAYOUT (widget));
3216
 
        gtk_cairo_transform_to_window (cr, widget, bin_window);
3217
 
 
3218
 
        region = eel_cairo_get_clip_region (cr);
3219
 
        if (region == NULL)
3220
 
                return FALSE;
3221
 
 
3222
 
#ifdef VERBOSE
3223
 
        g_print ("Draw\n");
3224
 
#endif
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;
3229
 
        }
3230
 
        if (canvas->need_update) {
3231
 
                g_return_val_if_fail (!canvas->doing_update, FALSE);
3232
 
 
3233
 
                canvas->doing_update = TRUE;
3234
 
                eel_canvas_item_invoke_update (canvas->root, 0, 0, 0);
3235
 
 
3236
 
                g_return_val_if_fail (canvas->doing_update, FALSE);
3237
 
 
3238
 
                canvas->doing_update = FALSE;
3239
 
 
3240
 
                canvas->need_update = FALSE;
3241
 
        }
3242
 
 
3243
 
        /* Hmmm. Would like to queue antiexposes if the update marked
3244
 
           anything that is gonna get redrawn as invalid */
3245
 
        
3246
 
        g_signal_emit (G_OBJECT (canvas), canvas_signals[DRAW_BACKGROUND], 0,
3247
 
                       cr);
3248
 
        
3249
 
        if (canvas->root->flags & EEL_CANVAS_ITEM_MAPPED)
3250
 
                EEL_CANVAS_ITEM_GET_CLASS (canvas->root)->draw (canvas->root, cr, region);
3251
 
 
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);
3255
 
 
3256
 
        cairo_region_destroy (region);
3257
 
        return FALSE;
3258
 
}
3259
 
 
3260
 
static void
3261
 
eel_canvas_draw_background (EelCanvas *canvas,
3262
 
                            cairo_t   *cr)
3263
 
{
3264
 
        cairo_rectangle_int_t rect;
3265
 
        GtkStyleContext *style_context;
3266
 
        GdkRGBA color;
3267
 
 
3268
 
        if (!gdk_cairo_get_clip_rectangle (cr, &rect))
3269
 
              return;
3270
 
 
3271
 
        cairo_save (cr);
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);
3277
 
        cairo_fill (cr);
3278
 
        cairo_restore (cr);
3279
 
}
3280
 
 
3281
 
static void
3282
 
do_update (EelCanvas *canvas)
3283
 
{
3284
 
        /* Cause the update if necessary */
3285
 
 
3286
 
update_again:
3287
 
        if (canvas->need_update) {
3288
 
                g_return_if_fail (!canvas->doing_update);
3289
 
 
3290
 
                canvas->doing_update = TRUE;
3291
 
                eel_canvas_item_invoke_update (canvas->root, 0, 0, 0);
3292
 
 
3293
 
                g_return_if_fail (canvas->doing_update);
3294
 
 
3295
 
                canvas->doing_update = FALSE;
3296
 
 
3297
 
                canvas->need_update = FALSE;
3298
 
        }
3299
 
 
3300
 
        /* Pick new current item */
3301
 
 
3302
 
        while (canvas->need_repick) {
3303
 
                canvas->need_repick = FALSE;
3304
 
                pick_current_item (canvas, &canvas->pick_event);
3305
 
        }
3306
 
 
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) {
3313
 
                goto update_again;
3314
 
        }
3315
 
}
3316
 
 
3317
 
/* Idle handler for the canvas.  It deals with pending updates and redraws. */
3318
 
static gint
3319
 
idle_handler (gpointer data)
3320
 
{
3321
 
        EelCanvas *canvas;
3322
 
 
3323
 
        canvas = EEL_CANVAS (data);
3324
 
        do_update (canvas);
3325
 
 
3326
 
        /* Reset idle id */
3327
 
        canvas->idle_id = 0;
3328
 
 
3329
 
        return FALSE;
3330
 
}
3331
 
 
3332
 
/* Convenience function to add an idle handler to a canvas */
3333
 
static void
3334
 
add_idle (EelCanvas *canvas)
3335
 
{
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
3340
 
                 * expose_event.
3341
 
                 */
3342
 
                canvas->idle_id = g_idle_add_full (GDK_PRIORITY_REDRAW - 20,
3343
 
                                                   idle_handler, canvas, NULL);
3344
 
        }
3345
 
}
3346
 
 
3347
 
/**
3348
 
 * eel_canvas_root:
3349
 
 * @canvas: A canvas.
3350
 
 *
3351
 
 * Queries the root group of a canvas.
3352
 
 *
3353
 
 * Return value: The root group of the specified canvas.
3354
 
 **/
3355
 
EelCanvasGroup *
3356
 
eel_canvas_root (EelCanvas *canvas)
3357
 
{
3358
 
        g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL);
3359
 
 
3360
 
        return EEL_CANVAS_GROUP (canvas->root);
3361
 
}
3362
 
 
3363
 
 
3364
 
/**
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.
3371
 
 *
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.
3375
 
 **/
3376
 
void
3377
 
eel_canvas_set_scroll_region (EelCanvas *canvas, double x1, double y1, double x2, double y2)
3378
 
{
3379
 
        double wxofs, wyofs;
3380
 
        int xofs, yofs;
3381
 
        GtkAdjustment *vadjustment, *hadjustment;
3382
 
 
3383
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3384
 
 
3385
 
        if ((canvas->scroll_x1 == x1) && (canvas->scroll_y1 == y1) &&
3386
 
            (canvas->scroll_x2 == x2) && (canvas->scroll_y2 == y2)) {
3387
 
                return;
3388
 
        }
3389
 
        
3390
 
        /*
3391
 
         * Set the new scrolling region.  If possible, do not move the visible contents of the
3392
 
         * canvas.
3393
 
         */
3394
 
        hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
3395
 
        vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
3396
 
 
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,*/
3402
 
                          &wxofs, &wyofs);
3403
 
 
3404
 
        canvas->scroll_x1 = x1;
3405
 
        canvas->scroll_y1 = y1;
3406
 
        canvas->scroll_x2 = x2;
3407
 
        canvas->scroll_y2 = y2;
3408
 
 
3409
 
        eel_canvas_w2c (canvas, wxofs, wyofs, &xofs, &yofs);
3410
 
 
3411
 
        scroll_to (canvas, xofs, yofs);
3412
 
 
3413
 
        canvas->need_repick = TRUE;
3414
 
 
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);
3418
 
        }
3419
 
}
3420
 
 
3421
 
 
3422
 
/**
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).
3429
 
 *
3430
 
 * Queries the scrolling region of a canvas.
3431
 
 **/
3432
 
void
3433
 
eel_canvas_get_scroll_region (EelCanvas *canvas, double *x1, double *y1, double *x2, double *y2)
3434
 
{
3435
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3436
 
 
3437
 
        if (x1)
3438
 
                *x1 = canvas->scroll_x1;
3439
 
 
3440
 
        if (y1)
3441
 
                *y1 = canvas->scroll_y1;
3442
 
 
3443
 
        if (x2)
3444
 
                *x2 = canvas->scroll_x2;
3445
 
 
3446
 
        if (y2)
3447
 
                *y2 = canvas->scroll_y2;
3448
 
}
3449
 
 
3450
 
void
3451
 
eel_canvas_set_center_scroll_region (EelCanvas *canvas,
3452
 
                                     gboolean center_scroll_region)
3453
 
{
3454
 
        GtkAdjustment *vadjustment, *hadjustment;
3455
 
 
3456
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3457
 
 
3458
 
        canvas->center_scroll_region = center_scroll_region != 0;
3459
 
 
3460
 
        hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (&canvas->layout));
3461
 
        vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (&canvas->layout));
3462
 
 
3463
 
        scroll_to (canvas,
3464
 
                   gtk_adjustment_get_value (hadjustment),
3465
 
                   gtk_adjustment_get_value (vadjustment));
3466
 
}
3467
 
 
3468
 
 
3469
 
/**
3470
 
 * eel_canvas_set_pixels_per_unit:
3471
 
 * @canvas: A canvas.
3472
 
 * @n: The number of pixels that correspond to one canvas unit.
3473
 
 *
3474
 
 * Sets the zooming factor of a canvas by specifying the number of pixels that
3475
 
 * correspond to one canvas unit.
3476
 
 **/
3477
 
void
3478
 
eel_canvas_set_pixels_per_unit (EelCanvas *canvas, double n)
3479
 
{
3480
 
        GtkWidget *widget;
3481
 
        double cx, cy;
3482
 
        int x1, y1;
3483
 
        int center_x, center_y;
3484
 
        GdkWindow *window;
3485
 
        GdkWindowAttr attributes;
3486
 
        gint attributes_mask;
3487
 
        GtkAllocation allocation;
3488
 
        GtkAdjustment *vadjustment, *hadjustment;
3489
 
 
3490
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3491
 
        g_return_if_fail (n > EEL_CANVAS_EPSILON);
3492
 
 
3493
 
        widget = GTK_WIDGET (canvas);
3494
 
 
3495
 
        gtk_widget_get_allocation (widget, &allocation);
3496
 
        center_x = allocation.width / 2;
3497
 
        center_y = allocation.height / 2;
3498
 
 
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;
3504
 
 
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;
3508
 
 
3509
 
        canvas->pixels_per_unit = n;
3510
 
 
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);
3514
 
        }
3515
 
 
3516
 
        /* Map a background None window over the bin_window to avoid
3517
 
         * scrolling the window scroll causing exposes.
3518
 
         */
3519
 
        window = NULL;
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;
3531
 
                
3532
 
                attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3533
 
                
3534
 
                window = gdk_window_new (gtk_widget_get_parent_window (widget),
3535
 
                                         &attributes, attributes_mask);
3536
 
                gdk_window_set_user_data (window, widget);
3537
 
                
3538
 
                gdk_window_show (window);
3539
 
        }
3540
 
 
3541
 
        scroll_to (canvas, x1, y1);
3542
 
 
3543
 
        /* If we created a an overlapping background None window, remove it how.
3544
 
         *
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.
3549
 
         */
3550
 
        if (window != NULL) {
3551
 
                gdk_window_hide (window);
3552
 
                gdk_window_set_user_data (window, NULL);
3553
 
                gdk_window_destroy (window);
3554
 
        }
3555
 
 
3556
 
        canvas->need_repick = TRUE;
3557
 
}
3558
 
 
3559
 
/**
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.
3564
 
 *
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.
3569
 
 **/
3570
 
void
3571
 
eel_canvas_scroll_to (EelCanvas *canvas, int cx, int cy)
3572
 
{
3573
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3574
 
 
3575
 
        scroll_to (canvas, cx, cy);
3576
 
}
3577
 
 
3578
 
/**
3579
 
 * eel_canvas_get_scroll_offsets:
3580
 
 * @canvas: A canvas.
3581
 
 * @cx: Horizontal scrolling offset (return value).
3582
 
 * @cy: Vertical scrolling offset (return value).
3583
 
 *
3584
 
 * Queries the scrolling offsets of a canvas.  The values are returned in canvas
3585
 
 * pixel units.
3586
 
 **/
3587
 
void
3588
 
eel_canvas_get_scroll_offsets (EelCanvas *canvas, int *cx, int *cy)
3589
 
{
3590
 
        GtkAdjustment *vadjustment, *hadjustment;
3591
 
 
3592
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3593
 
 
3594
 
        hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
3595
 
        vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
3596
 
 
3597
 
        if (cx)
3598
 
                *cx = gtk_adjustment_get_value (hadjustment);
3599
 
 
3600
 
        if (cy)
3601
 
                *cy = gtk_adjustment_get_value (vadjustment);
3602
 
}
3603
 
 
3604
 
/**
3605
 
 * eel_canvas_update_now:
3606
 
 * @canvas: A canvas.
3607
 
 *
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.
3612
 
 */
3613
 
void
3614
 
eel_canvas_update_now (EelCanvas *canvas)
3615
 
{
3616
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3617
 
 
3618
 
        if (!(canvas->need_update || canvas->need_redraw))
3619
 
                return;
3620
 
        remove_idle (canvas);
3621
 
        do_update (canvas);
3622
 
}
3623
 
 
3624
 
/**
3625
 
 * eel_canvas_get_item_at:
3626
 
 * @canvas: A canvas.
3627
 
 * @x: X position in world coordinates.
3628
 
 * @y: Y position in world coordinates.
3629
 
 *
3630
 
 * Looks for the item that is under the specified position, which must be
3631
 
 * specified in world coordinates.
3632
 
 *
3633
 
 * Return value: The sought item, or NULL if no item is at the specified
3634
 
 * coordinates.
3635
 
 **/
3636
 
EelCanvasItem *
3637
 
eel_canvas_get_item_at (EelCanvas *canvas, double x, double y)
3638
 
{
3639
 
        EelCanvasItem *item;
3640
 
        double dist;
3641
 
        int cx, cy;
3642
 
 
3643
 
        g_return_val_if_fail (EEL_IS_CANVAS (canvas), NULL);
3644
 
 
3645
 
        eel_canvas_w2c (canvas, x, y, &cx, &cy);
3646
 
 
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)
3649
 
                return item;
3650
 
        else
3651
 
                return NULL;
3652
 
}
3653
 
 
3654
 
/* Queues an update of the canvas */
3655
 
static void
3656
 
eel_canvas_request_update (EelCanvas *canvas)
3657
 
{
3658
 
        EEL_CANVAS_GET_CLASS (canvas)->request_update (canvas);
3659
 
}
3660
 
 
3661
 
static void
3662
 
eel_canvas_request_update_real (EelCanvas *canvas)
3663
 
{
3664
 
        canvas->need_update = TRUE;
3665
 
        add_idle (canvas);
3666
 
}
3667
 
 
3668
 
/**
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.
3675
 
 *
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.
3679
 
 **/
3680
 
void
3681
 
eel_canvas_request_redraw (EelCanvas *canvas, int x1, int y1, int x2, int y2)
3682
 
{
3683
 
        GdkRectangle bbox;
3684
 
 
3685
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3686
 
 
3687
 
        if (!gtk_widget_is_drawable (GTK_WIDGET (canvas))
3688
 
            || (x1 >= x2) || (y1 >= y2)) return;
3689
 
 
3690
 
        bbox.x = x1;
3691
 
        bbox.y = y1;
3692
 
        bbox.width = x2 - x1;
3693
 
        bbox.height = y2 - y1;
3694
 
 
3695
 
        gdk_window_invalidate_rect (gtk_layout_get_bin_window (GTK_LAYOUT (canvas)),
3696
 
                                    &bbox, FALSE);
3697
 
}
3698
 
 
3699
 
/**
3700
 
 * eel_canvas_w2c:
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).
3706
 
 *
3707
 
 * Converts world coordinates into canvas pixel coordinates.
3708
 
 **/
3709
 
void
3710
 
eel_canvas_w2c (EelCanvas *canvas, double wx, double wy, int *cx, int *cy)
3711
 
{
3712
 
        double zoom;
3713
 
 
3714
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3715
 
        
3716
 
        zoom = canvas->pixels_per_unit;
3717
 
        
3718
 
        if (cx)
3719
 
                *cx = floor ((wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs + 0.5);
3720
 
        if (cy)
3721
 
                *cy = floor ((wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs + 0.5);
3722
 
}
3723
 
 
3724
 
/**
3725
 
 * eel_canvas_w2c:
3726
 
 * @canvas: A canvas.
3727
 
 * @world: rectangle in world coordinates.
3728
 
 * @canvas: rectangle in canvase coordinates.
3729
 
 *
3730
 
 * Converts rectangles in world coordinates into canvas pixel coordinates.
3731
 
 **/
3732
 
void
3733
 
eel_canvas_w2c_rect_d (EelCanvas *canvas,
3734
 
                         double *x1, double *y1,
3735
 
                         double *x2, double *y2)
3736
 
{
3737
 
        eel_canvas_w2c_d (canvas,
3738
 
                            *x1, *y1,
3739
 
                            x1, y1);
3740
 
        eel_canvas_w2c_d (canvas,
3741
 
                            *x2, *y2,
3742
 
                            x2, y2);
3743
 
}
3744
 
 
3745
 
 
3746
 
 
3747
 
/**
3748
 
 * eel_canvas_w2c_d:
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).
3754
 
 *
3755
 
 * Converts world coordinates into canvas pixel coordinates.  This version
3756
 
 * produces coordinates in floating point coordinates, for greater precision.
3757
 
 **/
3758
 
void
3759
 
eel_canvas_w2c_d (EelCanvas *canvas, double wx, double wy, double *cx, double *cy)
3760
 
{
3761
 
        double zoom;
3762
 
 
3763
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3764
 
 
3765
 
        zoom = canvas->pixels_per_unit;
3766
 
        
3767
 
        if (cx)
3768
 
                *cx = (wx - canvas->scroll_x1)*zoom + canvas->zoom_xofs;
3769
 
        if (cy)
3770
 
                *cy = (wy - canvas->scroll_y1)*zoom + canvas->zoom_yofs;
3771
 
}
3772
 
 
3773
 
 
3774
 
/**
3775
 
 * eel_canvas_c2w:
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).
3781
 
 *
3782
 
 * Converts canvas pixel coordinates to world coordinates.
3783
 
 **/
3784
 
void
3785
 
eel_canvas_c2w (EelCanvas *canvas, int cx, int cy, double *wx, double *wy)
3786
 
{
3787
 
        double zoom;
3788
 
 
3789
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3790
 
 
3791
 
        zoom = canvas->pixels_per_unit;
3792
 
        
3793
 
        if (wx)
3794
 
                *wx = (cx - canvas->zoom_xofs)/zoom + canvas->scroll_x1;
3795
 
        if (wy)
3796
 
                *wy = (cy - canvas->zoom_yofs)/zoom + canvas->scroll_y1;
3797
 
}
3798
 
 
3799
 
 
3800
 
/**
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).
3807
 
 *
3808
 
 * Converts window-relative coordinates into world coordinates.  You can use
3809
 
 * this when you need to convert mouse coordinates into world coordinates, for
3810
 
 * example.
3811
 
 * Window coordinates are really the same as canvas coordinates now, but this
3812
 
 * function is here for backwards compatibility reasons.
3813
 
 **/
3814
 
void
3815
 
eel_canvas_window_to_world (EelCanvas *canvas, double winx, double winy,
3816
 
                              double *worldx, double *worldy)
3817
 
{
3818
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3819
 
 
3820
 
        if (worldx)
3821
 
                *worldx = canvas->scroll_x1 + ((winx - canvas->zoom_xofs)
3822
 
                                               / canvas->pixels_per_unit);
3823
 
 
3824
 
        if (worldy)
3825
 
                *worldy = canvas->scroll_y1 + ((winy - canvas->zoom_yofs)
3826
 
                                               / canvas->pixels_per_unit);
3827
 
}
3828
 
 
3829
 
 
3830
 
/**
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.
3837
 
 *
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.
3841
 
 **/
3842
 
void
3843
 
eel_canvas_world_to_window (EelCanvas *canvas, double worldx, double worldy,
3844
 
                            double *winx, double *winy)
3845
 
{
3846
 
        g_return_if_fail (EEL_IS_CANVAS (canvas));
3847
 
 
3848
 
        if (winx)
3849
 
                *winx = (canvas->pixels_per_unit)*(worldx - canvas->scroll_x1) + canvas->zoom_xofs;
3850
 
 
3851
 
        if (winy)
3852
 
                *winy = (canvas->pixels_per_unit)*(worldy - canvas->scroll_y1) + canvas->zoom_yofs;
3853
 
}
3854
 
 
3855
 
static gboolean
3856
 
boolean_handled_accumulator (GSignalInvocationHint *ihint,
3857
 
                             GValue                *return_accu,
3858
 
                             const GValue          *handler_return,
3859
 
                             gpointer               dummy)
3860
 
{
3861
 
        gboolean continue_emission;
3862
 
        gboolean signal_handled;
3863
 
        
3864
 
        signal_handled = g_value_get_boolean (handler_return);
3865
 
        g_value_set_boolean (return_accu, signal_handled);
3866
 
        continue_emission = !signal_handled;
3867
 
        
3868
 
        return continue_emission;
3869
 
}
3870
 
 
3871
 
static guint
3872
 
eel_canvas_item_accessible_add_focus_handler (AtkComponent    *component,
3873
 
                                              AtkFocusHandler handler)
3874
 
{
3875
 
        GSignalMatchType match_type;
3876
 
        guint signal_id;
3877
 
 
3878
 
        match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
3879
 
        signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
3880
 
 
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,
3884
 
                                                       signal_id, 0,
3885
 
                                                       g_cclosure_new (
3886
 
                                                       G_CALLBACK (handler), NULL,
3887
 
                                                       (GClosureNotify) NULL),
3888
 
                                                       FALSE);
3889
 
        } 
3890
 
        return 0;
3891
 
}
3892
 
 
3893
 
static void
3894
 
eel_canvas_item_accessible_get_item_extents (EelCanvasItem *item,
3895
 
                                             GdkRectangle  *rect)
3896
 
{
3897
 
        double bx1, bx2, by1, by2;
3898
 
        gint scroll_x, scroll_y;
3899
 
        gint x1, x2, y1, y2;
3900
 
 
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;
3912
 
}
3913
 
 
3914
 
static gboolean
3915
 
eel_canvas_item_accessible_is_item_in_window (EelCanvasItem *item,
3916
 
                                              GdkRectangle  *rect)
3917
 
{
3918
 
        GtkWidget *widget;
3919
 
        gboolean retval;
3920
 
 
3921
 
        widget = GTK_WIDGET (item->canvas);
3922
 
        if (gtk_widget_get_window (widget)) {
3923
 
                int window_width, window_height;
3924
 
 
3925
 
                gdk_window_get_geometry (gtk_widget_get_window (widget), NULL, NULL,
3926
 
                                         &window_width, &window_height);
3927
 
                /*
3928
 
                 * Check whether rectangles intersect
3929
 
                 */
3930
 
                if (rect->x + rect->width < 0 ||
3931
 
                    rect->y + rect->height < 0 ||
3932
 
                    rect->x > window_width  ||
3933
 
                    rect->y > window_height) {
3934
 
                        retval = FALSE;
3935
 
                } else {
3936
 
                        retval = TRUE;
3937
 
                }
3938
 
        } else {
3939
 
                retval = FALSE;
3940
 
        }
3941
 
        return retval;
3942
 
}
3943
 
 
3944
 
 
3945
 
static void
3946
 
eel_canvas_item_accessible_get_extents (AtkComponent *component,
3947
 
                                        gint            *x,
3948
 
                                        gint            *y,
3949
 
                                        gint            *width,
3950
 
                                        gint            *height,
3951
 
                                        AtkCoordType coord_type)
3952
 
{
3953
 
        AtkGObjectAccessible *atk_gobj;
3954
 
        GObject *obj;
3955
 
        EelCanvasItem *item;
3956
 
        gint window_x, window_y;
3957
 
        gint toplevel_x, toplevel_y;
3958
 
        GdkRectangle rect;
3959
 
        GdkWindow *window;
3960
 
        GtkWidget *canvas;
3961
 
 
3962
 
        atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
3963
 
        obj = atk_gobject_accessible_get_object (atk_gobj);
3964
 
 
3965
 
        if (obj == NULL) {
3966
 
                /* item is defunct */
3967
 
                return;
3968
 
        }
3969
 
 
3970
 
        /* Get the CanvasItem */
3971
 
        item = EEL_CANVAS_ITEM (obj);
3972
 
 
3973
 
        /* If this item has no parent canvas, something's broken */
3974
 
        g_return_if_fail (GTK_IS_WIDGET (item->canvas));
3975
 
 
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)) {
3980
 
                *x = G_MININT;
3981
 
                *y = G_MININT;
3982
 
                return;
3983
 
        }
3984
 
 
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);
3993
 
                *x -= toplevel_x;
3994
 
                *y -= toplevel_y;
3995
 
        }
3996
 
        return;
3997
 
}
3998
 
 
3999
 
static gint
4000
 
eel_canvas_item_accessible_get_mdi_zorder (AtkComponent *component)
4001
 
{
4002
 
        AtkGObjectAccessible *atk_gobj;
4003
 
        GObject *g_obj;
4004
 
        EelCanvasItem *item;
4005
 
 
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 */
4010
 
                return -1;
4011
 
        }
4012
 
 
4013
 
        item = EEL_CANVAS_ITEM (g_obj);
4014
 
        if (item->parent) {
4015
 
                return g_list_index (EEL_CANVAS_GROUP (item->parent)->item_list, item);
4016
 
        } else {
4017
 
                g_return_val_if_fail (item->canvas->root == item, -1);
4018
 
                return 0;
4019
 
        }
4020
 
}
4021
 
 
4022
 
static gboolean
4023
 
eel_canvas_item_accessible_grab_focus (AtkComponent *component)
4024
 
{
4025
 
        AtkGObjectAccessible *atk_gobj;
4026
 
        GObject *obj;
4027
 
        EelCanvasItem *item;
4028
 
        GtkWidget *toplevel;
4029
 
 
4030
 
        atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
4031
 
        obj = atk_gobject_accessible_get_object (atk_gobj);
4032
 
 
4033
 
        item = EEL_CANVAS_ITEM (obj);
4034
 
        if (item == NULL) {
4035
 
                /* item is defunct */
4036
 
                return FALSE;
4037
 
        }
4038
 
 
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));
4043
 
        }
4044
 
 
4045
 
        return TRUE;
4046
 
}
4047
 
 
4048
 
static void
4049
 
eel_canvas_item_accessible_remove_focus_handler (AtkComponent *component,
4050
 
                                                 guint          handler_id)
4051
 
{
4052
 
        g_signal_handler_disconnect (component, handler_id);
4053
 
}
4054
 
 
4055
 
static void
4056
 
eel_canvas_item_accessible_component_interface_init (AtkComponentIface *iface)
4057
 
{
4058
 
        g_return_if_fail (iface != NULL);
4059
 
 
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;
4065
 
}
4066
 
 
4067
 
static gboolean
4068
 
eel_canvas_item_accessible_is_item_on_screen (EelCanvasItem *item)
4069
 
{
4070
 
        GdkRectangle rect;
4071
 
 
4072
 
        eel_canvas_item_accessible_get_item_extents (item, &rect);
4073
 
        return eel_canvas_item_accessible_is_item_in_window (item, &rect);
4074
 
}
4075
 
 
4076
 
static void
4077
 
eel_canvas_item_accessible_initialize (AtkObject *obj, gpointer data)
4078
 
{
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));
4083
 
}
4084
 
 
4085
 
static AtkStateSet*
4086
 
eel_canvas_item_accessible_ref_state_set (AtkObject *accessible)
4087
 
{
4088
 
        AtkGObjectAccessible *atk_gobj;
4089
 
        GObject *obj;
4090
 
        EelCanvasItem *item;
4091
 
        AtkStateSet *state_set;
4092
 
 
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);
4096
 
 
4097
 
        item = EEL_CANVAS_ITEM (obj);
4098
 
        if (item == NULL) {
4099
 
                atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
4100
 
        } else {
4101
 
                if (item->flags & EEL_CANVAS_ITEM_VISIBLE) {
4102
 
                        atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
4103
 
                        
4104
 
                        if (eel_canvas_item_accessible_is_item_on_screen (item)) {
4105
 
                                atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
4106
 
                        }
4107
 
                }
4108
 
                if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))) {
4109
 
                        atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
4110
 
 
4111
 
                        if (item->canvas->focused_item == item) {
4112
 
                                atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
4113
 
                        }
4114
 
                }
4115
 
        }
4116
 
 
4117
 
        return state_set;
4118
 
}
4119
 
 
4120
 
static void
4121
 
eel_canvas_item_accessible_class_init (EelCanvasItemAccessibleClass *klass)
4122
 
{
4123
 
        AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
4124
 
 
4125
 
        accessible_item_parent_class = g_type_class_peek_parent (klass);
4126
 
 
4127
 
        atk_class->initialize = eel_canvas_item_accessible_initialize;
4128
 
        atk_class->ref_state_set = eel_canvas_item_accessible_ref_state_set;
4129
 
}
4130
 
 
4131
 
static void
4132
 
eel_canvas_item_accessible_init (EelCanvasItemAccessible *self)
4133
 
{
4134
 
 
4135
 
}
4136
 
 
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));
4142
 
 
4143
 
static GType eel_canvas_item_accessible_factory_get_type (void);
4144
 
 
4145
 
typedef AtkObjectFactory      EelCanvasItemAccessibleFactory;
4146
 
typedef AtkObjectFactoryClass EelCanvasItemAccessibleFactoryClass;
4147
 
G_DEFINE_TYPE (EelCanvasItemAccessibleFactory, eel_canvas_item_accessible_factory,
4148
 
               ATK_TYPE_OBJECT_FACTORY)
4149
 
 
4150
 
static GType
4151
 
eel_canvas_item_accessible_factory_get_accessible_type (void)
4152
 
{
4153
 
        return eel_canvas_item_accessible_get_type ();
4154
 
}
4155
 
 
4156
 
static AtkObject*
4157
 
eel_canvas_item_accessible_factory_create_accessible (GObject *for_object)
4158
 
{
4159
 
        AtkObject *accessible;
4160
 
 
4161
 
        accessible = g_object_new (eel_canvas_item_accessible_get_type (), NULL);
4162
 
        atk_object_initialize (accessible, for_object);
4163
 
        return accessible;
4164
 
}
4165
 
 
4166
 
static void
4167
 
eel_canvas_item_accessible_factory_init (EelCanvasItemAccessibleFactory *self)
4168
 
{
4169
 
 
4170
 
}
4171
 
 
4172
 
static void
4173
 
eel_canvas_item_accessible_factory_class_init (AtkObjectFactoryClass *klass)
4174
 
{
4175
 
        klass->create_accessible = eel_canvas_item_accessible_factory_create_accessible;
4176
 
        klass->get_accessible_type = eel_canvas_item_accessible_factory_get_accessible_type;
4177
 
}
4178
 
 
4179
 
/* Class initialization function for EelCanvasItemClass */
4180
 
static void
4181
 
eel_canvas_item_class_init (EelCanvasItemClass *klass)
4182
 
{
4183
 
        GObjectClass *gobject_class = (GObjectClass *) klass;
4184
 
 
4185
 
        item_parent_class = g_type_class_peek_parent (klass);
4186
 
 
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;
4190
 
 
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));
4196
 
        
4197
 
        g_object_class_install_property
4198
 
                (gobject_class, ITEM_PROP_VISIBLE,
4199
 
                 g_param_spec_boolean ("visible", NULL, NULL,
4200
 
                                      TRUE,
4201
 
                                      G_PARAM_READWRITE));
4202
 
 
4203
 
        item_signals[ITEM_EVENT] =
4204
 
                g_signal_new ("event",
4205
 
                              G_TYPE_FROM_CLASS (klass),
4206
 
                              G_SIGNAL_RUN_LAST,
4207
 
                              G_STRUCT_OFFSET (EelCanvasItemClass, event),
4208
 
                              boolean_handled_accumulator, NULL,
4209
 
                              g_cclosure_marshal_generic,
4210
 
                              G_TYPE_BOOLEAN, 1,
4211
 
                              GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
4212
 
 
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),
4218
 
                              NULL, NULL,
4219
 
                              g_cclosure_marshal_VOID__VOID,
4220
 
                              G_TYPE_NONE, 0);
4221
 
 
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;
4227
 
 
4228
 
        atk_registry_set_factory_type (atk_get_default_registry (),
4229
 
                                       EEL_TYPE_CANVAS_ITEM,
4230
 
                                       eel_canvas_item_accessible_factory_get_type ());
4231
 
}