~ubuntu-branches/ubuntu/maverick/gcompris/maverick

« back to all changes in this revision

Viewing changes to src/libgnomecanvas/gnome-canvas.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Gariepy, Marc Gariepy, Stephane Graber
  • Date: 2010-01-04 17:42:49 UTC
  • mfrom: (1.1.14 upstream)
  • Revision ID: james.westby@ubuntu.com-20100104174249-7bupatd9dtxyhvs4
Tags: 9.0-0ubuntu1
[Marc Gariepy]
* New upstream release (9.0).
* Remove cache.c from POTFILES to avoid FTBFS
* Remove unneeded rm in debian/rules (file no longer exists upstream)

[Stephane Graber]
* Bump Debian standards to 3.8.3
* Add patch system (dpatch)

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
 
 * GnomeCanvas widget - Tk-like canvas widget for Gnome
28
 
 *
29
 
 * GnomeCanvas 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 GnomeCanvasImage sizes are in units or pixels (scale or don't scale).
41
 
 *
42
 
 * - Implement a flag for gnome_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 *gnome_canvas_gimme_all_items_contained_in_this_area (GnomeCanvas *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 GnomeCanvasEllipse).
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
 
/*
65
 
 * Raph's TODO list for the antialiased canvas integration:
66
 
 *
67
 
 * - ::point() method for text item not accurate when affine transformed.
68
 
 *
69
 
 * - Clip rectangle not implemented in aa renderer for text item.
70
 
 *
71
 
 * - Clip paths only partially implemented.
72
 
 *
73
 
 * - Add more image loading techniques to work around imlib deficiencies.
74
 
 */
75
 
 
76
 
#include <config.h>
77
 
 
78
 
#include <math.h>
79
 
#include <string.h>
80
 
#include <stdio.h>
81
 
#include <gdk/gdkprivate.h>
82
 
#include <gtk/gtkmain.h>
83
 
#include <gtk/gtksignal.h>
84
 
#include "gnome-canvas.h"
85
 
#include "gnome-canvas-i18n.h"
86
 
#include "libart_lgpl/art_rect.h"
87
 
#include "libart_lgpl/art_rect_uta.h"
88
 
#include "libart_lgpl/art_uta_rect.h"
89
 
#include "libart_lgpl/art_uta_ops.h"
90
 
 
91
 
#include "gnome-canvas-marshal.h"
92
 
#include "gnome-canvas-marshal.c"
93
 
 
94
 
 
95
 
/* We must run our idle update handler *before* GDK wants to redraw. */
96
 
#define CANVAS_IDLE_PRIORITY (GDK_PRIORITY_REDRAW - 5)
97
 
 
98
 
 
99
 
static void gnome_canvas_request_update (GnomeCanvas      *canvas);
100
 
static void group_add                   (GnomeCanvasGroup *group,
101
 
                                         GnomeCanvasItem  *item);
102
 
static void group_remove                (GnomeCanvasGroup *group,
103
 
                                         GnomeCanvasItem  *item);
104
 
static void add_idle                    (GnomeCanvas      *canvas);
105
 
 
106
 
 
107
 
/*** GnomeCanvasItem ***/
108
 
 
109
 
/* Some convenience stuff */
110
 
#define GCI_UPDATE_MASK (GNOME_CANVAS_UPDATE_REQUESTED | GNOME_CANVAS_UPDATE_AFFINE | GNOME_CANVAS_UPDATE_CLIP | GNOME_CANVAS_UPDATE_VISIBILITY)
111
 
#define GCI_EPSILON 1e-18
112
 
#define GCI_PRINT_MATRIX(s,a) g_print ("%s %g %g %g %g %g %g\n", s, (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5])
113
 
 
114
 
enum {
115
 
        ITEM_PROP_0,
116
 
        ITEM_PROP_PARENT
117
 
};
118
 
 
119
 
enum {
120
 
        ITEM_EVENT,
121
 
        ITEM_LAST_SIGNAL
122
 
};
123
 
 
124
 
static void gnome_canvas_item_class_init     (GnomeCanvasItemClass *class);
125
 
static void gnome_canvas_item_init           (GnomeCanvasItem      *item);
126
 
static int  emit_event                       (GnomeCanvas *canvas, GdkEvent *event);
127
 
 
128
 
static guint item_signals[ITEM_LAST_SIGNAL];
129
 
 
130
 
static GtkObjectClass *item_parent_class;
131
 
 
132
 
 
133
 
/**
134
 
 * gnome_canvas_item_get_type:
135
 
 *
136
 
 * Registers the &GnomeCanvasItem class if necessary, and returns the type ID
137
 
 * associated to it.
138
 
 *
139
 
 * Return value:  The type ID of the &GnomeCanvasItem class.
140
 
 **/
141
 
GType
142
 
gnome_canvas_item_get_type (void)
143
 
{
144
 
        static GType canvas_item_type;
145
 
 
146
 
        if (!canvas_item_type) {
147
 
                static const GTypeInfo object_info = {
148
 
                        sizeof (GnomeCanvasItemClass),
149
 
                        (GBaseInitFunc) NULL,
150
 
                        (GBaseFinalizeFunc) NULL,
151
 
                        (GClassInitFunc) gnome_canvas_item_class_init,
152
 
                        (GClassFinalizeFunc) NULL,
153
 
                        NULL,                   /* class_data */
154
 
                        sizeof (GnomeCanvasItem),
155
 
                        0,                      /* n_preallocs */
156
 
                        (GInstanceInitFunc) gnome_canvas_item_init,
157
 
                        NULL                    /* value_table */
158
 
                };
159
 
 
160
 
                canvas_item_type = g_type_register_static (GTK_TYPE_OBJECT, "GnomeCanvasItem",
161
 
                                                           &object_info, 0);
162
 
        }
163
 
 
164
 
        return canvas_item_type;
165
 
}
166
 
 
167
 
/* Object initialization function for GnomeCanvasItem */
168
 
static void
169
 
gnome_canvas_item_init (GnomeCanvasItem *item)
170
 
{
171
 
        item->object.flags |= GNOME_CANVAS_ITEM_VISIBLE;
172
 
}
173
 
 
174
 
/**
175
 
 * gnome_canvas_item_new:
176
 
 * @parent: The parent group for the new item.
177
 
 * @type: The object type of the item.
178
 
 * @first_arg_name: A list of object argument name/value pairs, NULL-terminated,
179
 
 * used to configure the item.  For example, "fill_color", "black",
180
 
 * "width_units", 5.0, NULL.
181
 
 * @Varargs:
182
 
 *
183
 
 * Creates a new canvas item with @parent as its parent group.  The item is
184
 
 * created at the top of its parent's stack, and starts up as visible.  The item
185
 
 * is of the specified @type, for example, it can be
186
 
 * gnome_canvas_rect_get_type().  The list of object arguments/value pairs is
187
 
 * used to configure the item. If you need to pass construct time parameters, you
188
 
 * should use g_object_new() to pass the parameters and
189
 
 * gnome_canvas_item_construct() to set up the canvas item.
190
 
 *
191
 
 * Return value: The newly-created item.
192
 
 **/
193
 
GnomeCanvasItem *
194
 
gnome_canvas_item_new (GnomeCanvasGroup *parent, GType type, const gchar *first_arg_name, ...)
195
 
{
196
 
        GnomeCanvasItem *item;
197
 
        va_list args;
198
 
 
199
 
        g_return_val_if_fail (GNOME_IS_CANVAS_GROUP (parent), NULL);
200
 
        g_return_val_if_fail (g_type_is_a (type, gnome_canvas_item_get_type ()), NULL);
201
 
 
202
 
        item = GNOME_CANVAS_ITEM (g_object_new (type, NULL));
203
 
 
204
 
        va_start (args, first_arg_name);
205
 
        gnome_canvas_item_construct (item, parent, first_arg_name, args);
206
 
        va_end (args);
207
 
 
208
 
        return item;
209
 
}
210
 
 
211
 
 
212
 
/* Performs post-creation operations on a canvas item (adding it to its parent
213
 
 * group, etc.)
214
 
 */
215
 
static void
216
 
item_post_create_setup (GnomeCanvasItem *item)
217
 
{
218
 
        group_add (GNOME_CANVAS_GROUP (item->parent), item);
219
 
 
220
 
        gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
221
 
        item->canvas->need_repick = TRUE;
222
 
}
223
 
 
224
 
/* Set_property handler for canvas items */
225
 
static void
226
 
gnome_canvas_item_set_property (GObject *gobject, guint param_id,
227
 
                                const GValue *value, GParamSpec *pspec)
228
 
{
229
 
        GnomeCanvasItem *item;
230
 
 
231
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (gobject));
232
 
 
233
 
        item = GNOME_CANVAS_ITEM (gobject);
234
 
 
235
 
        switch (param_id) {
236
 
        case ITEM_PROP_PARENT:
237
 
                if (item->parent != NULL) {
238
 
                    g_warning ("Cannot set `parent' argument after item has "
239
 
                               "already been constructed.");
240
 
                } else if (g_value_get_object (value)) {
241
 
                        item->parent = GNOME_CANVAS_ITEM (g_value_get_object (value));
242
 
                        item->canvas = item->parent->canvas;
243
 
                        item_post_create_setup (item);
244
 
                }
245
 
                break;
246
 
        default:
247
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
248
 
                break;
249
 
        }
250
 
}
251
 
 
252
 
/* Get_property handler for canvas items */
253
 
static void
254
 
gnome_canvas_item_get_property (GObject *gobject, guint param_id,
255
 
                                GValue *value, GParamSpec *pspec)
256
 
{
257
 
        GnomeCanvasItem *item;
258
 
 
259
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (gobject));
260
 
 
261
 
        item = GNOME_CANVAS_ITEM (gobject);
262
 
 
263
 
        switch (param_id) {
264
 
        case ITEM_PROP_PARENT:
265
 
                g_value_set_object (value, item->parent);
266
 
                break;
267
 
 
268
 
        default:
269
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
270
 
                break;
271
 
        }
272
 
}
273
 
 
274
 
/**
275
 
 * gnome_canvas_item_construct:
276
 
 * @item: An unconstructed canvas item.
277
 
 * @parent: The parent group for the item.
278
 
 * @first_arg_name: The name of the first argument for configuring the item.
279
 
 * @args: The list of arguments used to configure the item.
280
 
 *
281
 
 * Constructs a canvas item; meant for use only by item implementations.
282
 
 **/
283
 
void
284
 
gnome_canvas_item_construct (GnomeCanvasItem *item, GnomeCanvasGroup *parent,
285
 
                             const gchar *first_arg_name, va_list args)
286
 
{
287
 
        g_return_if_fail (GNOME_IS_CANVAS_GROUP (parent));
288
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
289
 
 
290
 
        item->parent = GNOME_CANVAS_ITEM (parent);
291
 
        item->canvas = item->parent->canvas;
292
 
 
293
 
        g_object_set_valist (G_OBJECT (item), first_arg_name, args);
294
 
 
295
 
        item_post_create_setup (item);
296
 
}
297
 
 
298
 
 
299
 
/* If the item is visible, requests a redraw of it. */
300
 
static void
301
 
redraw_if_visible (GnomeCanvasItem *item)
302
 
{
303
 
        if (item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
304
 
                gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
305
 
}
306
 
 
307
 
/* Standard object dispose function for canvas items */
308
 
static void
309
 
gnome_canvas_item_dispose (GObject *object)
310
 
{
311
 
        GnomeCanvasItem *item;
312
 
 
313
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (object));
314
 
 
315
 
        item = GNOME_CANVAS_ITEM (object);
316
 
 
317
 
        if (item->canvas)
318
 
                redraw_if_visible (item);
319
 
 
320
 
        /* Make the canvas forget about us */
321
 
 
322
 
        if (item->canvas && item == item->canvas->current_item) {
323
 
                item->canvas->current_item = NULL;
324
 
                item->canvas->need_repick = TRUE;
325
 
        }
326
 
 
327
 
        if (item->canvas && item == item->canvas->new_current_item) {
328
 
                item->canvas->new_current_item = NULL;
329
 
                item->canvas->need_repick = TRUE;
330
 
        }
331
 
 
332
 
        if (item->canvas && item == item->canvas->grabbed_item) {
333
 
                item->canvas->grabbed_item = NULL;
334
 
                gdk_pointer_ungrab (GDK_CURRENT_TIME);
335
 
        }
336
 
 
337
 
        if (item->canvas && item == item->canvas->focused_item)
338
 
                item->canvas->focused_item = NULL;
339
 
 
340
 
        /* Normal destroy stuff */
341
 
 
342
 
        if (item->object.flags & GNOME_CANVAS_ITEM_MAPPED)
343
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
344
 
 
345
 
        if (item->object.flags & GNOME_CANVAS_ITEM_REALIZED)
346
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
347
 
 
348
 
        if (item->parent)
349
 
                group_remove (GNOME_CANVAS_GROUP (item->parent), item);
350
 
 
351
 
        g_free (item->xform);
352
 
        item->xform = NULL;
353
 
 
354
 
        G_OBJECT_CLASS (item_parent_class)->dispose (object);
355
 
        /* items should remove any reference to item->canvas after the
356
 
           first ::destroy */
357
 
        item->canvas = NULL;
358
 
}
359
 
 
360
 
/* Realize handler for canvas items */
361
 
static void
362
 
gnome_canvas_item_realize (GnomeCanvasItem *item)
363
 
{
364
 
        GTK_OBJECT_SET_FLAGS (item, GNOME_CANVAS_ITEM_REALIZED);
365
 
 
366
 
        gnome_canvas_item_request_update (item);
367
 
}
368
 
 
369
 
/* Unrealize handler for canvas items */
370
 
static void
371
 
gnome_canvas_item_unrealize (GnomeCanvasItem *item)
372
 
{
373
 
        GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_REALIZED);
374
 
}
375
 
 
376
 
/* Map handler for canvas items */
377
 
static void
378
 
gnome_canvas_item_map (GnomeCanvasItem *item)
379
 
{
380
 
        GTK_OBJECT_SET_FLAGS (item, GNOME_CANVAS_ITEM_MAPPED);
381
 
}
382
 
 
383
 
/* Unmap handler for canvas items */
384
 
static void
385
 
gnome_canvas_item_unmap (GnomeCanvasItem *item)
386
 
{
387
 
        GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_MAPPED);
388
 
}
389
 
 
390
 
/* Update handler for canvas items */
391
 
static void
392
 
gnome_canvas_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
393
 
{
394
 
        GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_UPDATE);
395
 
        GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_AFFINE);
396
 
        GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_CLIP);
397
 
        GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_VIS);
398
 
}
399
 
 
400
 
#define noHACKISH_AFFINE
401
 
 
402
 
/*
403
 
 * This routine invokes the update method of the item
404
 
 * Please notice, that we take parent to canvas pixel matrix as argument
405
 
 * unlike virtual method ::update, whose argument is item 2 canvas pixel
406
 
 * matrix
407
 
 *
408
 
 * I will try to force somewhat meaningful naming for affines (Lauris)
409
 
 * General naming rule is FROM2TO, where FROM and TO are abbreviations
410
 
 * So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel
411
 
 * I hope that this helps to keep track of what really happens
412
 
 *
413
 
 */
414
 
 
415
 
static void
416
 
gnome_canvas_item_invoke_update (GnomeCanvasItem *item, double *p2cpx, ArtSVP *clip_path, int flags)
417
 
{
418
 
        int child_flags;
419
 
        gdouble i2cpx[6];
420
 
 
421
 
#ifdef HACKISH_AFFINE
422
 
        double i2w[6], w2c[6], i2c[6];
423
 
#endif
424
 
 
425
 
        child_flags = flags;
426
 
        if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
427
 
                child_flags &= ~GNOME_CANVAS_UPDATE_IS_VISIBLE;
428
 
 
429
 
        /* Calculate actual item transformation matrix */
430
 
 
431
 
        if (item->xform) {
432
 
                if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
433
 
                        /* Item has full affine */
434
 
                        art_affine_multiply (i2cpx, item->xform, p2cpx);
435
 
                } else {
436
 
                        /* Item has only translation */
437
 
                        memcpy (i2cpx, p2cpx, 4 * sizeof (gdouble));
438
 
                        i2cpx[4] = item->xform[0] * p2cpx[0] + item->xform[1] * p2cpx[2] + p2cpx[4];
439
 
                        i2cpx[5] = item->xform[0] * p2cpx[1] + item->xform[1] * p2cpx[3] + p2cpx[5];
440
 
                }
441
 
        } else {
442
 
                /* Item has no matrix (i.e. identity) */
443
 
                memcpy (i2cpx, p2cpx, 6 * sizeof (gdouble));
444
 
        }
445
 
 
446
 
#ifdef HACKISH_AFFINE
447
 
        gnome_canvas_item_i2w_affine (item, i2w);
448
 
        gnome_canvas_w2c_affine (item->canvas, w2c);
449
 
        art_affine_multiply (i2c, i2w, w2c);
450
 
        /* invariant (doesn't hold now): child_affine == i2c */
451
 
        child_affine = i2c;
452
 
#endif
453
 
 
454
 
        /* apply object flags to child flags */
455
 
 
456
 
        child_flags &= ~GNOME_CANVAS_UPDATE_REQUESTED;
457
 
 
458
 
        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_UPDATE)
459
 
                child_flags |= GNOME_CANVAS_UPDATE_REQUESTED;
460
 
 
461
 
        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)
462
 
                child_flags |= GNOME_CANVAS_UPDATE_AFFINE;
463
 
 
464
 
        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_CLIP)
465
 
                child_flags |= GNOME_CANVAS_UPDATE_CLIP;
466
 
 
467
 
        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_VIS)
468
 
                child_flags |= GNOME_CANVAS_UPDATE_VISIBILITY;
469
 
 
470
 
        if (child_flags & GCI_UPDATE_MASK) {
471
 
                if (GNOME_CANVAS_ITEM_GET_CLASS (item)->update)
472
 
                        GNOME_CANVAS_ITEM_GET_CLASS (item)->update (item, i2cpx, clip_path, child_flags);
473
 
        }
474
 
}
475
 
 
476
 
/*
477
 
 * This routine invokes the point method of the item.
478
 
 * The arguments x, y should be in the parent item local coordinates.
479
 
 *
480
 
 * This is potentially evil, as we are relying on matrix inversion (Lauris)
481
 
 */
482
 
 
483
 
static double
484
 
gnome_canvas_item_invoke_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
485
 
{
486
 
        /* Calculate x & y in item local coordinates */
487
 
 
488
 
        if (item->xform) {
489
 
                if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
490
 
                        gdouble p2i[6], t;
491
 
                        /* Item has full affine */
492
 
                        art_affine_invert (p2i, item->xform);
493
 
                        t = x * p2i[0] + y * p2i[2] + p2i[4];
494
 
                        y = x * p2i[1] + y * p2i[3] + p2i[5];
495
 
                        x = t;
496
 
                } else {
497
 
                        /* Item has only translation */
498
 
                        x -= item->xform[0];
499
 
                        y -= item->xform[1];
500
 
                }
501
 
        }
502
 
 
503
 
#ifdef HACKISH_AFFINE
504
 
        double i2w[6], w2c[6], i2c[6], c2i[6];
505
 
        ArtPoint c, i;
506
 
#endif
507
 
 
508
 
#ifdef HACKISH_AFFINE
509
 
        gnome_canvas_item_i2w_affine (item, i2w);
510
 
        gnome_canvas_w2c_affine (item->canvas, w2c);
511
 
        art_affine_multiply (i2c, i2w, w2c);
512
 
        art_affine_invert (c2i, i2c);
513
 
        c.x = cx;
514
 
        c.y = cy;
515
 
        art_affine_point (&i, &c, c2i);
516
 
        x = i.x;
517
 
        y = i.y;
518
 
#endif
519
 
 
520
 
        if (GNOME_CANVAS_ITEM_GET_CLASS (item)->point)
521
 
                return GNOME_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item);
522
 
 
523
 
        return 1e18;
524
 
}
525
 
 
526
 
/**
527
 
 * gnome_canvas_item_set:
528
 
 * @item: A canvas item.
529
 
 * @first_arg_name: The list of object argument name/value pairs used to configure the item.
530
 
 * @Varargs:
531
 
 *
532
 
 * Configures a canvas item.  The arguments in the item are set to the specified
533
 
 * values, and the item is repainted as appropriate.
534
 
 **/
535
 
void
536
 
gnome_canvas_item_set (GnomeCanvasItem *item, const gchar *first_arg_name, ...)
537
 
{
538
 
        va_list args;
539
 
 
540
 
        va_start (args, first_arg_name);
541
 
        gnome_canvas_item_set_valist (item, first_arg_name, args);
542
 
        va_end (args);
543
 
}
544
 
 
545
 
 
546
 
/**
547
 
 * gnome_canvas_item_set_valist:
548
 
 * @item: A canvas item.
549
 
 * @first_arg_name: The name of the first argument used to configure the item.
550
 
 * @args: The list of object argument name/value pairs used to configure the item.
551
 
 *
552
 
 * Configures a canvas item.  The arguments in the item are set to the specified
553
 
 * values, and the item is repainted as appropriate.
554
 
 **/
555
 
void
556
 
gnome_canvas_item_set_valist (GnomeCanvasItem *item, const gchar *first_arg_name, va_list args)
557
 
