diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-05-07 19:21:57 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-05-07 19:21:57 +0800 |
commit | caa862135195b828d2e8355436fdd6eb0ec2443e (patch) | |
tree | 40198708ccf89ca4246c7da11a718fa5cc39de52 | |
parent | 19b29348068e367efc105732e9707cdb4132b4ee (diff) | |
download | gsoc2013-evolution-caa862135195b828d2e8355436fdd6eb0ec2443e.tar.gz gsoc2013-evolution-caa862135195b828d2e8355436fdd6eb0ec2443e.tar.zst gsoc2013-evolution-caa862135195b828d2e8355436fdd6eb0ec2443e.zip |
Convert EShellModule to EShellBackend
Split the GTypeModule loader out of EShellModule as EModule, and rename
EShellModule to EShellBackend. Backends (formerly modules) should now
subclass EShellBackend.
This commit converts EShell but breaks all the shell backends.
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 (); |