diff options
30 files changed, 1489 insertions, 1218 deletions
diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am index 7aea84963b..1efdb341f3 100644 --- a/addressbook/gui/component/Makefile.am +++ b/addressbook/gui/component/Makefile.am @@ -32,6 +32,7 @@ libevolution_module_contacts_la_SOURCES = \ e-book-shell-content.c \ e-book-shell-content.h \ e-book-shell-module.c \ + e-book-shell-module.h \ e-book-shell-module-migrate.c \ e-book-shell-module-migrate.h \ e-book-shell-sidebar.c \ diff --git a/addressbook/gui/component/e-book-shell-module.c b/addressbook/gui/component/e-book-shell-module.c index 80bbc8318e..03b2496dba 100644 --- a/addressbook/gui/component/e-book-shell-module.c +++ b/addressbook/gui/component/e-book-shell-module.c @@ -19,6 +19,8 @@ * */ +#include "e-book-shell-module.h" + #include <config.h> #include <string.h> @@ -26,11 +28,9 @@ #include <libebook/e-book.h> #include <libedataserver/e-url.h> #include <libedataserver/e-source.h> -#include <libedataserver/e-source-list.h> #include <libedataserver/e-source-group.h> #include "shell/e-shell.h" -#include "shell/e-shell-module.h" #include "shell/e-shell-window.h" #include "e-util/e-import.h" @@ -51,16 +51,23 @@ #include "smime/gui/certificate-manager.h" #endif -#define MODULE_NAME "addressbook" -#define MODULE_ALIASES "contacts" -#define MODULE_SCHEMES "" -#define MODULE_SORT_ORDER 300 +#define E_BOOK_SHELL_MODULE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_BOOK_SHELL_MODULE, EBookShellModulePrivate)) #define LDAP_BASE_URI "ldap://" #define PERSONAL_RELATIVE_URI "system" -/* Module Entry Point */ -void e_shell_module_init (GTypeModule *type_module); +struct _EBookShellModulePrivate { + ESourceList *source_list; +}; + +/* Module Entry Points */ +void e_shell_load (GTypeModule *type_module); +void e_shell_unload (GTypeModule *type_module); + +GType e_book_shell_module_type = 0; +static gpointer parent_class; static void book_module_ensure_sources (EShellModule *shell_module) @@ -68,7 +75,7 @@ book_module_ensure_sources (EShellModule *shell_module) /* XXX This is basically the same algorithm across all modules. * Maybe we could somehow integrate this into EShellModule? */ - ESourceList *source_list; + EBookShellModulePrivate *priv; ESourceGroup *on_this_computer; ESourceGroup *on_ldap_servers; ESource *personal; @@ -82,28 +89,19 @@ book_module_ensure_sources (EShellModule *shell_module) on_ldap_servers = NULL; personal = NULL; - if (!e_book_get_addressbooks (&source_list, NULL)) { + priv = E_BOOK_SHELL_MODULE_GET_PRIVATE (shell_module); + + if (!e_book_get_addressbooks (&priv->source_list, NULL)) { g_warning ("Could not get addressbook sources from GConf!"); return; } - /* Share the source list with all address book views. This - * is accessible via e_book_shell_view_get_source_list(). - * Note: EShellModule takes ownership of the reference. - * - * XXX I haven't yet decided if I want to add a proper - * EShellModule API for this. The mail module would - * not use it. */ - g_object_set_data_full ( - G_OBJECT (shell_module), "source-list", - source_list, (GDestroyNotify) g_object_unref); - data_dir = e_shell_module_get_data_dir (shell_module); filename = g_build_filename (data_dir, "local", NULL); base_uri = g_filename_to_uri (filename, NULL, NULL); g_free (filename); - groups = e_source_list_peek_groups (source_list); + groups = e_source_list_peek_groups (priv->source_list); for (iter = groups; iter != NULL; iter = iter->next) { ESourceGroup *source_group = iter->data; const gchar *group_base_uri; @@ -160,14 +158,14 @@ book_module_ensure_sources (EShellModule *shell_module) * but that happens in an idle loop and too late * to prevent the user from seeing a "Cannot * Open ... because of invalid URI" error. */ - e_source_list_sync (source_list, NULL); + e_source_list_sync (priv->source_list, NULL); } } else { ESourceGroup *source_group; source_group = e_source_group_new (name, base_uri); - e_source_list_add_group (source_list, source_group, -1); + e_source_list_add_group (priv->source_list, source_group, -1); g_object_unref (source_group); } @@ -192,7 +190,7 @@ book_module_ensure_sources (EShellModule *shell_module) ESourceGroup *source_group; source_group = e_source_group_new (name, LDAP_BASE_URI); - e_source_list_add_group (source_list, source_group, -1); + e_source_list_add_group (priv->source_list, source_group, -1); g_object_unref (source_group); } else { /* Force the group name to the current locale. */ @@ -330,19 +328,6 @@ static GtkActionEntry source_entries[] = { }; static gboolean -book_module_is_busy (EShellModule *shell_module) -{ - return !eab_editor_request_close_all (); -} - -static gboolean -book_module_shutdown (EShellModule *shell_module) -{ - /* FIXME */ - return TRUE; -} - -static gboolean book_module_handle_uri_cb (EShellModule *shell_module, const gchar *uri) { @@ -428,33 +413,31 @@ book_module_window_created_cb (EShellModule *shell_module, source_entries, G_N_ELEMENTS (source_entries)); } -static EShellModuleInfo module_info = { +static void +book_shell_module_dispose (GObject *object) +{ + EBookShellModulePrivate *priv; - MODULE_NAME, - MODULE_ALIASES, - MODULE_SCHEMES, - MODULE_SORT_ORDER, + priv = E_BOOK_SHELL_MODULE_GET_PRIVATE (object); - /* Methods */ - /* start */ NULL, - book_module_is_busy, - book_module_shutdown, - e_book_shell_module_migrate -}; + if (priv->source_list != NULL) { + g_object_unref (priv->source_list); + priv->source_list = NULL; + } -void -e_shell_module_init (GTypeModule *type_module) + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +book_shell_module_constructed (GObject *object) { EShell *shell; EShellModule *shell_module; - shell_module = E_SHELL_MODULE (type_module); + shell_module = E_SHELL_MODULE (object); shell = e_shell_module_get_shell (shell_module); - e_shell_module_set_info ( - shell_module, &module_info, - e_book_shell_view_get_type (type_module)); - /* XXX Why is this here? Address books aren't the only * things that use S/MIME. Maybe put it in EShell? */ #ifdef ENABLE_SMIME @@ -477,3 +460,95 @@ e_shell_module_init (GTypeModule *type_module) autocompletion_config_init (shell); } + +static gboolean +book_shell_module_is_busy (EShellModule *shell_module) +{ + return !eab_editor_request_close_all (); +} + +static gboolean +book_shell_module_shutdown (EShellModule *shell_module) +{ + /* FIXME */ + return TRUE; +} + +static void +book_shell_module_class_init (EBookShellModuleClass *class) +{ + GObjectClass *object_class; + EShellModuleClass *shell_module_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EBookShellModulePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = book_shell_module_dispose; + object_class->constructed = book_shell_module_constructed; + + shell_module_class = E_SHELL_MODULE_CLASS (class); + shell_module_class->name = "addressbook"; + shell_module_class->aliases = "contacts"; + shell_module_class->schemes = ""; + shell_module_class->sort_order = 300; + shell_module_class->view_type = E_TYPE_BOOK_SHELL_VIEW; + shell_module_class->start = NULL; + shell_module_class->is_busy = book_shell_module_is_busy; + shell_module_class->shutdown = book_shell_module_shutdown; + shell_module_class->migrate = e_book_shell_module_migrate; +} + +static void +book_shell_module_init (EBookShellModule *book_shell_module) +{ + book_shell_module->priv = + E_BOOK_SHELL_MODULE_GET_PRIVATE (book_shell_module); +} + +GType +e_book_shell_module_get_type (GTypeModule *type_module) +{ + if (e_book_shell_module_type == 0) { + const GTypeInfo type_info = { + sizeof (EBookShellModuleClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) book_shell_module_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EBookShellModule), + 0, /* n_preallocs */ + (GInstanceInitFunc) book_shell_module_init, + NULL /* value_table */ + }; + + e_book_shell_module_type = + g_type_module_register_type ( + type_module, E_TYPE_SHELL_MODULE, + "EBookShellModule", &type_info, 0); + } + + return e_book_shell_module_type; +} + +ESourceList * +e_book_shell_module_get_source_list (EBookShellModule *book_shell_module) +{ + g_return_val_if_fail ( + E_IS_BOOK_SHELL_MODULE (book_shell_module), NULL); + + return book_shell_module->priv->source_list; +} + +void +e_module_load (GTypeModule *type_module) +{ + e_book_shell_view_get_type (type_module); + e_book_shell_module_get_type (type_module); +} + +void +e_module_unload (GTypeModule *type_module) +{ +} diff --git a/addressbook/gui/component/e-book-shell-module.h b/addressbook/gui/component/e-book-shell-module.h new file mode 100644 index 0000000000..4a0088a557 --- /dev/null +++ b/addressbook/gui/component/e-book-shell-module.h @@ -0,0 +1,71 @@ +/* + * e-book-shell-module.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_SHELL_MODULE_H +#define E_BOOK_SHELL_MODULE_H + +#include <shell/e-shell-module.h> +#include <libedataserver/e-source-list.h> + +/* Standard GObject macros */ +#define E_TYPE_BOOK_SHELL_MODULE \ + (e_book_shell_module_type) +#define E_BOOK_SHELL_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_BOOK_SHELL_MODULE, EBookShellModule)) +#define E_BOOK_SHELL_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_BOOK_SHELL_MODULE, EBookShellModuleClass)) +#define E_IS_BOOK_SHELL_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_BOOK_SHELL_MODULE)) +#define E_IS_BOOK_SHELL_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_BOOK_SHELL_MODULE)) +#define E_BOOK_SHELL_MODULE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_BOOK_SHELL_MODULE, EBookShellModuleClass)) + +G_BEGIN_DECLS + +extern GType e_book_shell_module_type; + +typedef struct _EBookShellModule EBookShellModule; +typedef struct _EBookShellModuleClass EBookShellModuleClass; +typedef struct _EBookShellModulePrivate EBookShellModulePrivate; + +struct _EBookShellModule { + EShellModule parent; + EBookShellModulePrivate *priv; +}; + +struct _EBookShellModuleClass { + EShellModuleClass parent_class; +}; + +GType e_book_shell_module_get_type + (GTypeModule *type_module); +ESourceList * e_book_shell_module_get_source_list + (EBookShellModule *book_shell_module); + +G_END_DECLS + +#endif /* E_BOOK_SHELL_MODULE_H */ diff --git a/addressbook/gui/component/e-book-shell-sidebar.c b/addressbook/gui/component/e-book-shell-sidebar.c index fd9cdbe925..d7e121e110 100644 --- a/addressbook/gui/component/e-book-shell-sidebar.c +++ b/addressbook/gui/component/e-book-shell-sidebar.c @@ -24,8 +24,9 @@ #include <string.h> #include <glib/gi18n.h> -#include <e-book-shell-view.h> -#include <e-addressbook-selector.h> +#include "e-book-shell-view.h" +#include "e-book-shell-module.h" +#include "e-addressbook-selector.h" #define E_BOOK_SHELL_SIDEBAR_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -80,8 +81,9 @@ book_shell_sidebar_constructed (GObject *object) { EBookShellSidebarPrivate *priv; EShellView *shell_view; + EShellModule *shell_module; EShellSidebar *shell_sidebar; - EBookShellView *book_shell_view; + EBookShellModule *book_shell_module; ESourceList *source_list; GtkContainer *container; GtkWidget *widget; @@ -93,8 +95,9 @@ book_shell_sidebar_constructed (GObject *object) shell_sidebar = E_SHELL_SIDEBAR (object); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); - book_shell_view = E_BOOK_SHELL_VIEW (shell_view); - source_list = e_book_shell_view_get_source_list (book_shell_view); + shell_module = e_shell_view_get_shell_module (shell_view); + book_shell_module = E_BOOK_SHELL_MODULE (shell_module); + source_list = e_book_shell_module_get_source_list (book_shell_module); container = GTK_CONTAINER (shell_sidebar); diff --git a/addressbook/gui/component/e-book-shell-view-actions.c b/addressbook/gui/component/e-book-shell-view-actions.c index ed88b54855..4241c1f73e 100644 --- a/addressbook/gui/component/e-book-shell-view-actions.c +++ b/addressbook/gui/component/e-book-shell-view-actions.c @@ -47,6 +47,7 @@ action_address_book_delete_cb (GtkAction *action, { EShellView *shell_view; EShellWindow *shell_window; + EBookShellModule *book_shell_module; EBookShellSidebar *book_shell_sidebar; ESource *source; ESourceSelector *selector; @@ -59,6 +60,9 @@ action_address_book_delete_cb (GtkAction *action, shell_view = E_SHELL_VIEW (book_shell_view); shell_window = e_shell_view_get_shell_window (shell_view); + book_shell_module = book_shell_view->priv->book_shell_module; + source_list = e_book_shell_module_get_source_list (book_shell_module); + book_shell_sidebar = book_shell_view->priv->book_shell_sidebar; selector = e_book_shell_sidebar_get_selector (book_shell_sidebar); source = e_source_selector_peek_primary_selection (selector); @@ -93,7 +97,6 @@ action_address_book_delete_cb (GtkAction *action, source_group = e_source_peek_group (source); e_source_group_remove_source (source_group, source); - source_list = book_shell_view->priv->source_list; e_source_list_sync (source_list, NULL); g_object_unref (book); diff --git a/addressbook/gui/component/e-book-shell-view-private.c b/addressbook/gui/component/e-book-shell-view-private.c index 33fe07291d..1fe372a05b 100644 --- a/addressbook/gui/component/e-book-shell-view-private.c +++ b/addressbook/gui/component/e-book-shell-view-private.c @@ -400,15 +400,10 @@ e_book_shell_view_private_init (EBookShellView *book_shell_view, EShellViewClass *shell_view_class) { EBookShellViewPrivate *priv = book_shell_view->priv; - ESourceList *source_list; GHashTable *uid_to_view; GHashTable *uid_to_editor; GObject *object; - object = G_OBJECT (shell_view_class->type_module); - source_list = g_object_get_data (object, "source-list"); - g_return_if_fail (E_IS_SOURCE_LIST (source_list)); - uid_to_view = g_hash_table_new_full ( g_str_hash, g_str_equal, (GDestroyNotify) g_free, @@ -419,7 +414,6 @@ e_book_shell_view_private_init (EBookShellView *book_shell_view, (GDestroyNotify) g_free, (GDestroyNotify) g_free); - priv->source_list = g_object_ref (source_list); priv->uid_to_view = uid_to_view; priv->uid_to_editor = uid_to_editor; @@ -437,11 +431,13 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) EBookShellViewPrivate *priv = book_shell_view->priv; EShellContent *shell_content; EShellSidebar *shell_sidebar; + EShellModule *shell_module; EShellView *shell_view; EShellWindow *shell_window; ESourceSelector *selector; shell_view = E_SHELL_VIEW (book_shell_view); + shell_module = e_shell_view_get_shell_module (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); shell_window = e_shell_view_get_shell_window (shell_view); @@ -450,6 +446,7 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) e_shell_window_add_action_group (shell_window, "contacts-filter"); /* Cache these to avoid lots of awkward casting. */ + priv->book_shell_module = g_object_ref (shell_module); priv->book_shell_content = g_object_ref (shell_content); priv->book_shell_sidebar = g_object_ref (shell_sidebar); @@ -490,8 +487,7 @@ e_book_shell_view_private_dispose (EBookShellView *book_shell_view) { EBookShellViewPrivate *priv = book_shell_view->priv; - DISPOSE (priv->source_list); - + DISPOSE (priv->book_shell_module); DISPOSE (priv->book_shell_content); DISPOSE (priv->book_shell_sidebar); diff --git a/addressbook/gui/component/e-book-shell-view-private.h b/addressbook/gui/component/e-book-shell-view-private.h index 6f0d0af147..9be603e6d4 100644 --- a/addressbook/gui/component/e-book-shell-view-private.h +++ b/addressbook/gui/component/e-book-shell-view-private.h @@ -43,9 +43,10 @@ #include "addressbook/gui/widgets/e-addressbook-view.h" #include "addressbook/gui/widgets/e-addressbook-selector.h" -#include <e-book-shell-content.h> -#include <e-book-shell-sidebar.h> -#include <e-book-shell-view-actions.h> +#include "e-book-shell-module.h" +#include "e-book-shell-content.h" +#include "e-book-shell-sidebar.h" +#include "e-book-shell-view-actions.h" #define E_BOOK_SHELL_VIEW_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -92,13 +93,8 @@ enum { struct _EBookShellViewPrivate { - /*** Module Data ***/ - - ESourceList *source_list; - - /*** Other Stuff ***/ - /* These are just for convenience. */ + EBookShellModule *book_shell_module; EBookShellContent *book_shell_content; EBookShellSidebar *book_shell_sidebar; diff --git a/addressbook/gui/component/e-book-shell-view.c b/addressbook/gui/component/e-book-shell-view.c index 6244384390..9a6736b178 100644 --- a/addressbook/gui/component/e-book-shell-view.c +++ b/addressbook/gui/component/e-book-shell-view.c @@ -21,11 +21,6 @@ #include "e-book-shell-view-private.h" -enum { - PROP_0, - PROP_SOURCE_LIST -}; - GType e_book_shell_view_type = 0; static gpointer parent_class; @@ -80,23 +75,6 @@ book_shell_view_source_list_changed_cb (EBookShellView *book_shell_view, } static void -book_shell_view_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SOURCE_LIST: - g_value_set_object ( - value, e_book_shell_view_get_source_list ( - E_BOOK_SHELL_VIEW (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void book_shell_view_dispose (GObject *object) { EBookShellView *book_shell_view; @@ -124,12 +102,22 @@ static void book_shell_view_constructed (GObject *object) { EBookShellView *book_shell_view; + EBookShellModule *book_shell_module; + ESourceList *source_list; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (parent_class)->constructed (object); book_shell_view = E_BOOK_SHELL_VIEW (object); e_book_shell_view_private_constructed (book_shell_view); + + book_shell_module = book_shell_view->priv->book_shell_module; + source_list = e_book_shell_module_get_source_list (book_shell_module); + + g_signal_connect_swapped ( + source_list, "changed", + G_CALLBACK (book_shell_view_source_list_changed_cb), + book_shell_view); } static void @@ -267,8 +255,7 @@ book_shell_view_update_actions (EShellView *shell_view) } static void -book_shell_view_class_init (EBookShellViewClass *class, - GTypeModule *type_module) +book_shell_view_class_init (EBookShellViewClass *class) { GObjectClass *object_class; EShellViewClass *shell_view_class; @@ -277,7 +264,6 @@ book_shell_view_class_init (EBookShellViewClass *class, g_type_class_add_private (class, sizeof (EBookShellViewPrivate)); object_class = G_OBJECT_CLASS (class); - object_class->get_property = book_shell_view_get_property; object_class->dispose = book_shell_view_dispose; object_class->finalize = book_shell_view_finalize; object_class->constructed = book_shell_view_constructed; @@ -289,20 +275,9 @@ book_shell_view_class_init (EBookShellViewClass *class, shell_view_class->ui_manager_id = "org.gnome.evolution.contacts"; shell_view_class->search_options = "/contact-search-options"; shell_view_class->search_rules = "addresstypes.xml"; - shell_view_class->type_module = type_module; shell_view_class->new_shell_content = e_book_shell_content_new; shell_view_class->new_shell_sidebar = e_book_shell_sidebar_new; shell_view_class->update_actions = book_shell_view_update_actions; - - g_object_class_install_property ( - object_class, - PROP_SOURCE_LIST, - g_param_spec_object ( - "source-list", - _("Source List"), - _("The registry of address books"), - E_TYPE_SOURCE_LIST, - G_PARAM_READABLE)); } static void @@ -313,11 +288,6 @@ book_shell_view_init (EBookShellView *book_shell_view, E_BOOK_SHELL_VIEW_GET_PRIVATE (book_shell_view); e_book_shell_view_private_init (book_shell_view, shell_view_class); - - g_signal_connect_swapped ( - book_shell_view->priv->source_list, "changed", - G_CALLBACK (book_shell_view_source_list_changed_cb), - book_shell_view); } GType @@ -330,11 +300,11 @@ e_book_shell_view_get_type (GTypeModule *type_module) (GBaseFinalizeFunc) NULL, (GClassInitFunc) book_shell_view_class_init, (GClassFinalizeFunc) NULL, - type_module, + NULL, /* class_data */ sizeof (EBookShellView), - 0, /* n_preallocs */ + 0, /* n_preallocs */ (GInstanceInitFunc) book_shell_view_init, - NULL /* value_table */ + NULL /* value_table */ }; e_book_shell_view_type = @@ -345,11 +315,3 @@ e_book_shell_view_get_type (GTypeModule *type_module) return e_book_shell_view_type; } - -ESourceList * -e_book_shell_view_get_source_list (EBookShellView *book_shell_view) -{ - g_return_val_if_fail (E_IS_BOOK_SHELL_VIEW (book_shell_view), NULL); - - return book_shell_view->priv->source_list; -} diff --git a/addressbook/gui/component/e-book-shell-view.h b/addressbook/gui/component/e-book-shell-view.h index 2b3f02c759..c0b5a44c38 100644 --- a/addressbook/gui/component/e-book-shell-view.h +++ b/addressbook/gui/component/e-book-shell-view.h @@ -23,7 +23,6 @@ #define E_BOOK_SHELL_VIEW_H #include <e-shell-view.h> -#include <libedataserver/e-source-list.h> /* Standard GObject macros */ #define E_TYPE_BOOK_SHELL_VIEW \ @@ -61,10 +60,7 @@ struct _EBookShellViewClass { EShellViewClass parent_class; }; -GType e_book_shell_view_get_type - (GTypeModule *type_module); -ESourceList * e_book_shell_view_get_source_list - (EBookShellView *book_shell_view); +GType e_book_shell_view_get_type (GTypeModule *type_module); G_END_DECLS diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 384db63296..d06a349174 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -60,6 +60,7 @@ eutilinclude_HEADERS = \ e-marshal.h \ e-menu.h \ e-mktemp.h \ + e-module.h \ e-non-intrusive-error-dialog.h \ e-print.h \ e-plugin.h \ @@ -101,6 +102,7 @@ libeutil_la_SOURCES = \ e-marshal.c \ e-menu.c \ e-mktemp.c \ + e-module.c \ e-non-intrusive-error-dialog.c \ e-plugin-ui.c \ e-plugin.c \ diff --git a/e-util/e-module.c b/e-util/e-module.c new file mode 100644 index 0000000000..51e1e18bd6 --- /dev/null +++ b/e-util/e-module.c @@ -0,0 +1,318 @@ +/* + * e-module.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-module.h" + +#include <glib/gi18n.h> + +/* This is the symbol we call when loading a module. */ +#define LOAD_SYMBOL "e_module_load" + +/* This is the symbol we call when unloading a module. */ +#define UNLOAD_SYMBOL "e_module_unload" + +#define E_MODULE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MODULE, EModulePrivate)) + +struct _EModulePrivate { + GModule *module; + gchar *filename; + + void (*load) (GTypeModule *type_module); + void (*unload) (GTypeModule *type_module); +}; + +enum { + PROP_0, + PROP_FILENAME +}; + +static gpointer parent_class; + +static void +module_set_filename (EModule *module, + const gchar *filename) +{ + g_return_if_fail (module->priv->filename == NULL); + + module->priv->filename = g_strdup (filename); +} + +static void +module_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILENAME: + module_set_filename ( + E_MODULE (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +module_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILENAME: + g_value_set_string ( + value, e_module_get_filename ( + E_MODULE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +module_finalize (GObject *object) +{ + EModulePrivate *priv; + + priv = E_MODULE_GET_PRIVATE (object); + + g_free (priv->filename); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +module_load (GTypeModule *type_module) +{ + EModulePrivate *priv; + gpointer symbol; + + priv = E_MODULE_GET_PRIVATE (type_module); + + g_return_val_if_fail (priv->filename != NULL, FALSE); + priv->module = g_module_open (priv->filename, 0); + + if (priv->module == NULL) + goto fail; + + if (!g_module_symbol (priv->module, LOAD_SYMBOL, &symbol)) + goto fail; + + priv->load = symbol; + + if (!g_module_symbol (priv->module, UNLOAD_SYMBOL, &symbol)) + goto fail; + + priv->unload = symbol; + + priv->load (type_module); + + return TRUE; + +fail: + g_warning ("%s", g_module_error ()); + + if (priv->module != NULL) + g_module_close (priv->module); + + return FALSE; +} + +static void +module_unload (GTypeModule *type_module) +{ + EModulePrivate *priv; + + priv = E_MODULE_GET_PRIVATE (type_module); + + priv->unload (type_module); + + g_module_close (priv->module); + priv->module = NULL; + + priv->load = NULL; + priv->unload = NULL; +} + +static void +module_class_init (EModuleClass *class) +{ + GObjectClass *object_class; + GTypeModuleClass *type_module_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EModulePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = module_set_property; + object_class->get_property = module_get_property; + object_class->finalize = module_finalize; + + type_module_class = G_TYPE_MODULE_CLASS (class); + type_module_class->load = module_load; + type_module_class->unload = module_unload; + + /** + * EModule:filename + * + * The filename of the module. + **/ + g_object_class_install_property ( + object_class, + PROP_FILENAME, + g_param_spec_string ( + "filename", + _("Filename"), + _("The filename of the module"), + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +module_init (EModule *module) +{ + module->priv = E_MODULE_GET_PRIVATE (module); +} + +GType +e_module_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EModuleClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) module_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EModule), + 0, /* n_preallocs */ + (GInstanceInitFunc) module_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_TYPE_MODULE, "EModule", &type_info, 0); + } + + return type; +} + +/** + * e_module_new: + * @filename: filename of the shared library module + * + * Creates a new #EModule that will load the specific shared library + * when in use. + * + * Returns: a new #EModule for @filename + **/ +EModule * +e_module_new (const gchar *filename) +{ + g_return_val_if_fail (filename != NULL, NULL); + + return g_object_new (E_TYPE_MODULE, "filename", filename, NULL); +} + +/** + * e_module_get_filename: + * @module: an #EModule + * + * Returns the filename of the shared library for @module. The + * string is owned by @module and should not be modified or freed. + * + * Returns: the filename for @module + **/ +const gchar * +e_module_get_filename (EModule *module) +{ + g_return_val_if_fail (E_IS_MODULE (module), NULL); + + return module->priv->filename; +} + +/** + * e_module_load_all_in_directory: + * @dirname: pathname for a directory containing modules to load + * + * Loads all the modules in the specified directory into memory. If + * you want to unload them (enabling on-demand loading) you must call + * g_type_module_unuse() on all the modules. Free the returned list + * with g_list_free(). + * + * Returns: a list of #EModules loaded from @dirname + **/ +GList * +e_module_load_all_in_directory (const gchar *dirname) +{ + GDir *dir; + const gchar *basename; + GList *loaded_modules = NULL; + GError *error = NULL; + + g_return_val_if_fail (dirname != NULL, NULL); + + if (!g_module_supported ()) + return NULL; + + dir = g_dir_open (dirname, 0, &error); + if (dir == NULL) { + g_warning ("%s", error->message); + g_error_free (error); + return NULL; + } + + while ((basename = g_dir_read_name (dir)) != NULL) { + EModule *module; + gchar *filename; + + if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX)) + continue; + + filename = g_build_filename (dirname, basename, NULL); + + module = e_module_new (filename); + + if (!g_type_module_use (G_TYPE_MODULE (module))) { + g_printerr ("Failed to load module: %s\n", filename); + g_object_unref (module); + g_free (filename); + continue; + } + + g_free (filename); + + loaded_modules = g_list_prepend (loaded_modules, module); + } + + g_dir_close (dir); + + return loaded_modules; +} diff --git a/e-util/e-module.h b/e-util/e-module.h new file mode 100644 index 0000000000..022769dc1c --- /dev/null +++ b/e-util/e-module.h @@ -0,0 +1,81 @@ +/* + * e-module.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/** + * SECTION: e-module + * @short_description: generic module loader + * @include: e-util/e-module.h + **/ + +#ifndef E_MODULE_H +#define E_MODULE_H + +#include <gmodule.h> +#include <glib-object.h> + +/* Standard GObject macros */ +#define E_TYPE_MODULE \ + (e_module_get_type ()) +#define E_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MODULE, EModule)) +#define E_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MODULE, EModuleClass)) +#define E_IS_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MODULE)) +#define E_IS_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MODULE)) +#define E_MODULE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MODULE, EModuleClass)) + +G_BEGIN_DECLS + +typedef struct _EModule EModule; +typedef struct _EModuleClass EModuleClass; +typedef struct _EModulePrivate EModulePrivate; + +/** + * EModule: + * + * Contains only private data that should be read and manipulated using the + * functions below. + **/ +struct _EModule { + GTypeModule parent; + EModulePrivate *priv; +}; + +struct _EModuleClass { + GTypeModuleClass parent_class; +}; + +GType e_module_get_type (void); +EModule * e_module_new (const gchar *filename); +const gchar * e_module_get_filename (EModule *module); +GList * e_module_load_all_in_directory (const gchar *dirname); + +G_END_DECLS + +#endif /* E_MODULE_H */ diff --git a/shell/Makefile.am b/shell/Makefile.am index 8fd5896fe3..92262d6477 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -59,9 +59,9 @@ privsolib_LTLIBRARIES = \ eshellincludedir = $(privincludedir)/shell eshellinclude_HEADERS = \ + e-shell-backend.h \ e-shell-common.h \ e-shell-content.h \ - e-shell-module.h \ e-shell-settings.h \ e-shell-sidebar.h \ e-shell-switcher.h \ @@ -73,8 +73,8 @@ eshellinclude_HEADERS = \ libeshell_la_SOURCES = \ $(IDL_GENERATED) \ + e-shell-backend.c \ e-shell-content.c \ - e-shell-module.c \ e-shell-settings.c \ e-shell-sidebar.c \ e-shell-switcher.c \ diff --git a/shell/e-shell-backend.c b/shell/e-shell-backend.c new file mode 100644 index 0000000000..03dfcdc6aa --- /dev/null +++ b/shell/e-shell-backend.c @@ -0,0 +1,426 @@ +/* + * e-shell-backend.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-shell-backend.h" + +#include <errno.h> +#include <glib/gi18n.h> +#include <e-util/e-util.h> + +#include <e-shell.h> + +#define E_SHELL_BACKEND_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SHELL_BACKEND, EShellBackendPrivate)) + +struct _EShellBackendPrivate { + + gpointer shell; /* weak pointer */ + + gchar *config_dir; + gchar *data_dir; + + guint started : 1; +}; + +enum { + PROP_0, + PROP_SHELL +}; + +enum { + ACTIVITY_ADDED, + LAST_SIGNAL +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +shell_backend_set_shell (EShellBackend *shell_backend, + EShell *shell) +{ + g_return_if_fail (shell_backend->priv->shell == NULL); + + shell_backend->priv->shell = shell; + + g_object_add_weak_pointer ( + G_OBJECT (shell_backend), + &shell_backend->priv->shell); +} + +static void +shell_backend_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL: + shell_backend_set_shell ( + E_SHELL_BACKEND (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +shell_backend_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SHELL: + g_value_set_object ( + value, e_shell_backend_get_shell ( + E_SHELL_BACKEND (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +shell_backend_finalize (GObject *object) +{ + EShellBackendPrivate *priv; + + priv = E_SHELL_BACKEND_GET_PRIVATE (object); + + g_free (priv->data_dir); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +shell_backend_class_init (EShellBackendClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EShellBackendPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = shell_backend_set_property; + object_class->get_property = shell_backend_get_property; + object_class->finalize = shell_backend_finalize; + + /** + * EShellBackend:shell + * + * The #EShell singleton. + **/ + g_object_class_install_property ( + object_class, + PROP_SHELL, + g_param_spec_object ( + "shell", + _("Shell"), + _("The EShell singleton"), + E_TYPE_SHELL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + /** + * EShellBackend::activity-added + * @shell_backend: the #EShellBackend that emitted the signal + * @activity: an #EActivity + * + * Broadcasts a newly added activity. + **/ + signals[ACTIVITY_ADDED] = g_signal_new ( + "activity-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_ACTIVITY); +} + +static void +shell_backend_init (EShellBackend *shell_backend, + EShellBackendClass *class) +{ + gchar *dirname; + + shell_backend->priv = E_SHELL_BACKEND_GET_PRIVATE (shell_backend); + + /* Determine the user data directory for this backend. */ + shell_backend->priv->data_dir = g_build_filename ( + g_get_user_data_dir (), class->name, NULL); + + /* Determine the user configuration directory for this backend. */ + shell_backend->priv->config_dir = g_build_filename ( + shell_backend->priv->data_dir, "config", NULL); + + /* Create the user configuration directory for this backend, + * which should also create the user data directory. */ + dirname = shell_backend->priv->config_dir; + if (g_mkdir_with_parents (dirname, 0777) != 0) + g_critical ( + "Cannot create directory %s: %s", + dirname, g_strerror (errno)); +} + +GType +e_shell_backend_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EShellBackendClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) shell_backend_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EShellBackend), + 0, /* n_preallocs */ + (GInstanceInitFunc) shell_backend_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_OBJECT, "EShellBackend", &type_info, 0); + } + + return type; +} + +/** + * e_shell_backend_compare: + * @shell_backend_a: an #EShellBackend + * @shell_backend_b: an #EShellBackend + * + * Using the <structfield>sort_order</structfield> field from both backends' + * #EShellBackendClass, compares @shell_backend_a with @shell_mobule_b and + * returns -1, 0 or +1 if @shell_backend_a is found to be less than, equal + * to or greater than @shell_backend_b, respectively. + * + * Returns: -1, 0 or +1, for a less than, equal to or greater than result + **/ +gint +e_shell_backend_compare (EShellBackend *shell_backend_a, + EShellBackend *shell_backend_b) +{ + gint a = E_SHELL_BACKEND_GET_CLASS (shell_backend_a)->sort_order; + gint b = E_SHELL_BACKEND_GET_CLASS (shell_backend_b)->sort_order; + + return (a < b) ? -1 : (a > b); +} + +/** + * e_shell_backend_get_config_dir: + * @shell_backend: an #EShellBackend + * + * Returns the absolute path to the configuration directory for + * @shell_backend. The string is owned by @shell_backend and should + * not be modified or freed. + * + * Returns: the backend's configuration directory + **/ +const gchar * +e_shell_backend_get_config_dir (EShellBackend *shell_backend) +{ + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL); + g_return_val_if_fail (shell_backend->priv->config_dir != NULL, NULL); + + return shell_backend->priv->config_dir; +} + +/** + * e_shell_backend_get_data_dir: + * @shell_backend: an #EShellBackend + * + * Returns the absolute path to the data directory for @shell_backend. + * The string is owned by @shell_backend and should not be modified or + * freed. + * + * Returns: the backend's data directory + **/ +const gchar * +e_shell_backend_get_data_dir (EShellBackend *shell_backend) +{ + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL); + g_return_val_if_fail (shell_backend->priv->data_dir != NULL, NULL); + + return shell_backend->priv->data_dir; +} + +/** + * e_shell_backend_get_shell: + * @shell_backend: an #EShellBackend + * + * Returns the #EShell singleton. + * + * Returns: the #EShell + **/ +EShell * +e_shell_backend_get_shell (EShellBackend *shell_backend) +{ + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL); + + return E_SHELL (shell_backend->priv->shell); +} + +/** + * e_shell_backend_add_activity: + * @shell_backend: an #EShellBackend + * @activity: an #EActivity + * + * Emits an #EShellBackend::activity-added signal. + **/ +void +e_shell_backend_add_activity (EShellBackend *shell_backend, + EActivity *activity) +{ + g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend)); + g_return_if_fail (E_IS_ACTIVITY (activity)); + + g_signal_emit (shell_backend, signals[ACTIVITY_ADDED], 0, activity); +} + +/** + * e_shell_backend_start: + * @shell_backend: an #EShellBackend + * + * Tells the @shell_backend to begin loading data or running background + * tasks which may consume significant resources. This gets called in + * reponse to the user switching to the corresponding #EShellView for + * the first time. The function is idempotent for each @shell_backend. + **/ +void +e_shell_backend_start (EShellBackend *shell_backend) +{ + EShellBackendClass *class; + + g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend)); + + if (shell_backend->priv->started) + return; + + class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + + if (class->start != NULL) + class->start (shell_backend); + + shell_backend->priv->started = TRUE; +} + +/** + * e_shell_backend_is_busy: + * @shell_backend: an #EShellBackend + * + * Returns %TRUE if @shell_backend is busy and cannot be shutdown at + * present. Each backend must define what "busy" means to them and + * determine an appropriate response. + * + * XXX This function is likely to change or disappear. I'm toying with + * the idea of just having it check whether there are any unfinished + * #EActivity<!-- -->'s left, so we have a consistent and easily + * testable definition of what "busy" means. + * + * Returns: %TRUE if the backend is busy + **/ +gboolean +e_shell_backend_is_busy (EShellBackend *shell_backend) +{ + EShellBackendClass *class; + + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE); + + class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + + if (class->is_busy == NULL) + return FALSE; + + return class->is_busy (shell_backend); +} + +/** + * e_shell_backend_shutdown: + * @shell_backend: an #EShellBackend + * + * Alerts @shell_backend to begin shutdown procedures. If the backend is + * busy and cannot immediately shut down, the function returns %FALSE. + * A %TRUE response implies @shell_backend has successfully shut down. + * + * XXX This function is likely to change or disappear. I'm toying with + * the idea of just having it check whether there are any unfinished + * #EActivity<!-- -->'s left, so we have a consistent and easily + * testable definition of what "busy" means. + * + * Returns: %TRUE if the backend has shut down, %FALSE if the backend is + * busy and cannot immediately shut down + */ +gboolean +e_shell_backend_shutdown (EShellBackend *shell_backend) +{ + EShellBackendClass *class; + + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE); + + class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + + if (class->shutdown == NULL) + return TRUE; + + return class->shutdown (shell_backend); +} + +/** + * e_shell_migrate: + * @shell_backend: an #EShellBackend + * @major: major part of version to migrate from + * @minor: minor part of version to migrate from + * @micro: micro part of version to migrate from + * @error: return location for a #GError, or %NULL + * + * Attempts to migrate data and settings from version %major.%minor.%micro. + * Returns %TRUE if the migration was successful or if no action was + * necessary. Returns %FALSE and sets %error if the migration failed. + * + * Returns: %TRUE if successful, %FALSE otherwise + **/ +gboolean +e_shell_backend_migrate (EShellBackend *shell_backend, + gint major, + gint minor, + gint micro, + GError **error) +{ + EShellBackendClass *class; + + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE); + + class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + + if (class->migrate == NULL) + return TRUE; + + return class->migrate (shell_backend, major, minor, micro, error); +} diff --git a/shell/e-shell-backend.h b/shell/e-shell-backend.h new file mode 100644 index 0000000000..0dfab7a84b --- /dev/null +++ b/shell/e-shell-backend.h @@ -0,0 +1,150 @@ +/* + * e-shell-backend.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/** + * SECTION: e-shell-backend + * @short_description: dynamically loaded capabilities + * @include: shell/e-shell-backend.h + **/ + +#ifndef E_SHELL_BACKEND_H +#define E_SHELL_BACKEND_H + +#include <shell/e-shell-common.h> +#include <widgets/misc/e-activity.h> + +/* Standard GObject macros */ +#define E_TYPE_SHELL_BACKEND \ + (e_shell_backend_get_type ()) +#define E_SHELL_BACKEND(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SHELL_BACKEND, EShellBackend)) +#define E_SHELL_BACKEND_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SHELL_BACKEND, EShellBackendClass)) +#define E_IS_SHELL_BACKEND(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SHELL_BACKEND)) +#define E_IS_SHELL_BACKEND_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SHELL_BACKEND)) +#define E_SHELL_BACKEND_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SHELL_BACKEND, EShellBackendClass)) + +G_BEGIN_DECLS + +/* Avoid including <e-shell.h>, because it includes us! */ +struct _EShell; + +typedef struct _EShellBackend EShellBackend; +typedef struct _EShellBackendClass EShellBackendClass; +typedef struct _EShellBackendPrivate EShellBackendPrivate; + +/** + * EShellBackend: + * + * Contains only private data that should be read and manipulated using the + * functions below. + **/ +struct _EShellBackend { + GObject parent; + EShellBackendPrivate *priv; +}; + +/** + * EShellBackendClass: + * @parent_class: The parent class structure. + * @name: The name of the backend. Also becomes the name of + * the corresponding #EShellView subclass that the + * backend will register. + * @aliases: Colon-separated list of aliases that can be used + * when referring to a backend by name. + * @schemes: Colon-separated list of URI schemes. The #EShell + * will forward command-line URIs to the appropriate + * backend based on this list. + * @sort_order: Used to determine the order of backends listed in + * the main menu and in the switcher. See + * e_shell_backend_compare(). + * @view_type: #GType for the corresponding #EShellView subclass. + * @start: Method for notifying the backend to begin loading + * data and running background tasks. This is called + * just before the first instantiation of the + * corresponding #EShellView subclass. It allows the + * backend to delay initialization steps that consume + * significant resources until they are actually needed. + * @is_busy: Method for querying whether the backend has operations + * in progress that cannot be cancelled or finished + * immediately. Returning %TRUE prevents the application + * from shutting down. + * @shutdown: Method for notifying the backend to begin shutting + * down. Returning %FALSE indicates there are still + * unfinished operations and the #EShell should check + * back shortly. + * @migrate: Method for notifying the backend to migrate data and + * settings from the given version. Returns %TRUE if the + * migration was successful or if no action was necessary. + * Returns %FALSE and sets a #GError if the migration + * failed. + * + * #EShellBackendClass contains a number of important settings for subclasses. + **/ +struct _EShellBackendClass { + GObjectClass parent_class; + + const gchar *name; + const gchar *aliases; + const gchar *schemes; + gint sort_order; + GType view_type; + + /* Methods */ + void (*start) (EShellBackend *shell_backend); + gboolean (*is_busy) (EShellBackend *shell_backend); + gboolean (*shutdown) (EShellBackend *shell_backend); + gboolean (*migrate) (EShellBackend *shell_backend, + gint major, + gint minor, + gint micro, + GError **error); +}; + +GType e_shell_backend_get_type (void); +gint e_shell_backend_compare (EShellBackend *shell_backend_a, + EShellBackend *shell_backend_b); +const gchar * e_shell_backend_get_config_dir (EShellBackend *shell_backend); +const gchar * e_shell_backend_get_data_dir (EShellBackend *shell_backend); +const gchar * e_shell_backend_get_filename (EShellBackend *shell_backend); +struct _EShell *e_shell_backend_get_shell (EShellBackend *shell_backend); +void e_shell_backend_add_activity (EShellBackend *shell_backend, + EActivity *activity); +void e_shell_backend_start (EShellBackend *shell_backend); +gboolean e_shell_backend_is_busy (EShellBackend *shell_backend); +gboolean e_shell_backend_shutdown (EShellBackend *shell_backend); +gboolean e_shell_backend_migrate (EShellBackend *shell_backend, + gint major, + gint minor, + gint micro, + GError **error); + +G_END_DECLS + +#endif /* E_SHELL_BACKEND_H */ diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c index e83bb341ef..ff344ae986 100644 --- a/shell/e-shell-content.c +++ b/shell/e-shell-content.c @@ -27,7 +27,7 @@ #include <widgets/misc/e-action-combo-box.h> #include <widgets/misc/e-icon-entry.h> -#include <e-shell-module.h> +#include <e-shell-backend.h> #include <e-shell-view.h> #include <e-shell-window-actions.h> @@ -209,7 +209,7 @@ shell_content_init_search_context (EShellContent *shell_content) EShellContentClass *shell_content_class; EShellView *shell_view; EShellViewClass *shell_view_class; - EShellModule *shell_module; + EShellBackend *shell_backend; RuleContext *context; FilterRule *rule; FilterPart *part; @@ -217,7 +217,7 @@ shell_content_init_search_context (EShellContent *shell_content) gchar *user_filename; shell_view = e_shell_content_get_shell_view (shell_content); - shell_module = e_shell_view_get_shell_module (shell_view); + shell_backend = e_shell_view_get_shell_backend (shell_view); shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); g_return_if_fail (shell_view_class->search_rules != NULL); @@ -231,9 +231,9 @@ shell_content_init_search_context (EShellContent *shell_content) EVOLUTION_RULEDIR, shell_view_class->search_rules, NULL); /* The filename for custom saved searches is always of - * the form "$(shell_module_data_dir)/searches.xml". */ + * the form "$(shell_backend_data_dir)/searches.xml". */ user_filename = g_build_filename ( - e_shell_module_get_data_dir (shell_module), + e_shell_backend_get_data_dir (shell_backend), "searches.xml", NULL); context = shell_content_class->new_search_context (); diff --git a/shell/e-shell-migrate.c b/shell/e-shell-migrate.c index aa3e1e0f97..b141ba4c7c 100644 --- a/shell/e-shell-migrate.c +++ b/shell/e-shell-migrate.c @@ -53,17 +53,17 @@ shell_migrate_attempt (EShell *shell, gint minor, gint micro) { - GList *modules; + GList *backends; gboolean success = TRUE; - modules = e_shell_get_shell_modules (shell); + backends = e_shell_get_shell_backends (shell); - while (success && modules != NULL) { - EShellModule *shell_module = modules->data; + while (success && backends != NULL) { + EShellBackend *shell_backend = backends->data; GError *error = NULL; - success = e_shell_module_migrate ( - shell_module, major, minor, micro, &error); + success = e_shell_backend_migrate ( + shell_backend, major, minor, micro, &error); if (error != NULL) { gint response; @@ -78,7 +78,7 @@ shell_migrate_attempt (EShell *shell, g_error_free (error); } - modules = g_list_next (modules); + backends = g_list_next (backends); } return success; diff --git a/shell/e-shell-module.c b/shell/e-shell-module.c deleted file mode 100644 index 7e1bba1cec..0000000000 --- a/shell/e-shell-module.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * e-shell-module.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "e-shell-module.h" - -#include <errno.h> -#include <gmodule.h> -#include <glib/gi18n.h> -#include <e-util/e-util.h> - -#include <e-shell.h> - -/* This is the symbol we look for when loading a module. */ -#define INIT_SYMBOL "e_shell_module_init" - -#define E_SHELL_MODULE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_SHELL_MODULE, EShellModulePrivate)) - -struct _EShellModulePrivate { - - /* Set during module initialization. This must - * come first in the struct so EShell can read it. */ - EShellModuleInfo info; - - GModule *module; - gchar *filename; - - gpointer shell; /* weak pointer */ - gchar *config_dir; - gchar *data_dir; - - GType shell_view_type; - GHashTable *events; - - /* Initializes the loaded type module. */ - void (*init) (GTypeModule *type_module); - - guint started : 1; -}; - -enum { - PROP_0, - PROP_FILENAME, - PROP_SHELL -}; - -enum { - ACTIVITY_ADDED, - LAST_SIGNAL -}; - -static gpointer parent_class; -static guint signals[LAST_SIGNAL]; - -static void -shell_module_set_filename (EShellModule *shell_module, - const gchar *filename) -{ - g_return_if_fail (shell_module->priv->filename == NULL); - shell_module->priv->filename = g_strdup (filename); -} - -static void -shell_module_set_shell (EShellModule *shell_module, - EShell *shell) -{ - g_return_if_fail (shell_module->priv->shell == NULL); - - shell_module->priv->shell = shell; - - g_object_add_weak_pointer ( - G_OBJECT (shell_module), - &shell_module->priv->shell); -} - -static void -shell_module_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_FILENAME: - shell_module_set_filename ( - E_SHELL_MODULE (object), - g_value_get_string (value)); - return; - - case PROP_SHELL: - shell_module_set_shell ( - E_SHELL_MODULE (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -shell_module_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_FILENAME: - g_value_set_string ( - value, e_shell_module_get_filename ( - E_SHELL_MODULE (object))); - return; - - case PROP_SHELL: - g_value_set_object ( - value, e_shell_module_get_shell ( - E_SHELL_MODULE (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -shell_module_finalize (GObject *object) -{ - EShellModulePrivate *priv; - - priv = E_SHELL_MODULE_GET_PRIVATE (object); - - g_free (priv->filename); - g_free (priv->data_dir); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -shell_module_load (GTypeModule *type_module) -{ - EShellModulePrivate *priv; - gpointer symbol; - - priv = E_SHELL_MODULE_GET_PRIVATE (type_module); - - g_return_val_if_fail (priv->filename != NULL, FALSE); - priv->module = g_module_open (priv->filename, 0); - - if (priv->module == NULL) - goto fail; - - if (!g_module_symbol (priv->module, INIT_SYMBOL, &symbol)) - goto fail; - - priv->init = symbol; - priv->init (type_module); - - return TRUE; - -fail: - g_warning ("%s", g_module_error ()); - - if (priv->module != NULL) - g_module_close (priv->module); - - return FALSE; -} - -static void -shell_module_unload (GTypeModule *type_module) -{ - EShellModulePrivate *priv; - - priv = E_SHELL_MODULE_GET_PRIVATE (type_module); - - g_module_close (priv->module); - priv->module = NULL; - - priv->init = NULL; -} - -static void -shell_module_class_init (EShellModuleClass *class) -{ - GObjectClass *object_class; - GTypeModuleClass *type_module_class; - - parent_class = g_type_class_peek_parent (class); - g_type_class_add_private (class, sizeof (EShellModulePrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = shell_module_set_property; - object_class->get_property = shell_module_get_property; - object_class->finalize = shell_module_finalize; - - type_module_class = G_TYPE_MODULE_CLASS (class); - type_module_class->load = shell_module_load; - type_module_class->unload = shell_module_unload; - - /** - * EShellModule:filename - * - * The filename of the module. - **/ - g_object_class_install_property ( - object_class, - PROP_FILENAME, - g_param_spec_string ( - "filename", - _("Filename"), - _("The filename of the module"), - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - /** - * EShellModule:shell - * - * The #EShell singleton. - **/ - g_object_class_install_property ( - object_class, - PROP_SHELL, - g_param_spec_object ( - "shell", - _("Shell"), - _("The EShell singleton"), - E_TYPE_SHELL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - /** - * EShellModule::activity-added - * @shell_module: the #EShellModule that emitted the signal - * @activity: an #EActivity - * - * Broadcasts a newly added activity. - **/ - signals[ACTIVITY_ADDED] = g_signal_new ( - "activity-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_ACTIVITY); -} - -static void -shell_module_init (EShellModule *shell_module) -{ - shell_module->priv = E_SHELL_MODULE_GET_PRIVATE (shell_module); -} - -GType -e_shell_module_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - const GTypeInfo type_info = { - sizeof (EShellModuleClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) shell_module_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EShellModule), - 0, /* n_preallocs */ - (GInstanceInitFunc) shell_module_init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - G_TYPE_TYPE_MODULE, "EShellModule", &type_info, 0); - } - - return type; -} - -/** - * e_shell_module_new: - * @shell: an #EShell - * @filename: the name of the file containing the shell module - * - * Loads @filename as a #GTypeModule and tries to invoke a module - * function named <function>e_shell_module_init</function>, passing - * the newly loaded #GTypeModule as an argument. The shell module is - * responsible for defining such a function to perform the appropriate - * initialization steps. - * - * Returns: a new #EShellModule - **/ -EShellModule * -e_shell_module_new (EShell *shell, - const gchar *filename) -{ - g_return_val_if_fail (filename != NULL, NULL); - - return g_object_new ( - E_TYPE_SHELL_MODULE, "shell", shell, - "filename", filename, NULL); -} - -/** - * e_shell_module_compare: - * @shell_module_a: an #EShellModule - * @shell_module_b: an #EShellModule - * - * Using the <structfield>sort_order</structfield> field from both modules' - * #EShellModuleInfo, compares @shell_module_a with @shell_mobule_b and - * returns -1, 0 or +1 if @shell_module_a is found to be less than, equal - * to or greater than @shell_module_b, respectively. - * - * Returns: -1, 0 or +1, for a less than, equal to or greater than result - **/ -gint -e_shell_module_compare (EShellModule *shell_module_a, - EShellModule *shell_module_b) -{ - gint a = shell_module_a->priv->info.sort_order; - gint b = shell_module_b->priv->info.sort_order; - - return (a < b) ? -1 : (a > b); -} - -/** - * e_shell_module_get_config_dir: - * @shell_module: an #EShellModule - * - * Returns the absolute path to the configuration directory for - * @shell_module. The string is owned by @shell_module and should - * not be modified or freed. - * - * Returns: the module's configuration directory - **/ -const gchar * -e_shell_module_get_config_dir (EShellModule *shell_module) -{ - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), NULL); - g_return_val_if_fail (shell_module->priv->config_dir != NULL, NULL); - - return shell_module->priv->config_dir; -} - -/** - * e_shell_module_get_data_dir: - * @shell_module: an #EShellModule - * - * Returns the absolute path to the data directory for @shell_module. - * The string is owned by @shell_module and should not be modified or - * freed. - * - * Returns: the module's data directory - **/ -const gchar * -e_shell_module_get_data_dir (EShellModule *shell_module) -{ - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), NULL); - g_return_val_if_fail (shell_module->priv->data_dir != NULL, NULL); - - return shell_module->priv->data_dir; -} - -/** - * e_shell_module_get_filename: - * @shell_module: an #EShellModule - * - * Returns the name of the file from which @shell_module was loaded. - * The string is owned by @shell_module and should not be modified or - * freed. - * - * Returns: the module's file name - **/ -const gchar * -e_shell_module_get_filename (EShellModule *shell_module) -{ - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), NULL); - - return shell_module->priv->filename; -} - -/** - * e_shell_module_get_shell: - * @shell_module: an #EShellModule - * - * Returns the #EShell that was passed to e_shell_module_new(). - * - * Returns: the #EShell - **/ -EShell * -e_shell_module_get_shell (EShellModule *shell_module) -{ - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), NULL); - - return E_SHELL (shell_module->priv->shell); -} - -/** - * e_shell_module_get_shell_view_type: - * @shell_module: an #EShellModule - * - * Returns the #GType of the #EShellView subclass for @shell_module. - * - * Returns: the #GType of an #EShellView subclass - **/ -GType -e_shell_module_get_shell_view_type (EShellModule *shell_module) -{ - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), 0); - - return shell_module->priv->shell_view_type; -} - -/** - * e_shell_module_add_activity: - * @shell_module: an #EShellModule - * @activity: an #EActivity - * - * Emits an #EShellModule::activity-added signal. - **/ -void -e_shell_module_add_activity (EShellModule *shell_module, - EActivity *activity) -{ - g_return_if_fail (E_IS_SHELL_MODULE (shell_module)); - g_return_if_fail (E_IS_ACTIVITY (activity)); - - g_signal_emit (shell_module, signals[ACTIVITY_ADDED], 0, activity); -} - -/** - * e_shell_module_start: - * @shell_module: an #EShellModule - * - * Tells the @shell_module to begin loading data or running background - * tasks which may consume significant resources. This gets called in - * reponse to the user switching to the corresponding #EShellView for - * the first time. The function is idempotent for each @shell_module. - **/ -void -e_shell_module_start (EShellModule *shell_module) -{ - EShellModuleInfo *module_info; - - g_return_if_fail (E_IS_SHELL_MODULE (shell_module)); - - module_info = &shell_module->priv->info; - - if (module_info->start != NULL && !shell_module->priv->started) - module_info->start (shell_module); - - shell_module->priv->started = TRUE; -} - -/** - * e_shell_module_is_busy: - * @shell_module: an #EShellModule - * - * Returns %TRUE if @shell_module is busy and cannot be shutdown at - * present. Each module must define what "busy" means to them and - * determine an appropriate response. - * - * XXX This function is likely to change or disappear. I'm toying with - * the idea of just having it check whether there are any unfinished - * #EActivity<!-- -->'s left, so we have a consistent and easily - * testable definition of what "busy" means. - * - * Returns: %TRUE if the module is busy - **/ -gboolean -e_shell_module_is_busy (EShellModule *shell_module) -{ - EShellModuleInfo *module_info; - - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), FALSE); - - module_info = &shell_module->priv->info; - - if (module_info->is_busy != NULL) - return module_info->is_busy (shell_module); - - return FALSE; -} - -/** - * e_shell_module_shutdown: - * @shell_module: an #EShellModule - * - * Alerts @shell_module to begin shutdown procedures. If the module is - * busy and cannot immediately shut down, the function returns %FALSE. - * A %TRUE response implies @shell_module has successfully shut down. - * - * XXX This function is likely to change or disappear. I'm toying with - * the idea of just having it check whether there are any unfinished - * #EActivity<!-- -->'s left, so we have a consistent and easily - * testable definition of what "busy" means. - * - * Returns: %TRUE if the module has shut down, %FALSE if the module is - * busy and cannot immediately shut down - */ -gboolean -e_shell_module_shutdown (EShellModule *shell_module) -{ - EShellModuleInfo *module_info; - - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), TRUE); - - module_info = &shell_module->priv->info; - - if (module_info->shutdown != NULL) - return module_info->shutdown (shell_module); - - return TRUE; -} - -/** - * e_shell_migrate: - * @shell_module: an #EShellModule - * @major: major part of version to migrate from - * @minor: minor part of version to migrate from - * @micro: micro part of version to migrate from - * @error: return location for a #GError, or %NULL - * - * Attempts to migrate data and settings from version %major.%minor.%micro. - * Returns %TRUE if the migration was successful or if no action was - * necessary. Returns %FALSE and sets %error if the migration failed. - * - * Returns: %TRUE if successful, %FALSE otherwise - **/ -gboolean -e_shell_module_migrate (EShellModule *shell_module, - gint major, - gint minor, - gint micro, - GError **error) -{ - EShellModuleInfo *module_info; - - g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), TRUE); - - module_info = &shell_module->priv->info; - - if (module_info->migrate != NULL) - return module_info->migrate ( - shell_module, major, minor, micro, error); - - return TRUE; -} - -/** - * e_shell_module_set_info: - * @shell_module: an #EShellModule - * @info: an #EShellModuleInfo - * @shell_view_type: the #GType of a #EShellView subclass - * - * Registers basic configuration information about @shell_module that - * the #EShell can use for processing command-line arguments. - * - * Configuration information should be registered from - * @shell_module<!-- -->'s <function>e_shell_module_init</function> - * initialization function. See e_shell_module_new() for more information. - **/ -void -e_shell_module_set_info (EShellModule *shell_module, - const EShellModuleInfo *info, - GType shell_view_type) -{ - GTypeModule *type_module; - EShellModuleInfo *module_info; - const gchar *pathname; - - g_return_if_fail (E_IS_SHELL_MODULE (shell_module)); - g_return_if_fail (info != NULL); - - type_module = G_TYPE_MODULE (shell_module); - module_info = &shell_module->priv->info; - - /* A module name is required. */ - g_return_if_fail (info->name != NULL); - module_info->name = g_intern_string (info->name); - g_type_module_set_name (type_module, module_info->name); - - module_info->aliases = g_intern_string (info->aliases); - module_info->schemes = g_intern_string (info->schemes); - module_info->sort_order = info->sort_order; - - module_info->start = info->start; - module_info->is_busy = info->is_busy; - module_info->shutdown = info->shutdown; - module_info->migrate = info->migrate; - - /* Determine the user data directory for this module. */ - g_free (shell_module->priv->data_dir); - shell_module->priv->data_dir = g_build_filename ( - e_get_user_data_dir (), module_info->name, NULL); - - /* Determine the user configuration directory for this module. */ - g_free (shell_module->priv->config_dir); - shell_module->priv->config_dir = g_build_filename ( - shell_module->priv->data_dir, "config", NULL); - - /* Create the user configuration directory for this module, - * which should also create the user data directory. */ - pathname = shell_module->priv->config_dir; - if (g_mkdir_with_parents (pathname, 0777) != 0) - g_critical ( - "Cannot create directory %s: %s", - pathname, g_strerror (errno)); - - shell_module->priv->shell_view_type = shell_view_type; -} diff --git a/shell/e-shell-module.h b/shell/e-shell-module.h deleted file mode 100644 index 9032823bc2..0000000000 --- a/shell/e-shell-module.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * e-shell-module.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/** - * SECTION: e-shell-module - * @short_description: dynamically loaded capabilities - * @include: shell/e-shell-module.h - **/ - -#ifndef E_SHELL_MODULE_H -#define E_SHELL_MODULE_H - -#include <shell/e-shell-common.h> -#include <widgets/misc/e-activity.h> - -/* Standard GObject macros */ -#define E_TYPE_SHELL_MODULE \ - (e_shell_module_get_type ()) -#define E_SHELL_MODULE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_SHELL_MODULE, EShellModule)) -#define E_SHELL_MODULE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_SHELL_MODULE, EShellModuleClass)) -#define E_IS_SHELL_MODULE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_SHELL_MODULE)) -#define E_IS_SHELL_MODULE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_SHELL_MODULE)) -#define E_SHELL_MODULE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_SHELL_MODULE, EShellModuleClass)) - -G_BEGIN_DECLS - -/* Avoid including <e-shell.h>, because it includes us! */ -struct _EShell; - -typedef struct _EShellModule EShellModule; -typedef struct _EShellModuleInfo EShellModuleInfo; -typedef struct _EShellModuleClass EShellModuleClass; -typedef struct _EShellModulePrivate EShellModulePrivate; - -/** - * EShellModuleInfo: - * @name: The name of the module. Also becomes the name of - * the corresponding #EShellView subclass that the - * module will register. - * @aliases: Colon-separated list of aliases that can be used - * when referring to a module by name. - * @schemes: Colon-separated list of URI schemes. The #EShell - * will forward command-line URIs to the appropriate - * module based on this list. - * @sort_order: Used to determine the order of modules listed in - * the main menu and in the switcher. See - * e_shell_module_compare(). - * @start: Callback for notifying the module to begin loading data - * and running background tasks. This is called just before - * the first instantiation of the corresponding #EShellView - * subclass. It allows the module to delay initialization - * steps that consume significant resources until they are - * actually needed. - * @is_busy: Callback for querying whether the module has - * operations in progress that cannot be cancelled - * or finished immediately. Returning %TRUE prevents - * the application from shutting down. - * @shutdown: Callback for notifying the module to begin - * shutting down. Returning %FALSE indicates there - * are still unfinished operations and the #EShell - * should check back shortly. - * @migrate: Callback for notifying the module to migrate data and - * settings from the given version. Returns %TRUE if the - * migration was successful or if no action was necessary. - * Returns %FALSE and sets a #GError if the migration failed. - * - * Provides basic information about an #EShellModule instance. Shell - * modules should pass this structure to e_shell_module_set_info() in - * their "e_shell_module_init" functions. - **/ -struct _EShellModuleInfo { - const gchar *name; - const gchar *aliases; - const gchar *schemes; - gint sort_order; - - void (*start) (EShellModule *shell_module); - gboolean (*is_busy) (EShellModule *shell_module); - gboolean (*shutdown) (EShellModule *shell_module); - gboolean (*migrate) (EShellModule *shell_module, - gint major, - gint minor, - gint micro, - GError **error); -}; - -/** - * EShellModule: - * - * Contains only private data that should be read and manipulated using the - * functions below. - **/ -struct _EShellModule { - GTypeModule parent; - EShellModulePrivate *priv; -}; - -struct _EShellModuleClass { - GTypeModuleClass parent_class; -}; - -GType e_shell_module_get_type (void); -EShellModule * e_shell_module_new (struct _EShell *shell, - const gchar *filename); -gint e_shell_module_compare (EShellModule *shell_module_a, - EShellModule *shell_module_b); -const gchar * e_shell_module_get_config_dir (EShellModule *shell_module); -const gchar * e_shell_module_get_data_dir (EShellModule *shell_module); -const gchar * e_shell_module_get_filename (EShellModule *shell_module); -struct _EShell *e_shell_module_get_shell (EShellModule *shell_module); -GType e_shell_module_get_shell_view_type - (EShellModule *shell_module); -void e_shell_module_add_activity (EShellModule *shell_module, - EActivity *activity); -void e_shell_module_start (EShellModule *shell_module); -gboolean e_shell_module_is_busy (EShellModule *shell_module); -gboolean e_shell_module_shutdown (EShellModule *shell_module); -gboolean e_shell_module_migrate (EShellModule *shell_module, - gint major, - gint minor, - gint micro, - GError **error); -void e_shell_module_set_info (EShellModule *shell_module, - const EShellModuleInfo *info, - GType shell_view_type); - -G_END_DECLS - -#endif /* E_SHELL_MODULE_H */ diff --git a/shell/e-shell-settings.c b/shell/e-shell-settings.c index 23dd866bf8..9f03f38ce1 100644 --- a/shell/e-shell-settings.c +++ b/shell/e-shell-settings.c @@ -176,7 +176,7 @@ e_shell_settings_get_type (void) * @pspec: a #GParamSpec * * Installs a new class property for #EShellSettings. This is usually - * done during initialization of a #EShellModule or plugin, followed by + * done during initialization of a #EShellBackend or plugin, followed by * a call to e_shell_settings_bind_to_gconf() to bind the property to a * GConf key. **/ diff --git a/shell/e-shell-switcher.c b/shell/e-shell-switcher.c index e29fa1cb89..2980bd983d 100644 --- a/shell/e-shell-switcher.c +++ b/shell/e-shell-switcher.c @@ -558,7 +558,7 @@ e_shell_switcher_new (void) * appear in the order they were added. * * #EShellWindow adds switcher actions in the order given by the - * <structfield>sort_order</structfield> field in #EShellModuleInfo. + * <structfield>sort_order</structfield> field in #EShellBackendClass. **/ void e_shell_switcher_add_action (EShellSwitcher *switcher, diff --git a/shell/e-shell-taskbar.c b/shell/e-shell-taskbar.c index 9b9978d65e..c81f40827b 100644 --- a/shell/e-shell-taskbar.c +++ b/shell/e-shell-taskbar.c @@ -199,15 +199,15 @@ static void shell_taskbar_constructed (GObject *object) { EShellView *shell_view; - EShellModule *shell_module; + EShellBackend *shell_backend; EShellTaskbar *shell_taskbar; shell_taskbar = E_SHELL_TASKBAR (object); shell_view = e_shell_taskbar_get_shell_view (shell_taskbar); - shell_module = e_shell_view_get_shell_module (shell_view); + shell_backend = e_shell_view_get_shell_backend (shell_view); g_signal_connect_swapped ( - shell_module, "activity-added", + shell_backend, "activity-added", G_CALLBACK (shell_taskbar_activity_add), shell_taskbar); } diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index d7a564c567..454e517f90 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -27,11 +27,6 @@ #include "e-util/e-util.h" #include "e-util/e-plugin-ui.h" -#include "e-shell-content.h" -#include "e-shell-module.h" -#include "e-shell-sidebar.h" -#include "e-shell-taskbar.h" -#include "e-shell-window.h" #include "e-shell-window-actions.h" #define E_SHELL_VIEW_GET_PRIVATE(obj) \ @@ -40,6 +35,7 @@ struct _EShellViewPrivate { + gpointer shell_backend; /* weak pointer */ gpointer shell_window; /* weak pointer */ gchar *title; @@ -59,8 +55,8 @@ enum { PROP_ACTION, PROP_PAGE_NUM, PROP_TITLE, + PROP_SHELL_BACKEND, PROP_SHELL_CONTENT, - PROP_SHELL_MODULE, PROP_SHELL_SIDEBAR, PROP_SHELL_TASKBAR, PROP_SHELL_WINDOW, @@ -77,31 +73,36 @@ static gpointer parent_class; static gulong signals[LAST_SIGNAL]; static void -shell_view_init_view_collection (EShellViewClass *class) +shell_view_init_view_collection (EShellView *shell_view) { - EShellModule *shell_module; + EShellViewClass *view_class; + EShellBackendClass *backend_class; + EShellBackend *shell_backend; const gchar *base_dir; - const gchar *module_name; + const gchar *backend_name; gchar *system_dir; gchar *local_dir; - shell_module = E_SHELL_MODULE (class->type_module); - module_name = class->type_module->name; + view_class = E_SHELL_VIEW_GET_CLASS (shell_view); + + shell_backend = e_shell_view_get_shell_backend (shell_view); + backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + backend_name = backend_class->name; base_dir = EVOLUTION_GALVIEWSDIR; - system_dir = g_build_filename (base_dir, module_name, NULL); + system_dir = g_build_filename (base_dir, backend_name, NULL); - base_dir = e_shell_module_get_data_dir (shell_module); + base_dir = e_shell_backend_get_data_dir (shell_backend); local_dir = g_build_filename (base_dir, "views", NULL); /* The view collection is never destroyed. */ - class->view_collection = gal_view_collection_new (); + view_class->view_collection = gal_view_collection_new (); gal_view_collection_set_title ( - class->view_collection, class->label); + view_class->view_collection, view_class->label); gal_view_collection_set_storage_directories ( - class->view_collection, system_dir, local_dir); + view_class->view_collection, system_dir, local_dir); g_free (system_dir); g_free (local_dir); @@ -147,6 +148,19 @@ shell_view_set_action (EShellView *shell_view, } static void +shell_view_set_shell_backend (EShellView *shell_view, + EShellBackend *shell_backend) +{ + g_return_if_fail (shell_view->priv->shell_backend == NULL); + + shell_view->priv->shell_backend = shell_backend; + + g_object_add_weak_pointer ( + G_OBJECT (shell_backend), + &shell_view->priv->shell_backend); +} + +static void shell_view_set_shell_window (EShellView *shell_view, GtkWidget *shell_window) { @@ -184,6 +198,12 @@ shell_view_set_property (GObject *object, g_value_get_string (value)); return; + case PROP_SHELL_BACKEND: + shell_view_set_shell_backend ( + E_SHELL_VIEW (object), + g_value_get_object (value)); + return; + case PROP_SHELL_WINDOW: shell_view_set_shell_window ( E_SHELL_VIEW (object), @@ -225,16 +245,16 @@ shell_view_get_property (GObject *object, E_SHELL_VIEW (object))); return; - case PROP_SHELL_CONTENT: + case PROP_SHELL_BACKEND: g_value_set_object ( - value, e_shell_view_get_shell_content ( + value, e_shell_view_get_shell_backend ( E_SHELL_VIEW (object))); - return; - case PROP_SHELL_MODULE: + case PROP_SHELL_CONTENT: g_value_set_object ( - value, e_shell_view_get_shell_module ( + value, e_shell_view_get_shell_content ( E_SHELL_VIEW (object))); + return; case PROP_SHELL_SIDEBAR: g_value_set_object ( @@ -271,6 +291,12 @@ shell_view_dispose (GObject *object) priv = E_SHELL_VIEW_GET_PRIVATE (object); + if (priv->shell_backend != NULL) { + g_object_remove_weak_pointer ( + G_OBJECT (priv->shell_backend), &priv->shell_backend); + priv->shell_backend = NULL; + } + if (priv->shell_window != NULL) { g_object_remove_weak_pointer ( G_OBJECT (priv->shell_window), &priv->shell_window); @@ -328,6 +354,9 @@ shell_view_constructed (GObject *object) shell_view = E_SHELL_VIEW (object); class = E_SHELL_VIEW_GET_CLASS (object); + if (class->view_collection == NULL) + shell_view_init_view_collection (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); ui_manager = e_shell_window_get_ui_manager (shell_window); id = class->ui_manager_id; @@ -450,6 +479,22 @@ shell_view_class_init (EShellViewClass *class) G_PARAM_READWRITE)); /** + * EShellView::shell-backend + * + * The #EShellBackend for this shell view. + **/ + g_object_class_install_property ( + object_class, + PROP_SHELL_BACKEND, + g_param_spec_object ( + "shell-backend", + _("Shell Backend"), + _("The EShellBackend for this shell view"), + E_TYPE_SHELL_BACKEND, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + /** * EShellView:shell-content * * The content widget appears in an #EShellWindow<!-- -->'s @@ -467,21 +512,6 @@ shell_view_class_init (EShellViewClass *class) G_PARAM_READABLE)); /** - * EShellView::shell-module - * - * The #EShellModule for this shell view. - **/ - g_object_class_install_property ( - object_class, - PROP_SHELL_MODULE, - g_param_spec_object ( - "shell-module", - _("Shell Module"), - _("The EShellModule for this shell view"), - E_TYPE_SHELL_MODULE, - G_PARAM_READABLE)); - - /** * EShellView:shell-sidebar * * The sidebar widget appears in an #EShellWindow<!-- -->'s @@ -591,8 +621,7 @@ shell_view_class_init (EShellViewClass *class) } static void -shell_view_init (EShellView *shell_view, - EShellViewClass *class) +shell_view_init (EShellView *shell_view) { GtkSizeGroup *size_group; @@ -600,9 +629,6 @@ shell_view_init (EShellView *shell_view, shell_view->priv = E_SHELL_VIEW_GET_PRIVATE (shell_view); shell_view->priv->size_group = size_group; - - if (class->view_collection == NULL) - shell_view_init_view_collection (class); } GType @@ -637,8 +663,8 @@ e_shell_view_get_type (void) * @shell_view: an #EShellView * * Returns the view name for @shell_view, which is also the name of - * the corresponding #EShellModule (see the <structfield>name</structfield> - * field in #EShellModuleInfo). + * the corresponding #EShellBackend (see the <structfield>name</structfield> + * field in #EShellBackendInfo). * * Returns: the view name for @shell_view **/ @@ -786,30 +812,6 @@ e_shell_view_get_shell_window (EShellView *shell_view) } /** - * e_shell_view_get_shell_module: - * @shell_view: an #EShellView - * - * Returns the corresponding #EShellModule for @shell_view. - * - * Returns: the corresponding #EShellModule for @shell_view - **/ -EShellModule * -e_shell_view_get_shell_module (EShellView *shell_view) -{ - EShellViewClass *class; - - g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - - /* Calling this function during the shell view's instance - * initialization function will return the wrong result, - * so watch for that and emit a warning. */ - class = E_SHELL_VIEW_GET_CLASS (shell_view); - g_return_val_if_fail (E_IS_SHELL_VIEW_CLASS (class), NULL); - - return E_SHELL_MODULE (class->type_module); -} - -/** * e_shell_view_is_active: * @shell_view: an #EShellView * @@ -891,6 +893,22 @@ e_shell_view_get_size_group (EShellView *shell_view) } /** + * e_shell_view_get_shell_backend: + * @shell_view: an #EShellView + * + * Returns the corresponding #EShellBackend for @shell_view. + * + * Returns: the corresponding #EShellBackend for @shell_view + **/ +EShellBackend * +e_shell_view_get_shell_backend (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return E_SHELL_BACKEND (shell_view->priv->shell_backend); +} + +/** * e_shell_view_get_shell_content: * @shell_view: an #EShellView * diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h index 1392acfa0a..66a72325fb 100644 --- a/shell/e-shell-view.h +++ b/shell/e-shell-view.h @@ -29,8 +29,8 @@ #define E_SHELL_VIEW_H #include <shell/e-shell-common.h> +#include <shell/e-shell-backend.h> #include <shell/e-shell-content.h> -#include <shell/e-shell-module.h> #include <shell/e-shell-sidebar.h> #include <shell/e-shell-taskbar.h> #include <shell/e-shell-window.h> @@ -95,12 +95,6 @@ struct _EShellView { * search rules for this shell view. The XML files * are usually named something like <filename> * <emphasis>view</emphasis>types.xml</filename>. - * @type_module: The corresponding #GTypeModule for this shell - * view. Subclasses are responsible for setting - * this. An easy way do so is to pass it to the - * shell view's #GClassInitFunc via the - * <structfield>class_data</structfield> field in - * #GTypeInfo. * @view_collection: A unique #GalViewCollection instance is created * for each subclass and shared across all instances * of that subclass. That much is done automatically @@ -142,10 +136,6 @@ struct _EShellViewClass { /* Base name of the search rule definition file. */ const gchar *search_rules; - /* Subclasses should set this via the "class_data" field in - * the GTypeInfo they pass to g_type_module_register_type(). */ - GTypeModule *type_module; - /* A unique instance is created for each subclass. */ GalViewCollection *view_collection; @@ -173,11 +163,11 @@ gint e_shell_view_get_page_num (EShellView *shell_view); void e_shell_view_set_page_num (EShellView *shell_view, gint page_num); GtkSizeGroup * e_shell_view_get_size_group (EShellView *shell_view); +EShellBackend * e_shell_view_get_shell_backend (EShellView *shell_view); EShellContent * e_shell_view_get_shell_content (EShellView *shell_view); EShellSidebar * e_shell_view_get_shell_sidebar (EShellView *shell_view); EShellTaskbar * e_shell_view_get_shell_taskbar (EShellView *shell_view); EShellWindow * e_shell_view_get_shell_window (EShellView *shell_view); -EShellModule * e_shell_view_get_shell_module (EShellView *shell_view); void e_shell_view_update_actions (EShellView *shell_view); void e_shell_view_show_popup_menu (EShellView *shell_view, const gchar *widget_path, diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c index 3577e5b9bc..9c8c8d46df 100644 --- a/shell/e-shell-window-actions.c +++ b/shell/e-shell-window-actions.c @@ -1781,12 +1781,12 @@ shell_window_extract_actions (EShellWindow *shell_window, */ for (iter = *source_list; iter != NULL; iter = iter->next) { GtkAction *action = iter->data; - const gchar *module_name; + const gchar *backend_name; - module_name = g_object_get_data ( - G_OBJECT (action), "module-name"); + backend_name = g_object_get_data ( + G_OBJECT (action), "backend-name"); - if (strcmp (module_name, current_view) != 0) + if (strcmp (backend_name, current_view) != 0) continue; if (g_object_get_data (G_OBJECT (action), "primary")) @@ -1952,7 +1952,7 @@ e_shell_window_create_switcher_actions (EShellWindow *shell_window) ui_manager = e_shell_window_get_ui_manager (shell_window); merge_id = gtk_ui_manager_new_merge_id (ui_manager); shell = e_shell_window_get_shell (shell_window); - list = e_shell_get_shell_modules (shell); + list = e_shell_get_shell_backends (shell); /* Construct a group of radio actions from the various EShellView * subclasses and register them with the EShellSwitcher. These @@ -1964,7 +1964,7 @@ e_shell_window_create_switcher_actions (EShellWindow *shell_window) group = gtk_radio_action_get_group (action); for (iter = list; iter != NULL; iter = iter->next) { - EShellModule *shell_module = iter->data; + EShellBackend *shell_backend = iter->data; EShellViewClass *class; GType type; const gchar *view_name; @@ -1972,7 +1972,9 @@ e_shell_window_create_switcher_actions (EShellWindow *shell_window) gchar *action_name; gchar *tooltip; - type = e_shell_module_get_shell_view_type (shell_module); + /* The backend name is also the view name. */ + view_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name; + type = E_SHELL_BACKEND_GET_CLASS (shell_backend)->view_type; if (!g_type_is_a (type, E_TYPE_SHELL_VIEW)) { g_critical ( @@ -1991,14 +1993,6 @@ e_shell_window_create_switcher_actions (EShellWindow *shell_window) continue; } - if (class->type_module == NULL) { - g_critical ( - "Module member not set on %s", - G_OBJECT_CLASS_NAME (class)); - continue; - } - - view_name = class->type_module->name; action_name = g_strdup_printf (SWITCHER_FORMAT, view_name); tooltip = g_strdup_printf (_("Switch to %s"), class->label); diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c index c054d6a8a0..5fdd2467bc 100644 --- a/shell/e-shell-window.c +++ b/shell/e-shell-window.c @@ -39,41 +39,40 @@ enum { static gpointer parent_class; static EShellView * -shell_window_new_view (EShellWindow *shell_window, - GType shell_view_type, - const gchar *view_name, - const gchar *title) +shell_window_new_view (EShellBackend *shell_backend, + EShellWindow *shell_window) { GHashTable *loaded_views; - EShell *shell; - EShellModule *shell_module; EShellView *shell_view; GtkNotebook *notebook; GtkAction *action; GtkWidget *widget; + const gchar *name; gint page_num; + GType type; - /* First off, start the shell module. */ - shell = e_shell_window_get_shell (shell_window); - shell_module = e_shell_get_module_by_name (shell, view_name); - e_shell_module_start (shell_module); + name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name; + type = E_SHELL_BACKEND_GET_CLASS (shell_backend)->view_type; + + /* First off, start the shell backend. */ + e_shell_backend_start (shell_backend); /* Determine the page number for the new shell view. */ notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook); page_num = gtk_notebook_get_n_pages (notebook); /* Get the switcher action for this view. */ - action = e_shell_window_get_shell_view_action ( - shell_window, view_name); + action = e_shell_window_get_shell_view_action (shell_window, name); /* Create the shell view. */ shell_view = g_object_new ( - shell_view_type, "action", action, "page-num", - page_num, "shell-window", shell_window, NULL); + type, "action", action, "page-num", page_num, + "shell-backend", shell_backend, "shell-window", + shell_window, NULL); /* Register the shell view. */ loaded_views = shell_window->priv->loaded_views; - g_hash_table_insert (loaded_views, g_strdup (view_name), shell_view); + g_hash_table_insert (loaded_views, g_strdup (name), shell_view); /* Add pages to the various shell window notebooks. */ @@ -432,7 +431,7 @@ e_shell_window_get_shell (EShellWindow *shell_window) * @view_name: name of a shell view * * Returns the #EShellView named @view_name (see the - * <structfield>name</structfield> field in #EShellModuleInfo). This + * <structfield>name</structfield> field in #EShellBackendInfo). This * will also instantiate the #EShellView the first time it's requested. * To reduce resource consumption, Evolution tries to delay instantiating * shell views until the user switches to them. So in general, only the @@ -446,10 +445,10 @@ EShellView * e_shell_window_get_shell_view (EShellWindow *shell_window, const gchar *view_name) { - GHashTable *loaded_views; + EShell *shell; EShellView *shell_view; - GType *children; - guint n_children, ii; + EShellBackend *shell_backend; + GHashTable *loaded_views; g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); g_return_val_if_fail (view_name != NULL, NULL); @@ -460,33 +459,15 @@ e_shell_window_get_shell_view (EShellWindow *shell_window, if (shell_view != NULL) return shell_view; - children = g_type_children (E_TYPE_SHELL_VIEW, &n_children); - - for (ii = 0; ii < n_children && shell_view == NULL; ii++) { - GType shell_view_type = children[ii]; - EShellViewClass *class; - - class = g_type_class_ref (shell_view_type); - - if (class->type_module == NULL) { - g_critical ( - "Module member not set on %s", - G_OBJECT_CLASS_NAME (class)); - continue; - } - - if (strcmp (view_name, class->type_module->name) == 0) - shell_view = shell_window_new_view ( - shell_window, shell_view_type, - view_name, class->label); - - g_type_class_unref (class); - } + shell = e_shell_window_get_shell (shell_window); + shell_backend = e_shell_get_backend_by_name (shell, view_name); - if (shell_view == NULL) + if (shell_backend == NULL) { g_critical ("Unknown shell view name: %s", view_name); + return NULL; + } - return shell_view; + return shell_window_new_view (shell_backend, shell_window); } /** @@ -741,17 +722,17 @@ e_shell_window_add_action_group (EShellWindow *shell_window, /** * e_shell_window_register_new_item_actions: * @shell_window: an #EShellWindow - * @module_name: name of an #EShellModule + * @backend_name: name of an #EShellBackend * @entries: an array of #GtkActionEntry<!-- -->s * @n_entries: number of elements in the array * * Registers a list of #GtkAction<!-- -->s to appear in * @shell_window<!-- -->'s "New" menu and toolbar button. This * function should be called from an #EShell<!-- -->'s - * #EShell::window-created signal handler. The #EShellModule calling - * this function should pass its own name for the @module_name argument + * #EShell::window-created signal handler. The #EShellBackend calling + * this function should pass its own name for the @backend_name argument * (i.e. the <structfield>name</structfield> field from its own - * #EShellModuleInfo). + * #EShellBackendInfo). * * The registered #GtkAction<!-- -->s should be for creating individual * items such as an email message or a calendar appointment. The action @@ -760,7 +741,7 @@ e_shell_window_add_action_group (EShellWindow *shell_window, **/ void e_shell_window_register_new_item_actions (EShellWindow *shell_window, - const gchar *module_name, + const gchar *backend_name, GtkActionEntry *entries, guint n_entries) { @@ -770,13 +751,13 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, guint ii; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - g_return_if_fail (module_name != NULL); + g_return_if_fail (backend_name != NULL); g_return_if_fail (entries != NULL); action_group = ACTION_GROUP (NEW_ITEM); ui_manager = e_shell_window_get_ui_manager (shell_window); accel_group = gtk_ui_manager_get_accel_group (ui_manager); - module_name = g_intern_string (module_name); + backend_name = g_intern_string (backend_name); /* XXX The action label translations are retrieved from the * message context "New", but gtk_action_group_add_actions() @@ -794,7 +775,7 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, gtk_action_group_add_actions ( action_group, entries, n_entries, shell_window); - /* Tag each action with the name of the shell module that + /* Tag each action with the name of the shell backend that * registered it. This is used to help sort actions in the * "New" menu. */ @@ -811,11 +792,11 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, g_object_set_data ( G_OBJECT (action), - "module-name", (gpointer) module_name); + "backend-name", (gpointer) backend_name); /* The first action becomes the first item in the "New" * menu, and consequently its icon is shown in the "New" - * button when the shell module's view is active. This + * button when the shell backend's view is active. This * is all sorted out in shell_window_extract_actions(). * Note, the data value just needs to be non-zero. */ if (ii == 0) @@ -830,17 +811,17 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, /** * e_shell_window_register_new_source_actions: * @shell_window: an #EShellWindow - * @module_name: name of an #EShellModule + * @backend_name: name of an #EShellBackend * @entries: an array of #GtkActionEntry<!-- -->s * @n_entries: number of elements in the array * * Registers a list of #GtkAction<!-- -->s to appear in * @shell_window<!-- -->'s "New" menu and toolbar button. This * function should be called from an #EShell<!-- -->'s - * #EShell::window-created signal handler. The #EShellModule calling - * this function should pass its own name for the @module_name argument + * #EShell::window-created signal handler. The #EShellBackend calling + * this function should pass its own name for the @backend_name argument * (i.e. the <structfield>name</structfield> field from its own - * #EShellModuleInfo). + * #EShellBackendInfo). * * The registered #GtkAction<!-- -->s should be for creating item * containers such as an email folder or a calendar. The action labels @@ -849,7 +830,7 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, **/ void e_shell_window_register_new_source_actions (EShellWindow *shell_window, - const gchar *module_name, + const gchar *backend_name, GtkActionEntry *entries, guint n_entries) { @@ -859,13 +840,13 @@ e_shell_window_register_new_source_actions (EShellWindow *shell_window, guint ii; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - g_return_if_fail (module_name != NULL); + g_return_if_fail (backend_name != NULL); g_return_if_fail (entries != NULL); action_group = ACTION_GROUP (NEW_SOURCE); ui_manager = e_shell_window_get_ui_manager (shell_window); accel_group = gtk_ui_manager_get_accel_group (ui_manager); - module_name = g_intern_string (module_name); + backend_name = g_intern_string (backend_name); /* XXX The action label translations are retrieved from the * message context "New", but gtk_action_group_add_actions() @@ -883,7 +864,7 @@ e_shell_window_register_new_source_actions (EShellWindow *shell_window, gtk_action_group_add_actions ( action_group, entries, n_entries, shell_window); - /* Tag each action with the name of the shell module that + /* Tag each action with the name of the shell backend that * registered it. This is used to help sort actions in the * "New" menu. */ @@ -900,7 +881,7 @@ e_shell_window_register_new_source_actions (EShellWindow *shell_window, g_object_set_data ( G_OBJECT (action), - "module-name", (gpointer) module_name); + "backend-name", (gpointer) backend_name); } e_shell_window_update_new_menu (shell_window); diff --git a/shell/e-shell-window.h b/shell/e-shell-window.h index f9cdb60cf4..d78fb19774 100644 --- a/shell/e-shell-window.h +++ b/shell/e-shell-window.h @@ -100,16 +100,16 @@ void e_shell_window_set_safe_mode (EShellWindow *shell_window, void e_shell_window_add_action_group (EShellWindow *shell_window, const gchar *group_name); -/* These should be called from the shell module's window_created() handler. */ +/* These should be called from the shell backend's window_created() handler. */ void e_shell_window_register_new_item_actions (EShellWindow *shell_window, - const gchar *module_name, + const gchar *backend_name, GtkActionEntry *entries, guint n_entries); void e_shell_window_register_new_source_actions (EShellWindow *shell_window, - const gchar *module_name, + const gchar *backend_name, GtkActionEntry *entries, guint n_entries); diff --git a/shell/e-shell.c b/shell/e-shell.c index 2c5f00460a..d95853dffa 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -25,10 +25,11 @@ #include <libedataserverui/e-passwords.h> #include "e-util/e-util.h" +#include "e-util/e-module.h" #include "widgets/misc/e-preferences-window.h" +#include "e-shell-backend.h" #include "e-shell-migrate.h" -#include "e-shell-module.h" #include "e-shell-window.h" #define SHUTDOWN_TIMEOUT 500 /* milliseconds */ @@ -43,10 +44,10 @@ struct _EShellPrivate { GConfClient *gconf_client; GtkWidget *preferences_window; - /* Shell Modules */ - GList *loaded_modules; - GHashTable *modules_by_name; - GHashTable *modules_by_scheme; + /* Shell Backends */ + GList *loaded_backends; + GHashTable *backends_by_name; + GHashTable *backends_by_scheme; gpointer preparing_for_line_change; /* weak pointer */ @@ -270,11 +271,25 @@ shell_prepare_for_online (EShell *shell) g_object_unref (shell->priv->preparing_for_line_change); } -/* Helper for shell_query_module() */ +static void +shell_load_modules (EShell *shell) +{ + GList *modules; + + /* Load all shared library modules. */ + modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR); + + while (modules != NULL) { + g_type_module_unuse (G_TYPE_MODULE (modules->data)); + modules = g_list_delete_link (modules, modules); + } +} + +/* Helper for shell_process_backend() */ static void shell_split_and_insert_items (GHashTable *hash_table, const gchar *items, - EShellModule *shell_module) + EShellBackend *shell_backend) { gpointer key; gchar **strv; @@ -284,83 +299,63 @@ shell_split_and_insert_items (GHashTable *hash_table, for (ii = 0; strv[ii] != NULL; ii++) { key = (gpointer) g_intern_string (strv[ii]); - g_hash_table_insert (hash_table, key, shell_module); + g_hash_table_insert (hash_table, key, shell_backend); } g_strfreev (strv); } static void -shell_query_module (EShell *shell, - const gchar *filename) +shell_process_backend (EShell *shell, + EShellBackend *shell_backend) { - EShellModule *shell_module; - EShellModuleInfo *info; - GHashTable *modules_by_name; - GHashTable *modules_by_scheme; + EShellBackendClass *class; + GHashTable *backends_by_name; + GHashTable *backends_by_scheme; const gchar *string; - shell_module = e_shell_module_new (shell, filename); - - if (!g_type_module_use (G_TYPE_MODULE (shell_module))) { - g_critical ("Failed to load module: %s", filename); - g_object_unref (shell_module); - return; - } - - shell->priv->loaded_modules = g_list_insert_sorted ( - shell->priv->loaded_modules, shell_module, - (GCompareFunc) e_shell_module_compare); + shell->priv->loaded_backends = g_list_insert_sorted ( + shell->priv->loaded_backends, shell_backend, + (GCompareFunc) e_shell_backend_compare); /* Bookkeeping */ - info = (EShellModuleInfo *) shell_module->priv; - modules_by_name = shell->priv->modules_by_name; - modules_by_scheme = shell->priv->modules_by_scheme; + class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + backends_by_name = shell->priv->backends_by_name; + backends_by_scheme = shell->priv->backends_by_scheme; - if ((string = info->name) != NULL) + if ((string = class->name) != NULL) g_hash_table_insert ( - modules_by_name, (gpointer) - g_intern_string (string), shell_module); + backends_by_name, (gpointer) + g_intern_string (string), shell_backend); - if ((string = info->aliases) != NULL) + if ((string = class->aliases) != NULL) shell_split_and_insert_items ( - modules_by_name, string, shell_module); + backends_by_name, string, shell_backend); - if ((string = info->schemes) != NULL) + if ((string = class->schemes) != NULL) shell_split_and_insert_items ( - modules_by_scheme, string, shell_module); + backends_by_scheme, string, shell_backend); } static void -shell_load_modules (EShell *shell) +shell_create_backends (EShell *shell) { - GDir *dir; - const gchar *dirname; - const gchar *basename; - GError *error = NULL; + GType *children; + guint ii, n_children; - dirname = EVOLUTION_MODULEDIR; + /* Create an instance of each EShellBackend subclass. */ + children = g_type_children (E_TYPE_SHELL_BACKEND, &n_children); - dir = g_dir_open (dirname, 0, &error); - if (dir == NULL) { - g_critical ("%s", error->message); - g_error_free (error); - return; - } + for (ii = 0; ii < n_children; ii++) { + EShellBackend *shell_backend; + GType type = children[ii]; - while ((basename = g_dir_read_name (dir)) != NULL) { - gchar *filename; - - if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX)) - continue; - - filename = g_build_filename (dirname, basename, NULL); - shell_query_module (shell, filename); - g_free (filename); + shell_backend = g_object_new (type, "shell", shell, NULL); + shell_process_backend (shell, shell_backend); } - g_dir_close (dir); + g_free (children); } static gboolean @@ -372,21 +367,21 @@ shell_shutdown_timeout (EShell *shell) static guint message_timer = 1; /* Module list is read-only; do not free. */ - list = e_shell_get_shell_modules (shell); + list = e_shell_get_shell_backends (shell); - /* Any module can defer shutdown if it's still busy. */ + /* Any backend can defer shutdown if it's still busy. */ for (iter = list; proceed && iter != NULL; iter = iter->next) { - EShellModule *shell_module = iter->data; - proceed = e_shell_module_shutdown (shell_module); + EShellBackend *shell_backend = iter->data; + proceed = e_shell_backend_shutdown (shell_backend); /* Emit a message every few seconds to indicate - * which module(s) we're still waiting on. */ + * which backend(s) we're still waiting on. */ if (proceed || message_timer == 0) continue; g_message ( - _("Waiting for the \"%s\" module to finish..."), - G_TYPE_MODULE (shell_module)->name); + _("Waiting for the \"%s\" backend to finish..."), + E_SHELL_BACKEND_GET_CLASS (shell_backend)->name); } message_timer = (message_timer + 1) % 10; @@ -400,7 +395,7 @@ shell_shutdown_timeout (EShell *shell) g_list_foreach (list, (GFunc) gtk_widget_destroy, NULL); g_list_free (list); - /* If a module is still busy, try again after a short delay. */ + /* If a backend is still busy, try again after a short delay. */ } else if (source_id == 0) source_id = g_timeout_add ( SHUTDOWN_TIMEOUT, (GSourceFunc) @@ -485,11 +480,9 @@ shell_dispose (GObject *object) priv->preferences_window = NULL; } - g_list_foreach ( - priv->loaded_modules, - (GFunc) g_type_module_unuse, NULL); - g_list_free (priv->loaded_modules); - priv->loaded_modules = NULL; + g_list_foreach (priv->loaded_backends, (GFunc) g_object_unref, NULL); + g_list_free (priv->loaded_backends); + priv->loaded_backends = NULL; /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); @@ -502,8 +495,8 @@ shell_finalize (GObject *object) priv = E_SHELL_GET_PRIVATE (object); - g_hash_table_destroy (priv->modules_by_name); - g_hash_table_destroy (priv->modules_by_scheme); + g_hash_table_destroy (priv->backends_by_name); + g_hash_table_destroy (priv->backends_by_scheme); /* Indicates a clean shut down to the next session. */ if (!unique_app_is_running (UNIQUE_APP (object))) @@ -525,6 +518,7 @@ shell_constructed (GObject *object) e_file_lock_create (); shell_load_modules (E_SHELL (object)); + shell_create_backends (E_SHELL (object)); e_shell_migrate_attempt (E_SHELL (object)); } @@ -689,7 +683,7 @@ shell_class_init (EShellClass *class) * @uri: the URI to be handled * * Emitted when @shell receives a URI to be handled, usually by - * way of a command-line argument. An #EShellModule should listen + * way of a command-line argument. An #EShellBackend should listen * for this signal and try to handle the URI, usually by opening an * editor window for the identified resource. * @@ -709,16 +703,16 @@ shell_class_init (EShellClass *class) * @shell: the #EShell which emitted the signal * @activity: the #EActivity for offline preparations * - * Emitted when the user elects to work offline. An #EShellModule + * Emitted when the user elects to work offline. An #EShellBackend * should listen for this signal and make preparations for working * in offline mode. * * If preparations for working offline cannot immediately be * completed (such as when synchronizing with a remote server), - * the #EShellModule should reference the @activity until + * the #EShellBackend should reference the @activity until * preparations are complete, and then unreference the @activity. * This will delay Evolution from actually going to offline mode - * until all modules have unreferenced @activity. + * until all backends have unreferenced @activity. **/ signals[PREPARE_FOR_OFFLINE] = g_signal_new ( "prepare-for-offline", @@ -734,16 +728,16 @@ shell_class_init (EShellClass *class) * @shell: the #EShell which emitted the signal * @activity: the #EActivity for offline preparations * - * Emitted when the user elects to work online. An #EShellModule + * Emitted when the user elects to work online. An #EShellBackend * should listen for this signal and make preparations for working * in online mode. * * If preparations for working online cannot immediately be * completed (such as when re-connecting to a remote server), the - * #EShellModule should reference the @activity until preparations + * #EShellBackend should reference the @activity until preparations * are complete, and then unreference the @activity. This will * delay Evolution from actually going to online mode until all - * modules have unreferenced @activity. + * backends have unreferenced @activity. **/ signals[PREPARE_FOR_ONLINE] = g_signal_new ( "prepare-for-online", @@ -855,19 +849,19 @@ shell_class_init (EShellClass *class) static void shell_init (EShell *shell) { - GHashTable *modules_by_name; - GHashTable *modules_by_scheme; + GHashTable *backends_by_name; + GHashTable *backends_by_scheme; shell->priv = E_SHELL_GET_PRIVATE (shell); - modules_by_name = g_hash_table_new (g_str_hash, g_str_equal); - modules_by_scheme = g_hash_table_new (g_str_hash, g_str_equal); + backends_by_name = g_hash_table_new (g_str_hash, g_str_equal); + backends_by_scheme = g_hash_table_new (g_str_hash, g_str_equal); shell->priv->settings = g_object_new (E_TYPE_SHELL_SETTINGS, NULL); shell->priv->gconf_client = gconf_client_get_default (); shell->priv->preferences_window = e_preferences_window_new (); - shell->priv->modules_by_name = modules_by_name; - shell->priv->modules_by_scheme = modules_by_scheme; + shell->priv->backends_by_name = backends_by_name; + shell->priv->backends_by_scheme = backends_by_scheme; shell->priv->safe_mode = e_file_lock_exists (); g_object_ref_sink (shell->priv->preferences_window); @@ -949,37 +943,37 @@ e_shell_get_default (void) } /** - * e_shell_get_shell_modules: + * e_shell_get_shell_backends: * @shell: an #EShell * - * Returns a list of loaded #EShellModule instances. The list is + * Returns a list of loaded #EShellBackend instances. The list is * owned by @shell and should not be modified or freed. * - * Returns: a list of loaded #EShellModule instances + * Returns: a list of loaded #EShellBackend instances **/ GList * -e_shell_get_shell_modules (EShell *shell) +e_shell_get_shell_backends (EShell *shell) { g_return_val_if_fail (E_IS_SHELL (shell), NULL); - return shell->priv->loaded_modules; + return shell->priv->loaded_backends; } /** * e_shell_get_canonical_name: * @shell: an #EShell - * @name: the name or alias of an #EShellModule + * @name: the name or alias of an #EShellBackend * - * Returns the canonical name for the #EShellModule whose name or alias + * Returns the canonical name for the #EShellBackend whose name or alias * is @name. * - * Returns: the canonical #EShellModule name + * Returns: the canonical #EShellBackend name **/ const gchar * e_shell_get_canonical_name (EShell *shell, const gchar *name) { - EShellModule *shell_module; + EShellBackend *shell_backend; g_return_val_if_fail (E_IS_SHELL (shell), NULL); @@ -987,58 +981,58 @@ e_shell_get_canonical_name (EShell *shell, if (name == NULL) return NULL; - shell_module = e_shell_get_module_by_name (shell, name); + shell_backend = e_shell_get_backend_by_name (shell, name); - if (shell_module == NULL) + if (shell_backend == NULL) return NULL; - return G_TYPE_MODULE (shell_module)->name; + return E_SHELL_BACKEND_GET_CLASS (shell_backend)->name; } /** - * e_shell_get_module_by_name: + * e_shell_get_backend_by_name: * @shell: an #EShell - * @name: the name or alias of an #EShellModule + * @name: the name or alias of an #EShellBackend * - * Returns the corresponding #EShellModule for the given name or alias, + * Returns the corresponding #EShellBackend for the given name or alias, * or %NULL if @name is not recognized. * - * Returns: the #EShellModule named @name, or %NULL + * Returns: the #EShellBackend named @name, or %NULL **/ -EShellModule * -e_shell_get_module_by_name (EShell *shell, - const gchar *name) +EShellBackend * +e_shell_get_backend_by_name (EShell *shell, + const gchar *name) { GHashTable *hash_table; g_return_val_if_fail (E_IS_SHELL (shell), NULL); g_return_val_if_fail (name != NULL, NULL); - hash_table = shell->priv->modules_by_name; + hash_table = shell->priv->backends_by_name; return g_hash_table_lookup (hash_table, name); } /** - * e_shell_get_module_by_scheme: + * e_shell_get_backend_by_scheme: * @shell: an #EShell * @scheme: a URI scheme * - * Returns the #EShellModule that implements the given URI scheme, + * Returns the #EShellBackend that implements the given URI scheme, * or %NULL if @scheme is not recognized. * - * Returns: the #EShellModule that implements @scheme, or %NULL + * Returns: the #EShellBackend that implements @scheme, or %NULL **/ -EShellModule * -e_shell_get_module_by_scheme (EShell *shell, - const gchar *scheme) +EShellBackend * +e_shell_get_backend_by_scheme (EShell *shell, + const gchar *scheme) { GHashTable *hash_table; g_return_val_if_fail (E_IS_SHELL (shell), NULL); g_return_val_if_fail (scheme != NULL, NULL); - hash_table = shell->priv->modules_by_scheme; + hash_table = shell->priv->backends_by_scheme; return g_hash_table_lookup (hash_table, scheme); } diff --git a/shell/e-shell.h b/shell/e-shell.h index 35095e1352..c76b649124 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -31,7 +31,7 @@ #include <unique/unique.h> #include <gconf/gconf-client.h> #include <shell/e-shell-common.h> -#include <shell/e-shell-module.h> +#include <shell/e-shell-backend.h> #include <shell/e-shell-settings.h> /* Standard GObject macros */ @@ -76,12 +76,12 @@ struct _EShellClass { GType e_shell_get_type (void); EShell * e_shell_get_default (void); -GList * e_shell_get_shell_modules (EShell *shell); +GList * e_shell_get_shell_backends (EShell *shell); const gchar * e_shell_get_canonical_name (EShell *shell, const gchar *name); -EShellModule * e_shell_get_module_by_name (EShell *shell, +EShellBackend * e_shell_get_backend_by_name (EShell *shell, const gchar *name); -EShellModule * e_shell_get_module_by_scheme (EShell *shell, +EShellBackend * e_shell_get_backend_by_scheme (EShell *shell, const gchar *scheme); EShellSettings *e_shell_get_shell_settings (EShell *shell); GConfClient * e_shell_get_gconf_client (EShell *shell); diff --git a/shell/main.c b/shell/main.c index bf0a8c47c6..c71d6869ae 100644 --- a/shell/main.c +++ b/shell/main.c @@ -324,8 +324,8 @@ idle_cb (gchar **uris) if (unique_app_is_running (UNIQUE_APP (shell))) gtk_main_quit (); - /* This must be done after EShell has loaded all the modules. - * For example the mail module makes the global variable `session` + /* This must be done after EShell has loaded all the backends. + * For example the mail backend makes the global variable `session` * which is being used by several EPlugins */ else if (uris == NULL && !disable_eplugin) e_plugin_load_plugins_with_missing_symbols (); |