{
558
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
559
 
 
560
 
        g_object_set_valist (G_OBJECT (item), first_arg_name, args);
561
 
 
562
 
#if 0
563
 
        /* I commented this out, because item implementations have to schedule update/redraw */
564
 
        redraw_if_visible (item);
565
 
#endif
566
 
 
567
 
        item->canvas->need_repick = TRUE;
568
 
}
569
 
 
570
 
 
571
 
/**
572
 
 * gnome_canvas_item_affine_relative:
573
 
 * @item: A canvas item.
574
 
 * @affine: An affine transformation matrix.
575
 
 *
576
 
 * Combines the specified affine transformation matrix with the item's current
577
 
 * transformation. NULL affine is not allowed.
578
 
 **/
579
 
#define GCIAR_EPSILON 1e-6
580
 
void
581
 
gnome_canvas_item_affine_relative (GnomeCanvasItem *item, const double affine[6])
582
 
{
583
 
        gdouble i2p[6];
584
 
 
585
 
        g_return_if_fail (item != NULL);
586
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
587
 
        g_return_if_fail (affine != NULL);
588
 
 
589
 
        /* Calculate actual item transformation matrix */
590
 
 
591
 
        if (item->xform) {
592
 
                if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
593
 
                        /* Item has full affine */
594
 
                        art_affine_multiply (i2p, affine, item->xform);
595
 
                } else {
596
 
                        /* Item has only translation */
597
 
                        memcpy (i2p, affine, 6 * sizeof (gdouble));
598
 
                        i2p[4] += item->xform[0];
599
 
                        i2p[5] += item->xform[1];
600
 
                }
601
 
        } else {
602
 
                /* Item has no matrix (i.e. identity) */
603
 
                memcpy (i2p, affine, 6 * sizeof (gdouble));
604
 
        }
605
 
 
606
 
        gnome_canvas_item_affine_absolute (item, i2p);
607
 
}
608
 
 
609
 
/**
610
 
 * gnome_canvas_item_affine_absolute:
611
 
 * @item: A canvas item.
612
 
 * @affine: An affine transformation matrix.
613
 
 *
614
 
 * Makes the item's affine transformation matrix be equal to the specified
615
 
 * matrix. NULL affine is treated as identity.
616
 
 **/
617
 
void
618
 
gnome_canvas_item_affine_absolute (GnomeCanvasItem *item, const double i2p[6])
619
 
{
620
 
        g_return_if_fail (item != NULL);
621
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
622
 
 
623
 
        if (i2p &&
624
 
            (fabs (i2p[0] - 1.0) < GCI_EPSILON) &&
625
 
            (fabs (i2p[1] - 0.0) < GCI_EPSILON) &&
626
 
            (fabs (i2p[2] - 0.0) < GCI_EPSILON) &&
627
 
            (fabs (i2p[3] - 1.0) < GCI_EPSILON) &&
628
 
            (fabs (i2p[4] - 0.0) < GCI_EPSILON) &&
629
 
            (fabs (i2p[5] - 0.0) < GCI_EPSILON)) {
630
 
                /* We are identity */
631
 
                i2p = NULL;
632
 
        }
633
 
 
634
 
        if (i2p) {
635
 
                if (item->xform && !(item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL)) {
636
 
                        /* We do not want to deal with translation-only affines */
637
 
                        g_free (item->xform);
638
 
                        item->xform = NULL;
639
 
                }
640
 
                if (!item->xform) item->xform = g_new (gdouble, 6);
641
 
                memcpy (item->xform, i2p, 6 * sizeof (gdouble));
642
 
                item->object.flags |= GNOME_CANVAS_ITEM_AFFINE_FULL;
643
 
        } else {
644
 
                if (item->xform) {
645
 
                        g_free (item->xform);
646
 
                        item->xform = NULL;
647
 
                }
648
 
        }
649
 
 
650
 
        if (!(item->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)) {
651
 
                /* Request update */
652
 
                item->object.flags |= GNOME_CANVAS_ITEM_NEED_AFFINE;
653
 
                gnome_canvas_item_request_update (item);
654
 
        }
655
 
 
656
 
        item->canvas->need_repick = TRUE;
657
 
}
658
 
 
659
 
 
660
 
/**
661
 
 * gnome_canvas_item_move:
662
 
 * @item: A canvas item.
663
 
 * @dx: Horizontal offset.
664
 
 * @dy: Vertical offset.
665
 
 *
666
 
 * Moves a canvas item by creating an affine transformation matrix for
667
 
 * translation by using the specified values. This happens in item
668
 
 * local coordinate system, so if you have nontrivial transform, it
669
 
 * most probably does not do, what you want.
670
 
 **/
671
 
void
672
 
gnome_canvas_item_move (GnomeCanvasItem *item, double dx, double dy)
673
 
{
674
 
        double translate[6];
675
 
 
676
 
        g_return_if_fail (item != NULL);
677
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
678
 
 
679
 
        art_affine_translate (translate, dx, dy);
680
 
 
681
 
        gnome_canvas_item_affine_relative (item, translate);
682
 
}
683
 
 
684
 
/* Convenience function to reorder items in a group's child list.  This puts the
685
 
 * specified link after the "before" link. Returns TRUE if the list was changed.
686
 
 */
687
 
static gboolean
688
 
put_item_after (GList *link, GList *before)
689
 
{
690
 
        GnomeCanvasGroup *parent;
691
 
        GList *old_before, *old_after;
692
 
        GList *after;
693
 
 
694
 
        parent = GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (link->data)->parent);
695
 
 
696
 
        if (before)
697
 
                after = before->next;
698
 
        else
699
 
                after = parent->item_list;
700
 
 
701
 
        if (before == link || after == link)
702
 
                return FALSE;
703
 
 
704
 
        /* Unlink */
705
 
 
706
 
        old_before = link->prev;
707
 
        old_after = link->next;
708
 
 
709
 
        if (old_before)
710
 
                old_before->next = old_after;
711
 
        else
712
 
                parent->item_list = old_after;
713
 
 
714
 
        if (old_after)
715
 
                old_after->prev = old_before;
716
 
        else
717
 
                parent->item_list_end = old_before;
718
 
 
719
 
        /* Relink */
720
 
 
721
 
        link->prev = before;
722
 
        if (before)
723
 
                before->next = link;
724
 
        else
725
 
                parent->item_list = link;
726
 
 
727
 
        link->next = after;
728
 
        if (after)
729
 
                after->prev = link;
730
 
        else
731
 
                parent->item_list_end = link;
732
 
 
733
 
        return TRUE;
734
 
}
735
 
 
736
 
 
737
 
/**
738
 
 * gnome_canvas_item_raise:
739
 
 * @item: A canvas item.
740
 
 * @positions: Number of steps to raise the item.
741
 
 *
742
 
 * Raises the item in its parent's stack by the specified number of positions.
743
 
 * If the number of positions is greater than the distance to the top of the
744
 
 * stack, then the item is put at the top.
745
 
 **/
746
 
void
747
 
gnome_canvas_item_raise (GnomeCanvasItem *item, int positions)
748
 
{
749
 
        GList *link, *before;
750
 
        GnomeCanvasGroup *parent;
751
 
 
752
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
753
 
        g_return_if_fail (positions >= 0);
754
 
 
755
 
        if (!item->parent || positions == 0)
756
 
                return;
757
 
 
758
 
        parent = GNOME_CANVAS_GROUP (item->parent);
759
 
        link = g_list_find (parent->item_list, item);
760
 
        g_assert (link != NULL);
761
 
 
762
 
        for (before = link; positions && before; positions--)
763
 
                before = before->next;
764
 
 
765
 
        if (!before)
766
 
                before = parent->item_list_end;
767
 
 
768
 
        if (put_item_after (link, before)) {
769
 
                redraw_if_visible (item);
770
 
                item->canvas->need_repick = TRUE;
771
 
        }
772
 
}
773
 
 
774
 
 
775
 
/**
776
 
 * gnome_canvas_item_lower:
777
 
 * @item: A canvas item.
778
 
 * @positions: Number of steps to lower the item.
779
 
 *
780
 
 * Lowers the item in its parent's stack by the specified number of positions.
781
 
 * If the number of positions is greater than the distance to the bottom of the
782
 
 * stack, then the item is put at the bottom.
783
 
 **/
784
 
void
785
 
gnome_canvas_item_lower (GnomeCanvasItem *item, int positions)
786
 
{
787
 
        GList *link, *before;
788
 
        GnomeCanvasGroup *parent;
789
 
 
790
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
791
 
        g_return_if_fail (positions >= 1);
792
 
 
793
 
        if (!item->parent || positions == 0)
794
 
                return;
795
 
 
796
 
        parent = GNOME_CANVAS_GROUP (item->parent);
797
 
        link = g_list_find (parent->item_list, item);
798
 
        g_assert (link != NULL);
799
 
 
800
 
        if (link->prev)
801
 
                for (before = link->prev; positions && before; positions--)
802
 
                        before = before->prev;
803
 
        else
804
 
                before = NULL;
805
 
 
806
 
        if (put_item_after (link, before)) {
807
 
                redraw_if_visible (item);
808
 
                item->canvas->need_repick = TRUE;
809
 
        }
810
 
}
811
 
 
812
 
 
813
 
/**
814
 
 * gnome_canvas_item_raise_to_top:
815
 
 * @item: A canvas item.
816
 
 *
817
 
 * Raises an item to the top of its parent's stack.
818
 
 **/
819
 
void
820
 
gnome_canvas_item_raise_to_top (GnomeCanvasItem *item)
821
 
{
822
 
        GList *link;
823
 
        GnomeCanvasGroup *parent;
824
 
 
825
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
826
 
 
827
 
        if (!item->parent)
828
 
                return;
829
 
 
830
 
        parent = GNOME_CANVAS_GROUP (item->parent);
831
 
        link = g_list_find (parent->item_list, item);
832
 
        g_assert (link != NULL);
833
 
 
834
 
        if (put_item_after (link, parent->item_list_end)) {
835
 
                redraw_if_visible (item);
836
 
                item->canvas->need_repick = TRUE;
837
 
        }
838
 
}
839
 
 
840
 
 
841
 
/**
842
 
 * gnome_canvas_item_lower_to_bottom:
843
 
 * @item: A canvas item.
844
 
 *
845
 
 * Lowers an item to the bottom of its parent's stack.
846
 
 **/
847
 
void
848
 
gnome_canvas_item_lower_to_bottom (GnomeCanvasItem *item)
849
 
{
850
 
        GList *link;
851
 
        GnomeCanvasGroup *parent;
852
 
 
853
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
854
 
 
855
 
        if (!item->parent)
856
 
                return;
857
 
 
858
 
        parent = GNOME_CANVAS_GROUP (item->parent);
859
 
        link = g_list_find (parent->item_list, item);
860
 
        g_assert (link != NULL);
861
 
 
862
 
        if (put_item_after (link, NULL)) {
863
 
                redraw_if_visible (item);
864
 
                item->canvas->need_repick = TRUE;
865
 
        }
866
 
}
867
 
 
868
 
 
869
 
/**
870
 
 * gnome_canvas_item_show:
871
 
 * @item: A canvas item.
872
 
 *
873
 
 * Shows a canvas item.  If the item was already shown, then no action is taken.
874
 
 **/
875
 
void
876
 
gnome_canvas_item_show (GnomeCanvasItem *item)
877
 
{
878
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
879
 
 
880
 
        if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)) {
881
 
                item->object.flags |= GNOME_CANVAS_ITEM_VISIBLE;
882
 
                gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
883
 
                item->canvas->need_repick = TRUE;
884
 
        }
885
 
}
886
 
 
887
 
 
888
 
/**
889
 
 * gnome_canvas_item_hide:
890
 
 * @item: A canvas item.
891
 
 *
892
 
 * Hides a canvas item.  If the item was already hidden, then no action is
893
 
 * taken.
894
 
 **/
895
 
void
896
 
gnome_canvas_item_hide (GnomeCanvasItem *item)
897
 
{
898
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
899
 
 
900
 
        if (item->object.flags & GNOME_CANVAS_ITEM_VISIBLE) {
901
 
                item->object.flags &= ~GNOME_CANVAS_ITEM_VISIBLE;
902
 
                gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
903
 
                item->canvas->need_repick = TRUE;
904
 
        }
905
 
}
906
 
 
907
 
 
908
 
/**
909
 
 * gnome_canvas_item_grab:
910
 
 * @item: A canvas item.
911
 
 * @event_mask: Mask of events that will be sent to this item.
912
 
 * @cursor: If non-NULL, the cursor that will be used while the grab is active.
913
 
 * @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME.
914
 
 *
915
 
 * Specifies that all events that match the specified event mask should be sent
916
 
 * to the specified item, and also grabs the mouse by calling
917
 
 * gdk_pointer_grab().  The event mask is also used when grabbing the pointer.
918
 
 * If @cursor is not NULL, then that cursor is used while the grab is active.
919
 
 * The @etime parameter is the timestamp required for grabbing the mouse.
920
 
 *
921
 
 * Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED.  If
922
 
 * the specified item was hidden by calling gnome_canvas_item_hide(), then it
923
 
 * returns %GDK_GRAB_NOT_VIEWABLE.  Else, it returns the result of calling
924
 
 * gdk_pointer_grab().
925
 
 **/
926
 
int
927
 
gnome_canvas_item_grab (GnomeCanvasItem *item, guint event_mask, GdkCursor *cursor, guint32 etime)
928
 
{
929
 
        int retval;
930
 
 
931
 
        g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), GDK_GRAB_NOT_VIEWABLE);
932
 
        g_return_val_if_fail (GTK_WIDGET_MAPPED (item->canvas), GDK_GRAB_NOT_VIEWABLE);
933
 
 
934
 
        if (item->canvas->grabbed_item)
935
 
                return GDK_GRAB_ALREADY_GRABBED;
936
 
 
937
 
        if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
938
 
                return GDK_GRAB_NOT_VIEWABLE;
939
 
 
940
 
        retval = gdk_pointer_grab (item->canvas->layout.bin_window,
941
 
                                   FALSE,
942
 
                                   event_mask,
943
 
                                   NULL,
944
 
                                   cursor,
945
 
                                   etime);
946
 
 
947
 
        if (retval != GDK_GRAB_SUCCESS)
948
 
                return retval;
949
 
 
950
 
        item->canvas->grabbed_item = item;
951
 
        item->canvas->grabbed_event_mask = event_mask;
952
 
        item->canvas->current_item = item; /* So that events go to the grabbed item */
953
 
 
954
 
        return retval;
955
 
}
956
 
 
957
 
 
958
 
/**
959
 
 * gnome_canvas_item_ungrab:
960
 
 * @item: A canvas item that holds a grab.
961
 
 * @etime: The timestamp for ungrabbing the mouse.
962
 
 *
963
 
 * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the
964
 
 * mouse.
965
 
 **/
966
 
void
967
 
gnome_canvas_item_ungrab (GnomeCanvasItem *item, guint32 etime)
968
 
{
969
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
970
 
 
971
 
        if (item->canvas->grabbed_item != item)
972
 
                return;
973
 
 
974
 
        item->canvas->grabbed_item = NULL;
975
 
 
976
 
        gdk_pointer_ungrab (etime);
977
 
}
978
 
 
979
 
 
980
 
/**
981
 
 * gnome_canvas_item_i2w_affine:
982
 
 * @item: A canvas item
983
 
 * @affine: An affine transformation matrix (return value).
984
 
 *
985
 
 * Gets the affine transform that converts from the item's coordinate system to
986
 
 * world coordinates.
987
 
 **/
988
 
void
989
 
gnome_canvas_item_i2w_affine (GnomeCanvasItem *item, double affine[6])
990
 
{
991
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
992
 
        g_return_if_fail (affine != NULL);
993
 
 
994
 
        art_affine_identity (affine);
995
 
 
996
 
        while (item) {
997
 
                if (item->xform != NULL) {
998
 
                        if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
999
 
                                art_affine_multiply (affine, affine, item->xform);
1000
 
                        } else {
1001
 
                                affine[4] += item->xform[0];
1002
 
                                affine[5] += item->xform[1];
1003
 
                        }
1004
 
                }
1005
 
 
1006
 
                item = item->parent;
1007
 
        }
1008
 
}
1009
 
 
1010
 
/**
1011
 
 * gnome_canvas_item_w2i:
1012
 
 * @item: A canvas item.
1013
 
 * @x: X coordinate to convert (input/output value).
1014
 
 * @y: Y coordinate to convert (input/output value).
1015
 
 *
1016
 
 * Converts a coordinate pair from world coordinates to item-relative
1017
 
 * coordinates.
1018
 
 **/
1019
 
void
1020
 
gnome_canvas_item_w2i (GnomeCanvasItem *item, double *x, double *y)
1021
 
{
1022
 
        double affine[6], inv[6];
1023
 
        ArtPoint w, i;
1024
 
 
1025
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1026
 
        g_return_if_fail (x != NULL);
1027
 
        g_return_if_fail (y != NULL);
1028
 
 
1029
 
        gnome_canvas_item_i2w_affine (item, affine);
1030
 
        art_affine_invert (inv, affine);
1031
 
        w.x = *x;
1032
 
        w.y = *y;
1033
 
        art_affine_point (&i, &w, inv);
1034
 
        *x = i.x;
1035
 
        *y = i.y;
1036
 
}
1037
 
 
1038
 
 
1039
 
/**
1040
 
 * gnome_canvas_item_i2w:
1041
 
 * @item: A canvas item.
1042
 
 * @x: X coordinate to convert (input/output value).
1043
 
 * @y: Y coordinate to convert (input/output value).
1044
 
 *
1045
 
 * Converts a coordinate pair from item-relative coordinates to world
1046
 
 * coordinates.
1047
 
 **/
1048
 
void
1049
 
gnome_canvas_item_i2w (GnomeCanvasItem *item, double *x, double *y)
1050
 
{
1051
 
        double affine[6];
1052
 
        ArtPoint w, i;
1053
 
 
1054
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1055
 
        g_return_if_fail (x != NULL);
1056
 
        g_return_if_fail (y != NULL);
1057
 
 
1058
 
        gnome_canvas_item_i2w_affine (item, affine);
1059
 
        i.x = *x;
1060
 
        i.y = *y;
1061
 
        art_affine_point (&w, &i, affine);
1062
 
        *x = w.x;
1063
 
        *y = w.y;
1064
 
}
1065
 
 
1066
 
/**
1067
 
 * gnome_canvas_item_i2c_affine:
1068
 
 * @item: A canvas item.
1069
 
 * @affine: An affine transformation matrix (return value).
1070
 
 *
1071
 
 * Gets the affine transform that converts from item-relative coordinates to
1072
 
 * canvas pixel coordinates.
1073
 
 **/
1074
 
void
1075
 
gnome_canvas_item_i2c_affine (GnomeCanvasItem *item, double affine[6])
1076
 
{
1077
 
        double i2w[6], w2c[6];
1078
 
 
1079
 
        gnome_canvas_item_i2w_affine (item, i2w);
1080
 
        gnome_canvas_w2c_affine (item->canvas, w2c);
1081
 
        art_affine_multiply (affine, i2w, w2c);
1082
 
}
1083
 
 
1084
 
/* Returns whether the item is an inferior of or is equal to the parent. */
1085
 
static int
1086
 
is_descendant (GnomeCanvasItem *item, GnomeCanvasItem *parent)
1087
 
{
1088
 
        for (; item; item = item->parent)
1089
 
                if (item == parent)
1090
 
                        return TRUE;
1091
 
 
1092
 
        return FALSE;
1093
 
}
1094
 
 
1095
 
/**
1096
 
 * gnome_canvas_item_reparent:
1097
 
 * @item: A canvas item.
1098
 
 * @new_group: A canvas group.
1099
 
 *
1100
 
 * Changes the parent of the specified item to be the new group.  The item keeps
1101
 
 * its group-relative coordinates as for its old parent, so the item may change
1102
 
 * its absolute position within the canvas.
1103
 
 **/
1104
 
void
1105
 
gnome_canvas_item_reparent (GnomeCanvasItem *item, GnomeCanvasGroup *new_group)
1106
 
{
1107
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1108
 
        g_return_if_fail (GNOME_IS_CANVAS_GROUP (new_group));
1109
 
 
1110
 
        /* Both items need to be in the same canvas */
1111
 
        g_return_if_fail (item->canvas == GNOME_CANVAS_ITEM (new_group)->canvas);
1112
 
 
1113
 
        /* The group cannot be an inferior of the item or be the item itself --
1114
 
         * this also takes care of the case where the item is the root item of
1115
 
         * the canvas.  */
1116
 
        g_return_if_fail (!is_descendant (GNOME_CANVAS_ITEM (new_group), item));
1117
 
 
1118
 
        /* Everything is ok, now actually reparent the item */
1119
 
 
1120
 
        g_object_ref (G_OBJECT (item)); /* protect it from the unref in group_remove */
1121
 
 
1122
 
        redraw_if_visible (item);
1123
 
 
1124
 
        group_remove (GNOME_CANVAS_GROUP (item->parent), item);
1125
 
        item->parent = GNOME_CANVAS_ITEM (new_group);
1126
 
        group_add (new_group, item);
1127
 
 
1128
 
        /* Redraw and repick */
1129
 
 
1130
 
        redraw_if_visible (item);
1131
 
        item->canvas->need_repick = TRUE;
1132
 
 
1133
 
        g_object_unref (G_OBJECT (item));
1134
 
}
1135
 
 
1136
 
