source: trunk/third/evolution/shell/e-component-registry.c @ 18142

Revision 18142, 12.9 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18141, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* e-component-registry.c
3 *
4 * Copyright (C) 2000  Ximian, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Ettore Perazzoli
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include "e-component-registry.h"
28
29#include <glib.h>
30#include <gtk/gtktypeutils.h>
31
32#include <gal/util/e-util.h>
33
34#include "Evolution.h"
35
36#include "e-shell-utils.h"
37#include "evolution-shell-component-client.h"
38
39
40#define PARENT_TYPE GTK_TYPE_OBJECT
41static GtkObjectClass *parent_class = NULL;
42
43typedef struct _Component Component;
44
45struct _Component {
46        char *id;
47       
48        EvolutionShellComponentClient *client;
49
50        /* Names of the folder types we support (normal ASCII strings).  */
51        GList *folder_type_names;
52};
53
54struct _EComponentRegistryPrivate {
55        EShell *shell;
56
57        GHashTable *component_id_to_component;
58};
59
60
61/* Utility functions.  */
62
63static int
64sleep_with_g_main_loop_timeout_callback (void *data)
65{
66        GMainLoop *loop;
67
68        loop = (GMainLoop *) data;
69        g_main_quit (loop);
70
71        return FALSE;
72}
73
74/* This function is like `sleep()', but it uses the GMainLoop so CORBA
75   invocations can get through.  */
76static void
77sleep_with_g_main_loop (int num_seconds)
78{
79        GMainLoop *loop;
80
81        loop = g_main_new (TRUE);
82        g_timeout_add (1000 * num_seconds, sleep_with_g_main_loop_timeout_callback, loop);
83        g_main_run (loop);
84        g_main_destroy (loop);
85}
86
87static void
88wait_for_corba_object_to_die (Bonobo_Unknown corba_objref,
89                              const char *id)
90{
91        gboolean alive;
92        int count;
93
94        count = 1;
95        while (1) {
96                alive = bonobo_unknown_ping (corba_objref);
97                if (! alive)
98                        break;
99
100                g_print ("Waiting for component to die -- %s (%d)\n", id, count);
101                sleep_with_g_main_loop (1);
102                count ++;
103        }
104}
105
106
107/* Component information handling.  */
108
109static Component *
110component_new (const char *id,
111               EvolutionShellComponentClient *client)
112{
113        Component *new;
114
115        bonobo_object_ref (BONOBO_OBJECT (client));
116
117        new = g_new (Component, 1);
118        new->id                = g_strdup (id);
119        new->folder_type_names = NULL;
120        new->client            = client;
121
122        return new;
123}
124
125static gboolean
126component_free (Component *component)
127{
128        GNOME_Evolution_ShellComponent corba_shell_component;
129        CORBA_Environment ev;
130        gboolean retval;
131
132        CORBA_exception_init (&ev);
133
134        corba_shell_component = bonobo_object_corba_objref (BONOBO_OBJECT (component->client));
135        corba_shell_component = CORBA_Object_duplicate (corba_shell_component, &ev);
136
137        GNOME_Evolution_ShellComponent_unsetOwner (corba_shell_component, &ev);
138        if (ev._major == CORBA_NO_EXCEPTION)
139                retval = TRUE;
140        else
141                retval = FALSE;
142        CORBA_exception_free (&ev);
143
144        bonobo_object_unref (BONOBO_OBJECT (component->client));
145
146        wait_for_corba_object_to_die ((Bonobo_Unknown) corba_shell_component, component->id);
147        CORBA_Object_release (corba_shell_component, &ev);
148
149        e_free_string_list (component->folder_type_names);
150        g_free (component->id);
151
152        g_free (component);
153
154        return retval;
155}
156
157static gboolean
158register_type (EComponentRegistry *component_registry,
159               const char *name,
160               const char *icon_name,
161               const char *display_name,
162               const char *description,
163               gboolean user_creatable,
164               int num_exported_dnd_types,
165               const char **exported_dnd_types,
166               int num_accepted_dnd_types,
167               const char **accepted_dnd_types,
168               Component *handler,
169               gboolean override_duplicate)
170{
171        EComponentRegistryPrivate *priv;
172        EFolderTypeRegistry *folder_type_registry;
173
174        priv = component_registry->priv;
175
176        folder_type_registry = e_shell_get_folder_type_registry (priv->shell);
177        g_assert (folder_type_registry != NULL);
178
179        if (override_duplicate
180            && e_folder_type_registry_type_registered (folder_type_registry, name))
181                e_folder_type_registry_unregister_type (folder_type_registry, name);
182
183        if (! e_folder_type_registry_register_type (folder_type_registry,
184                                                    name, icon_name,
185                                                    display_name, description,
186                                                    user_creatable,
187                                                    num_exported_dnd_types,
188                                                    exported_dnd_types,
189                                                    num_accepted_dnd_types,
190                                                    accepted_dnd_types)) {
191                g_warning ("Trying to register duplicate folder type -- %s", name);
192                return FALSE;
193        }
194
195        e_folder_type_registry_set_handler_for_type (folder_type_registry, name, handler->client);
196
197        return TRUE;
198}
199
200static gboolean
201register_component (EComponentRegistry *component_registry,
202                    const char *id,
203                    gboolean override_duplicate,
204                    CORBA_Environment *ev)
205{
206        EComponentRegistryPrivate *priv;
207        GNOME_Evolution_ShellComponent component_corba_interface;
208        GNOME_Evolution_Shell shell_corba_interface;
209        GNOME_Evolution_FolderTypeList *supported_types;
210        GNOME_Evolution_URISchemaList *supported_schemas;
211        Component *component;
212        EvolutionShellComponentClient *client;
213        CORBA_Environment my_ev;
214        CORBA_unsigned_long i;
215
216        priv = component_registry->priv;
217
218        if (! override_duplicate && g_hash_table_lookup (priv->component_id_to_component, id) != NULL) {
219                g_warning ("Trying to register component twice -- %s", id);
220                return FALSE;
221        }
222
223        client = evolution_shell_component_client_new (id, ev);
224        if (client == NULL)
225                return FALSE;
226
227        /* FIXME we could use the EvolutionShellComponentClient API here instead, but for
228           now we don't care.  */
229
230        component_corba_interface = bonobo_object_corba_objref (BONOBO_OBJECT (client));
231        shell_corba_interface = bonobo_object_corba_objref (BONOBO_OBJECT (priv->shell));
232
233        CORBA_exception_init (&my_ev);
234
235        /* Register the supported folder types.  */
236
237        supported_types = GNOME_Evolution_ShellComponent__get_supportedTypes (component_corba_interface, &my_ev);
238        if (my_ev._major != CORBA_NO_EXCEPTION || supported_types->_length == 0) {
239                bonobo_object_unref (BONOBO_OBJECT (client));
240                CORBA_exception_free (&my_ev);
241                return FALSE;
242        }
243
244        CORBA_exception_free (&my_ev);
245
246        component = component_new (id, client);
247        g_hash_table_insert (priv->component_id_to_component, component->id, component);
248        bonobo_object_unref (BONOBO_OBJECT (client));
249
250        for (i = 0; i < supported_types->_length; i++) {
251                const GNOME_Evolution_FolderType *type;
252
253                type = supported_types->_buffer + i;
254
255                if (! register_type (component_registry,
256                                     type->name, type->iconName,
257                                     type->displayName, type->description,
258                                     type->userCreatable,
259                                     type->exportedDndTypes._length,
260                                     (const char **) type->exportedDndTypes._buffer,
261                                     type->acceptedDndTypes._length,
262                                     (const char **) type->acceptedDndTypes._buffer,
263                                     component,
264                                     override_duplicate)) {
265                        g_warning ("Cannot register type `%s' for component %s",
266                                   type->name, component->id);
267                }
268        }
269
270        CORBA_free (supported_types);
271
272        /* Register the supported external URI schemas.  */
273
274        supported_schemas = GNOME_Evolution_ShellComponent__get_externalUriSchemas (component_corba_interface, &my_ev);
275        if (my_ev._major == CORBA_NO_EXCEPTION) {
276                EUriSchemaRegistry *uri_schema_registry;
277
278                uri_schema_registry = e_shell_get_uri_schema_registry (priv->shell);
279
280                for (i = 0; i < supported_schemas->_length; i++) {
281                        const CORBA_char *schema;
282
283                        schema = supported_schemas->_buffer[i];
284                        e_uri_schema_registry_set_handler_for_schema (uri_schema_registry, schema, component->client);
285                }
286
287                CORBA_free (supported_schemas);
288        }
289
290        return TRUE;
291}
292
293
294/* GtkObject methods.  */
295
296static void
297component_id_foreach_free (void *key,
298                           void *value,
299                           void *user_data)
300{
301        Component *component;
302
303        component = (Component *) value;
304        component_free (component);
305}
306
307static void
308destroy (GtkObject *object)
309{
310        EComponentRegistry *component_registry;
311        EComponentRegistryPrivate *priv;
312
313        component_registry = E_COMPONENT_REGISTRY (object);
314        priv = component_registry->priv;
315
316        g_hash_table_foreach (priv->component_id_to_component, component_id_foreach_free, NULL);
317        g_hash_table_destroy (priv->component_id_to_component);
318
319        g_free (priv);
320
321        if (GTK_OBJECT_CLASS (parent_class)->destroy)
322                (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
323}
324
325
326static void
327class_init (EComponentRegistryClass *klass)
328{
329        GtkObjectClass *object_class;
330
331        object_class = GTK_OBJECT_CLASS (klass);
332        object_class->destroy = destroy;
333
334        parent_class = gtk_type_class (gtk_object_get_type ());
335}
336
337
338static void
339init (EComponentRegistry *component_registry)
340{
341        EComponentRegistryPrivate *priv;
342
343        priv = g_new (EComponentRegistryPrivate, 1);
344        priv->shell                     = NULL;
345        priv->component_id_to_component = g_hash_table_new (g_str_hash, g_str_equal);
346
347        component_registry->priv = priv;
348}
349
350
351void
352e_component_registry_construct (EComponentRegistry *component_registry,
353                                EShell *shell)
354{
355        EComponentRegistryPrivate *priv;
356
357        g_return_if_fail (component_registry != NULL);
358        g_return_if_fail (E_IS_COMPONENT_REGISTRY (component_registry));
359        g_return_if_fail (shell != NULL);
360        g_return_if_fail (E_IS_SHELL (shell));
361
362        priv = component_registry->priv;
363        priv->shell = shell;
364}
365
366EComponentRegistry *
367e_component_registry_new (EShell *shell)
368{
369        EComponentRegistry *component_registry;
370
371        g_return_val_if_fail (shell != NULL, NULL);
372        g_return_val_if_fail (E_IS_SHELL (shell), NULL);
373
374        component_registry = gtk_type_new (e_component_registry_get_type ());
375        e_component_registry_construct (component_registry, shell);
376
377        return component_registry;
378}
379
380
381gboolean
382e_component_registry_register_component (EComponentRegistry *component_registry,
383                                         const char *id,
384                                         CORBA_Environment *ev)
385{
386        g_return_val_if_fail (component_registry != NULL, FALSE);
387        g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), FALSE);
388        g_return_val_if_fail (id != NULL, FALSE);
389
390        return register_component (component_registry, id, FALSE, ev);
391}
392
393
394static void
395compose_id_list_foreach (void *key,
396                         void *value,
397                         void *data)
398{
399        GList **listp;
400        const char *id;
401
402        listp = (GList **) data;
403        id = (const char *) key;
404
405        *listp = g_list_prepend (*listp, g_strdup (id));
406}
407
408/**
409 * e_component_registry_get_id_list:
410 * @component_registry:
411 *
412 * Get the list of components registered.
413 *
414 * Return value: A GList of strings containining the IDs for all the registered
415 * components.  The list must be freed by the caller when not used anymore.
416 **/
417GList *
418e_component_registry_get_id_list (EComponentRegistry *component_registry)
419{
420        EComponentRegistryPrivate *priv;
421        GList *list;
422
423        g_return_val_if_fail (component_registry != NULL, NULL);
424        g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), NULL);
425
426        priv = component_registry->priv;
427        list = NULL;
428
429        g_hash_table_foreach (priv->component_id_to_component, compose_id_list_foreach, &list);
430
431        return list;
432}
433
434/**
435 * e_component_registry_get_component_by_id:
436 * @component_registry:
437 * @id: The component's OAF ID
438 *
439 * Get the registered component client for the specified ID.  If that component
440 * is not registered, return NULL.
441 *
442 * Return value: A pointer to the ShellComponentClient for that component.
443 **/
444EvolutionShellComponentClient *
445e_component_registry_get_component_by_id  (EComponentRegistry *component_registry,
446                                           const char *id)
447{
448        EComponentRegistryPrivate *priv;
449        const Component *component;
450
451        g_return_val_if_fail (component_registry != NULL, NULL);
452        g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), NULL);
453        g_return_val_if_fail (id != NULL, NULL);
454
455        priv = component_registry->priv;
456
457        component = g_hash_table_lookup (priv->component_id_to_component, id);
458        if (component == NULL)
459                return NULL;
460
461        return component->client;
462}
463
464
465EvolutionShellComponentClient *
466e_component_registry_restart_component  (EComponentRegistry *component_registry,
467                                         const char *id,
468                                         CORBA_Environment *ev)
469{
470        EComponentRegistryPrivate *priv;
471        Component *component;
472        CORBA_Environment my_ev;
473        CORBA_Object corba_objref;
474
475        g_return_val_if_fail (component_registry != NULL, NULL);
476        g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), NULL);
477        g_return_val_if_fail (id != NULL, NULL);
478
479        priv = component_registry->priv;
480
481        component = g_hash_table_lookup (priv->component_id_to_component, id);
482        if (component == NULL)
483                return NULL;
484
485        CORBA_exception_init (&my_ev);
486
487        g_hash_table_remove (priv->component_id_to_component, id);
488
489        corba_objref = CORBA_Object_duplicate (bonobo_object_corba_objref (BONOBO_OBJECT (component->client)), &my_ev);
490
491        component_free (component);
492
493        wait_for_corba_object_to_die (corba_objref, id);
494
495        CORBA_exception_free (&my_ev);
496
497        if (! register_component (component_registry, id, TRUE, ev))
498                return NULL;
499
500        return e_component_registry_get_component_by_id (component_registry, id);
501}
502
503
504E_MAKE_TYPE (e_component_registry, "EComponentRegistry", EComponentRegistry,
505             class_init, init, PARENT_TYPE)
Note: See TracBrowser for help on using the repository browser.