source: trunk/third/bonobo/bonobo/bonobo-canvas-component.c @ 16750

Revision 16750, 26.0 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16749, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * bonobo-canvas-component.c: implements the CORBA interface for
3 * the Bonobo::Canvas:Item interface used in Bonobo::Views.
4 *
5 * Author:
6 *   Miguel de Icaza (miguel@kernel.org)
7 *
8 * (C) 1999-2001 Helix Code, Inc.
9 */
10#include <stdio.h>
11#include <config.h>
12#include <gtk/gtksignal.h>
13#include <bonobo/Bonobo.h>
14#include <libgnomeui/gnome-canvas.h>
15#include <gdk/gdkx.h>
16#include <gdk/gdkprivate.h>
17#include <bonobo/bonobo-exception.h>
18#include <bonobo/bonobo-ui-component.h>
19#include <bonobo/bonobo-canvas-component.h>
20
21enum {
22        SET_BOUNDS,
23        EVENT,
24        LAST_SIGNAL
25};
26
27static gint gcc_signals [LAST_SIGNAL] = { 0, 0, };
28
29typedef BonoboCanvasComponent Gcc;
30#define GCC(x) BONOBO_CANVAS_COMPONENT(x)
31
32struct _BonoboCanvasComponentPrivate {
33        GnomeCanvasItem   *item;
34};
35
36#define PARENT_TYPE BONOBO_X_OBJECT_TYPE
37
38/* Returns the GnomeCanvasItemClass of an object */
39#define ICLASS(x) GNOME_CANVAS_ITEM_CLASS ((GTK_OBJECT (x)->klass))
40
41static GtkObjectClass *gcc_parent_class;
42
43static gboolean
44CORBA_SVP_Segment_to_SVPSeg (Bonobo_Canvas_SVPSegment *seg, ArtSVPSeg *art_seg)
45{
46        int i;
47
48        art_seg->points = art_new (ArtPoint, seg->points._length);
49        if (!art_seg->points)
50                return FALSE;
51
52        art_seg->dir = seg->up ? 0 : 1;
53        art_seg->bbox.x0 = seg->bbox.x0;
54        art_seg->bbox.x1 = seg->bbox.x1;
55        art_seg->bbox.y0 = seg->bbox.y0;
56        art_seg->bbox.y1 = seg->bbox.y1;
57
58        art_seg->n_points = seg->points._length;
59
60        for (i = 0; i < art_seg->n_points; i++){
61                art_seg->points [i].x = seg->points._buffer [i].x;
62                art_seg->points [i].y = seg->points._buffer [i].y;
63        }
64
65        return TRUE;
66}
67
68static void
69free_seg (ArtSVPSeg *seg)
70{
71        g_assert (seg != NULL);
72        g_assert (seg->points != NULL);
73       
74        art_free (seg->points);
75}
76
77/*
78 * Encodes an ArtUta
79 */
80static Bonobo_Canvas_ArtUTA *
81CORBA_UTA (ArtUta *uta)
82{
83        Bonobo_Canvas_ArtUTA *cuta;
84
85        cuta = Bonobo_Canvas_ArtUTA__alloc ();
86        if (!cuta)
87                return NULL;
88
89        if (!uta) {
90                cuta->width = 0;
91                cuta->height = 0;
92                cuta->utiles._length = 0;
93                cuta->utiles._maximum = 0;
94
95                return cuta;
96        }
97        cuta->utiles._buffer = CORBA_sequence_Bonobo_Canvas_int32_allocbuf (uta->width * uta->height);
98        cuta->utiles._length = uta->width * uta->height;
99        cuta->utiles._maximum = uta->width * uta->height;
100        if (!cuta->utiles._buffer) {
101                CORBA_free (cuta);
102                return NULL;
103        }
104               
105        cuta->x0 = uta->x0;
106        cuta->y0 = uta->y0;
107        cuta->width = uta->width;
108        cuta->height = uta->height;
109
110        memcpy (cuta->utiles._buffer, uta->utiles, uta->width * uta->height * sizeof (ArtUtaBbox));
111
112        return cuta;
113}
114
115static void
116restore_state (GnomeCanvasItem *item, const Bonobo_Canvas_State *state)
117{
118        double affine [6];
119        int i;
120
121        for (i = 0; i < 6; i++)
122                affine [i] = state->item_aff [i];
123
124        gnome_canvas_item_affine_absolute (item->canvas->root, affine);
125        item->canvas->pixels_per_unit = state->pixels_per_unit;
126        item->canvas->scroll_x1 = state->canvas_scroll_x1;
127        item->canvas->scroll_y1 = state->canvas_scroll_y1;
128        item->canvas->zoom_xofs = state->zoom_xofs;
129        item->canvas->zoom_yofs = state->zoom_yofs;
130        GTK_LAYOUT (item->canvas)->xoffset = state->xoffset;
131        GTK_LAYOUT (item->canvas)->yoffset = state->yoffset;
132}
133
134/* This is copied from gnome-canvas.c since it is declared static */
135static void
136invoke_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
137{
138        int child_flags;
139        double *child_affine;
140        double i2w[6], w2c[6], i2c[6];
141
142        child_flags = flags;
143        if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
144                child_flags &= ~GNOME_CANVAS_UPDATE_IS_VISIBLE;
145
146        /* Apply the child item's transform */
147        gnome_canvas_item_i2w_affine (item, i2w);
148        gnome_canvas_w2c_affine (item->canvas, w2c);
149        art_affine_multiply (i2c, i2w, w2c);
150        child_affine = i2c;
151
152        /* apply object flags to child flags */
153
154        child_flags &= ~GNOME_CANVAS_UPDATE_REQUESTED;
155
156        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_UPDATE)
157                child_flags |= GNOME_CANVAS_UPDATE_REQUESTED;
158
159        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)
160                child_flags |= GNOME_CANVAS_UPDATE_AFFINE;
161
162        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_CLIP)
163                child_flags |= GNOME_CANVAS_UPDATE_CLIP;
164
165        if (item->object.flags & GNOME_CANVAS_ITEM_NEED_VIS)
166                child_flags |= GNOME_CANVAS_UPDATE_VISIBILITY;
167
168        if ((child_flags & (GNOME_CANVAS_UPDATE_REQUESTED
169                            | GNOME_CANVAS_UPDATE_AFFINE
170                            | GNOME_CANVAS_UPDATE_CLIP
171                            | GNOME_CANVAS_UPDATE_VISIBILITY))
172            && GNOME_CANVAS_ITEM_CLASS (item->object.klass)->update)
173                (* GNOME_CANVAS_ITEM_CLASS (item->object.klass)->update) (
174                        item, child_affine, clip_path, child_flags);
175}
176
177static Bonobo_Canvas_ArtUTA *
178impl_Bonobo_Canvas_Component_update (PortableServer_Servant     servant,
179                                     const Bonobo_Canvas_State *state,
180                                     const Bonobo_Canvas_affine aff,
181                                     const Bonobo_Canvas_SVP   *clip_path,
182                                     CORBA_long                 flags,
183                                     CORBA_double              *x1,
184                                     CORBA_double              *y1,
185                                     CORBA_double              *x2,
186                                     CORBA_double              *y2,
187                                     CORBA_Environment         *ev)
188{
189        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
190        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
191        double affine [6];
192        int i;
193        ArtSVP *svp = NULL;
194        Bonobo_Canvas_ArtUTA *cuta;
195
196        restore_state (item, state);
197        for (i = 0; i < 6; i++)
198                affine [i] = aff [i];
199
200        if (clip_path->_length > 0) {
201                svp = art_alloc (sizeof (ArtSVP) + (clip_path->_length * sizeof (ArtSVPSeg)));
202                if (svp == NULL)
203                        goto fail;
204
205                svp->n_segs = clip_path->_length;
206               
207                for (i = 0; svp->n_segs; i++) {
208                        gboolean ok;
209               
210                        ok = CORBA_SVP_Segment_to_SVPSeg (&clip_path->_buffer [i], &svp->segs [i]);
211
212                        if (!ok) {
213                                int j;
214
215                                for (j = 0; j < i; j++) {
216                                        free_seg (&svp->segs [j]);
217                                }
218                                art_free (svp);
219                                goto fail;
220                        }
221                }
222        }
223       
224        invoke_update (item, affine, svp, flags);
225
226        if (svp){
227                for (i = 0; i < svp->n_segs; i++)
228                        free_seg (&svp->segs [i]);
229                art_free (svp);
230        }
231
232 fail:
233        if (getenv ("CC_DEBUG"))
234                printf ("%g %g %g %g\n", item->x1, item->x2, item->y1, item->y2);
235        *x1 = item->x1;
236        *x2 = item->x2;
237        *y1 = item->y1;
238        *y2 = item->y2;
239
240        cuta = CORBA_UTA (item->canvas->redraw_area);
241        if (cuta == NULL) {
242                CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
243                return NULL;
244        }
245
246        /*
247         * Now, mark our canvas as fully up to date
248         */
249        if (item->canvas->redraw_area) {
250                art_uta_free (item->canvas->redraw_area);
251                item->canvas->redraw_area = NULL;
252        }
253        item->canvas->need_redraw = FALSE;
254       
255        return cuta;
256}
257
258static GdkGC *the_gc = NULL;
259
260static void
261impl_Bonobo_Canvas_Component_realize (PortableServer_Servant  servant,
262                                      Bonobo_Canvas_window_id window,
263                                      CORBA_Environment      *ev)
264{
265        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
266        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
267        GdkWindow *gdk_window = gdk_window_foreign_new (window);
268
269        if (gdk_window == NULL) {
270                g_warning ("Invalid window id passed=0x%x", window);
271                return;
272        }
273
274        if (!the_gc)
275                the_gc = gdk_gc_new (gdk_window);
276
277        item->canvas->layout.bin_window = gdk_window;
278        ICLASS (item)->realize (item);
279}
280
281static void
282impl_Bonobo_Canvas_Component_unrealize (PortableServer_Servant servant,
283                                        CORBA_Environment     *ev)
284{
285        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
286        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
287
288        ICLASS (item)->unrealize (item);
289
290        if (item->canvas->layout.bin_window) {
291                gdk_pixmap_unref (item->canvas->layout.bin_window);
292                item->canvas->layout.bin_window = NULL;
293        }
294}
295
296static void
297impl_Bonobo_Canvas_Component_map (PortableServer_Servant servant,
298                                  CORBA_Environment     *ev)
299{
300        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
301        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
302       
303        ICLASS (item)->map (item);
304}
305
306static void
307impl_Bonobo_Canvas_Component_unmap (PortableServer_Servant servant,
308                                    CORBA_Environment     *ev)
309{
310        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
311        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
312       
313        ICLASS (item)->unmap (item);
314}
315
316static void
317my_gdk_pixmap_foreign_release (GdkPixmap *pixmap)
318{
319        GdkWindowPrivate *priv = (GdkWindowPrivate *) pixmap;
320
321        if (priv->ref_count != 1){
322                g_warning ("This item is keeping a refcount to a foreign pixmap");
323                return;
324        }
325
326        gdk_xid_table_remove (priv->xwindow);
327        g_dataset_destroy (priv);
328        g_free (priv);
329}
330
331static void
332impl_Bonobo_Canvas_Component_draw (PortableServer_Servant        servant,
333                                   const Bonobo_Canvas_State    *state,
334                                   const Bonobo_Canvas_window_id drawable,
335                                   CORBA_short                   x,
336                                   CORBA_short                   y,
337                                   CORBA_short                   width,
338                                   CORBA_short                   height,
339                                   CORBA_Environment            *ev)
340{
341        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
342        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
343        GdkPixmap *pix;
344       
345        gdk_flush ();
346        pix = gdk_pixmap_foreign_new (drawable);
347
348        if (pix == NULL){
349                g_warning ("Invalid window id passed=0x%x", drawable);
350                return;
351        }
352
353        restore_state (item, state);
354        ICLASS (item)->draw (item, pix, x, y, width, height);
355
356        my_gdk_pixmap_foreign_release (pix);
357        gdk_flush ();
358}
359
360static void
361impl_Bonobo_Canvas_Component_render (PortableServer_Servant servant,
362                                     Bonobo_Canvas_Buf     *buf,
363                                     CORBA_Environment     *ev)
364{
365        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
366        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
367        GnomeCanvasBuf canvas_buf;
368
369        if (!(buf->flags & Bonobo_Canvas_IS_BUF)) {
370                buf->rgb_buf._length = buf->row_stride * (buf->rect.y1 - buf->rect.y0);
371                buf->rgb_buf._maximum = buf->rgb_buf._length;
372               
373                buf->rgb_buf._buffer = CORBA_sequence_CORBA_octet_allocbuf (
374                        buf->rgb_buf._length);
375                CORBA_sequence_set_release (&buf->rgb_buf, TRUE);
376
377                if (buf->rgb_buf._buffer == NULL) {
378                        CORBA_exception_set_system (
379                                ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO);
380                        return;
381                }
382        }
383
384        canvas_buf.buf = buf->rgb_buf._buffer;
385       
386        canvas_buf.buf_rowstride = buf->row_stride;
387        canvas_buf.rect.x0 = buf->rect.x0;
388        canvas_buf.rect.x1 = buf->rect.x1;
389        canvas_buf.rect.y0 = buf->rect.y0;
390        canvas_buf.rect.y1 = buf->rect.y1;
391        canvas_buf.bg_color = buf->bg_color;
392        if (buf->flags & Bonobo_Canvas_IS_BG)
393                canvas_buf.is_bg = 1;
394        else
395                canvas_buf.is_bg = 0;
396
397        if (buf->flags & Bonobo_Canvas_IS_BUF)
398                canvas_buf.is_buf = 1;
399        else
400                canvas_buf.is_buf = 0;
401
402        ICLASS (item)->render (item, &canvas_buf);
403
404        /* return */
405        buf->flags =
406                (canvas_buf.is_bg ? Bonobo_Canvas_IS_BG : 0) |
407                (canvas_buf.is_buf ? Bonobo_Canvas_IS_BUF : 0);
408}
409
410static CORBA_boolean
411impl_Bonobo_Canvas_Component_contains (PortableServer_Servant servant,
412                                       CORBA_double           x,
413                                       CORBA_double           y,
414                                       CORBA_Environment     *ev)
415{
416        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
417        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
418        GnomeCanvasItem *new_item;
419        CORBA_boolean ret;
420       
421        if (getenv ("CC_DEBUG"))
422                printf ("Point %g %g: ", x, y);
423        ret = ICLASS (item)->point (item, x, y, 0, 0, &new_item) == 0.0;
424        if (getenv ("CC_DEBUG"))
425                printf ("=> %s\n", ret ? "yes" : "no");
426        return ret;
427}
428
429static void
430impl_Bonobo_Canvas_Component_bounds (PortableServer_Servant     servant,
431                                     const Bonobo_Canvas_State *state,
432                                     CORBA_double              *x1,
433                                     CORBA_double              *x2,
434                                     CORBA_double              *y1,
435                                     CORBA_double              *y2,
436                                     CORBA_Environment         *ev)
437{
438        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
439        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
440
441        restore_state (item, state);
442        ICLASS (item)->bounds (item, x1, y1, x2, y2);
443}
444
445/*
446 * Converts the event marshalled from the container into a GdkEvent
447 */
448static void
449Bonobo_Gdk_Event_to_GdkEvent (const Bonobo_Gdk_Event *gnome_event, GdkEvent *gdk_event)
450{
451        switch (gnome_event->_d){
452        case Bonobo_Gdk_FOCUS:
453                gdk_event->type = GDK_FOCUS_CHANGE;
454                gdk_event->focus_change.in = gnome_event->_u.focus.inside;
455                return;
456               
457        case Bonobo_Gdk_KEY:
458                if (gnome_event->_u.key.type == Bonobo_Gdk_KEY_PRESS)
459                        gdk_event->type = GDK_KEY_PRESS;
460                else
461                        gdk_event->type = GDK_KEY_RELEASE;
462                gdk_event->key.time = gnome_event->_u.key.time;
463                gdk_event->key.state = gnome_event->_u.key.state;
464                gdk_event->key.keyval = gnome_event->_u.key.keyval;
465                gdk_event->key.length = gnome_event->_u.key.length;
466                gdk_event->key.string = g_strdup (gnome_event->_u.key.str);
467                return;
468               
469        case Bonobo_Gdk_MOTION:
470                gdk_event->type = GDK_MOTION_NOTIFY;
471                gdk_event->motion.time = gnome_event->_u.motion.time;
472                gdk_event->motion.x = gnome_event->_u.motion.x;
473                gdk_event->motion.y = gnome_event->_u.motion.y;
474                gdk_event->motion.x_root = gnome_event->_u.motion.x_root;
475                gdk_event->motion.y_root = gnome_event->_u.motion.y_root;
476                gdk_event->motion.xtilt = gnome_event->_u.motion.xtilt;
477                gdk_event->motion.ytilt = gnome_event->_u.motion.ytilt;
478                gdk_event->motion.state = gnome_event->_u.motion.state;
479                gdk_event->motion.is_hint = gnome_event->_u.motion.is_hint;
480                return;
481               
482        case Bonobo_Gdk_BUTTON:
483                switch (gnome_event->_u.button.type){
484                case Bonobo_Gdk_BUTTON_PRESS:
485                        gdk_event->type = GDK_BUTTON_PRESS;
486                        break;
487                case Bonobo_Gdk_BUTTON_RELEASE:
488                        gdk_event->type = GDK_BUTTON_RELEASE;
489                        break;
490                case Bonobo_Gdk_BUTTON_2_PRESS:
491                        gdk_event->type = GDK_2BUTTON_PRESS;
492                        break;
493                case Bonobo_Gdk_BUTTON_3_PRESS:
494                        gdk_event->type = GDK_3BUTTON_PRESS;
495                        break;
496                }
497                gdk_event->button.time   = gnome_event->_u.button.time;
498                gdk_event->button.x      = gnome_event->_u.button.x;
499                gdk_event->button.y      = gnome_event->_u.button.y;
500                gdk_event->button.x_root = gnome_event->_u.button.x_root;
501                gdk_event->button.y_root = gnome_event->_u.button.y_root;
502                gdk_event->button.button = gnome_event->_u.button.button;
503                return;
504               
505        case Bonobo_Gdk_CROSSING:
506                if (gnome_event->_u.crossing.type == Bonobo_Gdk_ENTER)
507                        gdk_event->type = GDK_ENTER_NOTIFY;
508                else
509                        gdk_event->type = GDK_LEAVE_NOTIFY;
510               
511                gdk_event->crossing.time   = gnome_event->_u.crossing.time;
512                gdk_event->crossing.x      = gnome_event->_u.crossing.x;
513                gdk_event->crossing.y      = gnome_event->_u.crossing.y;
514                gdk_event->crossing.x_root = gnome_event->_u.crossing.x_root;
515                gdk_event->crossing.y_root = gnome_event->_u.crossing.y_root;
516                switch (gnome_event->_u.crossing.mode){
517                case Bonobo_Gdk_NORMAL:
518                        gdk_event->crossing.mode = GDK_CROSSING_NORMAL;
519                        break;
520                       
521                case Bonobo_Gdk_GRAB:
522                        gdk_event->crossing.mode = GDK_CROSSING_GRAB;
523                        break;
524                case Bonobo_Gdk_UNGRAB:
525                        gdk_event->crossing.mode = GDK_CROSSING_UNGRAB;
526                        break;
527                }
528                return;
529        }
530        g_assert_not_reached ();
531}
532
533static void
534free_event (GdkEvent *event)
535{
536        if (event->type == GDK_KEY_RELEASE || event->type == GDK_KEY_PRESS)
537                g_free (event->key.string);
538}
539
540/*
541 * Receives events from the container end, decodes it into a synthetic
542 * GdkEvent and forwards this to the CanvasItem
543 */
544static CORBA_boolean
545impl_Bonobo_Canvas_Component_event (PortableServer_Servant     servant,
546                                    const Bonobo_Canvas_State *state,
547                                    const Bonobo_Gdk_Event    *gnome_event,
548                                    CORBA_Environment         *ev)
549{
550        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
551        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
552        GdkEvent gdk_event;
553        int retval;
554
555        Bonobo_Gdk_Event_to_GdkEvent (gnome_event, &gdk_event);
556
557        restore_state (item, state);
558
559        gtk_signal_emit_by_name (GTK_OBJECT (gcc), "event", &gdk_event);
560
561        if (ICLASS (item)->event)
562                retval = ICLASS (item)->event (item, &gdk_event);
563        else
564                retval = FALSE;
565
566        free_event (&gdk_event);
567
568        return retval;
569}
570
571static void
572impl_Bonobo_Canvas_Component_setCanvasSize (PortableServer_Servant servant,
573                                            CORBA_short            x,
574                                            CORBA_short            y,
575                                            CORBA_short            width,
576                                            CORBA_short            height,
577                                            CORBA_Environment     *ev)
578{
579        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
580        GnomeCanvasItem *item = GNOME_CANVAS_ITEM (gcc->priv->item);
581        GtkAllocation alloc;
582
583        alloc.x = x;
584        alloc.y = y;
585        alloc.width = width;
586        alloc.height = height;
587
588        gtk_widget_size_allocate (GTK_WIDGET (item->canvas), &alloc);
589}
590
591static void
592impl_Bonobo_Canvas_Component_setBounds (PortableServer_Servant     servant,
593                                        const Bonobo_Canvas_DRect *bbox,
594                                        CORBA_Environment         *ev)
595{
596        Gcc *gcc = GCC (bonobo_object_from_servant (servant));
597
598        gtk_signal_emit (GTK_OBJECT (gcc), gcc_signals [SET_BOUNDS], bbox, &ev);
599}
600
601static void
602gcc_destroy (GtkObject *object)
603{
604        GnomeCanvasItem *item = BONOBO_CANVAS_COMPONENT (object)->priv->item;
605
606        gtk_object_destroy (GTK_OBJECT (item->canvas));
607
608        gcc_parent_class->destroy (object);
609}
610
611static void
612gcc_finalize (GtkObject *object)
613{
614        Gcc *gcc = GCC (object);
615
616        g_free (gcc->priv);
617
618        gcc_parent_class->finalize (object);
619}
620
621static void
622bonobo_canvas_component_class_init (BonoboCanvasComponentClass *klass)
623{
624        GtkObjectClass *object_class = (GtkObjectClass *) klass;
625        POA_Bonobo_Canvas_Component__epv *epv = &klass->epv;
626
627        gcc_parent_class = gtk_type_class (PARENT_TYPE);
628
629        object_class->destroy  = gcc_destroy;
630        object_class->finalize = gcc_finalize;
631
632        gcc_signals [SET_BOUNDS] =
633                gtk_signal_new ("set_bounds",
634                                GTK_RUN_LAST,
635                                object_class->type,
636                                GTK_SIGNAL_OFFSET (BonoboCanvasComponentClass, set_bounds),
637                                gtk_marshal_NONE__POINTER_POINTER,
638                                GTK_TYPE_NONE, 2,
639                                GTK_TYPE_POINTER, GTK_TYPE_POINTER);
640
641        gcc_signals [EVENT] = gtk_signal_new ("event",
642                        GTK_RUN_LAST, object_class->type,
643                        GTK_SIGNAL_OFFSET (BonoboCanvasComponentClass, event),
644                        gtk_marshal_BOOL__POINTER,
645                        GTK_TYPE_BOOL, 1, GTK_TYPE_POINTER);
646
647        gtk_object_class_add_signals (object_class, gcc_signals, LAST_SIGNAL);
648
649        epv->update         = impl_Bonobo_Canvas_Component_update;
650        epv->realize        = impl_Bonobo_Canvas_Component_realize;
651        epv->unrealize      = impl_Bonobo_Canvas_Component_unrealize;
652        epv->map            = impl_Bonobo_Canvas_Component_map;
653        epv->unmap          = impl_Bonobo_Canvas_Component_unmap;
654        epv->draw           = impl_Bonobo_Canvas_Component_draw;
655        epv->render         = impl_Bonobo_Canvas_Component_render;
656        epv->bounds         = impl_Bonobo_Canvas_Component_bounds;
657        epv->event          = impl_Bonobo_Canvas_Component_event;
658        epv->contains       = impl_Bonobo_Canvas_Component_contains;
659        epv->setCanvasSize  = impl_Bonobo_Canvas_Component_setCanvasSize;
660        epv->setBounds      = impl_Bonobo_Canvas_Component_setBounds;
661}
662
663static void
664bonobo_canvas_component_init (GtkObject *object)
665{
666        Gcc *gcc = GCC (object);
667
668        gcc->priv = g_new0 (BonoboCanvasComponentPrivate, 1);
669}
670
671BONOBO_X_TYPE_FUNC_FULL (BonoboCanvasComponent,
672                           Bonobo_Canvas_Component,
673                           PARENT_TYPE,
674                           bonobo_canvas_component);
675
676
677/**
678 * bonobo_canvas_component_construct:
679 * @comp: a #BonoboCanvasComponent to initialize
680 * @item: A #GnomeCanvasItem that is being exported
681 *
682 * Creates a CORBA server for the interface Bonobo::Canvas::Item
683 * wrapping @item.
684 *
685 * Returns: The BonoboCanvasComponent.
686 */
687BonoboCanvasComponent *
688bonobo_canvas_component_construct (BonoboCanvasComponent  *comp,
689                                  GnomeCanvasItem         *item)
690{
691        g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), NULL);
692        g_return_val_if_fail (BONOBO_IS_CANVAS_COMPONENT (comp), NULL);
693
694        comp->priv->item = item;
695
696        return comp;
697}
698
699                                 
700/**
701 * bonobo_canvas_component_new:
702 * @item: A GnomeCanvasItem that is being exported
703 *
704 * Creates a CORBA server for the interface Bonobo::Canvas::Item
705 * wrapping @item.
706 *
707 * Returns: The BonoboCanvasComponent.
708 */
709BonoboCanvasComponent *
710bonobo_canvas_component_new (GnomeCanvasItem *item)
711{
712        BonoboCanvasComponent *comp;
713       
714        g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), NULL);
715       
716        comp = gtk_type_new (bonobo_canvas_component_get_type ());
717
718        return bonobo_canvas_component_construct (comp, item);
719}
720
721/**
722 * bonobo_canvas_component_get_item:
723 * @comp: A #BonoboCanvasComponent object
724 *
725 * Returns: The GnomeCanvasItem that this BonoboCanvasComponent proxies
726 */
727GnomeCanvasItem *
728bonobo_canvas_component_get_item (BonoboCanvasComponent *comp)
729{
730        g_return_val_if_fail (comp != NULL, NULL);
731        g_return_val_if_fail (BONOBO_IS_CANVAS_COMPONENT (comp), NULL);
732
733        return comp->priv->item;
734}
735
736/*
737 * Hack root item
738 *
739 * This is a hack since we can not modify the existing GNOME Canvas to handle
740 * this case.
741 *
742 * Here is the problem we are solving:
743 *
744 *    1. Items usually queue a request to be updated/redrawn by calling
745 *       gnome_canvas_item_request_update().  This triggers in the container
746 *       canvas an idle handler to be queued to update the display on the
747 *       idle handler.
748 *       
749 *    2. There is no way we can catch this on the Canvas.
750 *
751 * To catch this we do:
752 *
753 *    3. replace the regular Canvas' root field (of type GnomeCanvasGroup)
754 *       with a RootItemHack item.  This item has an overriden ->update method
755 *       that will notify the container canvas on the container process about
756 *       our update requirement.
757 */
758
759static GnomeCanvasGroupClass *rih_parent_class;
760
761typedef struct {
762        GnomeCanvasGroup       group;
763        Bonobo_Canvas_ComponentProxy proxy;
764        GnomeCanvasItem *orig_root;
765} RootItemHack;
766
767typedef struct {
768        GnomeCanvasGroupClass parent_class;
769} RootItemHackClass;
770
771static GtkType root_item_hack_get_type (void);
772#define ROOT_ITEM_HACK_TYPE (root_item_hack_get_type ())
773#define ROOT_ITEM_HACK(obj) (GTK_CHECK_CAST((obj), ROOT_ITEM_HACK_TYPE, RootItemHack))
774
775static void
776rih_destroy (GtkObject *obj)
777{
778        RootItemHack *rih = ROOT_ITEM_HACK (obj);
779
780        bonobo_object_release_unref (rih->proxy, NULL);
781        gtk_object_destroy (GTK_OBJECT (rih->orig_root));
782
783        GTK_OBJECT_CLASS (rih_parent_class)->destroy (obj);
784}
785
786/*
787 * Invoked by our local canvas when an update is requested,
788 * we forward this to the container canvas
789 */
790static void
791rih_update (GnomeCanvasItem *item, double affine [6], ArtSVP *svp, int flags)
792{
793        RootItemHack *rih = (RootItemHack *) item;
794        CORBA_Environment ev;
795        GnomeCanvasItemClass *gci_class = gtk_type_class (
796                                        gnome_canvas_item_get_type ());
797
798        CORBA_exception_init (&ev);
799        Bonobo_Canvas_ComponentProxy_requestUpdate (rih->proxy, &ev);
800        CORBA_exception_free (&ev);
801
802        /*
803         * Mark our canvas and item as fully updated
804         */
805
806        (* gci_class->update) (item, affine, svp, flags);
807
808        if (item->canvas->redraw_area)
809                art_uta_free (item->canvas->redraw_area);
810        item->canvas->redraw_area = NULL;
811        item->canvas->need_redraw = FALSE;
812}
813
814static void
815rih_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
816          int x, int y, int width, int height)
817{
818        RootItemHack *rih = (RootItemHack *) item;
819        CORBA_Environment ev;
820
821        CORBA_exception_init (&ev);
822        Bonobo_Canvas_ComponentProxy_requestRedraw (
823                        rih->proxy, x, y, x + width, y + height, &ev);
824        CORBA_exception_free (&ev);
825}
826
827static void
828rih_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
829{
830        RootItemHack *rih = (RootItemHack *) item;
831        CORBA_Environment ev;
832
833        CORBA_exception_init (&ev);
834        Bonobo_Canvas_ComponentProxy_requestRedraw (
835                                        rih->proxy, item->x1, item->y1,
836                                        item->x2, item->y2, &ev);
837        CORBA_exception_free (&ev);
838}
839
840static void
841rih_class_init (GnomeCanvasItemClass *item_class)
842{
843        rih_parent_class = gtk_type_class (gnome_canvas_group_get_type ());
844
845        GTK_OBJECT_CLASS (item_class)->destroy  = rih_destroy;
846        item_class->update = rih_update;
847        item_class->draw = rih_draw;
848        item_class->render = rih_render;
849}
850     
851static GtkType
852root_item_hack_get_type (void)
853{
854        static GtkType type = 0;
855
856        if (!type) {
857                GtkTypeInfo info = {
858                        "RootItemHack",
859                        sizeof (RootItemHack),
860                        sizeof (RootItemHackClass),
861                        (GtkClassInitFunc) rih_class_init,
862                        (GtkObjectInitFunc) NULL,
863                        NULL, /* reserved_1 */
864                        NULL, /* reserved_2 */
865                        (GtkClassInitFunc) NULL
866                };
867
868                type = gtk_type_unique (gnome_canvas_group_get_type (), &info);
869        }
870
871        return type;
872}
873
874static RootItemHack *
875root_item_hack_new (GnomeCanvas *canvas, Bonobo_Canvas_ComponentProxy proxy)
876{
877        RootItemHack *item_hack;
878
879        item_hack = gtk_type_new (root_item_hack_get_type ());
880        item_hack->proxy = proxy;
881        item_hack->orig_root = canvas->root;
882        GNOME_CANVAS_ITEM (item_hack)->canvas = canvas;
883
884        return item_hack;
885}
886
887/**
888 * bonobo_canvas_new:
889 * @is_aa: Flag indicating is antialiased canvas is desired
890 * @proxy: Remote proxy for the component this canvas will support
891 *
892 * Returns: A #GnomeCanvas with the root replaced by a forwarding item.
893 */
894GnomeCanvas *
895bonobo_canvas_new (gboolean is_aa, Bonobo_Canvas_ComponentProxy proxy)
896{
897        GnomeCanvas *canvas;
898        GnomeCanvasItem *orig_root;
899
900        if (is_aa) {
901                gdk_rgb_init ();
902                canvas = GNOME_CANVAS (gnome_canvas_new_aa ());
903        } else
904                canvas = GNOME_CANVAS (gnome_canvas_new ());
905
906        orig_root = canvas->root;
907
908        canvas->root = GNOME_CANVAS_ITEM (root_item_hack_new (canvas, proxy));
909
910        gtk_widget_realize (GTK_WIDGET (canvas));
911       
912        /* Gross */
913        GTK_WIDGET_SET_FLAGS (canvas, GTK_VISIBLE | GTK_MAPPED);
914
915        return canvas;
916}
917
918/**
919 * bonobo_canvas_component_grab:
920 * @comp: A #BonoboCanvasComponent object
921 * @mask: Mask of events to grab
922 * @cursor: #GdkCursor to display during grab
923 * @time: Time of last event before grab
924 *
925 * Grabs the mouse focus via a call to the remote proxy.
926 */
927void
928bonobo_canvas_component_grab (BonoboCanvasComponent *comp, guint mask,
929                              GdkCursor *cursor, guint32 time)
930{
931        CORBA_Environment ev;
932
933        CORBA_exception_init (&ev);
934        Bonobo_Canvas_ComponentProxy_grabFocus (
935                ROOT_ITEM_HACK (comp->priv->item->canvas->root)->proxy,
936                mask, cursor->type, time, &ev);
937        CORBA_exception_free (&ev);
938}
939
940/**
941 * bonobo_canvas_component_ungrab:
942 * @comp: A #BonoboCanvasComponent object
943 * @time: Time of last event before grab
944 *
945 * Grabs the mouse focus via a call to the remote proxy.
946 */
947void
948bonobo_canvas_component_ungrab (BonoboCanvasComponent *comp, guint32 time)
949{
950        CORBA_Environment ev;
951
952        CORBA_exception_init (&ev);
953        Bonobo_Canvas_ComponentProxy_ungrabFocus (
954                ROOT_ITEM_HACK (comp->priv->item->canvas->root)->proxy, time, &ev);
955        CORBA_exception_free (&ev);
956}
957
958/**
959 * bonobo_canvas_component_get_ui_container:
960 * @comp: A #BonoboCanvasComponent object
961 *
962 * Returns: The UI container for the component's remote proxy.
963 */
964Bonobo_UIContainer
965bonobo_canvas_component_get_ui_container (BonoboCanvasComponent *comp)
966{
967        Bonobo_UIContainer corba_uic;
968        CORBA_Environment ev;
969
970        CORBA_exception_init (&ev);
971        corba_uic = Bonobo_Canvas_ComponentProxy_getUIContainer (
972                        ROOT_ITEM_HACK (comp->priv->item->canvas->root)->proxy, &ev);
973        CORBA_exception_free (&ev);
974
975        return corba_uic;
976}
977
Note: See TracBrowser for help on using the repository browser.