/**
1137
 
 * gnome_canvas_item_grab_focus:
1138
 
 * @item: A canvas item.
1139
 
 *
1140
 
 * Makes the specified item take the keyboard focus, so all keyboard events will
1141
 
 * be sent to it.  If the canvas widget itself did not have the focus, it grabs
1142
 
 * it as well.
1143
 
 **/
1144
 
void
1145
 
gnome_canvas_item_grab_focus (GnomeCanvasItem *item)
1146
 
{
1147
 
        GnomeCanvasItem *focused_item;
1148
 
        GdkEvent ev;
1149
 
 
1150
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1151
 
        g_return_if_fail (GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (item->canvas)));
1152
 
 
1153
 
        focused_item = item->canvas->focused_item;
1154
 
 
1155
 
        if (focused_item) {
1156
 
                ev.focus_change.type = GDK_FOCUS_CHANGE;
1157
 
                ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
1158
 
                ev.focus_change.send_event = FALSE;
1159
 
                ev.focus_change.in = FALSE;
1160
 
 
1161
 
                emit_event (item->canvas, &ev);
1162
 
        }
1163
 
 
1164
 
        item->canvas->focused_item = item;
1165
 
        gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
1166
 
 
1167
 
        if (focused_item) {
1168
 
                ev.focus_change.type = GDK_FOCUS_CHANGE;
1169
 
                ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
1170
 
                ev.focus_change.send_event = FALSE;
1171
 
                ev.focus_change.in = TRUE;
1172
 
 
1173
 
                emit_event (item->canvas, &ev);
1174
 
        }
1175
 
}
1176
 
 
1177
 
 
1178
 
/**
1179
 
 * gnome_canvas_item_get_bounds:
1180
 
 * @item: A canvas item.
1181
 
 * @x1: Leftmost edge of the bounding box (return value).
1182
 
 * @y1: Upper edge of the bounding box (return value).
1183
 
 * @x2: Rightmost edge of the bounding box (return value).
1184
 
 * @y2: Lower edge of the bounding box (return value).
1185
 
 *
1186
 
 * Queries the bounding box of a canvas item.  The bounds are returned in the
1187
 
 * coordinate system of the item's parent.
1188
 
 **/
1189
 
void
1190
 
gnome_canvas_item_get_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1191
 
{
1192
 
        double tx1, ty1, tx2, ty2;
1193
 
        ArtPoint p1, p2, p3, p4;
1194
 
        ArtPoint q1, q2, q3, q4;
1195
 
        double min_x1, min_y1, min_x2, min_y2;
1196
 
        double max_x1, max_y1, max_x2, max_y2;
1197
 
 
1198
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1199
 
 
1200
 
        tx1 = ty1 = tx2 = ty2 = 0.0;
1201
 
 
1202
 
        /* Get the item's bounds in its coordinate system */
1203
 
 
1204
 
        if (GNOME_CANVAS_ITEM_GET_CLASS (item)->bounds)
1205
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->bounds) (item, &tx1, &ty1, &tx2, &ty2);
1206
 
 
1207
 
        /* Make the bounds relative to the item's parent coordinate system */
1208
 
 
1209
 
        if (item->xform && (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL)) {
1210
 
                p1.x = p2.x = tx1;
1211
 
                p1.y = p4.y = ty1;
1212
 
                p3.x = p4.x = tx2;
1213
 
                p2.y = p3.y = ty2;
1214
 
 
1215
 
                art_affine_point (&q1, &p1, item->xform);
1216
 
                art_affine_point (&q2, &p2, item->xform);
1217
 
                art_affine_point (&q3, &p3, item->xform);
1218
 
                art_affine_point (&q4, &p4, item->xform);
1219
 
 
1220
 
                if (q1.x < q2.x) {
1221
 
                        min_x1 = q1.x;
1222
 
                        max_x1 = q2.x;
1223
 
                } else {
1224
 
                        min_x1 = q2.x;
1225
 
                        max_x1 = q1.x;
1226
 
                }
1227
 
 
1228
 
                if (q1.y < q2.y) {
1229
 
                        min_y1 = q1.y;
1230
 
                        max_y1 = q2.y;
1231
 
                } else {
1232
 
                        min_y1 = q2.y;
1233
 
                        max_y1 = q1.y;
1234
 
                }
1235
 
 
1236
 
                if (q3.x < q4.x) {
1237
 
                        min_x2 = q3.x;
1238
 
                        max_x2 = q4.x;
1239
 
                } else {
1240
 
                        min_x2 = q4.x;
1241
 
                        max_x2 = q3.x;
1242
 
                }
1243
 
 
1244
 
                if (q3.y < q4.y) {
1245
 
                        min_y2 = q3.y;
1246
 
                        max_y2 = q4.y;
1247
 
                } else {
1248
 
                        min_y2 = q4.y;
1249
 
                        max_y2 = q3.y;
1250
 
                }
1251
 
 
1252
 
                tx1 = MIN (min_x1, min_x2);
1253
 
                ty1 = MIN (min_y1, min_y2);
1254
 
                tx2 = MAX (max_x1, max_x2);
1255
 
                ty2 = MAX (max_y1, max_y2);
1256
 
        } else if (item->xform) {
1257
 
                tx1 += item->xform[0];
1258
 
                ty1 += item->xform[1];
1259
 
                tx2 += item->xform[0];
1260
 
                ty2 += item->xform[1];
1261
 
        }
1262
 
 
1263
 
        /* Return the values */
1264
 
 
1265
 
        if (x1)
1266
 
                *x1 = tx1;
1267
 
 
1268
 
        if (y1)
1269
 
                *y1 = ty1;
1270
 
 
1271
 
        if (x2)
1272
 
                *x2 = tx2;
1273
 
 
1274
 
        if (y2)
1275
 
                *y2 = ty2;
1276
 
}
1277
 
 
1278
 
 
1279
 
/**
1280
 
 * gnome_canvas_item_request_update
1281
 
 * @item: A canvas item.
1282
 
 *
1283
 
 * To be used only by item implementations.  Requests that the canvas queue an
1284
 
 * update for the specified item.
1285
 
 **/
1286
 
void
1287
 
gnome_canvas_item_request_update (GnomeCanvasItem *item)
1288
 
{
1289
 
        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_UPDATE)
1290
 
                return;
1291
 
 
1292
 
        item->object.flags |= GNOME_CANVAS_ITEM_NEED_UPDATE;
1293
 
 
1294
 
        if (item->parent != NULL) {
1295
 
                /* Recurse up the tree */
1296
 
                gnome_canvas_item_request_update (item->parent);
1297
 
        } else {
1298
 
                /* Have reached the top of the tree, make sure the update call gets scheduled. */
1299
 
                gnome_canvas_request_update (item->canvas);
1300
 
        }
1301
 
}
1302
 
 
1303
 
/*** GnomeCanvasGroup ***/
1304
 
 
1305
 
 
1306
 
enum {
1307
 
        GROUP_PROP_0,
1308
 
        GROUP_PROP_X,
1309
 
        GROUP_PROP_Y
1310
 
};
1311
 
 
1312
 
 
1313
 
static void gnome_canvas_group_class_init  (GnomeCanvasGroupClass *class);
1314
 
static void gnome_canvas_group_init        (GnomeCanvasGroup      *group);
1315
 
static void gnome_canvas_group_set_property(GObject               *object,
1316
 
                                            guint                  param_id,
1317
 
                                            const GValue          *value,
1318
 
                                            GParamSpec            *pspec);
1319
 
static void gnome_canvas_group_get_property(GObject               *object,
1320
 
                                            guint                  param_id,
1321
 
                                            GValue                *value,
1322
 
                                            GParamSpec            *pspec);
1323
 
 
1324
 
static void gnome_canvas_group_destroy     (GtkObject             *object);
1325
 
 
1326
 
static void   gnome_canvas_group_update      (GnomeCanvasItem *item, double *affine,
1327
 
                                              ArtSVP *clip_path, int flags);
1328
 
static void   gnome_canvas_group_realize     (GnomeCanvasItem *item);
1329
 
static void   gnome_canvas_group_unrealize   (GnomeCanvasItem *item);
1330
 
static void   gnome_canvas_group_map         (GnomeCanvasItem *item);
1331
 
static void   gnome_canvas_group_unmap       (GnomeCanvasItem *item);
1332
 
static void   gnome_canvas_group_draw        (GnomeCanvasItem *item, GdkDrawable *drawable,
1333
 
                                              int x, int y, int width, int height);
1334
 
static double gnome_canvas_group_point       (GnomeCanvasItem *item, double x, double y,
1335
 
                                              int cx, int cy,
1336
 
                                              GnomeCanvasItem **actual_item);
1337
 
static void   gnome_canvas_group_bounds      (GnomeCanvasItem *item, double *x1, double *y1,
1338
 
                                              double *x2, double *y2);
1339
 
static void   gnome_canvas_group_render      (GnomeCanvasItem *item,
1340
 
                                              GnomeCanvasBuf *buf);
1341
 
 
1342
 
 
1343
 
static GnomeCanvasItemClass *group_parent_class;
1344
 
 
1345
 
 
1346
 
/**
1347
 
 * gnome_canvas_group_get_type:
1348
 
 *
1349
 
 * Registers the &GnomeCanvasGroup class if necessary, and returns the type ID
1350
 
 * associated to it.
1351
 
 *
1352
 
 * Return value:  The type ID of the &GnomeCanvasGroup class.
1353
 
 **/
1354
 
GType
1355
 
gnome_canvas_group_get_type (void)
1356
 
{
1357
 
        static GType canvas_group_type;
1358
 
 
1359
 
        if (!canvas_group_type) {
1360
 
                static const GTypeInfo object_info = {
1361
 
                        sizeof (GnomeCanvasGroupClass),
1362
 
                        (GBaseInitFunc) NULL,
1363
 
                        (GBaseFinalizeFunc) NULL,
1364
 
                        (GClassInitFunc) gnome_canvas_group_class_init,
1365
 
                        (GClassFinalizeFunc) NULL,
1366
 
                        NULL,                   /* class_data */
1367
 
                        sizeof (GnomeCanvasGroup),
1368
 
                        0,                      /* n_preallocs */
1369
 
                        (GInstanceInitFunc) gnome_canvas_group_init,
1370
 
                        NULL                    /* value_table */
1371
 
                };
1372
 
 
1373
 
                canvas_group_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasGroup",
1374
 
                                                            &object_info, 0);
1375
 
        }
1376
 
 
1377
 
        return canvas_group_type;
1378
 
}
1379
 
 
1380
 
/* Class initialization function for GnomeCanvasGroupClass */
1381
 
static void
1382
 
gnome_canvas_group_class_init (GnomeCanvasGroupClass *class)
1383
 
{
1384
 
        GObjectClass *gobject_class;
1385
 
        GtkObjectClass *object_class;
1386
 
        GnomeCanvasItemClass *item_class;
1387
 
 
1388
 
        gobject_class = (GObjectClass *) class;
1389
 
        object_class = (GtkObjectClass *) class;
1390
 
        item_class = (GnomeCanvasItemClass *) class;
1391
 
 
1392
 
        group_parent_class = g_type_class_peek_parent (class);
1393
 
 
1394
 
        gobject_class->set_property = gnome_canvas_group_set_property;
1395
 
        gobject_class->get_property = gnome_canvas_group_get_property;
1396
 
 
1397
 
        g_object_class_install_property
1398
 
                (gobject_class, GROUP_PROP_X,
1399
 
                 g_param_spec_double ("x",
1400
 
                                      "X",
1401
 
                                      "X",
1402
 
                                      -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
1403
 
                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
1404
 
        g_object_class_install_property
1405
 
                (gobject_class, GROUP_PROP_Y,
1406
 
                 g_param_spec_double ("y",
1407
 
                                      "Y",
1408
 
                                      "Y",
1409
 
                                      -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
1410
 
                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
1411
 
 
1412
 
        object_class->destroy = gnome_canvas_group_destroy;
1413
 
 
1414
 
        item_class->update = gnome_canvas_group_update;
1415
 
        item_class->realize = gnome_canvas_group_realize;
1416
 
        item_class->unrealize = gnome_canvas_group_unrealize;
1417
 
        item_class->map = gnome_canvas_group_map;
1418
 
        item_class->unmap = gnome_canvas_group_unmap;
1419
 
        item_class->draw = gnome_canvas_group_draw;
1420
 
        item_class->render = gnome_canvas_group_render;
1421
 
        item_class->point = gnome_canvas_group_point;
1422
 
        item_class->bounds = gnome_canvas_group_bounds;
1423
 
}
1424
 
 
1425
 
/* Object initialization function for GnomeCanvasGroup */
1426
 
static void
1427
 
gnome_canvas_group_init (GnomeCanvasGroup *group)
1428
 
{
1429
 
#if 0
1430
 
        group->xpos = 0.0;
1431
 
        group->ypos = 0.0;
1432
 
#endif
1433
 
}
1434
 
 
1435
 
/* Translate handler for canvas groups */
1436
 
static double *
1437
 
gnome_canvas_ensure_translate (GnomeCanvasItem *item)
1438
 
{
1439
 
        if (item->xform == NULL) {
1440
 
                GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_AFFINE_FULL);
1441
 
                item->xform = g_new (double, 2);
1442
 
                item->xform[0] = 0.0;
1443
 
                item->xform[1] = 0.0;
1444
 
                return item->xform;
1445
 
        } else if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
1446
 
                return item->xform + 4;
1447
 
        } else {
1448
 
                return item->xform;
1449
 
        }
1450
 
}
1451
 
 
1452
 
/* Set_property handler for canvas groups */
1453
 
static void
1454
 
gnome_canvas_group_set_property (GObject *gobject, guint param_id,
1455
 
                                 const GValue *value, GParamSpec *pspec)
1456
 
{
1457
 
        GnomeCanvasItem *item;
1458
 
        double *xlat;
1459
 
 
1460
 
        g_return_if_fail (GNOME_IS_CANVAS_GROUP (gobject));
1461
 
 
1462
 
        item = GNOME_CANVAS_ITEM (gobject);
1463
 
 
1464
 
        switch (param_id) {
1465
 
        case GROUP_PROP_X:
1466
 
                xlat = gnome_canvas_ensure_translate (item);
1467
 
                xlat[0] = g_value_get_double (value);
1468
 
                break;
1469
 
 
1470
 
        case GROUP_PROP_Y:
1471
 
                xlat = gnome_canvas_ensure_translate (item);
1472
 
                xlat[1] = g_value_get_double (value);
1473
 
                break;
1474
 
 
1475
 
        default:
1476
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
1477
 
                break;
1478
 
        }
1479
 
}
1480
 
 
1481
 
/* Get_property handler for canvas groups */
1482
 
static void
1483
 
gnome_canvas_group_get_property (GObject *gobject, guint param_id,
1484
 
                                 GValue *value, GParamSpec *pspec)
1485
 
{
1486
 
        GnomeCanvasItem *item;
1487
 
 
1488
 
        g_return_if_fail (GNOME_IS_CANVAS_GROUP (gobject));
1489
 
 
1490
 
        item = GNOME_CANVAS_ITEM (gobject);
1491
 
 
1492
 
        switch (param_id) {
1493
 
        case GROUP_PROP_X:
1494
 
                if (item->xform == NULL)
1495
 
                        g_value_set_double (value, 0);
1496
 
                else if (GTK_OBJECT (gobject)->flags & GNOME_CANVAS_ITEM_AFFINE_FULL)
1497
 
                        g_value_set_double (value, item->xform[4]);
1498
 
                else
1499
 
                        g_value_set_double (value, item->xform[0]);
1500
 
                break;
1501
 
 
1502
 
        case GROUP_PROP_Y:
1503
 
                if (item->xform == NULL)
1504
 
                        g_value_set_double (value, 0);
1505
 
                else if (GTK_OBJECT (gobject)->flags & GNOME_CANVAS_ITEM_AFFINE_FULL)
1506
 
                        g_value_set_double (value, item->xform[5]);
1507
 
                else
1508
 
                        g_value_set_double (value, item->xform[1]);
1509
 
                break;
1510
 
 
1511
 
        default:
1512
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
1513
 
                break;
1514
 
        }
1515
 
}
1516
 
 
1517
 
/* Destroy handler for canvas groups */
1518
 
static void
1519
 
gnome_canvas_group_destroy (GtkObject *object)
1520
 
{
1521
 
        GnomeCanvasGroup *group;
1522
 
 
1523
 
        g_return_if_fail (GNOME_IS_CANVAS_GROUP (object));
1524
 
 
1525
 
        group = GNOME_CANVAS_GROUP (object);
1526
 
 
1527
 
        while (group->item_list) {
1528
 
                // child is unref'ed by the child's group_remove().
1529
 
                gtk_object_destroy (GTK_OBJECT (group->item_list->data));
1530
 
        }
1531
 
 
1532
 
        if (GTK_OBJECT_CLASS (group_parent_class)->destroy)
1533
 
                (* GTK_OBJECT_CLASS (group_parent_class)->destroy) (object);
1534
 
}
1535
 
 
1536
 
/* Update handler for canvas groups */
1537
 
static void
1538
 
gnome_canvas_group_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1539
 
{
1540
 
        GnomeCanvasGroup *group;
1541
 
        GList *list;
1542
 
        GnomeCanvasItem *i;
1543
 
        ArtDRect bbox, child_bbox;
1544
 
 
1545
 
        group = GNOME_CANVAS_GROUP (item);
1546
 
 
1547
 
        (* group_parent_class->update) (item, affine, clip_path, flags);
1548
 
 
1549
 
        bbox.x0 = 0;
1550
 
        bbox.y0 = 0;
1551
 
        bbox.x1 = 0;
1552
 
        bbox.y1 = 0;
1553
 
 
1554
 
        for (list = group->item_list; list; list = list->next) {
1555
 
                i = list->data;
1556
 
 
1557
 
                gnome_canvas_item_invoke_update (i, affine, clip_path, flags);
1558
 
 
1559
 
                child_bbox.x0 = i->x1;
1560
 
                child_bbox.y0 = i->y1;
1561
 
                child_bbox.x1 = i->x2;
1562
 
                child_bbox.y1 = i->y2;
1563
 
                art_drect_union (&bbox, &bbox, &child_bbox);
1564
 
        }
1565
 
        item->x1 = bbox.x0;
1566
 
        item->y1 = bbox.y0;
1567
 
        item->x2 = bbox.x1;
1568
 
        item->y2 = bbox.y1;
1569
 
}
1570
 
 
1571
 
/* Realize handler for canvas groups */
1572
 
static void
1573
 
gnome_canvas_group_realize (GnomeCanvasItem *item)
1574
 
{
1575
 
        GnomeCanvasGroup *group;
1576
 
        GList *list;
1577
 
        GnomeCanvasItem *i;
1578
 
 
1579
 
        group = GNOME_CANVAS_GROUP (item);
1580
 
 
1581
 
        for (list = group->item_list; list; list = list->next) {
1582
 
                i = list->data;
1583
 
 
1584
 
                if (!(i->object.flags & GNOME_CANVAS_ITEM_REALIZED))
1585
 
                        (* GNOME_CANVAS_ITEM_GET_CLASS (i)->realize) (i);
1586
 
        }
1587
 
 
1588
 
        (* group_parent_class->realize) (item);
1589
 
}
1590
 
 
1591
 
/* Unrealize handler for canvas groups */
1592
 
static void
1593
 
gnome_canvas_group_unrealize (GnomeCanvasItem *item)
1594
 
{
1595
 
        GnomeCanvasGroup *group;
1596
 
        GList *list;
1597
 
        GnomeCanvasItem *i;
1598
 
 
1599
 
        group = GNOME_CANVAS_GROUP (item);
1600
 
 
1601
 
        for (list = group->item_list; list; list = list->next) {
1602
 
                i = list->data;
1603
 
 
1604
 
                if (i->object.flags & GNOME_CANVAS_ITEM_REALIZED)
1605
 
                        (* GNOME_CANVAS_ITEM_GET_CLASS (i)->unrealize) (i);
1606
 
        }
1607
 
 
1608
 
        (* group_parent_class->unrealize) (item);
1609
 
}
1610
 
 
1611
 
/* Map handler for canvas groups */
1612
 
static void
1613
 
gnome_canvas_group_map (GnomeCanvasItem *item)
1614
 
{
1615
 
        GnomeCanvasGroup *group;
1616
 
        GList *list;
1617
 
        GnomeCanvasItem *i;
1618
 
 
1619
 
        group = GNOME_CANVAS_GROUP (item);
1620
 
 
1621
 
        for (list = group->item_list; list; list = list->next) {
1622
 
                i = list->data;
1623
 
 
1624
 
                if (!(i->object.flags & GNOME_CANVAS_ITEM_MAPPED))
1625
 
                        (* GNOME_CANVAS_ITEM_GET_CLASS (i)->map) (i);
1626
 
        }
1627
 
 
1628
 
        (* group_parent_class->map) (item);
1629
 
}
1630
 
 
1631
 
/* Unmap handler for canvas groups */
1632
 
static void
1633
 
gnome_canvas_group_unmap (GnomeCanvasItem *item)
1634
 
{
1635
 
        GnomeCanvasGroup *group;
1636
 
        GList *list;
1637
 
        GnomeCanvasItem *i;
1638
 
 
1639
 
        group = GNOME_CANVAS_GROUP (item);
1640
 
 
1641
 
        for (list = group->item_list; list; list = list->next) {
1642
 
                i = list->data;
1643
 
 
1644
 
                if (i->object.flags & GNOME_CANVAS_ITEM_MAPPED)
1645
 
                        (* GNOME_CANVAS_ITEM_GET_CLASS (i)->unmap) (i);
1646
 
        }
1647
 
 
1648
 
        (* group_parent_class->unmap) (item);
1649
 
}
1650
 
 
1651
 
/* Draw handler for canvas groups */
1652
 
static void
1653
 
gnome_canvas_group_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
1654
 
                         int x, int y, int width, int height)
1655
 
{
1656
 
        GnomeCanvasGroup *group;
1657
 
        GList *list;
1658
 
        GnomeCanvasItem *child = NULL;
1659
 
 
1660
 
        group = GNOME_CANVAS_GROUP (item);
1661
 
 
1662
 
        for (list = group->item_list; list; list = list->next) {
1663
 
                child = list->data;
1664
 
 
1665
 
                if (((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
1666
 
                     && ((child->x1 < (x + width))
1667
 
                         && (child->y1 < (y + height))
1668
 
                         && (child->x2 > x)
1669
 
                         && (child->y2 > y)))
1670
 
                    || ((GTK_OBJECT_FLAGS (child) & GNOME_CANVAS_ITEM_ALWAYS_REDRAW)
1671
 
                        && (child->x1 < child->canvas->redraw_x2)
1672
 
                        && (child->y1 < child->canvas->redraw_y2)
1673
 
                        && (child->x2 > child->canvas->redraw_x1)
1674
 
                        && (child->y2 > child->canvas->redraw_y2)))
1675
 
                        if (GNOME_CANVAS_ITEM_GET_CLASS (child)->draw)
1676
 
                                (* GNOME_CANVAS_ITEM_GET_CLASS (child)->draw) (
1677
 
                                        child, drawable, x, y, width, height);
1678
 
        }
1679
 
}
1680
 
 
1681
 
/* Point handler for canvas groups */
1682
 
static double
1683
 
gnome_canvas_group_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
1684
 
                          GnomeCanvasItem **actual_item)
1685
 
{
1686
 
        GnomeCanvasGroup *group;
1687
 
        GList *list;
1688
 
        GnomeCanvasItem *child, *point_item;
1689
 
        int x1, y1, x2, y2;
1690
 
        double gx, gy;
1691
 
        double dist, best;
1692
 
        int has_point;
1693
 
 
1694
 
        group = GNOME_CANVAS_GROUP (item);
1695
 
 
1696
 
        x1 = cx - item->canvas->close_enough;
1697
 
        y1 = cy - item->canvas->close_enough;
1698
 
        x2 = cx + item->canvas->close_enough;
1699
 
        y2 = cy + item->canvas->close_enough;
1700
 
 
1701
 
        best = 0.0;
1702
 
        *actual_item = NULL;
1703
 
 
1704
 
        gx = x;
1705
 
        gy = y;
1706
 
 
1707
 
        dist = 0.0; /* keep gcc happy */
1708
 
 
1709
 
        for (list = group->item_list; list; list = list->next) {
1710
 
                child = list->data;
1711
 
 
1712
 
                if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1))
1713
 
                        continue;
1714
 
 
1715
 
                point_item = NULL; /* cater for incomplete item implementations */
1716
 
 
1717
 
                if ((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
1718
 
                    && GNOME_CANVAS_ITEM_GET_CLASS (child)->point) {
1719
 
                        dist = gnome_canvas_item_invoke_point (child, gx, gy, cx, cy, &point_item);
1720
 
                        has_point = TRUE;
1721
 
                } else
1722
 
                        has_point = FALSE;
1723
 
 
1724
 
                if (has_point
1725
 
                    && point_item
1726
 
                    && ((int) (dist * item->canvas->pixels_per_unit + 0.5)
1727
 
                        <= item->canvas->close_enough)) {
1728
 
                        best = dist;
1729
 
                        *actual_item = point_item;
1730
 
                }
1731
 
        }
1732
 
 
1733
 
        return best;
1734
 
}
1735
 
 
1736
 
