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

Revision 18142, 35.5 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/* evolution-shell-component.c
3 *
4 * Copyright (C) 2000, 2001 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 "evolution-shell-component.h"
28
29#include "e-shell-corba-icon-utils.h"
30
31#include <fcntl.h>
32
33#include <glib.h>
34#include <gtk/gtksignal.h>
35#include <bonobo/bonobo-object.h>
36#include <libgnome/gnome-i18n.h>
37
38#include <gal/util/e-util.h>
39
40
41#define PING_DELAY 10000
42
43
44#define PARENT_TYPE BONOBO_X_OBJECT_TYPE
45
46static BonoboXObjectClass *parent_class = NULL;
47
48struct _UserCreatableItemType {
49        char *id;
50        char *description;
51        char *menu_description;
52        char *tooltip;
53        char menu_shortcut;
54        GdkPixbuf *icon;
55        char *folder_type;
56};
57typedef struct _UserCreatableItemType UserCreatableItemType;
58
59struct _EvolutionShellComponentPrivate {
60        GList *folder_types;    /* EvolutionShellComponentFolderType */
61        GList *external_uri_schemas; /* char * */
62
63        EvolutionShellComponentCreateViewFn create_view_fn;
64        EvolutionShellComponentCreateFolderFn create_folder_fn;
65        EvolutionShellComponentRemoveFolderFn remove_folder_fn;
66        EvolutionShellComponentXferFolderFn xfer_folder_fn;
67        EvolutionShellComponentPopulateFolderContextMenuFn populate_folder_context_menu_fn;
68        EvolutionShellComponentUnpopulateFolderContextMenuFn unpopulate_folder_context_menu_fn;
69        EvolutionShellComponentGetDndSelectionFn get_dnd_selection_fn;
70        EvolutionShellComponentRequestQuitFn request_quit_fn;
71
72        EvolutionShellClient *owner_client;
73
74        GSList *user_creatable_item_types; /* UserCreatableItemType */
75
76        /* This is used for
77           populateFolderContextMenu/unpopulateFolderContextMenu.  */
78        BonoboUIComponent *uic;
79
80        int ping_timeout_id;
81
82        void *closure;
83};
84
85enum {
86        OWNER_SET,
87        OWNER_UNSET,
88        OWNER_DIED,
89        DEBUG,
90        INTERACTIVE,
91        HANDLE_EXTERNAL_URI,
92        USER_CREATE_NEW_ITEM,
93        SEND_RECEIVE,
94        LAST_SIGNAL
95};
96
97static guint signals[LAST_SIGNAL] = { 0 };
98
99
100/* UserCreatableItemType handling.  */
101
102static UserCreatableItemType *
103user_creatable_item_type_new (const char *id,
104                              const char *description,
105                              const char *menu_description,
106                              const char *tooltip,
107                              const char *folder_type,
108                              char menu_shortcut,
109                              GdkPixbuf *icon)
110{
111        UserCreatableItemType *type;
112
113        type = g_new (UserCreatableItemType, 1);
114        type->id               = g_strdup (id);
115        type->description      = g_strdup (description);
116        type->menu_description = g_strdup (menu_description);
117        type->tooltip          = g_strdup (tooltip);
118        type->menu_shortcut    = menu_shortcut;
119        type->folder_type      = g_strdup (folder_type);
120
121        if (icon == NULL)
122                type->icon = NULL;
123        else
124                type->icon = gdk_pixbuf_ref (icon);
125
126        return type;
127}
128
129static void
130user_creatable_item_type_free (UserCreatableItemType *type)
131{
132        g_free (type->id);
133        g_free (type->description);
134        g_free (type->menu_description);
135        g_free (type->folder_type);
136
137        if (type->icon != NULL)
138                gdk_pixbuf_unref (type->icon);
139
140        g_free (type);
141}
142
143
144/* Helper functions.  */
145
146/* Notice that, if passed a NULL pointer, this string will construct a
147   zero-element NULL-terminated string array instead of returning NULL itself
148   (i.e. it will return a pointer to a single g_malloc()ed NULL pointer).  */
149static char **
150duplicate_null_terminated_string_array (char *array[])
151{
152        char **new;
153        int count;
154        int i;
155
156        if (array == NULL) {
157                count = 0;
158        } else {
159                for (count = 0; array[count] != NULL; count++)
160                        ;
161        }
162
163        new = g_new (char *, count + 1);
164
165        for (i = 0; i < count; i++)
166                new[i] = g_strdup (array[i]);
167        new[count] = NULL;
168
169        return new;
170}
171
172/* The following will create a CORBA sequence of strings from the specified
173 * NULL-terminated array, without duplicating the strings.  */
174static void
175fill_corba_sequence_from_null_terminated_string_array (CORBA_sequence_CORBA_string *corba_sequence,
176                                                       char **array)
177{
178        int count;
179        int i;
180
181        g_assert (corba_sequence != NULL);
182        g_assert (array != NULL);
183
184        CORBA_sequence_set_release (corba_sequence, TRUE);
185
186        count = 0;
187        while (array[count] != NULL)
188                count++;
189
190        corba_sequence->_maximum = count;
191        corba_sequence->_length = count;
192        corba_sequence->_buffer = CORBA_sequence_CORBA_string_allocbuf (count);
193
194        for (i = 0; i < count; i++)
195                corba_sequence->_buffer[i] = CORBA_string_dup (array[i]);
196
197        CORBA_sequence_set_release (corba_sequence, TRUE);
198}
199
200
201/* Owner pinging.  */
202
203static gboolean
204owner_ping_callback (void *data)
205{
206        EvolutionShellComponent *shell_component;
207        EvolutionShellComponentPrivate *priv;
208        Bonobo_Unknown owner_objref;
209        CORBA_Environment ev;
210        gboolean alive;
211
212        shell_component = EVOLUTION_SHELL_COMPONENT (data);
213        priv = shell_component->priv;
214
215        owner_objref = bonobo_object_corba_objref (BONOBO_OBJECT (priv->owner_client));
216
217        if (owner_objref == CORBA_OBJECT_NIL)
218                return FALSE;
219
220        /* We are duplicating the object here, as we might get an ::unsetOwner
221           while we invoke the pinging, and this would make the objref invalid
222           and thus crash the stubs (cfr. #13802).  */
223
224        CORBA_exception_init (&ev);
225        owner_objref = CORBA_Object_duplicate (owner_objref, &ev);
226
227        alive = bonobo_unknown_ping (owner_objref);
228
229        CORBA_Object_release (owner_objref, &ev);
230        CORBA_exception_free (&ev);
231
232        if (alive)
233                return TRUE;
234
235        /* This is tricky.  During the pinging, we might have gotten an
236           ::unsetOwner invocation which has invalidated our owner_client.  In
237           this case, no "owner_died" should be emitted.  */
238       
239        if (priv->owner_client != NULL) {
240                g_print ("\t*** The shell has disappeared\n");
241                gtk_signal_emit (GTK_OBJECT (shell_component), signals[OWNER_DIED]);
242        }
243
244        priv->ping_timeout_id = -1;
245
246        return FALSE;
247}
248
249static void
250setup_owner_pinging (EvolutionShellComponent *shell_component)
251{
252        EvolutionShellComponentPrivate *priv;
253
254        priv = shell_component->priv;
255
256        if (priv->ping_timeout_id != -1)
257                g_source_remove (priv->ping_timeout_id);
258
259        priv->ping_timeout_id = g_timeout_add (PING_DELAY, owner_ping_callback, shell_component);
260}
261
262
263/* CORBA interface implementation.  */
264
265static GNOME_Evolution_FolderTypeList *
266impl__get_supportedTypes (PortableServer_Servant servant,
267                          CORBA_Environment *ev)
268{
269        BonoboObject *bonobo_object;
270        EvolutionShellComponent *shell_component;
271        EvolutionShellComponentPrivate *priv;
272        GNOME_Evolution_FolderTypeList *folder_type_list;
273        unsigned int i;
274        GList *p;
275
276        bonobo_object = bonobo_object_from_servant (servant);
277        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
278        priv = shell_component->priv;
279
280        folder_type_list = GNOME_Evolution_FolderTypeList__alloc ();
281        CORBA_sequence_set_release (folder_type_list, TRUE);
282        folder_type_list->_length = g_list_length (priv->folder_types);
283        folder_type_list->_maximum = folder_type_list->_length;
284        folder_type_list->_buffer = CORBA_sequence_GNOME_Evolution_FolderType_allocbuf (folder_type_list->_maximum);
285
286        for (p = priv->folder_types, i = 0; p != NULL; p = p->next, i++) {
287                GNOME_Evolution_FolderType *corba_folder_type;
288                EvolutionShellComponentFolderType *folder_type;
289
290                folder_type = (EvolutionShellComponentFolderType *) p->data;
291
292                corba_folder_type = folder_type_list->_buffer + i;
293                corba_folder_type->name          = CORBA_string_dup (folder_type->name);
294                corba_folder_type->iconName      = CORBA_string_dup (folder_type->icon_name);
295                corba_folder_type->displayName   = CORBA_string_dup (folder_type->display_name);
296                corba_folder_type->description   = CORBA_string_dup (folder_type->description);
297                corba_folder_type->userCreatable = folder_type->user_creatable;
298
299                fill_corba_sequence_from_null_terminated_string_array (& corba_folder_type->acceptedDndTypes,
300                                                                       folder_type->accepted_dnd_types);
301                fill_corba_sequence_from_null_terminated_string_array (& corba_folder_type->exportedDndTypes,
302                                                                       folder_type->exported_dnd_types);
303        }
304
305        CORBA_sequence_set_release (folder_type_list, TRUE);
306
307        return folder_type_list;
308}
309
310static GNOME_Evolution_URISchemaList *
311impl__get_externalUriSchemas (PortableServer_Servant servant,
312                              CORBA_Environment *ev)
313{
314        EvolutionShellComponent *shell_component;
315        EvolutionShellComponentPrivate *priv;
316        GNOME_Evolution_URISchemaList *uri_schema_list;
317        GList *p;
318        int i;
319
320        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object_from_servant (servant));
321        priv = shell_component->priv;
322
323        uri_schema_list = GNOME_Evolution_URISchemaList__alloc ();
324
325        /* FIXME: We could probably keep this to FALSE and avoid
326           CORBA_string_duplicating.  */
327        CORBA_sequence_set_release (uri_schema_list, TRUE);
328
329        if (priv->external_uri_schemas == NULL) {
330                uri_schema_list->_length = 0;
331                uri_schema_list->_maximum = 0;
332                uri_schema_list->_buffer = NULL;
333                return uri_schema_list;
334        }
335
336        uri_schema_list->_length = g_list_length (priv->external_uri_schemas);
337        uri_schema_list->_maximum = uri_schema_list->_length;
338        uri_schema_list->_buffer = CORBA_sequence_GNOME_Evolution_URISchema_allocbuf (uri_schema_list->_maximum);
339
340        for (p = priv->external_uri_schemas, i = 0; p != NULL; p = p->next, i++) {
341                const char *schema;
342
343                schema = (const char *) p->data;
344                uri_schema_list->_buffer[i] = CORBA_string_dup (schema);
345        }
346
347        CORBA_sequence_set_release (uri_schema_list, TRUE);
348
349        return uri_schema_list;
350}
351
352static GNOME_Evolution_UserCreatableItemTypeList *
353impl__get_userCreatableItemTypes (PortableServer_Servant servant,
354                                  CORBA_Environment *ev)
355{
356        EvolutionShellComponent *shell_component;
357        EvolutionShellComponentPrivate *priv;
358        GNOME_Evolution_UserCreatableItemTypeList *list;
359        GSList *p;
360        int i;
361
362        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object_from_servant (servant));
363        priv = shell_component->priv;
364
365        list = GNOME_Evolution_UserCreatableItemTypeList__alloc ();
366        list->_maximum = g_slist_length (priv->user_creatable_item_types);
367        list->_length  = list->_maximum;
368        list->_buffer  = CORBA_sequence_GNOME_Evolution_UserCreatableItemType_allocbuf (list->_maximum);
369
370        for (p = priv->user_creatable_item_types, i = 0; p != NULL; p = p->next, i ++) {
371                GNOME_Evolution_UserCreatableItemType *corba_type;
372                const UserCreatableItemType *type;
373
374                corba_type = list->_buffer + i;
375                type = (const UserCreatableItemType *) p->data;
376
377                corba_type->id              = CORBA_string_dup (type->id);
378                corba_type->description     = CORBA_string_dup (type->description);
379                corba_type->menuDescription = CORBA_string_dup (type->menu_description);
380                corba_type->tooltip         = CORBA_string_dup (type->tooltip != NULL ? type->tooltip : "");
381                corba_type->folderType      = CORBA_string_dup (type->folder_type != NULL ? type->folder_type : "");
382                corba_type->menuShortcut    = type->menu_shortcut;
383
384                e_store_corba_icon_from_pixbuf (type->icon, & corba_type->icon);
385        }
386
387        CORBA_sequence_set_release (list, TRUE);
388
389        return list;
390}
391
392static void
393impl_setOwner (PortableServer_Servant servant,
394               const GNOME_Evolution_Shell shell,
395               const CORBA_char *evolution_homedir,
396               CORBA_Environment *ev)
397{
398        BonoboObject *bonobo_object;
399        EvolutionShellComponent *shell_component;
400        EvolutionShellComponentPrivate *priv;
401        GNOME_Evolution_Shell shell_duplicate;
402
403        bonobo_object = bonobo_object_from_servant (servant);
404        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
405        priv = shell_component->priv;
406
407        if (priv->owner_client != NULL) {
408                int owner_is_dead;
409
410                owner_is_dead = CORBA_Object_non_existent
411                        (bonobo_object_corba_objref (BONOBO_OBJECT (priv->owner_client)), ev);
412                if (ev->_major != CORBA_NO_EXCEPTION)
413                        owner_is_dead = TRUE;
414
415                if (! owner_is_dead) {
416                        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
417                                             ex_GNOME_Evolution_ShellComponent_AlreadyOwned, NULL);
418                } else {
419                        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
420                                             ex_GNOME_Evolution_ShellComponent_OldOwnerHasDied, NULL);
421
422                        gtk_signal_emit (GTK_OBJECT (shell_component), signals[OWNER_DIED]);
423                }
424
425                return;
426        }
427
428        shell_duplicate = CORBA_Object_duplicate (shell, ev);
429
430        if (ev->_major == CORBA_NO_EXCEPTION) {
431                priv->owner_client = evolution_shell_client_new (shell_duplicate);
432                gtk_signal_emit (GTK_OBJECT (shell_component), signals[OWNER_SET], priv->owner_client, evolution_homedir);
433
434                setup_owner_pinging (shell_component);
435        }
436}
437
438static void
439impl_unsetOwner (PortableServer_Servant servant,
440                 CORBA_Environment *ev)
441{
442        BonoboObject *bonobo_object;
443        EvolutionShellComponent *shell_component;
444        EvolutionShellComponentPrivate *priv;
445
446        bonobo_object = bonobo_object_from_servant (servant);
447        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
448        priv = shell_component->priv;
449
450        if (priv->owner_client == NULL) {
451                CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
452                                     ex_GNOME_Evolution_ShellComponent_NotOwned, NULL);
453                return;
454        }
455
456        gtk_signal_emit (GTK_OBJECT (shell_component), signals[OWNER_UNSET]);
457}
458
459static void
460impl_debug (PortableServer_Servant servant,
461            const CORBA_char *log_path,
462            CORBA_Environment *ev)
463{
464        BonoboObject *bonobo_object;
465        EvolutionShellComponent *shell_component;
466        int fd;
467
468        bonobo_object = bonobo_object_from_servant (servant);
469        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
470
471        fd = open (log_path, O_WRONLY | O_APPEND);
472        if (!fd)
473                return;
474
475        dup2 (fd, STDOUT_FILENO);
476        dup2 (fd, STDERR_FILENO);
477        close (fd);
478
479        gtk_signal_emit (GTK_OBJECT (shell_component), signals[DEBUG]);
480}
481
482static void
483impl_interactive (PortableServer_Servant servant,
484                  CORBA_boolean interactive,
485                  CORBA_Environment *ev)
486{
487        BonoboObject *bonobo_object;
488        EvolutionShellComponent *shell_component;
489
490        bonobo_object = bonobo_object_from_servant (servant);
491        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
492
493        gtk_signal_emit (GTK_OBJECT (shell_component), signals[INTERACTIVE], interactive);
494}
495
496static Bonobo_Control
497impl_createView (PortableServer_Servant servant,
498                 const CORBA_char *physical_uri,
499                 const CORBA_char *type,
500                 const CORBA_char *view_info,
501                 CORBA_Environment *ev)
502{
503        BonoboObject *bonobo_object;
504        EvolutionShellComponent *shell_component;
505        EvolutionShellComponentPrivate *priv;
506        EvolutionShellComponentResult result;
507        BonoboControl *control;
508
509        bonobo_object = bonobo_object_from_servant (servant);
510        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
511        priv = shell_component->priv;
512
513        result = (* priv->create_view_fn) (shell_component, physical_uri, type,
514                                           view_info, &control, priv->closure);
515
516        if (result != EVOLUTION_SHELL_COMPONENT_OK) {
517                switch (result) {
518                case EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE:
519                        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
520                                             ex_GNOME_Evolution_ShellComponent_UnsupportedType,
521                                             NULL);
522                        break;
523                case EVOLUTION_SHELL_COMPONENT_INTERNALERROR:
524                        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
525                                             ex_GNOME_Evolution_ShellComponent_InternalError,
526                                             NULL);
527                        break;
528                default:
529                        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
530                                             ex_GNOME_Evolution_ShellComponent_NotFound,
531                                             NULL);
532                }
533
534                return CORBA_OBJECT_NIL;
535        }
536
537        return CORBA_Object_duplicate (bonobo_object_corba_objref (BONOBO_OBJECT (control)), ev);
538}
539
540static void
541impl_handleExternalURI (PortableServer_Servant servant,
542                        const CORBA_char *uri,
543                        CORBA_Environment *ev)
544{
545        EvolutionShellComponent *shell_component;
546
547        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object_from_servant (servant));
548
549        gtk_signal_emit (GTK_OBJECT (shell_component), signals[HANDLE_EXTERNAL_URI], uri);
550}
551
552static void
553impl_createFolderAsync (PortableServer_Servant servant,
554                        const GNOME_Evolution_ShellComponentListener listener,
555                        const CORBA_char *physical_uri,
556                        const CORBA_char *type,
557                        CORBA_Environment *ev)
558{
559        BonoboObject *bonobo_object;
560        EvolutionShellComponent *shell_component;
561        EvolutionShellComponentPrivate *priv;
562
563        bonobo_object = bonobo_object_from_servant (servant);
564        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
565        priv = shell_component->priv;
566
567        if (priv->create_folder_fn == NULL) {
568                GNOME_Evolution_ShellComponentListener_notifyResult (listener,
569                                                                     GNOME_Evolution_ShellComponentListener_UNSUPPORTED_OPERATION,
570                                                                     ev);
571                return;
572        }
573
574        (* priv->create_folder_fn) (shell_component, physical_uri, type, listener, priv->closure);
575}
576
577static void
578impl_removeFolderAsync (PortableServer_Servant servant,
579                        const GNOME_Evolution_ShellComponentListener listener,
580                        const CORBA_char *physical_uri,
581                        const CORBA_char *type,
582                        CORBA_Environment *ev)
583{
584        BonoboObject *bonobo_object;
585        EvolutionShellComponent *shell_component;
586        EvolutionShellComponentPrivate *priv;
587
588        bonobo_object = bonobo_object_from_servant (servant);
589        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
590        priv = shell_component->priv;
591
592        if (priv->remove_folder_fn == NULL) {
593                GNOME_Evolution_ShellComponentListener_notifyResult (listener,
594                                                                     GNOME_Evolution_ShellComponentListener_UNSUPPORTED_OPERATION,
595                                                                     ev);
596                return;
597        }
598
599        (* priv->remove_folder_fn) (shell_component, physical_uri, type, listener, priv->closure);
600}
601
602static void
603impl_xferFolderAsync (PortableServer_Servant servant,
604                      const GNOME_Evolution_ShellComponentListener listener,
605                      const CORBA_char *source_physical_uri,
606                      const CORBA_char *destination_physical_uri,
607                      const CORBA_char *type,
608                      const CORBA_boolean remove_source,
609                      CORBA_Environment *ev)
610{
611        BonoboObject *bonobo_object;
612        EvolutionShellComponent *shell_component;
613        EvolutionShellComponentPrivate *priv;
614
615        bonobo_object = bonobo_object_from_servant (servant);
616        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
617        priv = shell_component->priv;
618
619        if (priv->xfer_folder_fn == NULL) {
620                GNOME_Evolution_ShellComponentListener_notifyResult (listener,
621                                                                     GNOME_Evolution_ShellComponentListener_UNSUPPORTED_OPERATION,
622                                                                     ev);
623                return;
624        }
625
626        (* priv->xfer_folder_fn) (shell_component,
627                                  source_physical_uri,
628                                  destination_physical_uri,
629                                  type,
630                                  remove_source,
631                                  listener,
632                                  priv->closure);
633}
634
635static void
636impl_populateFolderContextMenu (PortableServer_Servant servant,
637                                const Bonobo_UIContainer corba_uih,
638                                const CORBA_char *physical_uri,
639                                const CORBA_char *type,
640                                CORBA_Environment *ev)
641{
642        BonoboObject *bonobo_object;
643        EvolutionShellComponent *shell_component;
644        EvolutionShellComponentPrivate *priv;
645
646        bonobo_object = bonobo_object_from_servant (servant);
647        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
648        priv = shell_component->priv;
649
650        if (priv->populate_folder_context_menu_fn == NULL)
651                return;
652
653        if (priv->uic != NULL) {
654                CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
655                                     ex_GNOME_Evolution_ShellComponent_AlreadyPopulated,
656                                     NULL);
657                return;
658        }
659
660        priv->uic = bonobo_ui_component_new_default ();
661        bonobo_ui_component_set_container (priv->uic, corba_uih);
662        bonobo_object_release_unref (corba_uih, NULL);
663
664        (* priv->populate_folder_context_menu_fn) (shell_component, priv->uic, physical_uri, type, priv->closure);
665}
666
667static void
668impl_unpopulateFolderContextMenu (PortableServer_Servant servant,
669                                  const Bonobo_UIContainer corba_uih,
670                                  const CORBA_char *physical_uri,
671                                  const CORBA_char *type,
672                                  CORBA_Environment *ev)
673{
674        BonoboObject *bonobo_object;
675        EvolutionShellComponent *shell_component;
676        EvolutionShellComponentPrivate *priv;
677
678        bonobo_object = bonobo_object_from_servant (servant);
679        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object);
680        priv = shell_component->priv;
681
682        if (priv->unpopulate_folder_context_menu_fn == NULL)
683                return;
684
685        if (priv->uic == NULL) {
686                CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
687                                     ex_GNOME_Evolution_ShellComponent_NotPopulated,
688                                     NULL);
689                return;
690        }
691
692        (* priv->unpopulate_folder_context_menu_fn) (shell_component, priv->uic, physical_uri, type, priv->closure);
693
694        bonobo_object_unref (BONOBO_OBJECT (priv->uic));
695        priv->uic = NULL;
696}
697
698static void
699impl_userCreateNewItem (PortableServer_Servant servant,
700                        const CORBA_char *id,
701                        const CORBA_char *parent_physical_uri,
702                        const CORBA_char *parent_type,
703                        CORBA_Environment *ev)
704{
705        EvolutionShellComponent *shell_component;
706        EvolutionShellComponentPrivate *priv;
707
708        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object_from_servant (servant));
709        priv = shell_component->priv;
710
711        /* FIXME: Check that the type is good.  */
712
713        gtk_signal_emit (GTK_OBJECT (shell_component), signals[USER_CREATE_NEW_ITEM], id, parent_physical_uri, parent_type);
714}
715
716static void
717impl_sendReceive (PortableServer_Servant servant,
718                  const CORBA_boolean show_dialog,
719                  CORBA_Environment *ev)
720{
721        EvolutionShellComponent *shell_component;
722
723        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object_from_servant (servant));
724        gtk_signal_emit (GTK_OBJECT (shell_component), signals[SEND_RECEIVE], show_dialog);
725}
726
727static void
728impl_requestQuit (PortableServer_Servant servant,
729                  const GNOME_Evolution_ShellComponentListener listener,
730                  CORBA_Environment *ev)
731{
732        EvolutionShellComponent *shell_component;
733        gboolean allow_quit;
734
735        shell_component = EVOLUTION_SHELL_COMPONENT (bonobo_object_from_servant (servant));
736
737        if (shell_component->priv->request_quit_fn == NULL)
738                allow_quit = TRUE;
739        else
740                allow_quit = (* shell_component->priv->request_quit_fn) (shell_component,
741                                                                         shell_component->priv->closure);
742
743        if (allow_quit)
744                GNOME_Evolution_ShellComponentListener_notifyResult (listener,
745                                                                     GNOME_Evolution_ShellComponentListener_OK,
746                                                                     ev);
747        else
748                GNOME_Evolution_ShellComponentListener_notifyResult (listener,
749                                                                     GNOME_Evolution_ShellComponentListener_CANCEL,
750                                                                     ev);
751}
752
753
754/* GtkObject methods.  */
755
756static void
757destroy (GtkObject *object)
758{
759        EvolutionShellComponent *shell_component;
760        EvolutionShellComponentPrivate *priv;
761        CORBA_Environment ev;
762        GSList *sp;
763        GList *p;
764
765        shell_component = EVOLUTION_SHELL_COMPONENT (object);
766
767        priv = shell_component->priv;
768
769        if (priv->ping_timeout_id != -1) {
770                g_source_remove (priv->ping_timeout_id);
771                priv->ping_timeout_id = -1;
772        }
773
774        CORBA_exception_init (&ev);
775
776        if (priv->owner_client != NULL) {
777                BonoboObject *owner_client_object;
778
779                owner_client_object = BONOBO_OBJECT (priv->owner_client);
780                priv->owner_client = NULL;
781                bonobo_object_unref (BONOBO_OBJECT (owner_client_object));
782        }
783
784        CORBA_exception_free (&ev);
785
786        for (p = priv->folder_types; p != NULL; p = p->next) {
787                EvolutionShellComponentFolderType *folder_type;
788
789                folder_type = (EvolutionShellComponentFolderType *) p->data;
790
791                g_free (folder_type->name);
792                g_free (folder_type->icon_name);
793                g_strfreev (folder_type->exported_dnd_types);
794                g_strfreev (folder_type->accepted_dnd_types);
795
796                g_free (folder_type);
797        }
798        g_list_free (priv->folder_types);
799
800        e_free_string_list (priv->external_uri_schemas);
801
802        for (sp = priv->user_creatable_item_types; sp != NULL; sp = sp->next)
803                user_creatable_item_type_free ((UserCreatableItemType *) sp->data);
804        g_slist_free (priv->user_creatable_item_types);
805
806        if (priv->uic != NULL)
807                bonobo_object_unref (BONOBO_OBJECT (priv->uic));
808
809        g_free (priv);
810
811        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
812}
813
814
815/* EvolutionShellComponent methods.  */
816
817static void
818impl_owner_unset (EvolutionShellComponent *shell_component)
819{
820        EvolutionShellComponentPrivate *priv;
821        BonoboObject *owner_client_object;
822
823        priv = shell_component->priv;
824
825        if (priv->ping_timeout_id != -1) {
826                g_source_remove (priv->ping_timeout_id);
827                priv->ping_timeout_id = -1;
828        }
829
830        owner_client_object = BONOBO_OBJECT (priv->owner_client);
831        priv->owner_client = NULL;
832        bonobo_object_unref (BONOBO_OBJECT (owner_client_object));
833}
834
835static void
836impl_owner_died (EvolutionShellComponent *shell_component)
837{
838        EvolutionShellComponentPrivate *priv;
839        BonoboObject *owner_client_object;
840
841        priv = shell_component->priv;
842
843        owner_client_object = BONOBO_OBJECT (priv->owner_client);
844        priv->owner_client = NULL;
845        bonobo_object_unref (BONOBO_OBJECT (owner_client_object));
846
847        /* The default implementation for ::owner_died emits ::owner_unset, so
848           that we make the behavior for old components kind of correct without
849           even if they don't handle the new ::owner_died signal correctly
850           yet.  */
851
852        gtk_signal_emit (GTK_OBJECT (shell_component), signals[OWNER_UNSET]);
853}
854
855
856/* Initialization.  */
857
858static void
859class_init (EvolutionShellComponentClass *klass)
860{
861        EvolutionShellComponentClass *shell_component_class;
862        GtkObjectClass *object_class;
863        POA_GNOME_Evolution_ShellComponent__epv *epv = &klass->epv;
864
865        object_class = GTK_OBJECT_CLASS (klass);
866        object_class->destroy = destroy;
867
868        signals[OWNER_SET]
869                = gtk_signal_new ("owner_set",
870                                  GTK_RUN_FIRST,
871                                  object_class->type,
872                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, owner_set),
873                                  gtk_marshal_NONE__POINTER_POINTER,
874                                  GTK_TYPE_NONE, 2,
875                                  GTK_TYPE_POINTER, GTK_TYPE_POINTER);
876
877        signals[OWNER_DIED]
878                = gtk_signal_new ("owner_died",
879                                  GTK_RUN_FIRST,
880                                  object_class->type,
881                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, owner_died),
882                                  gtk_marshal_NONE__NONE,
883                                  GTK_TYPE_NONE, 0);
884
885        signals[OWNER_UNSET]
886                = gtk_signal_new ("owner_unset",
887                                  GTK_RUN_FIRST,
888                                  object_class->type,
889                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, owner_unset),
890                                  gtk_marshal_NONE__NONE,
891                                  GTK_TYPE_NONE, 0);
892
893        signals[DEBUG]
894                = gtk_signal_new ("debug",
895                                  GTK_RUN_FIRST,
896                                  object_class->type,
897                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, debug),
898                                  gtk_marshal_NONE__NONE,
899                                  GTK_TYPE_NONE, 0);
900
901        signals[INTERACTIVE]
902                = gtk_signal_new ("interactive",
903                                  GTK_RUN_FIRST,
904                                  object_class->type,
905                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, interactive),
906                                  gtk_marshal_NONE__BOOL,
907                                  GTK_TYPE_NONE, 1,
908                                  GTK_TYPE_BOOL);
909
910        signals[HANDLE_EXTERNAL_URI]
911                = gtk_signal_new ("handle_external_uri",
912                                  GTK_RUN_FIRST,
913                                  object_class->type,
914                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, handle_external_uri),
915                                  gtk_marshal_NONE__STRING,
916                                  GTK_TYPE_NONE, 1,
917                                  GTK_TYPE_STRING);
918
919        signals[USER_CREATE_NEW_ITEM]
920                = gtk_signal_new ("user_create_new_item",
921                                  GTK_RUN_FIRST,
922                                  object_class->type,
923                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, user_create_new_item),
924                                  gtk_marshal_NONE__POINTER_POINTER_POINTER,
925                                  GTK_TYPE_NONE, 3,
926                                  GTK_TYPE_STRING,
927                                  GTK_TYPE_STRING,
928                                  GTK_TYPE_STRING);
929
930        signals[SEND_RECEIVE]
931                = gtk_signal_new ("send_receive",
932                                  GTK_RUN_FIRST,
933                                  object_class->type,
934                                  GTK_SIGNAL_OFFSET (EvolutionShellComponentClass, send_receive),
935                                  gtk_marshal_NONE__BOOL,
936                                  GTK_TYPE_NONE, 1,
937                                  GTK_TYPE_BOOL);
938
939        gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
940
941        parent_class = gtk_type_class (PARENT_TYPE);
942
943        epv->_get_supportedTypes         = impl__get_supportedTypes;
944        epv->_get_externalUriSchemas     = impl__get_externalUriSchemas;
945        epv->_get_userCreatableItemTypes = impl__get_userCreatableItemTypes;
946        epv->setOwner                    = impl_setOwner;
947        epv->unsetOwner                  = impl_unsetOwner;
948        epv->debug                       = impl_debug;
949        epv->interactive                 = impl_interactive;
950        epv->createView                  = impl_createView;
951        epv->handleExternalURI           = impl_handleExternalURI;
952        epv->createFolderAsync           = impl_createFolderAsync;
953        epv->removeFolderAsync           = impl_removeFolderAsync;
954        epv->xferFolderAsync             = impl_xferFolderAsync;
955        epv->populateFolderContextMenu   = impl_populateFolderContextMenu;
956        epv->unpopulateFolderContextMenu = impl_unpopulateFolderContextMenu;
957        epv->userCreateNewItem           = impl_userCreateNewItem;
958        epv->sendReceive                 = impl_sendReceive;
959        epv->requestQuit                 = impl_requestQuit;
960
961        shell_component_class = EVOLUTION_SHELL_COMPONENT_CLASS (object_class);
962        shell_component_class->owner_died = impl_owner_died;
963        shell_component_class->owner_unset = impl_owner_unset;
964}
965
966static void
967init (EvolutionShellComponent *shell_component)
968{
969        EvolutionShellComponentPrivate *priv;
970
971        priv = g_new (EvolutionShellComponentPrivate, 1);
972
973        priv->folder_types                    = NULL;
974        priv->external_uri_schemas            = NULL;
975
976        priv->create_view_fn                    = NULL;
977        priv->create_folder_fn                  = NULL;
978        priv->remove_folder_fn                  = NULL;
979        priv->xfer_folder_fn                    = NULL;
980        priv->populate_folder_context_menu_fn   = NULL;
981        priv->unpopulate_folder_context_menu_fn = NULL;
982
983        priv->owner_client                      = NULL;
984        priv->user_creatable_item_types         = NULL;
985        priv->closure                           = NULL;
986
987        priv->ping_timeout_id                   = -1;
988
989        priv->uic                               = NULL;
990
991        shell_component->priv = priv;
992}
993
994
995void
996evolution_shell_component_construct (EvolutionShellComponent *shell_component,
997                                     const EvolutionShellComponentFolderType folder_types[],
998                                     const char *external_uri_schemas[],
999                                     EvolutionShellComponentCreateViewFn create_view_fn,
1000                                     EvolutionShellComponentCreateFolderFn create_folder_fn,
1001                                     EvolutionShellComponentRemoveFolderFn remove_folder_fn,
1002                                     EvolutionShellComponentXferFolderFn xfer_folder_fn,
1003                                     EvolutionShellComponentPopulateFolderContextMenuFn populate_folder_context_menu_fn,
1004                                     EvolutionShellComponentUnpopulateFolderContextMenuFn unpopulate_folder_context_menu_fn,
1005                                     EvolutionShellComponentGetDndSelectionFn get_dnd_selection_fn,
1006                                     EvolutionShellComponentRequestQuitFn request_quit_fn,
1007                                     void *closure)
1008{
1009        EvolutionShellComponentPrivate *priv;
1010        int i;
1011
1012        g_return_if_fail (shell_component != NULL);
1013        g_return_if_fail (EVOLUTION_IS_SHELL_COMPONENT (shell_component));
1014        g_return_if_fail (folder_types != NULL);
1015
1016        priv = shell_component->priv;
1017
1018        priv->create_view_fn                    = create_view_fn;
1019        priv->create_folder_fn                  = create_folder_fn;
1020        priv->remove_folder_fn                  = remove_folder_fn;
1021        priv->xfer_folder_fn                    = xfer_folder_fn;
1022        priv->populate_folder_context_menu_fn   = populate_folder_context_menu_fn;
1023        priv->unpopulate_folder_context_menu_fn = unpopulate_folder_context_menu_fn;
1024        priv->get_dnd_selection_fn              = get_dnd_selection_fn;
1025        priv->request_quit_fn                   = request_quit_fn;
1026
1027        priv->closure = closure;
1028
1029        for (i = 0; folder_types[i].name != NULL; i++) {
1030                EvolutionShellComponentFolderType *new;
1031
1032                if (folder_types[i].icon_name == NULL
1033                    || folder_types[i].name[0] == '\0'
1034                    || folder_types[i].icon_name[0] == '\0')
1035                        continue;
1036
1037                new = g_new (EvolutionShellComponentFolderType, 1);
1038                new->name               = g_strdup (folder_types[i].name);
1039                new->icon_name          = g_strdup (folder_types[i].icon_name);
1040
1041                /* Notice that these get translated here.  */
1042                new->display_name       = g_strdup (_(folder_types[i].display_name));
1043                new->description        = g_strdup (_(folder_types[i].description));
1044
1045                new->user_creatable     = folder_types[i].user_creatable;
1046                new->accepted_dnd_types = duplicate_null_terminated_string_array (folder_types[i].accepted_dnd_types);
1047                new->exported_dnd_types = duplicate_null_terminated_string_array (folder_types[i].exported_dnd_types);
1048
1049                priv->folder_types = g_list_prepend (priv->folder_types, new);
1050        }
1051
1052        if (priv->folder_types == NULL)
1053                g_warning ("No valid folder types constructing EShellComponent %p", shell_component);
1054
1055        if (external_uri_schemas != NULL) {
1056                for (i = 0; external_uri_schemas[i] != NULL; i++)
1057                        priv->external_uri_schemas = g_list_prepend (priv->external_uri_schemas,
1058                                                                     g_strdup (external_uri_schemas[i]));
1059        }
1060}
1061
1062EvolutionShellComponent *
1063evolution_shell_component_new (const EvolutionShellComponentFolderType folder_types[],
1064                               const char *external_uri_schemas[],
1065                               EvolutionShellComponentCreateViewFn create_view_fn,
1066                               EvolutionShellComponentCreateFolderFn create_folder_fn,
1067                               EvolutionShellComponentRemoveFolderFn remove_folder_fn,
1068                               EvolutionShellComponentXferFolderFn xfer_folder_fn,
1069                               EvolutionShellComponentPopulateFolderContextMenuFn populate_folder_context_menu_fn,
1070                               EvolutionShellComponentUnpopulateFolderContextMenuFn unpopulate_folder_context_menu_fn,
1071                               EvolutionShellComponentGetDndSelectionFn get_dnd_selection_fn,
1072                               EvolutionShellComponentRequestQuitFn request_quit_fn,
1073                               void *closure)
1074{
1075        EvolutionShellComponent *new;
1076
1077        g_return_val_if_fail (folder_types != NULL, NULL);
1078
1079        new = gtk_type_new (evolution_shell_component_get_type ());
1080
1081        evolution_shell_component_construct (new,
1082                                             folder_types,
1083                                             external_uri_schemas,
1084                                             create_view_fn,
1085                                             create_folder_fn,
1086                                             remove_folder_fn,
1087                                             xfer_folder_fn,
1088                                             populate_folder_context_menu_fn,
1089                                             unpopulate_folder_context_menu_fn,
1090                                             get_dnd_selection_fn,
1091                                             request_quit_fn,
1092                                             closure);
1093
1094        return new;
1095}
1096
1097EvolutionShellClient *
1098evolution_shell_component_get_owner  (EvolutionShellComponent *shell_component)
1099{
1100        g_return_val_if_fail (shell_component != NULL, NULL);
1101        g_return_val_if_fail (EVOLUTION_IS_SHELL_COMPONENT (shell_component), NULL);
1102
1103        return shell_component->priv->owner_client;
1104}
1105
1106
1107void
1108evolution_shell_component_add_user_creatable_item  (EvolutionShellComponent *shell_component,
1109                                                    const char *id,
1110                                                    const char *description,
1111                                                    const char *menu_description,
1112                                                    const char *tooltip,
1113                                                    const char *folder_type,
1114                                                    char menu_shortcut,
1115                                                    GdkPixbuf *icon)
1116{
1117        EvolutionShellComponentPrivate *priv;
1118        UserCreatableItemType *type;
1119
1120        g_return_if_fail (shell_component != NULL);
1121        g_return_if_fail (EVOLUTION_IS_SHELL_COMPONENT (shell_component));
1122        g_return_if_fail (id != NULL);
1123        g_return_if_fail (description != NULL);
1124        g_return_if_fail (menu_description != NULL);
1125
1126        priv = shell_component->priv;
1127
1128        type = user_creatable_item_type_new (id, description, menu_description, tooltip, folder_type, menu_shortcut, icon);
1129
1130        priv->user_creatable_item_types = g_slist_prepend (priv->user_creatable_item_types, type);
1131}
1132
1133
1134/* Public utility functions.  */
1135
1136const char *
1137evolution_shell_component_result_to_string (EvolutionShellComponentResult result)
1138{
1139        switch (result) {
1140        case EVOLUTION_SHELL_COMPONENT_OK:
1141                return _("Success");
1142        case EVOLUTION_SHELL_COMPONENT_CANCEL:
1143                return _("Cancel");
1144        case EVOLUTION_SHELL_COMPONENT_CORBAERROR:
1145                return _("CORBA error");
1146        case EVOLUTION_SHELL_COMPONENT_INTERRUPTED:
1147                return _("Interrupted");
1148        case EVOLUTION_SHELL_COMPONENT_INVALIDARG:
1149                return _("Invalid argument");
1150        case EVOLUTION_SHELL_COMPONENT_ALREADYOWNED:
1151                return _("Already has an owner");
1152        case EVOLUTION_SHELL_COMPONENT_NOTOWNED:
1153                return _("No owner");
1154        case EVOLUTION_SHELL_COMPONENT_NOTFOUND:
1155                return _("Not found");
1156        case EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE:
1157                return _("Unsupported type");
1158        case EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDSCHEMA:
1159                return _("Unsupported schema");
1160        case EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDOPERATION:
1161                return _("Unsupported operation");
1162        case EVOLUTION_SHELL_COMPONENT_INTERNALERROR:
1163                return _("Internal error");
1164        case EVOLUTION_SHELL_COMPONENT_BUSY:
1165                return _("Busy");
1166        case EVOLUTION_SHELL_COMPONENT_EXISTS:
1167                return _("Exists");
1168        case EVOLUTION_SHELL_COMPONENT_INVALIDURI:
1169                return _("Invalid URI");
1170        case EVOLUTION_SHELL_COMPONENT_PERMISSIONDENIED:
1171                return _("Permission denied");
1172        case EVOLUTION_SHELL_COMPONENT_HASSUBFOLDERS:
1173                return _("Has subfolders");
1174        case EVOLUTION_SHELL_COMPONENT_NOSPACE:
1175                return _("No space left");
1176        case EVOLUTION_SHELL_COMPONENT_OLDOWNERHASDIED:
1177                return _("Old owner has died");
1178        case EVOLUTION_SHELL_COMPONENT_UNKNOWNERROR:
1179        default:
1180                return _("Unknown error");
1181        }
1182}
1183
1184
1185E_MAKE_X_TYPE (evolution_shell_component, "EvolutionShellComponent", EvolutionShellComponent,
1186               class_init, init, PARENT_TYPE,
1187               POA_GNOME_Evolution_ShellComponent__init,
1188               GTK_STRUCT_OFFSET (EvolutionShellComponentClass, epv))
Note: See TracBrowser for help on using the repository browser.