source: trunk/third/bonobo/bonobo/bonobo-widget.c @ 15579

Revision 15579, 18.8 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15578, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/**
3 * bonobo-widget.c: BonoboWidget object.
4 *
5 * Authors:
6 *   Nat Friedman    (nat@helixcode.com)
7 *
8 * Copyright 1999 Helix Code, Inc.
9 *
10 * Bonobo component embedding for hydrocephalic imbeciles.
11 *
12 * Pure cane sugar.
13 *
14 * This purpose of BonoboWidget is to make container-side use of
15 * Bonobo as easy as pie.  This widget has two functions:
16 *
17 *   1. Provide a simple wrapper for embedding a single-view
18 *      subdocument.  In this case, BonoboWidget handles creating
19 *      the embeddable, binding it to a local BonoboClientSite,
20 *      creating a view for it, and displaying the view.  You can use
21 *      the accessor functions (bonobo_widget_get_view_frame,
22 *      etc) to get at the actual Bonobo objects which underlie the
23 *      whole process.
24 *
25 *      In order to do this, just call:
26 *
27 *        bw = bonobo_widget_new_subdoc ("moniker of subdoc embddable",
28 *                                        top_level_uicontainer);
29 *
30 *      And then insert the 'bw' widget into the widget tree of your
31 *      application like so:
32 *
33 *        gtk_container_add (some_container, bw);
34 *
35 *      You are free to make the UIContainer argument to
36 *      bonobo_widget_new_subdoc() be CORBA_OBJECT_NIL.
37 *
38 *   2. Provide a simple wrapper for embedding Controls.  Embedding
39 *      controls is already really easy, but BonoboWidget reduces
40 *      the work from about 5 lines to 1.  To embed a given control,
41 *      just do:
42 *
43 *        bw = bonobo_widget_new_control ("moniker for control");
44 *        gtk_container_add (some_container, bw);
45 *
46 *      Ta da!
47 *
48 *      NB. A simple moniker might look like 'file:/tmp/a.jpeg' or
49 *      OAFIID:GNOME_Evolution_Calendar_Control
50 */
51
52#include <config.h>
53#include <gtk/gtksignal.h>
54#include <gtk/gtkmarshal.h>
55#include <bonobo/Bonobo.h>
56#include <bonobo/bonobo-main.h>
57#include <bonobo/bonobo-object.h>
58#include <bonobo/bonobo-widget.h>
59#include <bonobo/bonobo-exception.h>
60#include <bonobo/bonobo-moniker-util.h>
61
62struct _BonoboWidgetPrivate {
63
64        BonoboObjectClient *server;
65
66        /*
67         * Control stuff.
68         */
69        BonoboControlFrame *control_frame;
70       
71        /*
72         * Subdocument (Embeddable/View) things.
73         */
74        BonoboItemContainer *container;
75        BonoboClientSite    *client_site;
76        BonoboViewFrame     *view_frame;
77        Bonobo_UIContainer   uic;
78};
79
80static BonoboWrapperClass *bonobo_widget_parent_class;
81
82static BonoboObjectClient *
83bonobo_widget_launch_component (const char *moniker,
84                                const char *if_name)
85{
86        Bonobo_Unknown corba_ref;
87        BonoboObjectClient *server;
88        CORBA_Environment ev;
89
90        CORBA_exception_init (&ev);
91        corba_ref = bonobo_get_object (moniker, if_name, &ev);
92
93        if (BONOBO_EX (&ev)) {
94                char *txt;
95                g_warning ("Activation exception '%s'",
96                           (txt = bonobo_exception_get_text (&ev)));
97                g_free (txt);
98                server = CORBA_OBJECT_NIL;
99        }
100
101        CORBA_exception_free (&ev);
102
103        if (corba_ref == CORBA_OBJECT_NIL)
104                return NULL;
105
106        return bonobo_object_client_from_corba (corba_ref);
107}
108
109
110/*
111 *
112 * Control support for BonoboWidget.
113 *
114 */
115/**
116 * bonobo_widget_construct_control_from_objref:
117 * @bw: A BonoboWidget to construct
118 * @control: A CORBA Object reference to an IDL:Bonobo/Control:1.0
119 * @uic: Bonobo_UIContainer for the launched object.
120 *
121 * This is a constructor function.  Only usable for wrapping and
122 * derivation of new objects.  For normal use, please refer to
123 * #bonobo_widget_new_control_from_objref.
124 *
125 * Returns: A #BonoboWidget (the @bw)
126 */
127BonoboWidget *
128bonobo_widget_construct_control_from_objref (BonoboWidget      *bw,
129                                             Bonobo_Control     control,
130                                             Bonobo_UIContainer uic)
131{
132        GtkWidget    *control_frame_widget;
133
134        /*
135         * Create a local ControlFrame for it.
136         */
137        bw->priv->control_frame = bonobo_control_frame_new (uic);
138
139        bonobo_control_frame_bind_to_control (bw->priv->control_frame, control);
140
141        /*
142         * People that pass us controls get them sunk.
143         */
144        bonobo_object_release_unref (control, NULL);
145
146        bonobo_control_frame_set_autoactivate (bw->priv->control_frame, TRUE);
147
148        /*
149         * Grab the actual widget which visually contains the remote
150         * Control.  This is a GtkSocket, in reality.
151         */
152        control_frame_widget = bonobo_control_frame_get_widget (bw->priv->control_frame);
153
154        /*
155         * Now stick it into this BonoboWidget.
156         */
157        gtk_container_add (GTK_CONTAINER (bw),
158                           control_frame_widget);
159        gtk_widget_show (control_frame_widget);
160
161        if (uic != CORBA_OBJECT_NIL)
162                bw->priv->uic = bonobo_object_dup_ref (uic, NULL);
163
164        return bw;
165}
166
167/**
168 * bonobo_widget_construct_control:
169 * @bw: A BonoboWidget to construct
170 * @moniker: A Moniker describing the object to be activated
171 * @uic: Bonobo_UIContainer for the launched object.
172 *
173 * This is a constructor function.  Only usable for wrapping and
174 * derivation of new objects.  For normal use, please refer to
175 * #bonobo_widget_new_control.
176 *
177 * This function will unref the passed in @bw in case it cannot launch
178 * the component and return %NULL in such a case.  Otherwise it returns
179 * the @bw itself.
180 *
181 * Returns: A #BonoboWidget or %NULL
182 */
183BonoboWidget *
184bonobo_widget_construct_control (BonoboWidget      *bw,
185                                 const char        *moniker,
186                                 Bonobo_UIContainer uic)
187{
188        Bonobo_Control control;
189
190        /*
191         * Create the remote Control object.
192         */
193        bw->priv->server = bonobo_widget_launch_component (
194                moniker, "IDL:Bonobo/Control:1.0");
195        if (bw->priv->server == NULL) {
196                gtk_object_unref (GTK_OBJECT (bw));
197                return NULL;
198        }
199
200        control = BONOBO_OBJREF (bw->priv->server);
201
202        return bonobo_widget_construct_control_from_objref (bw, control, uic);
203}
204
205/**
206 * bonobo_widget_new_control_from_objref:
207 * @control: A CORBA Object reference to an IDL:Bonobo/Control:1.0
208 * @uic: Bonobo_UIContainer for the launched object.
209 *
210 * This function is a simple wrapper for easily embedding controls
211 * into applications.  This function is used when you have already
212 * a CORBA object reference to an IDL:Bonobo/Control:1.0 (the
213 * @control) argument.
214 *
215 * Returns: the @control wrapped as a #GtkWidget.
216 */
217GtkWidget *
218bonobo_widget_new_control_from_objref (Bonobo_Control     control,
219                                       Bonobo_UIContainer uic)
220{
221        BonoboWidget *bw;
222
223        g_return_val_if_fail (control != CORBA_OBJECT_NIL, NULL);
224
225        bw = gtk_type_new (BONOBO_WIDGET_TYPE);
226
227        bw = bonobo_widget_construct_control_from_objref (bw, control, uic);
228
229        if (bw == NULL)
230                return NULL;
231
232        return GTK_WIDGET (bw);
233}
234
235/**
236 * bonobo_widget_new_control:
237 * @moniker: A Moniker describing the object to be activated
238 * @uic: Bonobo_UIContainer for the launched object.
239 *
240 * This function is a simple wrapper for easily embedding controls
241 * into applications.  It will launch the component identified by @id
242 * and will return it as a GtkWidget.
243 *
244 * Returns: A #GtkWidget that is bound to the Bonobo Control.
245 */
246GtkWidget *
247bonobo_widget_new_control (const char        *moniker,
248                           Bonobo_UIContainer uic)
249{
250        BonoboWidget *bw;
251
252        g_return_val_if_fail (moniker != NULL, NULL);
253
254        bw = gtk_type_new (BONOBO_WIDGET_TYPE);
255
256        bw = bonobo_widget_construct_control (bw, moniker, uic);
257
258        if (bw == NULL)
259                return NULL;
260        else
261                return GTK_WIDGET (bw);
262}
263
264/**
265 * bonobo_widget_get_control_frame:
266 * @bonobo_widget: a Bonobo Widget returned by one of the bonobo_widget_new() functions.
267 *
268 * Every IDL:Bonobo/Control:1.0 needs to be placed inside an
269 * IDL:Bonobo/ControlFrame:1.0.  This returns the BonoboControlFrame
270 * object that wraps the Control in the @bonobo_widget.
271 *
272 * Returns: The BonoboControlFrame associated with the @bonobo_widget
273 */
274BonoboControlFrame *
275bonobo_widget_get_control_frame (BonoboWidget *bonobo_widget)
276{
277        g_return_val_if_fail (bonobo_widget != NULL, NULL);
278        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
279
280        return bonobo_widget->priv->control_frame;
281}
282
283
284/*
285 *
286 * Subdocument support for BonoboWidget.
287 *
288 */
289static BonoboWidget *
290bonobo_widget_create_subdoc_object (BonoboWidget      *bw,
291                                    const char        *moniker,
292                                    Bonobo_UIContainer uic)
293{
294        GtkWidget *view_widget;
295       
296        /*
297         * Create the BonoboContainer.  This will contain
298         * just one BonoboClientSite.
299         */
300        bw->priv->container = bonobo_item_container_new ();
301
302        bw->priv->server = bonobo_widget_launch_component (
303                moniker, "IDL:Bonobo/Embeddable:1.0");
304        if (bw->priv->server == NULL)
305                return NULL;
306       
307        /*
308         * Create the client site.  This is the container-side point
309         * of contact for the remote component.
310         */
311        bw->priv->client_site = bonobo_client_site_new (bw->priv->container);
312
313        /*
314         * Bind the local ClientSite object to the remote Embeddable
315         * component.
316         */
317        if (!bonobo_client_site_bind_embeddable (bw->priv->client_site, bw->priv->server))
318                return NULL;
319
320        /*
321         * Now create a new view for the remote object.
322         */
323        bw->priv->view_frame = bonobo_client_site_new_view (bw->priv->client_site, uic);
324
325        /*
326         * Add the view frame.
327         */
328        view_widget = bonobo_view_frame_get_wrapper (bw->priv->view_frame);
329        gtk_container_add (GTK_CONTAINER (bw), view_widget);
330        gtk_widget_show (view_widget);
331
332        if (uic != CORBA_OBJECT_NIL)
333                bw->priv->uic = bonobo_object_dup_ref (uic, NULL);
334       
335        return bw;
336}
337
338/**
339 * bonobo_widget_new_subdoc:
340 * @moniker: A moniker description of the Object to be activated.
341 * @uic: Bonobo_UIContainer for the launched object.
342 *
343 * This function is a simple wrapper for easily embedding documents
344 * into applications.  It will launch the component identified by @id
345 * and will return it as a GtkWidget.
346 *
347 * This will launch a single view of the embeddable activated by @moniker.
348 *
349 * FIXME: this function should really be using bonobo_get_object() instead
350 * of bonobo_activate_object() to launch the object.
351 *
352 * Returns: A #GtkWidget that is bound to the Bonobo Control.
353 */
354GtkWidget *
355bonobo_widget_new_subdoc (const char        *moniker,
356                          Bonobo_UIContainer uic)
357{
358        BonoboWidget *bw;
359
360        g_return_val_if_fail (moniker != NULL, NULL);
361
362        bw = gtk_type_new (BONOBO_WIDGET_TYPE);
363
364        if (bw == NULL)
365                return NULL;
366
367        if (!bonobo_widget_create_subdoc_object (bw, moniker, uic)) {
368                gtk_object_destroy (GTK_OBJECT (bw));
369                return NULL;
370        }
371 
372        bonobo_view_frame_set_covered (bw->priv->view_frame, FALSE);
373
374        return GTK_WIDGET (bw);
375}
376
377/**
378 * bonobo_widget_get_container
379 * @bonobo_widget: the #BonoboWidget to query.
380 *
381 * This operation is only valid for BonoboWidgets that were created
382 * by the bonobo_widget_new_subdoc().
383 *
384 * Returns: the BonoboItemContainer associated with this @bonobo_widget
385 */
386BonoboItemContainer *
387bonobo_widget_get_container (BonoboWidget *bonobo_widget)
388{
389        g_return_val_if_fail (bonobo_widget != NULL, NULL);
390        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
391
392        return bonobo_widget->priv->container;
393}
394
395/**
396 * bonobo_widget_get_client_site:
397 * @bonobo_widget: the #BonoboWidget to query.
398 *
399 * This operation is only valid for BonoboWidgets that were created
400 * by the bonobo_widget_new_subdoc().
401 *
402 * Returns: the #BonoboClientSite associated with this @bonobo_widget
403 */
404BonoboClientSite *
405bonobo_widget_get_client_site (BonoboWidget *bonobo_widget)
406{
407        g_return_val_if_fail (bonobo_widget != NULL, NULL);
408        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
409
410        return bonobo_widget->priv->client_site;
411}
412
413/**
414 * bonobo_widget_get_view_frame:
415 * @bonobo_widget: the #BonoboWidget to query.
416 *
417 * This operation is only valid for BonoboWidgets that were created
418 * by the bonobo_widget_new_subdoc().
419 *
420 * Returns: The #BonoboViewFrame associated with this @bonobo_widget.
421 */
422BonoboViewFrame *
423bonobo_widget_get_view_frame (BonoboWidget *bonobo_widget)
424{
425        g_return_val_if_fail (bonobo_widget != NULL, NULL);
426        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
427
428        return bonobo_widget->priv->view_frame;
429}
430
431/**
432 * bonobo_widget_get_uih:
433 * @bonobo_widget: the #BonoboWidget to query.
434 *
435 * Returns: the CORBA object reference to the Bonobo_UIContainer
436 * associated with the @bonobo_widget.
437 */
438Bonobo_UIContainer
439bonobo_widget_get_uih (BonoboWidget *bonobo_widget)
440{
441        g_return_val_if_fail (bonobo_widget != NULL, NULL);
442        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
443
444        return bonobo_widget->priv->uic;
445}
446
447
448
449/*
450 *
451 * Generic (non-control/subdoc specific) BonoboWidget stuff.
452 *
453 */
454
455/**
456 * bonobo_widget_get_server:
457 * @bonobo_widget: the #BonoboWidget to query.
458 *
459 * Returns: The BonoboObjectClient (a wrapper for the CORBA object
460 * reference) to the object that this BonoboWidget is wrapping.
461 */
462BonoboObjectClient *
463bonobo_widget_get_server (BonoboWidget *bonobo_widget)
464{
465        g_return_val_if_fail (bonobo_widget != NULL, NULL);
466        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
467
468        return bonobo_widget->priv->server;
469}
470
471Bonobo_Unknown
472bonobo_widget_get_objref (BonoboWidget *bonobo_widget)
473{
474        g_return_val_if_fail (bonobo_widget != NULL, NULL);
475        g_return_val_if_fail (BONOBO_IS_WIDGET (bonobo_widget), NULL);
476
477        return BONOBO_OBJREF (bonobo_widget->priv->server);
478}
479
480static void
481bonobo_widget_destroy (GtkObject *object)
482{
483        BonoboWidget *bw = BONOBO_WIDGET (object);
484        BonoboWidgetPrivate *priv = bw->priv;
485       
486        if (priv->control_frame)
487                bonobo_object_unref (BONOBO_OBJECT (priv->control_frame));
488        if (priv->container)
489                bonobo_object_unref (BONOBO_OBJECT (priv->container));
490        if (priv->client_site)
491                bonobo_object_unref (BONOBO_OBJECT (priv->client_site));
492        if (priv->view_frame)
493                bonobo_object_unref (BONOBO_OBJECT (priv->view_frame));
494        if (priv->uic != CORBA_OBJECT_NIL)
495                bonobo_object_release_unref (priv->uic, NULL);
496
497        g_free (priv);
498        GTK_OBJECT_CLASS (bonobo_widget_parent_class)->destroy (object);
499}
500
501static void
502bonobo_widget_size_request (GtkWidget *widget,
503                            GtkRequisition *requisition)
504{
505        GtkBin *bin;
506
507        g_return_if_fail (widget != NULL);
508        g_return_if_fail (BONOBO_IS_WIDGET (widget));
509        g_return_if_fail (requisition != NULL);
510
511        bin = GTK_BIN (widget);
512
513        if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) {
514                GtkRequisition child_requisition;
515     
516                gtk_widget_size_request (bin->child, &child_requisition);
517
518                requisition->width = child_requisition.width;
519                requisition->height = child_requisition.height;
520        }
521}
522
523static void
524bonobo_widget_size_allocate (GtkWidget *widget,
525                             GtkAllocation *allocation)
526{
527        GtkBin *bin;
528        GtkAllocation child_allocation;
529
530        g_return_if_fail (widget != NULL);
531        g_return_if_fail (BONOBO_IS_WIDGET (widget));
532        g_return_if_fail (allocation != NULL);
533
534        widget->allocation = *allocation;
535        bin = GTK_BIN (widget);
536
537        child_allocation.x = allocation->x;
538        child_allocation.y = allocation->y;
539        child_allocation.width = allocation->width;
540        child_allocation.height = allocation->height;
541
542        if (bin->child) {
543                gtk_widget_size_allocate (bin->child, &child_allocation);
544        }
545}
546
547static void
548bonobo_widget_class_init (BonoboWidgetClass *klass)
549{
550        GtkObjectClass *object_class = (GtkObjectClass *) klass;
551        GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
552
553        bonobo_widget_parent_class = gtk_type_class (GTK_TYPE_BIN);
554
555        widget_class->size_request = bonobo_widget_size_request;
556        widget_class->size_allocate = bonobo_widget_size_allocate;
557
558        object_class->destroy = bonobo_widget_destroy;
559}
560
561static void
562bonobo_widget_init (BonoboWidget *bw)
563{
564        bw->priv = g_new0 (BonoboWidgetPrivate, 1);
565}
566
567GtkType
568bonobo_widget_get_type (void)
569{
570        static GtkType type = 0;
571
572        if (! type) {
573                static const GtkTypeInfo info = {
574                        "BonoboWidget",
575                        sizeof (BonoboWidget),
576                        sizeof (BonoboWidgetClass),
577                        (GtkClassInitFunc) bonobo_widget_class_init,
578                        (GtkObjectInitFunc) bonobo_widget_init,
579                        NULL, /* reserved_1 */
580                        NULL, /* reserved_2 */
581                        (GtkClassInitFunc) NULL
582                };
583
584                type = gtk_type_unique (gtk_bin_get_type (), &info);
585        }
586
587        return type;
588}
589
590/**
591 * bonobo_widget_set_property:
592 * @control: A #BonoboWidget that represents an IDL:Bonobo/Control:1.0
593 * @first_prop: first property name to set.
594 *
595 * This is a utility function used to set a number of properties
596 * in the Bonobo Control in @control.
597 *
598 * This function takes a variable list of arguments that must be NULL
599 * terminated.  Arguments come in tuples: a string (for the argument
600 * name) and the data type that is to be transfered.  The
601 * implementation of the actual setting of the PropertyBag values is
602 * done by the bonobo_property_bag_client_setv() function).
603 *
604 * FIXME: This function is error prone because it depends on the
605 * client and the server to agree on the data types to be sent.  If
606 * the server arguments change the data type, this routine will not
607 * be able to cope gracefully with this condition.
608 *
609 * This only works for BonoboWidgets that represent controls (ie,
610 * that were returned by bonobo_widget_new_control_from_objref() or
611 * bonobo_widget_new_control().
612 */
613void
614bonobo_widget_set_property (BonoboWidget      *control,
615                            const char        *first_prop, ...)
616{
617        Bonobo_PropertyBag pb;
618        CORBA_Environment  ev;
619
620        va_list args;
621        va_start (args, first_prop);
622
623        g_return_if_fail (control != NULL);
624        g_return_if_fail (first_prop != NULL);
625        g_return_if_fail (control->priv != NULL);
626        g_return_if_fail (BONOBO_IS_WIDGET (control));
627
628        CORBA_exception_init (&ev);
629       
630        pb = bonobo_control_frame_get_control_property_bag (
631                control->priv->control_frame, &ev);
632
633        if (BONOBO_EX (&ev))
634                g_warning ("Error getting property bag from control");
635        else {
636                /* FIXME: this should use ev */
637                char *err = bonobo_property_bag_client_setv (pb, &ev, first_prop, args);
638
639                if (err)
640                        g_warning ("Error '%s'", err);
641        }
642
643        bonobo_object_release_unref (pb, &ev);
644
645        CORBA_exception_free (&ev);
646
647        va_end (args);
648}
649
650
651/**
652 * bonobo_widget_get_property:
653 * @control: A #BonoboWidget that represents an IDL:Bonobo/Control:1.0
654 * @first_prop: first property name to set.
655 *
656 * This is a utility function used to get a number of properties
657 * in the Bonobo Control in @control.
658 *
659 * This function takes a variable list of arguments that must be NULL
660 * terminated.  Arguments come in tuples: a string (for the argument
661 * name) and a pointer where the data will be stored.  The
662 * implementation of the actual setting of the PropertyBag values is
663 * done by the bonobo_property_bag_client_setv() function).
664 *
665 * FIXME: This function is error prone because it depends on the
666 * client and the server to agree on the data types to be sent.  If
667 * the server arguments change the data type, this routine will not
668 * be able to cope gracefully with this condition.
669 *
670 * This only works for BonoboWidgets that represent controls (ie,
671 * that were returned by bonobo_widget_new_control_from_objref() or
672 * bonobo_widget_new_control().
673 */
674void
675bonobo_widget_get_property (BonoboWidget      *control,
676                            const char        *first_prop, ...)
677{
678        Bonobo_PropertyBag pb;
679        CORBA_Environment  ev;
680
681        va_list args;
682        va_start (args, first_prop);
683
684        g_return_if_fail (control != NULL);
685        g_return_if_fail (first_prop != NULL);
686        g_return_if_fail (control->priv != NULL);
687        g_return_if_fail (BONOBO_IS_WIDGET (control));
688
689        CORBA_exception_init (&ev);
690       
691        pb = bonobo_control_frame_get_control_property_bag (
692                control->priv->control_frame, &ev);
693
694        if (BONOBO_EX (&ev))
695                g_warning ("Error getting property bag from control");
696        else {
697                /* FIXME: this should use ev */
698                char *err = bonobo_property_bag_client_getv (pb, &ev, first_prop, args);
699
700                if (err)
701                        g_warning ("Error '%s'", err);
702        }
703
704        bonobo_object_release_unref (pb, &ev);
705
706        CORBA_exception_free (&ev);
707
708        va_end (args);
709}
Note: See TracBrowser for help on using the repository browser.