/* Bounds handler for canvas groups */
1737
 
static void
1738
 
gnome_canvas_group_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1739
 
{
1740
 
        GnomeCanvasGroup *group;
1741
 
        GnomeCanvasItem *child;
1742
 
        GList *list;
1743
 
        double tx1, ty1, tx2, ty2;
1744
 
        double minx, miny, maxx, maxy;
1745
 
        int set;
1746
 
 
1747
 
        group = GNOME_CANVAS_GROUP (item);
1748
 
 
1749
 
        /* Get the bounds of the first visible item */
1750
 
 
1751
 
        child = NULL; /* Unnecessary but eliminates a warning. */
1752
 
 
1753
 
        set = FALSE;
1754
 
 
1755
 
        for (list = group->item_list; list; list = list->next) {
1756
 
                child = list->data;
1757
 
 
1758
 
                if (child->object.flags & GNOME_CANVAS_ITEM_VISIBLE) {
1759
 
                        set = TRUE;
1760
 
                        gnome_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy);
1761
 
                        break;
1762
 
                }
1763
 
        }
1764
 
 
1765
 
        /* If there were no visible items, return an empty bounding box */
1766
 
 
1767
 
        if (!set) {
1768
 
                *x1 = *y1 = *x2 = *y2 = 0.0;
1769
 
                return;
1770
 
        }
1771
 
 
1772
 
        /* Now we can grow the bounds using the rest of the items */
1773
 
 
1774
 
        list = list->next;
1775
 
 
1776
 
        for (; list; list = list->next) {
1777
 
                child = list->data;
1778
 
 
1779
 
                if (!(child->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
1780
 
                        continue;
1781
 
 
1782
 
                gnome_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2);
1783
 
 
1784
 
                if (tx1 < minx)
1785
 
                        minx = tx1;
1786
 
 
1787
 
                if (ty1 < miny)
1788
 
                        miny = ty1;
1789
 
 
1790
 
                if (tx2 > maxx)
1791
 
                        maxx = tx2;
1792
 
 
1793
 
                if (ty2 > maxy)
1794
 
                        maxy = ty2;
1795
 
        }
1796
 
 
1797
 
        *x1 = minx;
1798
 
        *y1 = miny;
1799
 
        *x2 = maxx;
1800
 
        *y2 = maxy;
1801
 
}
1802
 
 
1803
 
/* Render handler for canvas groups */
1804
 
static void
1805
 
gnome_canvas_group_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
1806
 
{
1807
 
        GnomeCanvasGroup *group;
1808
 
        GnomeCanvasItem *child;
1809
 
        GList *list;
1810
 
 
1811
 
        group = GNOME_CANVAS_GROUP (item);
1812
 
 
1813
 
        for (list = group->item_list; list; list = list->next) {
1814
 
                child = list->data;
1815
 
 
1816
 
                if (((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
1817
 
                     && ((child->x1 < buf->rect.x1)
1818
 
                         && (child->y1 < buf->rect.y1)
1819
 
                         && (child->x2 > buf->rect.x0)
1820
 
                         && (child->y2 > buf->rect.y0)))
1821
 
                    || ((GTK_OBJECT_FLAGS (child) & GNOME_CANVAS_ITEM_ALWAYS_REDRAW)
1822
 
                        && (child->x1 < child->canvas->redraw_x2)
1823
 
                        && (child->y1 < child->canvas->redraw_y2)
1824
 
                        && (child->x2 > child->canvas->redraw_x1)
1825
 
                        && (child->y2 > child->canvas->redraw_y2)))
1826
 
                        if (GNOME_CANVAS_ITEM_GET_CLASS (child)->render)
1827
 
                                (* GNOME_CANVAS_ITEM_GET_CLASS (child)->render) (
1828
 
                                        child, buf);
1829
 
        }
1830
 
}
1831
 
 
1832
 
/* Adds an item to a group */
1833
 
static void
1834
 
group_add (GnomeCanvasGroup *group, GnomeCanvasItem *item)
1835
 
{
1836
 
        g_object_ref (G_OBJECT (item));
1837
 
        gtk_object_sink (GTK_OBJECT (item));
1838
 
 
1839
 
        if (!group->item_list) {
1840
 
                group->item_list = g_list_append (group->item_list, item);
1841
 
                group->item_list_end = group->item_list;
1842
 
        } else
1843
 
                group->item_list_end = g_list_append (group->item_list_end, item)->next;
1844
 
 
1845
 
        if (group->item.object.flags & GNOME_CANVAS_ITEM_REALIZED)
1846
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
1847
 
 
1848
 
        if (group->item.object.flags & GNOME_CANVAS_ITEM_MAPPED)
1849
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->map) (item);
1850
 
 
1851
 
        g_object_notify (G_OBJECT (item), "parent");
1852
 
}
1853
 
 
1854
 
/* Removes an item from a group */
1855
 
static void
1856
 
group_remove (GnomeCanvasGroup *group, GnomeCanvasItem *item)
1857
 
{
1858
 
        GList *children;
1859
 
 
1860
 
        g_return_if_fail (GNOME_IS_CANVAS_GROUP (group));
1861
 
        g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
1862
 
 
1863
 
        for (children = group->item_list; children; children = children->next)
1864
 
                if (children->data == item) {
1865
 
                        if (item->object.flags & GNOME_CANVAS_ITEM_MAPPED)
1866
 
                                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
1867
 
 
1868
 
                        if (item->object.flags & GNOME_CANVAS_ITEM_REALIZED)
1869
 
                                (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
1870
 
 
1871
 
                        /* Unparent the child */
1872
 
 
1873
 
                        item->parent = NULL;
1874
 
                        g_object_unref (G_OBJECT (item));
1875
 
 
1876
 
                        /* Remove it from the list */
1877
 
 
1878
 
                        if (children == group->item_list_end)
1879
 
                                group->item_list_end = children->prev;
1880
 
 
1881
 
                        group->item_list = g_list_remove_link (group->item_list, children);
1882
 
                        g_list_free (children);
1883
 
                        break;
1884
 
                }
1885
 
}
1886
 
 
1887
 
 
1888
 
/*** GnomeCanvas ***/
1889
 
 
1890
 
 
1891
 
enum {
1892
 
        DRAW_BACKGROUND,
1893
 
        RENDER_BACKGROUND,
1894
 
        LAST_SIGNAL
1895
 
};
1896
 
 
1897
 
static void gnome_canvas_class_init          (GnomeCanvasClass *class);
1898
 
static void gnome_canvas_init                (GnomeCanvas      *canvas);
1899
 
static void gnome_canvas_destroy             (GtkObject        *object);
1900
 
static void gnome_canvas_map                 (GtkWidget        *widget);
1901
 
static void gnome_canvas_unmap               (GtkWidget        *widget);
1902
 
static void gnome_canvas_realize             (GtkWidget        *widget);
1903
 
static void gnome_canvas_unrealize           (GtkWidget        *widget);
1904
 
static void gnome_canvas_size_allocate       (GtkWidget        *widget,
1905
 
                                              GtkAllocation    *allocation);
1906
 
static gint gnome_canvas_button              (GtkWidget        *widget,
1907
 
                                              GdkEventButton   *event);
1908
 
static gint gnome_canvas_motion              (GtkWidget        *widget,
1909
 
                                              GdkEventMotion   *event);
1910
 
static gint gnome_canvas_expose              (GtkWidget        *widget,
1911
 
                                              GdkEventExpose   *event);
1912
 
static gboolean gnome_canvas_key             (GtkWidget        *widget,
1913
 
                                              GdkEventKey      *event);
1914
 
static gint gnome_canvas_crossing            (GtkWidget        *widget,
1915
 
                                              GdkEventCrossing *event);
1916
 
static gint gnome_canvas_focus_in            (GtkWidget        *widget,
1917
 
                                              GdkEventFocus    *event);
1918
 
static gint gnome_canvas_focus_out           (GtkWidget        *widget,
1919
 
                                              GdkEventFocus    *event);
1920
 
static void gnome_canvas_request_update_real (GnomeCanvas      *canvas);
1921
 
static void gnome_canvas_draw_background     (GnomeCanvas      *canvas,
1922
 
                                              GdkDrawable      *drawable,
1923
 
                                              int               x,
1924
 
                                              int               y,
1925
 
                                              int               width,
1926
 
                                              int               height);
1927
 
 
1928
 
 
1929
 
static GtkLayoutClass *canvas_parent_class;
1930
 
 
1931
 
static guint canvas_signals[LAST_SIGNAL];
1932
 
 
1933
 
enum {
1934
 
        PROP_AA = 1
1935
 
};
1936
 
 
1937
 
/**
1938
 
 * gnome_canvas_get_type:
1939
 
 *
1940
 
 * Registers the &GnomeCanvas class if necessary, and returns the type ID
1941
 
 * associated to it.
1942
 
 *
1943
 
 * Return value:  The type ID of the &GnomeCanvas class.
1944
 
 **/
1945
 
GType
1946
 
gnome_canvas_get_type (void)
1947
 
{
1948
 
        static GType canvas_type;
1949
 
 
1950
 
        if (!canvas_type) {
1951
 
                static const GTypeInfo object_info = {
1952
 
                        sizeof (GnomeCanvasClass),
1953
 
                        (GBaseInitFunc) NULL,
1954
 
                        (GBaseFinalizeFunc) NULL,
1955
 
                        (GClassInitFunc) gnome_canvas_class_init,
1956
 
                        (GClassFinalizeFunc) NULL,
1957
 
                        NULL,                   /* class_data */
1958
 
                        sizeof (GnomeCanvas),
1959
 
                        0,                      /* n_preallocs */
1960
 
                        (GInstanceInitFunc) gnome_canvas_init,
1961
 
                        NULL                    /* value_table */
1962
 
                };
1963
 
 
1964
 
                canvas_type = g_type_register_static (GTK_TYPE_LAYOUT, "GnomeCanvas",
1965
 
                                                      &object_info, 0);
1966
 
        }
1967
 
 
1968
 
        return canvas_type;
1969
 
}
1970
 
 
1971
 
static void
1972
 
gnome_canvas_get_property (GObject    *object,
1973
 
                           guint       prop_id,
1974
 
                           GValue     *value,
1975
 
                           GParamSpec *pspec)
1976
 
{
1977
 
        switch (prop_id) {
1978
 
        case PROP_AA:
1979
 
                g_value_set_boolean (value, GNOME_CANVAS (object)->aa);
1980
 
                break;
1981
 
        default:
1982
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1983
 
                break;
1984
 
        }
1985
 
}
1986
 
 
1987
 
static void
1988
 
gnome_canvas_set_property (GObject      *object,
1989
 
                           guint         prop_id,
1990
 
                           const GValue *value,
1991
 
                           GParamSpec   *pspec)
1992
 
{
1993
 
        switch (prop_id) {
1994
 
        case PROP_AA:
1995
 
                GNOME_CANVAS (object)->aa = g_value_get_boolean (value);
1996
 
                break;
1997
 
        default:
1998
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1999
 
                break;
2000
 
        }
2001
 
}
2002
 
 
2003
 
/* Class initialization function for GnomeCanvasClass */
2004
 
static void
2005
 
gnome_canvas_class_init (GnomeCanvasClass *klass)
2006
 
{
2007
 
        GObjectClass   *gobject_class;
2008
 
        GtkObjectClass *object_class;
2009
 
        GtkWidgetClass *widget_class;
2010
 
 
2011
 
        gobject_class = (GObjectClass *)klass;
2012
 
        object_class  = (GtkObjectClass *) klass;
2013
 
        widget_class  = (GtkWidgetClass *) klass;
2014
 
 
2015
 
        canvas_parent_class = g_type_class_peek_parent (klass);
2016
 
 
2017
 
        gobject_class->set_property = gnome_canvas_set_property;
2018
 
        gobject_class->get_property = gnome_canvas_get_property;
2019
 
 
2020
 
        object_class->destroy = gnome_canvas_destroy;
2021
 
 
2022
 
        widget_class->map = gnome_canvas_map;
2023
 
        widget_class->unmap = gnome_canvas_unmap;
2024
 
        widget_class->realize = gnome_canvas_realize;
2025
 
        widget_class->unrealize = gnome_canvas_unrealize;
2026
 
        widget_class->size_allocate = gnome_canvas_size_allocate;
2027
 
        widget_class->button_press_event = gnome_canvas_button;
2028
 
        widget_class->button_release_event = gnome_canvas_button;
2029
 
        widget_class->motion_notify_event = gnome_canvas_motion;
2030
 
        widget_class->expose_event = gnome_canvas_expose;
2031
 
        widget_class->key_press_event = gnome_canvas_key;
2032
 
        widget_class->key_release_event = gnome_canvas_key;
2033
 
        widget_class->enter_notify_event = gnome_canvas_crossing;
2034
 
        widget_class->leave_notify_event = gnome_canvas_crossing;
2035
 
        widget_class->focus_in_event = gnome_canvas_focus_in;
2036
 
        widget_class->focus_out_event = gnome_canvas_focus_out;
2037
 
 
2038
 
        klass->draw_background = gnome_canvas_draw_background;
2039
 
        klass->render_background = NULL;
2040
 
        klass->request_update = gnome_canvas_request_update_real;
2041
 
 
2042
 
        g_object_class_install_property (G_OBJECT_CLASS (object_class),
2043
 
                                         PROP_AA,
2044
 
                                         g_param_spec_boolean ("aa",
2045
 
                                                               "Antialiased",
2046
 
                                                               "The antialiasing mode of the canvas.",
2047
 
                                                               FALSE,
2048
 
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
2049
 
 
2050
 
        canvas_signals[DRAW_BACKGROUND] =
2051
 
                g_signal_new ("draw_background",
2052
 
                              G_TYPE_FROM_CLASS (object_class),
2053
 
                              G_SIGNAL_RUN_LAST,
2054
 
                              G_STRUCT_OFFSET (GnomeCanvasClass, draw_background),
2055
 
                              NULL, NULL,
2056
 
                              gnome_canvas_marshal_VOID__OBJECT_INT_INT_INT_INT,
2057
 
                              G_TYPE_NONE, 5, GDK_TYPE_DRAWABLE,
2058
 
                              G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
2059
 
        canvas_signals[RENDER_BACKGROUND] =
2060
 
                g_signal_new ("render_background",
2061
 
                              G_TYPE_FROM_CLASS (object_class),
2062
 
                              G_SIGNAL_RUN_LAST,
2063
 
                              G_STRUCT_OFFSET (GnomeCanvasClass, render_background),
2064
 
                              NULL, NULL,
2065
 
                              g_cclosure_marshal_VOID__POINTER,
2066
 
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
2067
 
}
2068
 
 
2069
 
/* Callback used when the root item of a canvas is destroyed.  The user should
2070
 
 * never ever do this, so we panic if this happens.
2071
 
 */
2072
 
static void
2073
 
panic_root_destroyed (GtkObject *object, gpointer data)
2074
 
{
2075
 
        g_error ("Eeeek, root item %p of canvas %p was destroyed!", object, data);
2076
 
}
2077
 
 
2078
 
/* Object initialization function for GnomeCanvas */
2079
 
static void
2080
 
gnome_canvas_init (GnomeCanvas *canvas)
2081
 
{
2082
 
        GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
2083
 
 
2084
 
        canvas->need_update = FALSE;
2085
 
        canvas->need_redraw = FALSE;
2086
 
        canvas->redraw_area = NULL;
2087
 
        canvas->idle_id = 0;
2088
 
 
2089
 
        canvas->scroll_x1 = 0.0;
2090
 
        canvas->scroll_y1 = 0.0;
2091
 
        canvas->scroll_x2 = canvas->layout.width;
2092
 
        canvas->scroll_y2 = canvas->layout.height;
2093
 
 
2094
 
        canvas->pixels_per_unit = 1.0;
2095
 
 
2096
 
        canvas->pick_event.type = GDK_LEAVE_NOTIFY;
2097
 
        canvas->pick_event.crossing.x = 0;
2098
 
        canvas->pick_event.crossing.y = 0;
2099
 
 
2100
 
        canvas->dither = GDK_RGB_DITHER_MAX;
2101
 
 
2102
 
        /* This may not be what people want, but it is set to be turned on by
2103
 
         * default to have the same initial behavior as the canvas in GNOME 1.4.
2104
 
         */
2105
 
        canvas->center_scroll_region = TRUE;
2106
 
 
2107
 
        gtk_layout_set_hadjustment (GTK_LAYOUT (canvas), NULL);
2108
 
        gtk_layout_set_vadjustment (GTK_LAYOUT (canvas), NULL);
2109
 
 
2110
 
        /* Disable the gtk+ double buffering since the canvas uses it's own. */
2111
 
        gtk_widget_set_double_buffered (GTK_WIDGET (canvas), FALSE);
2112
 
 
2113
 
        /* Create the root item as a special case */
2114
 
 
2115
 
        canvas->root = GNOME_CANVAS_ITEM (g_object_new (gnome_canvas_group_get_type (), NULL));
2116
 
        canvas->root->canvas = canvas;
2117
 
 
2118
 
        g_object_ref (canvas->root);
2119
 
        gtk_object_sink (GTK_OBJECT (canvas->root));
2120
 
 
2121
 
        canvas->root_destroy_id = g_signal_connect (canvas->root, "destroy",
2122
 
                                                    G_CALLBACK (panic_root_destroyed),
2123
 
                                                    canvas);
2124
 
 
2125
 
        canvas->need_repick = TRUE;
2126
 
}
2127
 
 
2128
 
/* Convenience function to remove the idle handler of a canvas */
2129
 
static void
2130
 
remove_idle (GnomeCanvas *canvas)
2131
 
{
2132
 
        if (canvas->idle_id == 0)
2133
 
                return;
2134
 
 
2135
 
        gtk_idle_remove (canvas->idle_id);
2136
 
        canvas->idle_id = 0;
2137
 
}
2138
 
 
2139
 
/* Removes the transient state of the canvas (idle handler, grabs). */
2140
 
static void
2141
 
shutdown_transients (GnomeCanvas *canvas)
2142
 
{
2143
 
        /* We turn off the need_redraw flag, since if the canvas is mapped again
2144
 
         * it will request a redraw anyways.  We do not turn off the need_update
2145
 
         * flag, though, because updates are not queued when the canvas remaps
2146
 
         * itself.
2147
 
         */
2148
 
        if (canvas->need_redraw) {
2149
 
                canvas->need_redraw = FALSE;
2150
 
                art_uta_free (canvas->redraw_area);
2151
 
                canvas->redraw_area = NULL;
2152
 
                canvas->redraw_x1 = 0;
2153
 
                canvas->redraw_y1 = 0;
2154
 
                canvas->redraw_x2 = 0;
2155
 
                canvas->redraw_y2 = 0;
2156
 
        }
2157
 
 
2158
 
        if (canvas->grabbed_item) {
2159
 
                canvas->grabbed_item = NULL;
2160
 
                gdk_pointer_ungrab (GDK_CURRENT_TIME);
2161
 
        }
2162
 
 
2163
 
        remove_idle (canvas);
2164
 
}
2165
 
 
2166
 
/* Destroy handler for GnomeCanvas */
2167
 
static void
2168
 
gnome_canvas_destroy (GtkObject *object)
2169
 
{
2170
 
        GnomeCanvas *canvas;
2171
 
 
2172
 
        g_return_if_fail (GNOME_IS_CANVAS (object));
2173
 
 
2174
 
        /* remember, destroy can be run multiple times! */
2175
 
 
2176
 
        canvas = GNOME_CANVAS (object);
2177
 
 
2178
 
        if (canvas->root_destroy_id) {
2179
 
                g_signal_handler_disconnect (canvas->root, canvas->root_destroy_id);
2180
 
                canvas->root_destroy_id = 0;
2181
 
        }
2182
 
        if (canvas->root) {
2183
 
                gtk_object_destroy (GTK_OBJECT (canvas->root));
2184
 
                g_object_unref (G_OBJECT (canvas->root));
2185
 
                canvas->root = NULL;
2186
 
        }
2187
 
 
2188
 
        shutdown_transients (canvas);
2189
 
 
2190
 
        if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy)
2191
 
                (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object);
2192
 
}
2193
 
 
2194
 
/**
2195
 
 * gnome_canvas_new:
2196
 
 *
2197
 
 * Creates a new empty canvas in non-antialiased mode.
2198
 
 *
2199
 
 * Return value: A newly-created canvas.
2200
 
 **/
2201
 
GtkWidget *
2202
 
gnome_canvas_new (void)
2203
 
{
2204
 
        return GTK_WIDGET (g_object_new (gnome_canvas_get_type (), NULL));
2205
 
}
2206
 
 
2207
 
/**
2208
 
 * gnome_canvas_new_aa:
2209
 
 *
2210
 
 * Creates a new empty canvas in antialiased mode.
2211
 
 *
2212
 
 * Return value: A newly-created antialiased canvas.
2213
 
 **/
2214
 
GtkWidget *
2215
 
gnome_canvas_new_aa (void)
2216
 
{
2217
 
        return GTK_WIDGET (g_object_new (GNOME_TYPE_CANVAS,
2218
 
                                         "aa", TRUE,
2219
 
                                         NULL));
2220
 
}
2221
 
 
2222
 
/* Map handler for the canvas */
2223
 
static void
2224
 
gnome_canvas_map (GtkWidget *widget)
2225
 
{
2226
 
        GnomeCanvas *canvas;
2227
 
 
2228
 
        g_return_if_fail (GNOME_IS_CANVAS (widget));
2229
 
 
2230
 
        /* Normal widget mapping stuff */
2231
 
 
2232
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->map)
2233
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->map) (widget);
2234
 
 
2235
 
        canvas = GNOME_CANVAS (widget);
2236
 
 
2237
 
        if (canvas->need_update)
2238
 
                add_idle (canvas);
2239
 
 
2240
 
        /* Map items */
2241
 
 
2242
 
        if (GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->map)
2243
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->map) (canvas->root);
2244
 
}
2245
 
 
2246
 
/* Unmap handler for the canvas */
2247
 
static void
2248
 
gnome_canvas_unmap (GtkWidget *widget)
2249
 
{
2250
 
        GnomeCanvas *canvas;
2251
 
 
2252
 
        g_return_if_fail (GNOME_IS_CANVAS (widget));
2253
 
 
2254
 
        canvas = GNOME_CANVAS (widget);
2255
 
 
2256
 
        shutdown_transients (canvas);
2257
 
 
2258
 
        /* Unmap items */
2259
 
 
2260
 
        if (GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap)
2261
 
                (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (canvas->root);
2262
 
 
2263
 
        /* Normal widget unmapping stuff */
2264
 
 
2265
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->unmap)
2266
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (widget);
2267
 
}
2268
 
 
2269
 
/* Realize handler for the canvas */
2270
 
static void
2271
 
gnome_canvas_realize (GtkWidget *widget)
2272
 
{
2273
 
        GnomeCanvas *canvas;
2274
 
 
2275
 
        g_return_if_fail (GNOME_IS_CANVAS (widget));
2276
 
 
2277
 
        /* Normal widget realization stuff */
2278
 
 
2279
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->realize)
2280
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->realize) (widget);
2281
 
 
2282
 
        canvas = GNOME_CANVAS (widget);
2283
 
 
2284
 
        gdk_window_set_events (canvas->layout.bin_window,
2285
 
                               (gdk_window_get_events (canvas->layout.bin_window)
2286
 
                                 | GDK_EXPOSURE_MASK
2287
 
                                 | GDK_BUTTON_PRESS_MASK
2288
 
                                 | GDK_BUTTON_RELEASE_MASK
2289
 
                                 | GDK_POINTER_MOTION_MASK
2290
 
                                 | GDK_KEY_PRESS_MASK
2291
 
                                 | GDK_KEY_RELEASE_MASK
2292
 
                                 | GDK_ENTER_NOTIFY_MASK
2293
 
                                 | GDK_LEAVE_NOTIFY_MASK
2294
 
                                 | GDK_FOCUS_CHANGE_MASK));
2295
 
 
2296
 
        /* Create our own temporary pixmap gc and realize all the items */
2297
 
 
2298
 
        canvas->pixmap_gc = gdk_gc_new (canvas->layout.bin_window);
2299
 
 
2300
 
        (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->realize) (canvas->root);
2301
 
}
2302
 
 
2303
 
/* Unrealize handler for the canvas */
2304
 
static void
2305
 
gnome_canvas_unrealize (GtkWidget *widget)
2306
 
{
2307
 
        GnomeCanvas *canvas;
2308
 
 
2309
 
        g_return_if_fail (GNOME_IS_CANVAS (widget));
2310
 
 
2311
 
        canvas = GNOME_CANVAS (widget);
2312
 
 
2313
 
        shutdown_transients (canvas);
2314
 
 
2315
 
        /* Unrealize items and parent widget */
2316
 
 
2317
 
        (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->unrealize) (canvas->root);
2318
 
 
2319
 
        gdk_gc_destroy (canvas->pixmap_gc);
2320
 
        canvas->pixmap_gc = NULL;
2321
 
 
2322
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize)
2323
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget);
2324
 
}
2325
 
 
2326
 
/* Handles scrolling of the canvas.  Adjusts the scrolling and zooming offset to
2327
 
 * keep as much as possible of the canvas scrolling region in view.
2328
 
 */
2329
 
static void
2330
 
scroll_to (GnomeCanvas *canvas, int cx, int cy)
2331
 
{
2332
 
        int scroll_width, scroll_height;
2333
 
        int right_limit, bottom_limit;
2334
 
        int old_zoom_xofs, old_zoom_yofs;
2335
 
        int changed_x = FALSE, changed_y = FALSE;
2336
 
        int canvas_width, canvas_height;
2337
 
 
2338
 
        canvas_width = GTK_WIDGET (canvas)->allocation.width;
2339
 
        canvas_height = GTK_WIDGET (canvas)->allocation.height;
2340
 
 
2341
 
        scroll_width = floor ((canvas->scroll_x2 - canvas->scroll_x1) * canvas->pixels_per_unit
2342
 
                              + 0.5);
2343
 
        scroll_height = floor ((canvas->scroll_y2 - canvas->scroll_y1) * canvas->pixels_per_unit
2344
 
                               + 0.5);
2345
 
 
2346
 
        right_limit = scroll_width - canvas_width;
2347
 
        bottom_limit = scroll_height - canvas_height;
2348
 
 
2349
 
        old_zoom_xofs = canvas->zoom_xofs;
2350
 
        old_zoom_yofs = canvas->zoom_yofs;
2351
 
 
2352
 
        if (right_limit < 0) {
2353
 
                cx = 0;
2354
 
 
2355
 
                if (canvas->center_scroll_region) {
2356
 
                        canvas->zoom_xofs = (canvas_width - scroll_width) / 2;
2357
 
                        scroll_width = canvas_width;
2358
 
                } else
2359
 
                        canvas->zoom_xofs = 0;
2360
 
        } else if (cx < 0) {
2361
 
                cx = 0;
2362
 
                canvas->zoom_xofs = 0;
2363
 
        } else if (cx > right_limit) {
2364
 
                cx = right_limit;
2365
 
                canvas->zoom_xofs = 0;
2366
 
        } else
2367
 
                canvas->zoom_xofs = 0;
2368
 
 
2369
 
        if (bottom_limit < 0) {
2370
 
                cy = 0;
2371
 
 
2372
 
                if (canvas->center_scroll_region) {
2373
 
                        canvas->zoom_yofs = (canvas_height - scroll_height) / 2;
2374
 
                        scroll_height = canvas_height;
2375
 
                } else
2376
 
                        canvas->zoom_yofs = 0;
2377
 
        } else if (cy < 0) {
2378
 
                cy = 0;
2379
 
                canvas->zoom_yofs = 0;
2380
 
        } else if (cy > bottom_limit) {
2381
 
                cy = bottom_limit;
2382
 
                canvas->zoom_yofs = 0;
2383
 
        } else
2384
 
                canvas->zoom_yofs = 0;
2385
 
 
2386
 
        if ((canvas->zoom_xofs != old_zoom_xofs) || (canvas->zoom_yofs != old_zoom_yofs)) {
2387
 
                /* This can only occur, if either canvas size or widget size changes */
2388
 
                /* So I think we can request full redraw here */
2389
 
                /* The reason is, that coverage UTA will be invalidated by offset change */
2390
 
                /* fixme: Strictly this is not correct - we have to remove our own idle (Lauris) */
2391
 
                /* More stuff - we have to mark root as needing fresh affine (Lauris) */
2392
 
                if (!(canvas->root->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)) {
2393
 
                        canvas->root->object.flags |= GNOME_CANVAS_ITEM_NEED_AFFINE;
2394
 
                        gnome_canvas_request_update (canvas);
2395
 
                }
2396
 
                gtk_widget_queue_draw (GTK_WIDGET (canvas));
2397
 
        }
2398
 
 
2399
 
        if (canvas->layout.hadjustment && ((int) canvas->layout.hadjustment->value) != cx) {
2400
 
                canvas->layout.hadjustment->value = cx;
2401
 
                changed_x = TRUE;
2402
 
        }
2403
 
 
2404
 
        if (canvas->layout.vadjustment && ((int) canvas->layout.vadjustment->value) != cy) {
2405
 
                canvas->layout.vadjustment->value = cy;
2406
 
                changed_y = TRUE;
2407
 
        }
2408
 
 
2409
 
        if ((scroll_width != (int) canvas->layout.width)
2410
 
            || (scroll_height != (int) canvas->layout.height))
2411
 
                gtk_layout_set_size (GTK_LAYOUT (canvas), scroll_width, scroll_height);
2412
 
 
2413
 
        /* Signal GtkLayout that it should do a redraw. */
2414
 
 
2415
 
        if (changed_x)
2416
 
                g_signal_emit_by_name (canvas->layout.hadjustment, "value_changed");
2417
 
 
2418
 
        if (changed_y)
2419
 
                g_signal_emit_by_name (canvas->layout.vadjustment, "value_changed");
2420
 
}
2421
 
 
2422
 
/* Size allocation handler for the canvas */
2423
 
static void
2424
 
gnome_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
2425
 
{
2426
 
        GnomeCanvas *canvas;
2427
 
 
2428
 
        g_return_if_fail (GNOME_IS_CANVAS (widget));
2429
 
        g_return_if_fail (allocation != NULL);
2430
 
 
2431
 
        if (GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate)
2432
 
                (* GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (widget, allocation);
2433
 
 
2434
 
        canvas = GNOME_CANVAS (widget);
2435
 
 
2436
 
        /* Recenter the view, if appropriate */
2437
 
 
2438
 
        canvas->layout.hadjustment->page_size = allocation->width;
2439
 
        canvas->layout.hadjustment->page_increment = allocation->width / 2;
2440
 
 
2441
 
        canvas->layout.vadjustment->page_size = allocation->height;
2442
 
        canvas->layout.vadjustment->page_increment = allocation->height / 2;
2443
 
 
2444
 
        scroll_to (canvas,
2445
 
                   canvas->layout.hadjustment->value,
2446
 
                   canvas->layout.vadjustment->value);
2447
 
 
2448
 
        g_signal_emit_by_name (canvas->layout.hadjustment, "changed");
2449
 
        g_signal_emit_by_name (canvas->layout.vadjustment, "changed");
2450
 
}
2451
 
 
2452
 
/* Emits an event for an item in the canvas, be it the current item, grabbed
2453
 
 * item, or focused item, as appropriate.
2454
 
 */
2455
 
 
2456
 
static int
2457
 
emit_event (GnomeCanvas *canvas, GdkEvent *event)
2458
 
{
2459
 
        GdkEvent *ev;
2460
 
        gint finished;
2461
 
        GnomeCanvasItem *item;
2462
 
        GnomeCanvasItem *parent;
2463
 
        guint mask;
2464
 
 
2465
 
        /* Perform checks for grabbed items */
2466
 
 
2467
 
        if (canvas->grabbed_item &&
2468
 
            !is_descendant (canvas->current_item, canvas->grabbed_item)) {
2469
 
                /* I think this warning is annoying and I don't know what it's for
2470
 
                 * so I'll disable it for now.
2471
 
                 */
2472
 
/*                g_warning ("emit_event() returning FALSE!\n");*/
2473
 
                return FALSE;
2474
 
        }
2475
 
 
2476
 
        if (canvas->grabbed_item) {
2477
 
                switch (event->type) {
2478
 
                case GDK_ENTER_NOTIFY:
2479
 
                        mask = GDK_ENTER_NOTIFY_MASK;
2480
 
                        break;
2481
 
 
2482
 
                case GDK_LEAVE_NOTIFY:
2483
 
                        mask = GDK_LEAVE_NOTIFY_MASK;
2484
 
                        break;
2485
 
 
2486
 
                case GDK_MOTION_NOTIFY:
2487
 
                        mask = GDK_POINTER_MOTION_MASK;
2488
 
                        break;
2489
 
 
2490
 
                case GDK_BUTTON_PRESS:
2491
 
                case GDK_2BUTTON_PRESS:
2492
 
                case GDK_3BUTTON_PRESS:
2493
 
                        mask = GDK_BUTTON_PRESS_MASK;
2494
 
                        break;
2495
 
 
2496
 
                case GDK_BUTTON_RELEASE:
2497
 
                        mask = GDK_BUTTON_RELEASE_MASK;
2498
 
                        break;
2499
 
 
2500
 
                case GDK_KEY_PRESS:
2501
 
                        mask = GDK_KEY_PRESS_MASK;
2502
 
                        break;
2503
 
 
2504
 
                case GDK_KEY_RELEASE:
2505
 
                        mask = GDK_KEY_RELEASE_MASK;
2506
 
                        break;
2507
 
 
2508
 
                default:
2509
 
                        mask = 0;
2510
 
                        break;
2511
 
                }
2512
 
 
2513
 
                if (!(mask & canvas->grabbed_event_mask))
2514
 
                        return FALSE;
2515
 
        }
2516
 
 
2517
 
        /* Convert to world coordinates -- we have two cases because of diferent
2518
 
         * offsets of the fields in the event structures.
2519
 
         */
2520
 
 
2521
 
        ev = gdk_event_copy (event);
2522
 
 
2523
 
        switch (ev->type)
2524
 
        {
2525
 
        case GDK_ENTER_NOTIFY:
2526
 
        case GDK_LEAVE_NOTIFY:
2527
 
                gnome_canvas_window_to_world (canvas,
2528
 
                                              ev->crossing.x, ev->crossing.y,
2529
 
                                              &ev->crossing.x, &ev->crossing.y);
2530
 
                break;
2531
 
 
2532
 
        case GDK_MOTION_NOTIFY:
2533
 
        case GDK_BUTTON_PRESS:
2534
 
        case GDK_2BUTTON_PRESS:
2535
 
        case GDK_3BUTTON_PRESS:
2536
 
        case GDK_BUTTON_RELEASE:
2537
 
                gnome_canvas_window_to_world (canvas,
2538
 
                                              ev->motion.x, ev->motion.y,
2539
 
                                              &ev->motion.x, &ev->motion.y);
2540
 
                break;
2541
 
 
2542
 
        default:
2543
 
                break;
2544
 
        }
2545
 
 
2546
 
        /* Choose where we send the event */
2547
 
 
2548
 
        item = canvas->current_item;
2549
 
 
2550
 
        if (canvas->focused_item
2551
 
            && ((event->type == GDK_KEY_PRESS) ||
2552
 
                (event->type == GDK_KEY_RELEASE) ||
2553
 
                (event->type == GDK_FOCUS_CHANGE)))
2554
 
                item = canvas->focused_item;
2555
 
 
2556
 
        /* The event is propagated up the hierarchy (for if someone connected to
2557
 
         * a group instead of a leaf event), and emission is stopped if a
2558
 
         * handler returns TRUE, just like for GtkWidget events.
2559
 
         */
2560
 
 
2561
 
        finished = FALSE;
2562
 
 
2563
 
        while (item && !finished) {
2564
 
                g_object_ref (G_OBJECT (item));
2565
 
 
2566
 
                g_signal_emit (item, item_signals[ITEM_EVENT], 0,
2567
 
                               ev, &finished);
2568
 
 
2569
 
                parent = item->parent;
2570
 
                g_object_unref (G_OBJECT (item));
2571
 
 
2572
 
                item = parent;
2573
 
        }
2574
 
 
2575
 
        gdk_event_free (ev);
2576
 
 
2577
 
        return finished;
2578
 
}
2579
 
 
2580
 
/* Re-picks the current item in the canvas, based on the event's coordinates.
2581
 
 * Also emits enter/leave events for items as appropriate.
2582
 
 */
2583
 
static int
2584
 
pick_current_item (GnomeCanvas *canvas, GdkEvent *event)
2585
 
{
2586
 
        int button_down;
2587
 
        double x, y;
2588
 
        int cx, cy;
2589
 
        int retval;
2590
 
 
2591
 
        retval = FALSE;
2592
 
 
2593
 
        /* If a button is down, we'll perform enter and leave events on the
2594
 
         * current item, but not enter on any other item.  This is more or less
2595
 
         * like X pointer grabbing for canvas items.
2596
 
         */
2597
 
        button_down = canvas->state & (GDK_BUTTON1_MASK
2598
 
                                       | GDK_BUTTON2_MASK
2599
 
                                       | GDK_BUTTON3_MASK
2600
 
                                       | GDK_BUTTON4_MASK
2601
 
                                       | GDK_BUTTON5_MASK);
2602
 
        if (!button_down)
2603
 
                canvas->left_grabbed_item = FALSE;
2604
 
 
2605
 
        /* Save the event in the canvas.  This is used to synthesize enter and
2606
 
         * leave events in case the current item changes.  It is also used to
2607
 
         * re-pick the current item if the current one gets deleted.  Also,
2608
 
         * synthesize an enter event.
2609
 
         */
2610
 
        if (event != &canvas->pick_event) {
2611
 
                if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) {
2612
 
                        /* these fields have the same offsets in both types of events */
2613
 
 
2614
 
                        canvas->pick_event.crossing.type       = GDK_ENTER_NOTIFY;
2615
 
                        canvas->pick_event.crossing.window     = event->motion.window;
2616
 
                        canvas->pick_event.crossing.send_event = event->motion.send_event;
2617
 
                        canvas->pick_event.crossing.subwindow  = NULL;
2618
 
                        canvas->pick_event.crossing.x          = event->motion.x;
2619
 
                        canvas->pick_event.crossing.y          = event->motion.y;
2620
 
                        canvas->pick_event.crossing.mode       = GDK_CROSSING_NORMAL;
2621
 
                        canvas->pick_event.crossing.detail     = GDK_NOTIFY_NONLINEAR;
2622
 
                        canvas->pick_event.crossing.focus      = FALSE;
2623
 
                        canvas->pick_event.crossing.state      = event->motion.state;
2624
 
 
2625
 
                        /* these fields don't have the same offsets in both types of events */
2626
 
 
2627
 
                        if (event->type == GDK_MOTION_NOTIFY) {
2628
 
                                canvas->pick_event.crossing.x_root = event->motion.x_root;
2629
 
                                canvas->pick_event.crossing.y_root = event->motion.y_root;
2630
 
                        } else {
2631
 
                                canvas->pick_event.crossing.x_root = event->button.x_root;
2632
 
                                canvas->pick_event.crossing.y_root = event->button.y_root;
2633
 
                        }
2634
 
                } else
2635
 
                        canvas->pick_event = *event;
2636
 
        }
2637
 
 
2638
 
        /* Don't do anything else if this is a recursive call */
2639
 
 
2640
 
        if (canvas->in_repick)
2641
 
                return retval;
2642
 
 
2643
 
        /* LeaveNotify means that there is no current item, so we don't look for one */
2644
 
 
2645
 
        if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
2646
 
                /* these fields don't have the same offsets in both types of events */
2647
 
 
2648
 
                if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
2649
 
                        x = canvas->pick_event.crossing.x - canvas->zoom_xofs;
2650
 
                        y = canvas->pick_event.crossing.y - canvas->zoom_yofs;
2651
 
                } else {
2652
 
                        x = canvas->pick_event.motion.x - canvas->zoom_xofs;
2653
 
                        y = canvas->pick_event.motion.y - canvas->zoom_yofs;
2654
 
                }
2655
 
 
2656
 
                /* canvas pixel coords */
2657
 
 
2658
 
                cx = (int) (x + 0.5);
2659
 
                cy = (int) (y + 0.5);
2660
 
 
2661
 
                /* world coords */
2662
 
 
2663
 
                x = canvas->scroll_x1 + x / canvas->pixels_per_unit;
2664
 
                y = canvas->scroll_y1 + y / canvas->pixels_per_unit;
2665
 
 
2666
 
                /* find the closest item */
2667
 
 
2668
 
                if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
2669
 
                        gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy,
2670
 
                                                        &canvas->new_current_item);
2671
 
                else
2672
 
                        canvas->new_current_item = NULL;
2673
 
        } else
2674
 
                canvas->new_current_item = NULL;
2675
 
 
2676
 
        if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item)
2677
 
                return retval; /* current item did not change */
2678
 
 
2679
 
        /* Synthesize events for old and new current items */
2680
 
 
2681
 
        if ((canvas->new_current_item != canvas->current_item)
2682
 
            && (canvas->current_item != NULL)
2683
 
            && !canvas->left_grabbed_item) {
2684
 
                GdkEvent new_event;
2685
 
 
2686
 
                new_event = canvas->pick_event;
2687
 
                new_event.type = GDK_LEAVE_NOTIFY;
2688
 
 
2689
 
                new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
2690
 
                new_event.crossing.subwindow = NULL;
2691
 
                canvas->in_repick = TRUE;
2692
 
                retval = emit_event (canvas, &new_event);
2693
 
                canvas->in_repick = FALSE;
2694
 
        }
2695
 
 
2696
 
        /* new_current_item may have been set to NULL during the call to emit_event() above */
2697
 
 
2698
 
        if ((canvas->new_current_item != canvas->current_item) && button_down) {
2699
 
                canvas->left_grabbed_item = TRUE;
2700
 
                return retval;
2701
 
        }
2702
 
 
2703
 
        /* Handle the rest of cases */
2704
 
 
2705
 
        canvas->left_grabbed_item = FALSE;
2706
 
        canvas->current_item = canvas->new_current_item;
2707
 
 
2708
 
        if (canvas->current_item != NULL) {
2709
 
                GdkEvent new_event;
2710
 
 
2711
 
                new_event = canvas->pick_event;
2712
 
                new_event.type = GDK_ENTER_NOTIFY;
2713
 
                new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
2714
 
                new_event.crossing.subwindow = NULL;
2715
 
                retval = emit_event (canvas, &new_event);
2716
 
        }
2717
 
 
2718
 
        return retval;
2719
 
}
2720
 
 
2721
 
/* Button event handler for the canvas */
2722
 
static gint
2723
 
gnome_canvas_button (GtkWidget *widget, GdkEventButton *event)
2724
 
{
2725
 
        GnomeCanvas *canvas;
2726
 
        int mask;
2727
 
        int retval;
2728
 
 
2729
 
        g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
2730
 
        g_return_val_if_fail (event != NULL, FALSE);
2731
 
 
2732
 
        retval = FALSE;
2733
 
 
2734
 
        canvas = GNOME_CANVAS (widget);
2735
 
 
2736
 
        /*
2737
 
         * dispatch normally regardless of the event's window if an item has
2738
 
         * has a pointer grab in effect
2739
 
         */
2740
 
        if (!canvas->grabbed_item && event->window != canvas->layout.bin_window)
2741
 
                return retval;
2742
 
 
2743
 
        switch (event->button) {
2744
 
        case 1:
2745
 
                mask = GDK_BUTTON1_MASK;
2746
 
                break;
2747
 
        case 2:
2748
 
                mask = GDK_BUTTON2_MASK;
2749
 
                break;
2750
 
        case 3:
2751
 
                mask = GDK_BUTTON3_MASK;
2752
 
                break;
2753
 
        case 4:
2754
 
                mask = GDK_BUTTON4_MASK;
2755
 
                break;
2756
 
        case 5:
2757
 
                mask = GDK_BUTTON5_MASK;
2758
 
                break;
2759
 
        default:
2760
 
                mask = 0;
2761
 
        }
2762
 
 
2763
 
        switch (event->type) {
2764
 
        case GDK_BUTTON_PRESS:
2765
 
        case GDK_2BUTTON_PRESS:
2766
 
        case GDK_3BUTTON_PRESS:
2767
 
                /* Pick the current item as if the button were not pressed, and
2768
 
                 * then process the event.
2769
 
                 */
2770
 
                canvas->state = event->state;
2771
 
                pick_current_item (canvas, (GdkEvent *) event);
2772
 
                canvas->state ^= mask;
2773
 
                retval = emit_event (canvas, (GdkEvent *) event);
2774
 
                break;
2775
 
 
2776
 
        case GDK_BUTTON_RELEASE:
2777
 
                /* Process the event as if the button were pressed, then repick
2778
 
                 * after the button has been released
2779
 
                 */
2780
 
                canvas->state = event->state;
2781
 
                retval = emit_event (canvas, (GdkEvent *) event);
2782
 
                event->state ^= mask;
2783
 
                canvas->state = event->state;
2784
 
                pick_current_item (canvas, (GdkEvent *) event);
2785
 
                event->state ^= mask;
2786
 
                break;
2787
 
 
2788
 
        default:
2789
 
                g_assert_not_reached ();
2790
 
        }
2791
 
 
2792
 
        return retval;
2793
 
}
2794
 
 
2795
 
/* Motion event handler for the canvas */
2796
 
static gint
2797
 
gnome_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
2798
 
{
2799
 
        GnomeCanvas *canvas;
2800
 
 
2801
 
        g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
2802
 
        g_return_val_if_fail (event != NULL, FALSE);
2803
 
 
2804
 
        canvas = GNOME_CANVAS (widget);
2805
 
 
2806
 
        if (event->window != canvas->layout.bin_window)
2807
 
                return FALSE;
2808
 
 
2809
 
        canvas->state = event->state;
2810
 
        pick_current_item (canvas, (GdkEvent *) event);
2811
 
        return emit_event (canvas, (GdkEvent *) event);
2812
 
}
2813
 
 
2814
 
/* Key event handler for the canvas */
2815
 
static gboolean
2816
 
gnome_canvas_key (GtkWidget *widget, GdkEventKey *event)
2817
 
{
2818
 
        GnomeCanvas *canvas;
2819
 
 
2820
 
        g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
2821
 
        g_return_val_if_fail (event != NULL, FALSE);
2822
 
 
2823
 
        canvas = GNOME_CANVAS (widget);
2824
 
 
2825
 
        if (!emit_event (canvas, (GdkEvent *) event)) {
2826
 
                GtkWidgetClass *widget_class;
2827
 
 
2828
 
                widget_class = GTK_WIDGET_CLASS (canvas_parent_class);
2829
 
 
2830
 
                if (event->type == GDK_KEY_PRESS) {
2831
 
                        if (widget_class->key_press_event)
2832
 
                                return (* widget_class->key_press_event) (widget, event);
2833
 
                } else if (event->type == GDK_KEY_RELEASE) {
2834
 
                        if (widget_class->key_release_event)
2835
 
                                return (* widget_class->key_release_event) (widget, event);
2836
 
                } else
2837
 
                        g_assert_not_reached ();
2838
 
 
2839
 
                return FALSE;
2840
 
        } else
2841
 
                return TRUE;
2842
 
}
2843
 
 
2844
 
 
2845
 
/* Crossing event handler for the canvas */
2846
 
static gint
2847
 
gnome_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event)
2848
 
{
2849
 
        GnomeCanvas *canvas;
2850
 
 
2851
 
        g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
2852
 
        g_return_val_if_fail (event != NULL, FALSE);
2853
 
 
2854
 
        canvas = GNOME_CANVAS (widget);
2855
 
 
2856
 
        if (event->window != canvas->layout.bin_window)
2857
 
                return FALSE;
2858
 
 
2859
 
        canvas->state = event->state;
2860
 
        return pick_current_item (canvas, (GdkEvent *) event);
2861
 
}
2862
 
 
2863
 
/* Focus in handler for the canvas */
2864
 
static gint
2865
 
gnome_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event)
2866
 
{
2867
 
        GnomeCanvas *canvas;
2868
 
 
2869
 
        GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
2870
 
 
2871
 
        canvas = GNOME_CANVAS (widget);
2872
 
 
2873
 
        if (canvas->focused_item)
2874
 
                return emit_event (canvas, (GdkEvent *) event);
2875
 
        else
2876
 
                return FALSE;
2877
 
}
2878
 
 
2879
 
/* Focus out handler for the canvas */
2880
 
static gint
2881
 
gnome_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event)
2882
 
{
2883
 
        GnomeCanvas *canvas;
2884
 
 
2885
 
        GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
2886
 
 
2887
 
        canvas = GNOME_CANVAS (widget);
2888
 
 
2889
 
        if (canvas->focused_item)
2890
 
                return emit_event (canvas, (GdkEvent *) event);
2891
 
        else
2892
 
                return FALSE;
2893
 
}
2894
 
 
2895
 
#define IMAGE_WIDTH 512
2896
 
#define IMAGE_HEIGHT 512
2897
 
 
2898
 
#define IMAGE_WIDTH_AA 256
2899
 
#define IMAGE_HEIGHT_AA 64
2900
 
 
2901
 
static void
2902
 
gnome_canvas_paint_rect (GnomeCanvas *canvas, gint x0, gint y0, gint x1, gint y1)
2903
 
{
2904
 
        GtkWidget *widget;
2905
 
        gint draw_x1, draw_y1;
2906
 
        gint draw_x2, draw_y2;
2907
 
        gint xblock, yblock;
2908
 
        guchar *px;
2909
 
        GdkPixmap *pixmap;
2910
 
 
2911
 
        g_return_if_fail (!canvas->need_update);
2912
 
 
2913
 
        widget = GTK_WIDGET (canvas);
2914
 
 
2915
 
        draw_x1 = MAX (x0, canvas->layout.hadjustment->value - canvas->zoom_xofs);
2916
 
        draw_y1 = MAX (y0, canvas->layout.vadjustment->value - canvas->zoom_yofs);
2917
 
        draw_x2 = MIN (draw_x1 + GTK_WIDGET (canvas)->allocation.width, x1);
2918
 
        draw_y2 = MIN (draw_y1 + GTK_WIDGET (canvas)->allocation.height, y1);
2919
 
 
2920
 
        /* As we can come from expose, we have to tile here */
2921
 
        xblock = (canvas->aa) ? IMAGE_WIDTH_AA : IMAGE_WIDTH;
2922
 
        yblock = (canvas->aa) ? IMAGE_HEIGHT_AA : IMAGE_HEIGHT;
2923
 
 
2924
 
        px = NULL;
2925
 
        pixmap = NULL;
2926
 
 
2927
 
        for (y0 = draw_y1; y0 < draw_y2; y0 += yblock) {
2928
 
                y1 = MIN (y0 + yblock, draw_y2);
2929
 
                for (x0 = draw_x1; x0 < draw_x2; x0 += xblock) {
2930
 
                        x1 = MIN (x0 + xblock, draw_x2);
2931
 
 
2932
 
                        canvas->redraw_x1 = x0;
2933
 
                        canvas->redraw_y1 = y0;
2934
 
                        canvas->redraw_x2 = x1;
2935
 
                        canvas->redraw_y2 = y1;
2936
 
                        canvas->draw_xofs = x0;
2937
 
                        canvas->draw_yofs = y0;
2938
 
 
2939
 
                        if (canvas->aa) {
2940
 
                                GnomeCanvasBuf buf;
2941
 
                                GdkColor *color;
2942
 
 
2943
 
                                if (!px) px = g_new (guchar, IMAGE_WIDTH_AA * IMAGE_HEIGHT_AA * 3);
2944
 
 
2945
 
                                buf.buf = px;
2946
 
                                buf.buf_rowstride = IMAGE_WIDTH_AA * 3;
2947
 
                                buf.rect.x0 = x0;
2948
 
                                buf.rect.y0 = y0;
2949
 
                                buf.rect.x1 = x1;
2950
 
                                buf.rect.y1 = y1;
2951
 
                                color = &widget->style->bg[GTK_STATE_NORMAL];
2952
 
                                buf.bg_color = (((color->red & 0xff00) << 8) | (color->green & 0xff00) | (color->blue >> 8));
2953
 
                                buf.is_bg = 1;
2954
 
                                buf.is_buf = 0;
2955
 
 
2956
 
                                g_signal_emit (G_OBJECT (canvas), canvas_signals[RENDER_BACKGROUND], 0, &buf);
2957
 
 
2958
 
                                if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
2959
 
                                        (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->render) (canvas->root, &buf);
2960
 
 
2961
 
                                if (buf.is_bg) {
2962
 
                                        gdk_rgb_gc_set_foreground (canvas->pixmap_gc, buf.bg_color);
2963
 
                                        gdk_draw_rectangle (canvas->layout.bin_window,
2964
 
                                                            canvas->pixmap_gc,
2965
 
                                                            TRUE,
2966
 
                                                            (x0 + canvas->zoom_xofs),
2967
 
                                                            (y0 + canvas->zoom_yofs),
2968
 
                                                            x1 - x0, y1 - y0);
2969
 
                                } else {
2970
 
                                        gdk_draw_rgb_image_dithalign (canvas->layout.bin_window,
2971
 
                                                                      canvas->pixmap_gc,
2972
 
                                                                      (x0 + canvas->zoom_xofs),
2973
 
                                                                      (y0 + canvas->zoom_yofs),
2974
 
                                                                      x1 - x0, y1 - y0,
2975
 
                                                                      canvas->dither,
2976
 
                                                                      buf.buf,
2977
 
                                                                      IMAGE_WIDTH_AA * 3,
2978
 
                                                                      x0, y0);
2979
 
                                }
2980
 
                        } else {
2981
 
                                if (!pixmap) pixmap = gdk_pixmap_new (canvas->layout.bin_window, IMAGE_WIDTH, IMAGE_HEIGHT,
2982
 
                                                                      gtk_widget_get_visual (widget)->depth);
2983
 
 
2984
 
                                g_signal_emit (G_OBJECT (canvas), canvas_signals[DRAW_BACKGROUND], 0, pixmap,
2985
 
                                               x0, y0, x1 - x0, y1 - y0);
2986
 
 
2987
 
                                if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
2988
 
                                        (* GNOME_CANVAS_ITEM_GET_CLASS (
2989
 
                                                canvas->root)->draw) (
2990
 
                                                        canvas->root, pixmap,
2991
 
                                                        x0, y0,
2992
 
                                                        x1 - x0, y1 - y0);
2993
 
                                /* Copy the pixmap to the window and clean up */
2994
 
 
2995
 
                                gdk_draw_pixmap (canvas->layout.bin_window,
2996
 
                                                 canvas->pixmap_gc,
2997
 
                                                 pixmap,
2998
 
                                                 0, 0,
2999
 
                                                 x0 + canvas->zoom_xofs,
3000
 
                                                 y0 + canvas->zoom_yofs,
3001
 
                                                 x1 - x0, y1 - y0);
3002
 
                        }
3003
 
                }
3004
 
        }
3005
 
 
3006
 
        if (px) g_free (px);
3007
 
        if (pixmap) gdk_pixmap_unref (pixmap);
3008
 
}
3009
 
 
3010
 
/* Expose handler for the canvas */
3011
 
static gint
3012
 
gnome_canvas_expose (GtkWidget *widget, GdkEventExpose *event)
3013
 
{
3014
 
        GnomeCanvas *canvas;
3015
 
        GdkRectangle *rects;
3016
 
        gint n_rects;
3017
 
        int i;
3018
 
 
3019
 
        canvas = GNOME_CANVAS (widget);
3020
 
 
3021
 
        if (!GTK_WIDGET_DRAWABLE (widget) || (event->window != canvas->layout.bin_window))
3022
 
                return FALSE;
3023
 
 
3024
 
#ifdef VERBOSE
3025
 
        g_print ("Expose\n");
3026
 
#endif
3027
 
 
3028
 
        gdk_region_get_rectangles (event->region, &rects, &n_rects);
3029
 
 
3030
 
        for (i = 0; i < n_rects; i++) {
3031
 
                ArtIRect rect;
3032
 
 
3033
 
                rect.x0 = rects[i].x - canvas->zoom_xofs;
3034
 
                rect.y0 = rects[i].y - canvas->zoom_yofs;
3035
 
                rect.x1 = rects[i].x + rects[i].width - canvas->zoom_xofs;
3036
 
                rect.y1 = rects[i].y + rects[i].height - canvas->zoom_yofs;
3037
 
 
3038
 
                if (canvas->need_update || canvas->need_redraw) {
3039
 
                        ArtUta *uta;
3040
 
                        /* Update or drawing is scheduled, so just mark exposed area as dirty */
3041
 
                        uta = art_uta_from_irect (&rect);
3042
 
                        gnome_canvas_request_redraw_uta (canvas, uta);
3043
 
                } else {
3044
 
                        /* No pending updates, draw exposed area immediately */
3045
 
                        gnome_canvas_paint_rect (canvas, rect.x0, rect.y0, rect.x1, rect.y1);
3046
 
 
3047
 
                        /* And call expose on parent container class */
3048
 
                        if (GTK_WIDGET_CLASS (canvas_parent_class)->expose_event)
3049
 
                                (* GTK_WIDGET_CLASS (canvas_parent_class)->expose_event) (
3050
 
                                        widget, event);
3051
 
                }
3052
 
        }
3053
 
 
3054
 
        g_free (rects);
3055
 
 
3056
 
        return FALSE;
3057
 
}
3058
 
 
3059
 
/* Repaints the areas in the canvas that need it */
3060
 
static void
3061
 
paint (GnomeCanvas *canvas)
3062
 
{
3063
 
        ArtIRect *rects;
3064
 
        gint n_rects, i;
3065
 
 
3066
 
        if (canvas->aa)
3067
 
                rects = art_rect_list_from_uta (canvas->redraw_area,
3068
 
                                                IMAGE_WIDTH_AA, IMAGE_HEIGHT_AA,
3069
 
                                                &n_rects);
3070
 
        else
3071
 
                rects = art_rect_list_from_uta (canvas->redraw_area,
3072
 
                                                IMAGE_WIDTH, IMAGE_HEIGHT,
3073
 
                                                &n_rects);
3074
 
 
3075
 
        art_uta_free (canvas->redraw_area);
3076
 
        canvas->redraw_area = NULL;
3077
 
        canvas->need_redraw = FALSE;
3078
 
 
3079
 
        /* Send synthetic expose events */
3080
 
        for (i = 0; i < n_rects; i++) {
3081
 
                GdkEventExpose ex;
3082
 
                gint x0, y0, x1, y1;
3083
 
 
3084
 
                x0 = MAX (canvas->layout.hadjustment->value - canvas->zoom_xofs, rects[i].x0);
3085
 
                y0 = MAX (canvas->layout.vadjustment->value - canvas->zoom_yofs, rects[i].y0);
3086
 
                x1 = MIN (x0 + GTK_WIDGET (canvas)->allocation.width, rects[i].x1);
3087
 
                y1 = MIN (y0 + GTK_WIDGET (canvas)->allocation.height, rects[i].y1);
3088
 
 
3089
 
                if ((x0 < x1) && (y0 < y1)) {
3090
 
                        /* Here we are - whatever type is canvas, we have to send synthetic expose to layout (Lauris) */
3091
 
                        ex.type = GDK_EXPOSE;
3092
 
                        ex.window = canvas->layout.bin_window;
3093
 
                        ex.send_event = TRUE;
3094
 
                        ex.area.x = x0 + canvas->zoom_xofs;
3095
 
                        ex.area.y = y0 + canvas->zoom_yofs;
3096
 
                        ex.area.width = x1 - x0;
3097
 
                        ex.area.height = y1 - y0;
3098
 
                        ex.region = gdk_region_rectangle (&ex.area);
3099
 
                        ex.count = 0;
3100
 
                        gtk_widget_send_expose (GTK_WIDGET (canvas), (GdkEvent *) &ex);
3101
 
                        gdk_region_destroy (ex.region);
3102
 
                }
3103
 
        }
3104
 
 
3105
 
        art_free (rects);
3106
 
 
3107
 
        canvas->redraw_x1 = 0;
3108
 
        canvas->redraw_y1 = 0;
3109
 
        canvas->redraw_x2 = 0;
3110
 
        canvas->redraw_y2 = 0;
3111
 
}
3112
 
 
3113
 
static void
3114
 
gnome_canvas_draw_background (GnomeCanvas *canvas, GdkDrawable *drawable,
3115
 
                              int x, int y, int width, int height)
3116
 
{
3117
 
        /* By default, we use the style background. */
3118
 
        gdk_gc_set_foreground (canvas->pixmap_gc,
3119
 
                               &GTK_WIDGET (canvas)->style->bg[GTK_STATE_NORMAL]);
3120
 
        gdk_draw_rectangle (drawable,
3121
 
                            canvas->pixmap_gc,
3122
 
                            TRUE,
3123
 
                            0, 0,
3124
 
                            width, height);
3125
 
}
3126
 
 
3127
 
static void
3128
 
do_update (GnomeCanvas *canvas)
3129
 
{
3130
 
        /* Cause the update if necessary */
3131
 
 
3132
 
update_again:
3133
 
        if (canvas->need_update) {
3134
 
                gdouble w2cpx[6];
3135
 
 
3136
 
                /* We start updating root with w2cpx affine */
3137
 
                w2cpx[0] = canvas->pixels_per_unit;
3138
 
                w2cpx[1] = 0.0;
3139
 
                w2cpx[2] = 0.0;
3140
 
                w2cpx[3] = canvas->pixels_per_unit;
3141
 
                w2cpx[4] = -canvas->scroll_x1 * canvas->pixels_per_unit;
3142
 
                w2cpx[5] = -canvas->scroll_y1 * canvas->pixels_per_unit;
3143
 
 
3144
 
                gnome_canvas_item_invoke_update (canvas->root, w2cpx, NULL, 0);
3145
 
 
3146
 
                canvas->need_update = FALSE;
3147
 
        }
3148
 
 
3149
 
        /* Pick new current item */
3150
 
 
3151
 
        while (canvas->need_repick) {
3152
 
                canvas->need_repick = FALSE;
3153
 
                pick_current_item (canvas, &canvas->pick_event);
3154
 
        }
3155
 
 
3156
 
        /* it is possible that during picking we emitted an event in which
3157
 
           the user then called some function which then requested update
3158
 
           of something.  Without this we'd be left in a state where
3159
 
           need_update would have been left TRUE and the canvas would have
3160
 
           been left unpainted. */
3161
 
        if (canvas->need_update) {
3162
 
                goto update_again;
3163
 
        }
3164
 
 
3165
 
        /* Paint if able to */
3166
 
 
3167
 
        if (GTK_WIDGET_DRAWABLE (canvas) && canvas->need_redraw)
3168
 
                paint (canvas);
3169
 
}
3170
 
 
3171
 
/* Idle handler for the canvas.  It deals with pending updates and redraws. */
3172
 
static gboolean
3173
 
idle_handler (gpointer data)
3174
 
{
3175
 
        GnomeCanvas *canvas;
3176
 
 
3177
 
        GDK_THREADS_ENTER ();
3178
 
 
3179
 
        canvas = GNOME_CANVAS (data);
3180
 
        do_update (canvas);
3181
 
 
3182
 
        /* Reset idle id */
3183
 
        canvas->idle_id = 0;
3184
 
 
3185
 
        GDK_THREADS_LEAVE ();
3186
 
 
3187
 
        return FALSE;
3188
 
}
3189
 
 
3190
 
/* Convenience function to add an idle handler to a canvas */
3191
 
static void
3192
 
add_idle (GnomeCanvas *canvas)
3193
 
{
3194
 
        g_assert (canvas->need_update || canvas->need_redraw);
3195
 
 
3196
 
        if (!canvas->idle_id)
3197
 
                canvas->idle_id = g_idle_add_full (CANVAS_IDLE_PRIORITY,
3198
 
                                                   idle_handler,
3199
 
                                                   canvas,
3200
 
                                                   NULL);
3201
 
 
3202
 
/*      canvas->idle_id = gtk_idle_add (idle_handler, canvas); */
3203
 
}
3204
 
 
3205
 
/**
3206
 
 * gnome_canvas_root:
3207
 
 * @canvas: A canvas.
3208
 
 *
3209
 
 * Queries the root group of a canvas.
3210
 
 *
3211
 
 * Return value: The root group of the specified canvas.
3212
 
 **/
3213
 
GnomeCanvasGroup *
3214
 
gnome_canvas_root (GnomeCanvas *canvas)
3215
 
{
3216
 
        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL);
3217
 
 
3218
 
        return GNOME_CANVAS_GROUP (canvas->root);
3219
 
}
3220
 
 
3221
 
 
3222
 
/**
3223
 
 * gnome_canvas_set_scroll_region:
3224
 
 * @canvas: A canvas.
3225
 
 * @x1: Leftmost limit of the scrolling region.
3226
 
 * @y1: Upper limit of the scrolling region.
3227
 
 * @x2: Rightmost limit of the scrolling region.
3228
 
 * @y2: Lower limit of the scrolling region.
3229
 
 *
3230
 
 * Sets the scrolling region of a canvas to the specified rectangle.  The canvas
3231
 
 * will then be able to scroll only within this region.  The view of the canvas
3232
 
 * is adjusted as appropriate to display as much of the new region as possible.
3233
 
 **/
3234
 
void
3235
 
gnome_canvas_set_scroll_region (GnomeCanvas *canvas, double x1, double y1, double x2, double y2)
3236
 
{
3237
 
        double wxofs, wyofs;
3238
 
        int xofs, yofs;
3239
 
 
3240
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3241
 
 
3242
 
        /*
3243
 
         * Set the new scrolling region.  If possible, do not move the visible contents of the
3244
 
         * canvas.
3245
 
         */
3246
 
 
3247
 
        gnome_canvas_c2w (canvas,
3248
 
                          GTK_LAYOUT (canvas)->hadjustment->value + canvas->zoom_xofs,
3249
 
                          GTK_LAYOUT (canvas)->vadjustment->value + canvas->zoom_yofs,
3250
 
                          /*canvas->zoom_xofs,
3251
 
                          canvas->zoom_yofs,*/
3252
 
                          &wxofs, &wyofs);
3253
 
 
3254
 
        canvas->scroll_x1 = x1;
3255
 
        canvas->scroll_y1 = y1;
3256
 
        canvas->scroll_x2 = x2;
3257
 
        canvas->scroll_y2 = y2;
3258
 
 
3259
 
        gnome_canvas_w2c (canvas, wxofs, wyofs, &xofs, &yofs);
3260
 
 
3261
 
        scroll_to (canvas, xofs, yofs);
3262
 
 
3263
 
        canvas->need_repick = TRUE;
3264
 
#if 0
3265
 
        /* todo: should be requesting update */
3266
 
        (* GNOME_CANVAS_ITEM_CLASS (canvas->root->object.klass)->update) (
3267
 
                canvas->root, NULL, NULL, 0);
3268
 
#endif
3269
 
}
3270
 
 
3271
 
 
3272
 
/**
3273
 
 * gnome_canvas_get_scroll_region:
3274
 
 * @canvas: A canvas.
3275
 
 * @x1: Leftmost limit of the scrolling region (return value).
3276
 
 * @y1: Upper limit of the scrolling region (return value).
3277
 
 * @x2: Rightmost limit of the scrolling region (return value).
3278
 
 * @y2: Lower limit of the scrolling region (return value).
3279
 
 *
3280
 
 * Queries the scrolling region of a canvas.
3281
 
 **/
3282
 
void
3283
 
gnome_canvas_get_scroll_region (GnomeCanvas *canvas, double *x1, double *y1, double *x2, double *y2)
3284
 
{
3285
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3286
 
 
3287
 
        if (x1)
3288
 
                *x1 = canvas->scroll_x1;
3289
 
 
3290
 
        if (y1)
3291
 
                *y1 = canvas->scroll_y1;
3292
 
 
3293
 
        if (x2)
3294
 
                *x2 = canvas->scroll_x2;
3295
 
 
3296
 
        if (y2)
3297
 
                *y2 = canvas->scroll_y2;
3298
 
}
3299
 
 
3300
 
/**
3301
 
 * gnome_canvas_set_center_scroll_region:
3302
 
 * @canvas: A canvas.
3303
 
 * @center_scroll_region: Whether to center the scrolling region in the canvas
3304
 
 * window when it is smaller than the canvas' allocation.
3305
 
 *
3306
 
 * When the scrolling region of the canvas is smaller than the canvas window,
3307
 
 * e.g.  the allocation of the canvas, it can be either centered on the window
3308
 
 * or simply made to be on the upper-left corner on the window.  This function
3309
 
 * lets you configure this property.
3310
 
 **/
3311
 
void
3312
 
gnome_canvas_set_center_scroll_region (GnomeCanvas *canvas, gboolean center_scroll_region)
3313
 
{
3314
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3315
 
 
3316
 
        canvas->center_scroll_region = center_scroll_region != 0;
3317
 
 
3318
 
        scroll_to (canvas,
3319
 
                   canvas->layout.hadjustment->value,
3320
 
                   canvas->layout.vadjustment->value);
3321
 
}
3322
 
 
3323
 
/**
3324
 
 * gnome_canvas_get_center_scroll_region:
3325
 
 * @canvas: A canvas.
3326
 
 *
3327
 
 * Returns whether the canvas is set to center the scrolling region in the window
3328
 
 * if the former is smaller than the canvas' allocation.
3329
 
 *
3330
 
 * Return value: Whether the scroll region is being centered in the canvas window.
3331
 
 **/
3332
 
gboolean
3333
 
gnome_canvas_get_center_scroll_region (GnomeCanvas *canvas)
3334
 
{
3335
 
        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), FALSE);
3336
 
 
3337
 
        return canvas->center_scroll_region ? TRUE : FALSE;
3338
 
}
3339
 
 
3340
 
/**
3341
 
 * gnome_canvas_set_pixels_per_unit:
3342
 
 * @canvas: A canvas.
3343
 
 * @n: The number of pixels that correspond to one canvas unit.
3344
 
 *
3345
 
 * Sets the zooming factor of a canvas by specifying the number of pixels that
3346
 
 * correspond to one canvas unit.
3347
 
 *
3348
 
 * The anchor point for zooming, i.e. the point that stays fixed and all others
3349
 
 * zoom inwards or outwards from it, depends on whether the canvas is set to
3350
 
 * center the scrolling region or not.  You can control this using the
3351
 
 * gnome_canvas_set_center_scroll_region() function.  If the canvas is set to
3352
 
 * center the scroll region, then the center of the canvas window is used as the
3353
 
 * anchor point for zooming.  Otherwise, the upper-left corner of the canvas
3354
 
 * window is used as the anchor point.
3355
 
 **/
3356
 
void
3357
 
gnome_canvas_set_pixels_per_unit (GnomeCanvas *canvas, double n)
3358
 
{
3359
 
        double ax, ay;
3360
 
        int x1, y1;
3361
 
        int anchor_x, anchor_y;
3362
 
 
3363
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3364
 
        g_return_if_fail (n > GNOME_CANVAS_EPSILON);
3365
 
 
3366
 
        if (canvas->center_scroll_region) {
3367
 
                anchor_x = GTK_WIDGET (canvas)->allocation.width / 2;
3368
 
                anchor_y = GTK_WIDGET (canvas)->allocation.height / 2;
3369
 
        } else
3370
 
                anchor_x = anchor_y = 0;
3371
 
 
3372
 
        /* Find the coordinates of the anchor point in units. */
3373
 
        if(canvas->layout.hadjustment) {
3374
 
                ax = (canvas->layout.hadjustment->value + anchor_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs;
3375
 
        } else {
3376
 
                ax = (0.0                               + anchor_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs;
3377
 
        }
3378
 
        if(canvas->layout.hadjustment) {
3379
 
                ay = (canvas->layout.vadjustment->value + anchor_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs;
3380
 
        } else {
3381
 
                ay = (0.0                               + anchor_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs;
3382
 
        }
3383
 
 
3384
 
        /* Now calculate the new offset of the upper left corner. */
3385
 
        x1 = ((ax - canvas->scroll_x1) * n) - anchor_x;
3386
 
        y1 = ((ay - canvas->scroll_y1) * n) - anchor_y;
3387
 
 
3388
 
        canvas->pixels_per_unit = n;
3389
 
 
3390
 
        scroll_to (canvas, x1, y1);
3391
 
 
3392
 
        if (!(canvas->root->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)) {
3393
 
                canvas->root->object.flags |= GNOME_CANVAS_ITEM_NEED_AFFINE;
3394
 
                gnome_canvas_request_update (canvas);
3395
 
        }
3396
 
 
3397
 
        canvas->need_repick = TRUE;
3398
 
}
3399
 
 
3400
 
/**
3401
 
 * gnome_canvas_scroll_to:
3402
 
 * @canvas: A canvas.
3403
 
 * @cx: Horizontal scrolling offset in canvas pixel units.
3404
 
 * @cy: Vertical scrolling offset in canvas pixel units.
3405
 
 *
3406
 
 * Makes a canvas scroll to the specified offsets, given in canvas pixel units.
3407
 
 * The canvas will adjust the view so that it is not outside the scrolling
3408
 
 * region.  This function is typically not used, as it is better to hook
3409
 
 * scrollbars to the canvas layout's scrolling adjusments.
3410
 
 **/
3411
 
void
3412
 
gnome_canvas_scroll_to (GnomeCanvas *canvas, int cx, int cy)
3413
 
{
3414
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3415
 
 
3416
 
        scroll_to (canvas, cx, cy);
3417
 
}
3418
 
 
3419
 
/**
3420
 
 * gnome_canvas_get_scroll_offsets:
3421
 
 * @canvas: A canvas.
3422
 
 * @cx: Horizontal scrolling offset (return value).
3423
 
 * @cy: Vertical scrolling offset (return value).
3424
 
 *
3425
 
 * Queries the scrolling offsets of a canvas.  The values are returned in canvas
3426
 
 * pixel units.
3427
 
 **/
3428
 
void
3429
 
gnome_canvas_get_scroll_offsets (GnomeCanvas *canvas, int *cx, int *cy)
3430
 
{
3431
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3432
 
 
3433
 
        if (cx)
3434
 
                *cx = canvas->layout.hadjustment->value;
3435
 
 
3436
 
        if (cy)
3437
 
                *cy = canvas->layout.vadjustment->value;
3438
 
}
3439
 
 
3440
 
/**
3441
 
 * gnome_canvas_update_now:
3442
 
 * @canvas: A canvas.
3443
 
 *
3444
 
 * Forces an immediate update and redraw of a canvas.  If the canvas does not
3445
 
 * have any pending update or redraw requests, then no action is taken.  This is
3446
 
 * typically only used by applications that need explicit control of when the
3447
 
 * display is updated, like games.  It is not needed by normal applications.
3448
 
 */
3449
 
void
3450
 
gnome_canvas_update_now (GnomeCanvas *canvas)
3451
 
{
3452
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3453
 
 
3454
 
        if (!(canvas->need_update || canvas->need_redraw)) {
3455
 
                g_assert (canvas->idle_id == 0);
3456
 
                g_assert (canvas->redraw_area == NULL);
3457
 
                return;
3458
 
        }
3459
 
 
3460
 
        remove_idle (canvas);
3461
 
        do_update (canvas);
3462
 
}
3463
 
 
3464
 
/**
3465
 
 * gnome_canvas_get_item_at:
3466
 
 * @canvas: A canvas.
3467
 
 * @x: X position in world coordinates.
3468
 
 * @y: Y position in world coordinates.
3469
 
 *
3470
 
 * Looks for the item that is under the specified position, which must be
3471
 
 * specified in world coordinates.
3472
 
 *
3473
 
 * Return value: The sought item, or NULL if no item is at the specified
3474
 
 * coordinates.
3475
 
 **/
3476
 
GnomeCanvasItem *
3477
 
gnome_canvas_get_item_at (GnomeCanvas *canvas, double x, double y)
3478
 
{
3479
 
        GnomeCanvasItem *item;
3480
 
        double dist;
3481
 
        int cx, cy;
3482
 
 
3483
 
        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL);
3484
 
 
3485
 
        gnome_canvas_w2c (canvas, x, y, &cx, &cy);
3486
 
 
3487
 
        dist = gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &item);
3488
 
        if ((int) (dist * canvas->pixels_per_unit + 0.5) <= canvas->close_enough)
3489
 
                return item;
3490
 
        else
3491
 
                return NULL;
3492
 
}
3493
 
 
3494
 
/* Queues an update of the canvas */
3495
 
static void
3496
 
gnome_canvas_request_update (GnomeCanvas *canvas)
3497
 
{
3498
 
        GNOME_CANVAS_GET_CLASS (canvas)->request_update (canvas);
3499
 
}
3500
 
 
3501
 
static void
3502
 
gnome_canvas_request_update_real (GnomeCanvas *canvas)
3503
 
{
3504
 
        if (canvas->need_update)
3505
 
                return;
3506
 
 
3507
 
        canvas->need_update = TRUE;
3508
 
        if (GTK_WIDGET_MAPPED ((GtkWidget *) canvas))
3509
 
                add_idle (canvas);
3510
 
}
3511
 
 
3512
 
/* Computes the union of two microtile arrays while clipping the result to the
3513
 
 * specified rectangle.  Any of the specified utas can be NULL, in which case it
3514
 
 * is taken to be an empty region.
3515
 
 */
3516
 
static ArtUta *
3517
 
uta_union_clip (ArtUta *uta1, ArtUta *uta2, ArtIRect *clip)
3518
 
{
3519
 
        ArtUta *uta;
3520
 
        ArtUtaBbox *utiles;
3521
 
        int clip_x1, clip_y1, clip_x2, clip_y2;
3522
 
        int union_x1, union_y1, union_x2, union_y2;
3523
 
        int new_x1, new_y1, new_x2, new_y2;
3524
 
        int x, y;
3525
 
        int ofs, ofs1, ofs2;
3526
 
 
3527
 
        g_assert (clip != NULL);
3528
 
 
3529
 
        /* Compute the tile indices for the clipping rectangle */
3530
 
 
3531
 
        clip_x1 = clip->x0 >> ART_UTILE_SHIFT;
3532
 
        clip_y1 = clip->y0 >> ART_UTILE_SHIFT;
3533
 
        clip_x2 = (clip->x1 >> ART_UTILE_SHIFT) + 1;
3534
 
        clip_y2 = (clip->y1 >> ART_UTILE_SHIFT) + 1;
3535
 
 
3536
 
        /* Get the union of the bounds of both utas */
3537
 
 
3538
 
        if (!uta1) {
3539
 
                if (!uta2)
3540
 
                        return art_uta_new (clip_x1, clip_y1, clip_x1 + 1, clip_y1 + 1);
3541
 
 
3542
 
                union_x1 = uta2->x0;
3543
 
                union_y1 = uta2->y0;
3544
 
                union_x2 = uta2->x0 + uta2->width;
3545
 
                union_y2 = uta2->y0 + uta2->height;
3546
 
        } else {
3547
 
                if (!uta2) {
3548
 
                        union_x1 = uta1->x0;
3549
 
                        union_y1 = uta1->y0;
3550
 
                        union_x2 = uta1->x0 + uta1->width;
3551
 
                        union_y2 = uta1->y0 + uta1->height;
3552
 
                } else {
3553
 
                        union_x1 = MIN (uta1->x0, uta2->x0);
3554
 
                        union_y1 = MIN (uta1->y0, uta2->y0);
3555
 
                        union_x2 = MAX (uta1->x0 + uta1->width, uta2->x0 + uta2->width);
3556
 
                        union_y2 = MAX (uta1->y0 + uta1->height, uta2->y0 + uta2->height);
3557
 
                }
3558
 
        }
3559
 
 
3560
 
        /* Clip the union of the bounds */
3561
 
 
3562
 
        new_x1 = MAX (clip_x1, union_x1);
3563
 
        new_y1 = MAX (clip_y1, union_y1);
3564
 
        new_x2 = MIN (clip_x2, union_x2);
3565
 
        new_y2 = MIN (clip_y2, union_y2);
3566
 
 
3567
 
        if (new_x1 >= new_x2 || new_y1 >= new_y2)
3568
 
                return art_uta_new (clip_x1, clip_y1, clip_x1 + 1, clip_y1 + 1);
3569
 
 
3570
 
        /* Make the new clipped union */
3571
 
 
3572
 
        uta = art_new (ArtUta, 1);
3573
 
        uta->x0 = new_x1;
3574
 
        uta->y0 = new_y1;
3575
 
        uta->width = new_x2 - new_x1;
3576
 
        uta->height = new_y2 - new_y1;
3577
 
        uta->utiles = utiles = art_new (ArtUtaBbox, uta->width * uta->height);
3578
 
 
3579
 
        ofs = 0;
3580
 
        ofs1 = ofs2 = 0;
3581
 
 
3582
 
        for (y = new_y1; y < new_y2; y++) {
3583
 
                if (uta1)
3584
 
                        ofs1 = (y - uta1->y0) * uta1->width + new_x1 - uta1->x0;
3585
 
 
3586
 
                if (uta2)
3587
 
                        ofs2 = (y - uta2->y0) * uta2->width + new_x1 - uta2->x0;
3588
 
 
3589
 
                for (x = new_x1; x < new_x2; x++) {
3590
 
                        ArtUtaBbox bb1, bb2, bb;
3591
 
 
3592
 
                        if (!uta1
3593
 
                            || x < uta1->x0 || y < uta1->y0
3594
 
                            || x >= uta1->x0 + uta1->width || y >= uta1->y0 + uta1->height)
3595
 
                                bb1 = 0;
3596
 
                        else
3597
 
                                bb1 = uta1->utiles[ofs1];
3598
 
 
3599
 
                        if (!uta2
3600
 
                            || x < uta2->x0 || y < uta2->y0
3601
 
                            || x >= uta2->x0 + uta2->width || y >= uta2->y0 + uta2->height)
3602
 
                                bb2 = 0;
3603
 
                        else
3604
 
                                bb2 = uta2->utiles[ofs2];
3605
 
 
3606
 
                        if (bb1 == 0)
3607
 
                                bb = bb2;
3608
 
                        else if (bb2 == 0)
3609
 
                                bb = bb1;
3610
 
                        else
3611
 
                                bb = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb1),
3612
 
                                                             ART_UTA_BBOX_X0 (bb2)),
3613
 
                                                        MIN (ART_UTA_BBOX_Y0 (bb1),
3614
 
                                                             ART_UTA_BBOX_Y0 (bb2)),
3615
 
                                                        MAX (ART_UTA_BBOX_X1 (bb1),
3616
 
                                                             ART_UTA_BBOX_X1 (bb2)),
3617
 
                                                        MAX (ART_UTA_BBOX_Y1 (bb1),
3618
 
                                                             ART_UTA_BBOX_Y1 (bb2)));
3619
 
 
3620
 
                        utiles[ofs] = bb;
3621
 
 
3622
 
                        ofs++;
3623
 
                        ofs1++;
3624
 
                        ofs2++;
3625
 
                }
3626
 
        }
3627
 
 
3628
 
        return uta;
3629
 
}
3630
 
 
3631
 
static inline void
3632
 
get_visible_region (GnomeCanvas *canvas, ArtIRect *visible)
3633
 
{
3634
 
        visible->x0 = canvas->layout.hadjustment->value - canvas->zoom_xofs;
3635
 
        visible->y0 = canvas->layout.vadjustment->value - canvas->zoom_yofs;
3636
 
        visible->x1 = visible->x0 + GTK_WIDGET (canvas)->allocation.width;
3637
 
        visible->y1 = visible->y0 + GTK_WIDGET (canvas)->allocation.height;
3638
 
}
3639
 
 
3640
 
/**
3641
 
 * gnome_canvas_request_redraw_uta:
3642
 
 * @canvas: A canvas.
3643
 
 * @uta: Microtile array that specifies the area to be redrawn.  It will
3644
 
 * be freed by this function, so the argument you pass will be invalid
3645
 
 * after you call this function.
3646
 
 *
3647
 
 * Informs a canvas that the specified area, given as a microtile array, needs
3648
 
 * to be repainted.  To be used only by item implementations.
3649
 
 **/
3650
 
void
3651
 
gnome_canvas_request_redraw_uta (GnomeCanvas *canvas,
3652
 
                                 ArtUta      *uta)
3653
 
{
3654
 
        ArtIRect visible;
3655
 
 
3656
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3657
 
        g_return_if_fail (uta != NULL);
3658
 
 
3659
 
        if (!GTK_WIDGET_DRAWABLE (canvas)) {
3660
 
                art_uta_free (uta);
3661
 
                return;
3662
 
        }
3663
 
 
3664
 
        get_visible_region (canvas, &visible);
3665
 
 
3666
 
        if (canvas->need_redraw) {
3667
 
                ArtUta *new_uta;
3668
 
 
3669
 
                g_assert (canvas->redraw_area != NULL);
3670
 
                /* ALEX: This can fail if e.g. redraw_uta is called by an item
3671
 
                   update function and we're called from update_now -> do_update
3672
 
                   because update_now sets idle_id == 0. There is also some way
3673
 
                   to get it from the expose handler (see bug #102811).
3674
 
                   g_assert (canvas->idle_id != 0);  */
3675
 
 
3676
 
                new_uta = uta_union_clip (canvas->redraw_area, uta, &visible);
3677
 
                art_uta_free (canvas->redraw_area);
3678
 
                art_uta_free (uta);
3679
 
                canvas->redraw_area = new_uta;
3680
 
                if (canvas->idle_id == 0)
3681
 
                        add_idle (canvas);
3682
 
        } else {
3683
 
                ArtUta *new_uta;
3684
 
 
3685
 
                g_assert (canvas->redraw_area == NULL);
3686
 
 
3687
 
                new_uta = uta_union_clip (uta, NULL, &visible);
3688
 
                art_uta_free (uta);
3689
 
                canvas->redraw_area = new_uta;
3690
 
 
3691
 
                canvas->need_redraw = TRUE;
3692
 
                add_idle (canvas);
3693
 
        }
3694
 
}
3695
 
 
3696
 
 
3697
 
/**
3698
 
 * gnome_canvas_request_redraw:
3699
 
 * @canvas: A canvas.
3700
 
 * @x1: Leftmost coordinate of the rectangle to be redrawn.
3701
 
 * @y1: Upper coordinate of the rectangle to be redrawn.
3702
 
 * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1.
3703
 
 * @y2: Lower coordinate of the rectangle to be redrawn, plus 1.
3704
 
 *
3705
 
 * Convenience function that informs a canvas that the specified rectangle needs
3706
 
 * to be repainted.  This function converts the rectangle to a microtile array
3707
 
 * and feeds it to gnome_canvas_request_redraw_uta().  The rectangle includes
3708
 
 * @x1 and @y1, but not @x2 and @y2.  To be used only by item implementations.
3709
 
 **/
3710
 
void
3711
 
gnome_canvas_request_redraw (GnomeCanvas *canvas, int x1, int y1, int x2, int y2)
3712
 
{
3713
 
        ArtUta *uta;
3714
 
        ArtIRect bbox;
3715
 
        ArtIRect visible;
3716
 
        ArtIRect clip;
3717
 
 
3718
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3719
 
 
3720
 
        if (!GTK_WIDGET_DRAWABLE (canvas) || (x1 >= x2) || (y1 >= y2))
3721
 
                return;
3722
 
 
3723
 
        bbox.x0 = x1;
3724
 
        bbox.y0 = y1;
3725
 
        bbox.x1 = x2;
3726
 
        bbox.y1 = y2;
3727
 
 
3728
 
        get_visible_region (canvas, &visible);
3729
 
 
3730
 
        art_irect_intersect (&clip, &bbox, &visible);
3731
 
 
3732
 
        if (!art_irect_empty (&clip)) {
3733
 
                uta = art_uta_from_irect (&clip);
3734
 
                gnome_canvas_request_redraw_uta (canvas, uta);
3735
 
        }
3736
 
}
3737
 
 
3738
 
 
3739
 
/**
3740
 
 * gnome_canvas_w2c_affine:
3741
 
 * @canvas: A canvas.
3742
 
 * @affine: An affine transformation matrix (return value).
3743
 
 *
3744
 
 * Gets the affine transform that converts from world coordinates to canvas
3745
 
 * pixel coordinates.
3746
 
 **/
3747
 
void
3748
 
gnome_canvas_w2c_affine (GnomeCanvas *canvas, double affine[6])
3749
 
{
3750
 
        double zooom;
3751
 
 
3752
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3753
 
        g_return_if_fail (affine != NULL);
3754
 
 
3755
 
        zooom = canvas->pixels_per_unit;
3756
 
 
3757
 
        affine[0] = zooom;
3758
 
        affine[1] = 0;
3759
 
        affine[2] = 0;
3760
 
        affine[3] = zooom;
3761
 
        affine[4] = -canvas->scroll_x1 * zooom;
3762
 
        affine[5] = -canvas->scroll_y1 * zooom;
3763
 
}
3764
 
 
3765
 
/**
3766
 
 * gnome_canvas_w2c:
3767
 
 * @canvas: A canvas.
3768
 
 * @wx: World X coordinate.
3769
 
 * @wy: World Y coordinate.
3770
 
 * @cx: X pixel coordinate (return value).
3771
 
 * @cy: Y pixel coordinate (return value).
3772
 
 *
3773
 
 * Converts world coordinates into canvas pixel coordinates.
3774
 
 **/
3775
 
void
3776
 
gnome_canvas_w2c (GnomeCanvas *canvas, double wx, double wy, int *cx, int *cy)
3777
 
{
3778
 
        double affine[6];
3779
 
        ArtPoint w, c;
3780
 
 
3781
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3782
 
 
3783
 
        gnome_canvas_w2c_affine (canvas, affine);
3784
 
        w.x = wx;
3785
 
        w.y = wy;
3786
 
        art_affine_point (&c, &w, affine);
3787
 
        if (cx)
3788
 
                *cx = floor (c.x + 0.5);
3789
 
        if (cy)
3790
 
                *cy = floor (c.y + 0.5);
3791
 
}
3792
 
 
3793
 
/**
3794
 
 * gnome_canvas_w2c_d:
3795
 
 * @canvas: A canvas.
3796
 
 * @wx: World X coordinate.
3797
 
 * @wy: World Y coordinate.
3798
 
 * @cx: X pixel coordinate (return value).
3799
 
 * @cy: Y pixel coordinate (return value).
3800
 
 *
3801
 
 * Converts world coordinates into canvas pixel coordinates.  This
3802
 
 * version returns coordinates in floating point coordinates, for
3803
 
 * greater precision.
3804
 
 **/
3805
 
void
3806
 
gnome_canvas_w2c_d (GnomeCanvas *canvas, double wx, double wy, double *cx, double *cy)
3807
 
{
3808
 
        double affine[6];
3809
 
        ArtPoint w, c;
3810
 
 
3811
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3812
 
 
3813
 
        gnome_canvas_w2c_affine (canvas, affine);
3814
 
        w.x = wx;
3815
 
        w.y = wy;
3816
 
        art_affine_point (&c, &w, affine);
3817
 
        if (cx)
3818
 
                *cx = c.x;
3819
 
        if (cy)
3820
 
                *cy = c.y;
3821
 
}
3822
 
 
3823
 
 
3824
 
/**
3825
 
 * gnome_canvas_c2w:
3826
 
 * @canvas: A canvas.
3827
 
 * @cx: Canvas pixel X coordinate.
3828
 
 * @cy: Canvas pixel Y coordinate.
3829
 
 * @wx: X world coordinate (return value).
3830
 
 * @wy: Y world coordinate (return value).
3831
 
 *
3832
 
 * Converts canvas pixel coordinates to world coordinates.
3833
 
 **/
3834
 
void
3835
 
gnome_canvas_c2w (GnomeCanvas *canvas, int cx, int cy, double *wx, double *wy)
3836
 
{
3837
 
        double affine[6], inv[6];
3838
 
        ArtPoint w, c;
3839
 
 
3840
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3841
 
 
3842
 
        gnome_canvas_w2c_affine (canvas, affine);
3843
 
        art_affine_invert (inv, affine);
3844
 
        c.x = cx;
3845
 
        c.y = cy;
3846
 
        art_affine_point (&w, &c, inv);
3847
 
        if (wx)
3848
 
                *wx = w.x;
3849
 
        if (wy)
3850
 
                *wy = w.y;
3851
 
}
3852
 
 
3853
 
 
3854
 
/**
3855
 
 * gnome_canvas_window_to_world:
3856
 
 * @canvas: A canvas.
3857
 
 * @winx: Window-relative X coordinate.
3858
 
 * @winy: Window-relative Y coordinate.
3859
 
 * @worldx: X world coordinate (return value).
3860
 
 * @worldy: Y world coordinate (return value).
3861
 
 *
3862
 
 * Converts window-relative coordinates into world coordinates.  You can use
3863
 
 * this when you need to convert mouse coordinates into world coordinates, for
3864
 
 * example.
3865
 
 **/
3866
 
void
3867
 
gnome_canvas_window_to_world (GnomeCanvas *canvas, double winx, double winy,
3868
 
                              double *worldx, double *worldy)
3869
 
{
3870
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3871
 
 
3872
 
        if (worldx)
3873
 
                *worldx = canvas->scroll_x1 + ((winx - canvas->zoom_xofs)
3874
 
                                               / canvas->pixels_per_unit);
3875
 
 
3876
 
        if (worldy)
3877
 
                *worldy = canvas->scroll_y1 + ((winy - canvas->zoom_yofs)
3878
 
                                               / canvas->pixels_per_unit);
3879
 
}
3880
 
 
3881
 
 
3882
 
/**
3883
 
 * gnome_canvas_world_to_window:
3884
 
 * @canvas: A canvas.
3885
 
 * @worldx: World X coordinate.
3886
 
 * @worldy: World Y coordinate.
3887
 
 * @winx: X window-relative coordinate.
3888
 
 * @winy: Y window-relative coordinate.
3889
 
 *
3890
 
 * Converts world coordinates into window-relative coordinates.
3891
 
 **/
3892
 
void
3893
 
gnome_canvas_world_to_window (GnomeCanvas *canvas, double worldx, double worldy,
3894
 
                              double *winx, double *winy)
3895
 
{
3896
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3897
 
 
3898
 
        if (winx)
3899
 
                *winx = (canvas->pixels_per_unit)*(worldx - canvas->scroll_x1) + canvas->zoom_xofs;
3900
 
 
3901
 
        if (winy)
3902
 
                *winy = (canvas->pixels_per_unit)*(worldy - canvas->scroll_y1) + canvas->zoom_yofs;
3903
 
}
3904
 
 
3905
 
 
3906
 
 
3907
 
/**
3908
 
 * gnome_canvas_get_color:
3909
 
 * @canvas: A canvas.
3910
 
 * @spec: X color specification, or NULL for "transparent".
3911
 
 * @color: Returns the allocated color.
3912
 
 *
3913
 
 * Allocates a color based on the specified X color specification.  As a
3914
 
 * convenience to item implementations, it returns TRUE if the color was
3915
 
 * allocated, or FALSE if the specification was NULL.  A NULL color
3916
 
 * specification is considered as "transparent" by the canvas.
3917
 
 *
3918
 
 * Return value: TRUE if @spec is non-NULL and the color is allocated.  If @spec
3919
 
 * is NULL, then returns FALSE.
3920
 
 **/
3921
 
int
3922
 
gnome_canvas_get_color (GnomeCanvas *canvas, const char *spec, GdkColor *color)
3923
 
{
3924
 
        GdkColormap *colormap;
3925
 
 
3926
 
        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), FALSE);
3927
 
        g_return_val_if_fail (color != NULL, FALSE);
3928
 
 
3929
 
        if (!spec) {
3930
 
                color->pixel = 0;
3931
 
                color->red = 0;
3932
 
                color->green = 0;
3933
 
                color->blue = 0;
3934
 
                return FALSE;
3935
 
        }
3936
 
 
3937
 
        gdk_color_parse (spec, color);
3938
 
 
3939
 
        colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
3940
 
 
3941
 
        gdk_rgb_find_color (colormap, color);
3942
 
 
3943
 
        return TRUE;
3944
 
}
3945
 
 
3946
 
/**
3947
 
 * gnome_canvas_get_color_pixel:
3948
 
 * @canvas: A canvas.
3949
 
 * @rgba: RGBA color specification.
3950
 
 *
3951
 
 * Allocates a color from the RGBA value passed into this function.  The alpha
3952
 
 * opacity value is discarded, since normal X colors do not support it.
3953
 
 *
3954
 
 * Return value: Allocated pixel value corresponding to the specified color.
3955
 
 **/
3956
 
gulong
3957
 
gnome_canvas_get_color_pixel (GnomeCanvas *canvas, guint rgba)
3958
 
{
3959
 
        GdkColormap *colormap;
3960
 
        GdkColor color;
3961
 
 
3962
 
        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), 0);
3963
 
 
3964
 
        color.red = ((rgba & 0xff000000) >> 16) + ((rgba & 0xff000000) >> 24);
3965
 
        color.green = ((rgba & 0x00ff0000) >> 8) + ((rgba & 0x00ff0000) >> 16);
3966
 
        color.blue = (rgba & 0x0000ff00) + ((rgba & 0x0000ff00) >> 8);
3967
 
        color.pixel = 0;
3968
 
 
3969
 
        colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
3970
 
 
3971
 
        gdk_rgb_find_color (colormap, &color);
3972
 
 
3973
 
        return color.pixel;
3974
 
}
3975
 
 
3976
 
 
3977
 
/**
3978
 
 * gnome_canvas_set_stipple_origin:
3979
 
 * @canvas: A canvas.
3980
 
 * @gc: GC on which to set the stipple origin.
3981
 
 *
3982
 
 * Sets the stipple origin of the specified GC as is appropriate for the canvas,
3983
 
 * so that it will be aligned with other stipple patterns used by canvas items.
3984
 
 * This is typically only needed by item implementations.
3985
 
 **/
3986
 
void
3987
 
gnome_canvas_set_stipple_origin (GnomeCanvas *canvas, GdkGC *gc)
3988
 
{
3989
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
3990
 
        g_return_if_fail (GDK_IS_GC (gc));
3991
 
 
3992
 
        gdk_gc_set_ts_origin (gc, -canvas->draw_xofs, -canvas->draw_yofs);
3993
 
}
3994
 
 
3995
 
/**
3996
 
 * gnome_canvas_set_dither:
3997
 
 * @canvas: A canvas.
3998
 
 * @dither: Type of dithering used to render an antialiased canvas.
3999
 
 *
4000
 
 * Controls dithered rendering for antialiased canvases. The value of
4001
 
 * dither should be #GDK_RGB_DITHER_NONE, #GDK_RGB_DITHER_NORMAL, or
4002
 
 * #GDK_RGB_DITHER_MAX. The default canvas setting is
4003
 
 * #GDK_RGB_DITHER_NORMAL.
4004
 
 **/
4005
 
void
4006
 
gnome_canvas_set_dither (GnomeCanvas *canvas, GdkRgbDither dither)
4007
 
{
4008
 
        g_return_if_fail (GNOME_IS_CANVAS (canvas));
4009
 
 
4010
 
        canvas->dither = dither;
4011
 
}
4012
 
 
4013
 
/**
4014
 
 * gnome_canvas_get_dither:
4015
 
 * @canvas: A canvas.
4016
 
 *
4017
 
 * Returns the type of dithering used to render an antialiased canvas.
4018
 
 *
4019
 
 * Return value: The dither setting.
4020
 
 **/
4021
 
GdkRgbDither
4022
 
gnome_canvas_get_dither (GnomeCanvas *canvas)
4023
 
{
4024
 
        g_return_val_if_fail (GNOME_IS_CANVAS (canvas), GDK_RGB_DITHER_NONE);
4025
 
 
4026
 
        return canvas->dither;
4027
 
}
4028
 
 
4029
 
static gboolean
4030
 
boolean_handled_accumulator (GSignalInvocationHint *ihint,
4031
 
                             GValue                *return_accu,
4032
 
                             const GValue          *handler_return,
4033
 
                             gpointer               dummy)
4034
 
{
4035
 
        gboolean continue_emission;
4036
 
        gboolean signal_handled;
4037
 
 
4038
 
        signal_handled = g_value_get_boolean (handler_return);
4039
 
        g_value_set_boolean (return_accu, signal_handled);
4040
 
        continue_emission = !signal_handled;
4041
 
 
4042
 
        return continue_emission;
4043
 
}
4044
 
 
4045
 
/* Class initialization function for GnomeCanvasItemClass */
4046
 
static void
4047
 
gnome_canvas_item_class_init (GnomeCanvasItemClass *class)
4048
 
{
4049
 
        GObjectClass *gobject_class;
4050
 
 
4051
 
        gobject_class = (GObjectClass *) class;
4052
 
 
4053
 
        item_parent_class = g_type_class_peek_parent (class);
4054
 
 
4055
 
        gobject_class->set_property = gnome_canvas_item_set_property;
4056
 
        gobject_class->get_property = gnome_canvas_item_get_property;
4057
 
 
4058
 
        g_object_class_install_property
4059
 
                (gobject_class, ITEM_PROP_PARENT,
4060
 
                 g_param_spec_object ("parent", NULL, NULL,
4061
 
                                      GNOME_TYPE_CANVAS_ITEM,
4062
 
                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
4063
 
 
4064
 
        item_signals[ITEM_EVENT] =
4065
 
                g_signal_new ("event",
4066
 
                              G_TYPE_FROM_CLASS (class),
4067
 
                              G_SIGNAL_RUN_LAST,
4068
 
                              G_STRUCT_OFFSET (GnomeCanvasItemClass, event),
4069
 
                              boolean_handled_accumulator, NULL,
4070
 
                              gnome_canvas_marshal_BOOLEAN__BOXED,
4071
 
                              G_TYPE_BOOLEAN, 1,
4072
 
                              GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
4073
 
 
4074
 
        gobject_class->dispose = gnome_canvas_item_dispose;
4075
 
 
4076
 
        class->realize = gnome_canvas_item_realize;
4077
 
        class->unrealize = gnome_canvas_item_unrealize;
4078
 
        class->map = gnome_canvas_item_map;
4079
 
        class->unmap = gnome_canvas_item_unmap;
4080
 
        class->update = gnome_canvas_item_update;
4081
 
}