aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@src.gnome.org>2008-08-19 10:55:45 +0800
committerMatthew Barnes <mbarnes@src.gnome.org>2008-08-19 10:55:45 +0800
commit035744f29bdea64cfb38f2e507020d5914cd666e (patch)
tree98f062db0de5a09700524fe219d0a377f30a706a
parent4187293731274274e4283d9039f6e30c95578118 (diff)
downloadgsoc2013-evolution-035744f29bdea64cfb38f2e507020d5914cd666e.tar.gz
gsoc2013-evolution-035744f29bdea64cfb38f2e507020d5914cd666e.tar.zst
gsoc2013-evolution-035744f29bdea64cfb38f2e507020d5914cd666e.zip
Committing the day's progress.
Realized the "New" menu construction algorithm needs to live independently of shell view instances since we lazy load the shell views but have to display all possible "New" items immediately. Prototype the mechanisms for managing the various shell views and keeping track of which one is current. Various other tightening up and rethinking of APIs. svn path=/branches/kill-bonobo/; revision=36022
-rw-r--r--shell/e-shell-module.c74
-rw-r--r--shell/e-shell-module.h17
-rw-r--r--shell/e-shell-registry.c31
-rw-r--r--shell/e-shell-registry.h2
-rw-r--r--shell/e-shell-view.c238
-rw-r--r--shell/e-shell-view.h16
-rw-r--r--shell/e-shell-window-actions.c196
-rw-r--r--shell/e-shell-window-private.c14
-rw-r--r--shell/e-shell-window-private.h5
-rw-r--r--shell/e-shell-window.c180
-rw-r--r--shell/e-shell-window.h29
-rw-r--r--shell/e-shell.c1
-rw-r--r--shell/test/e-test-shell-module.c26
-rw-r--r--shell/test/e-test-shell-view.c10
14 files changed, 478 insertions, 361 deletions
diff --git a/shell/e-shell-module.c b/shell/e-shell-module.c
index e969bbe382..5efddd532c 100644
--- a/shell/e-shell-module.c
+++ b/shell/e-shell-module.c
@@ -237,21 +237,17 @@ e_shell_module_get_filename (EShellModule *shell_module)
return shell_module->priv->filename;
}
-GType
-e_shell_module_get_view_type (EShellModule *shell_module)
-{
- g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), 0);
-
- return shell_module->priv->info.shell_view_type;
-}
-
gboolean
e_shell_module_is_busy (EShellModule *shell_module)
{
+ EShellModuleInfo *module_info;
+
g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), FALSE);
- if (shell_module->priv->info.is_busy != NULL)
- return shell_module->priv->info.is_busy ();
+ module_info = &shell_module->priv->info;
+
+ if (module_info->is_busy != NULL)
+ return module_info->is_busy (shell_module);
return FALSE;
}
@@ -259,10 +255,14 @@ e_shell_module_is_busy (EShellModule *shell_module)
gboolean
e_shell_module_shutdown (EShellModule *shell_module)
{
+ EShellModuleInfo *module_info;
+
g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), TRUE);
- if (shell_module->priv->info.shutdown != NULL)
- return shell_module->priv->info.shutdown ();
+ module_info = &shell_module->priv->info;
+
+ if (module_info->shutdown != NULL)
+ return module_info->shutdown (shell_module);
return TRUE;
}
@@ -271,11 +271,15 @@ gboolean
e_shell_module_handle_uri (EShellModule *shell_module,
const gchar *uri)
{
+ EShellModuleInfo *module_info;
+
g_return_val_if_fail (E_IS_SHELL_MODULE (shell_module), FALSE);
g_return_val_if_fail (uri != NULL, FALSE);
- if (shell_module->priv->info.handle_uri != NULL)
- return shell_module->priv->info.handle_uri (uri);
+ module_info = &shell_module->priv->info;
+
+ if (module_info->handle_uri != NULL)
+ return module_info->handle_uri (shell_module, uri);
return FALSE;
}
@@ -283,37 +287,55 @@ e_shell_module_handle_uri (EShellModule *shell_module,
void
e_shell_module_send_and_receive (EShellModule *shell_module)
{
+ EShellModuleInfo *module_info;
+
g_return_if_fail (E_IS_SHELL_MODULE (shell_module));
- if (shell_module->priv->info.send_and_receive != NULL)
- shell_module->priv->info.send_and_receive ();
+ module_info = &shell_module->priv->info;
+
+ if (module_info->send_and_receive != NULL)
+ module_info->send_and_receive (shell_module);
}
void
e_shell_module_window_created (EShellModule *shell_module,
EShellWindow *shell_window)
{
+ EShellModuleInfo *module_info;
+
g_return_if_fail (E_IS_SHELL_MODULE (shell_module));
g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
- if (shell_module->priv->info.window_created != NULL)
- shell_module->priv->info.window_created (shell_window);
+ module_info = &shell_module->priv->info;
+
+ if (module_info->window_created != NULL)
+ module_info->window_created (shell_module, shell_window);
}
void
e_shell_module_set_info (EShellModule *shell_module,
const EShellModuleInfo *info)
{
+ GTypeModule *module;
+ EShellModuleInfo *module_info;
+
g_return_if_fail (E_IS_SHELL_MODULE (shell_module));
g_return_if_fail (info != NULL);
- shell_module->priv->info.sort_order = info->sort_order;
- shell_module->priv->info.aliases = g_intern_string (info->aliases);
- shell_module->priv->info.schemes = g_intern_string (info->schemes);
- shell_module->priv->info.shell_view_type = info->shell_view_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 (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;
- shell_module->priv->info.is_busy = info->is_busy;
- shell_module->priv->info.shutdown = info->shutdown;
- shell_module->priv->info.send_and_receive = info->send_and_receive;
- shell_module->priv->info.window_created = info->window_created;
+ module_info->is_busy = info->is_busy;
+ module_info->shutdown = info->shutdown;
+ module_info->send_and_receive = info->send_and_receive;
+ module_info->window_created = info->window_created;
}
diff --git a/shell/e-shell-module.h b/shell/e-shell-module.h
index 7ea9dee4ef..c1bbf6b594 100644
--- a/shell/e-shell-module.h
+++ b/shell/e-shell-module.h
@@ -51,16 +51,18 @@ typedef struct _EShellModuleClass EShellModuleClass;
typedef struct _EShellModulePrivate EShellModulePrivate;
struct _EShellModuleInfo {
- gint sort_order;
+ const gchar *name;
const gchar *aliases; /* colon-separated list */
const gchar *schemes; /* colon-separated list */
- GType shell_view_type; /* EShellView subclass */
+ gint sort_order;
- gboolean (*is_busy) (void);
- gboolean (*shutdown) (void);
- gboolean (*handle_uri) (const gchar *uri);
- void (*send_and_receive) (void);
- void (*window_created) (EShellWindow *window);
+ gboolean (*is_busy) (EShellModule *shell_module);
+ gboolean (*shutdown) (EShellModule *shell_module);
+ gboolean (*handle_uri) (EShellModule *shell_module,
+ const gchar *uri);
+ void (*send_and_receive) (EShellModule *shell_module);
+ void (*window_created) (EShellModule *shell_module,
+ EShellWindow *shell_window);
};
struct _EShellModule {
@@ -77,7 +79,6 @@ EShellModule * e_shell_module_new (const gchar *filename);
gint e_shell_module_compare (EShellModule *shell_module_a,
EShellModule *shell_module_b);
const gchar * e_shell_module_get_filename (EShellModule *shell_module);
-GType e_shell_module_get_view_type (EShellModule *shell_module);
gboolean e_shell_module_is_busy (EShellModule *shell_module);
gboolean e_shell_module_shutdown (EShellModule *shell_module);
gboolean e_shell_module_handle_uri (EShellModule *shell_module,
diff --git a/shell/e-shell-registry.c b/shell/e-shell-registry.c
index 91f489111a..14808ebb01 100644
--- a/shell/e-shell-registry.c
+++ b/shell/e-shell-registry.c
@@ -66,7 +66,7 @@ shell_registry_query_module (const gchar *filename)
info = (EShellModuleInfo *) shell_module->priv;
- if ((string = G_TYPE_MODULE (shell_module)->name) != NULL)
+ if ((string = info->name) != NULL)
g_hash_table_insert (
modules_by_name, (gpointer)
g_intern_string (string), shell_module);
@@ -122,32 +122,19 @@ e_shell_registry_list_modules (void)
return loaded_modules;
}
-GType *
-e_shell_registry_get_view_types (guint *n_types)
+const gchar *
+e_shell_registry_get_canonical_name (const gchar *name)
{
- GType *types;
- GList *iter;
- guint ii = 0;
-
- types = g_new0 (GType, g_list_length (loaded_modules) + 1);
-
- for (iter = loaded_modules; iter != NULL; iter = iter->next) {
- EShellModule *shell_module = iter->data;
- EShellModuleInfo *info;
-
- info = (EShellModuleInfo *) shell_module->priv;
+ EShellModule *shell_module;
- /* Allow for modules with no corresponding view type. */
- if (!g_type_is_a (info->shell_view_type, E_TYPE_SHELL_VIEW))
- continue;
+ g_return_val_if_fail (name != NULL, NULL);
- types[ii++] = info->shell_view_type;
- }
+ shell_module = e_shell_registry_get_module_by_name (name);
- if (n_types != NULL)
- *n_types = ii;
+ if (shell_module == NULL)
+ return NULL;
- return types;
+ return G_TYPE_MODULE (shell_module)->name;
}
EShellModule *
diff --git a/shell/e-shell-registry.h b/shell/e-shell-registry.h
index ad86a94797..335e5e1c3f 100644
--- a/shell/e-shell-registry.h
+++ b/shell/e-shell-registry.h
@@ -28,7 +28,7 @@ G_BEGIN_DECLS
void e_shell_registry_init (void);
GList * e_shell_registry_list_modules (void);
-GType * e_shell_registry_get_view_types (guint *n_types);
+const gchar * e_shell_registry_get_canonical_name (const gchar *name);
EShellModule * e_shell_registry_get_module_by_name (const gchar *name);
EShellModule * e_shell_registry_get_module_by_scheme (const gchar *scheme);
diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c
index 1187c17ee4..52f6479b18 100644
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@ -42,102 +42,6 @@ enum {
static gpointer parent_class;
-static gint
-shell_view_compare_actions (GtkAction *action1,
- GtkAction *action2)
-{
- gchar *label1, *label2;
- gint result;
-
- /* XXX This is really inefficient, but we're only sorting
- * a small number of actions (repeatedly, though). */
-
- g_object_get (action1, "label", &label1, NULL);
- g_object_get (action2, "label", &label2, NULL);
-
- result = g_utf8_collate (label1, label2);
-
- g_free (label1);
- g_free (label2);
-
- return result;
-}
-
-static void
-shell_view_extract_actions (EShellView *shell_view,
- GList **source_list,
- GList **destination_list)
-{
- GList *match_list = NULL;
- GList *iter;
-
- /* Pick out the actions from the source list that are tagged
- * as belonging to the given EShellView and move them to the
- * destination list. */
-
- /* Example: Suppose [A] and [C] are tagged for this EShellView.
- *
- * source_list = [A] -> [B] -> [C]
- * ^ ^
- * | |
- * match_list = [ ] --------> [ ]
- *
- *
- * destination_list = [1] -> [2] (other actions)
- */
- for (iter = *source_list; iter != NULL; iter = iter->next) {
- GtkAction *action = iter->data;
- EShellView *action_shell_view;
-
- action_shell_view = g_object_get_data (
- G_OBJECT (action), "shell-view");
-
- if (action_shell_view != shell_view)
- continue;
-
- match_list = g_list_append (match_list, iter);
- }
-
- /* source_list = [B] match_list = [A] -> [C] */
- for (iter = match_list; iter != NULL; iter = iter->next) {
- GList *link = iter->data;
-
- iter->data = link->data;
- *source_list = g_list_delete_link (*source_list, link);
- }
-
- /* destination_list = [1] -> [2] -> [A] -> [C] */
- *destination_list = g_list_concat (*destination_list, match_list);
-}
-
-static void
-shell_view_register_new_actions (EShellView *shell_view,
- GtkActionGroup *action_group,
- const GtkActionEntry *entries,
- guint n_entries)
-{
- guint ii;
-
- gtk_action_group_add_actions (
- action_group, entries, n_entries, shell_view);
-
- /* Tag each action with the shell view that registered it.
- * This is used to help sort items in the "New" menu. */
-
- for (ii = 0; ii < n_entries; ii++) {
- const gchar *action_name;
- GtkAction *action;
-
- action_name = entries[ii].name;
-
- action = gtk_action_group_get_action (
- action_group, action_name);
-
- g_object_set_data (
- G_OBJECT (action), "shell-view", shell_view);
- }
-}
-
static void
shell_view_set_window (EShellView *shell_view,
GtkWidget *window)
@@ -226,80 +130,6 @@ shell_view_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static GtkWidget *
-shell_view_create_new_menu (EShellView *shell_view)
-{
- GtkActionGroup *action_group;
- GList *new_item_actions;
- GList *new_source_actions;
- GList *iter, *list = NULL;
- GtkWidget *menu;
- GtkWidget *separator;
- GtkWidget *window;
-
- window = e_shell_view_get_window (shell_view);
-
- /* Get sorted lists of "new item" and "new source" actions. */
-
- action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM (window);
-
- new_item_actions = g_list_sort (
- gtk_action_group_list_actions (action_group),
- (GCompareFunc) shell_view_compare_actions);
-
- action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE (window);
-
- new_source_actions = g_list_sort (
- gtk_action_group_list_actions (action_group),
- (GCompareFunc) shell_view_compare_actions);
-
- /* Give priority to actions that belong to this shell view. */
-
- shell_view_extract_actions (
- shell_view, &new_item_actions, &list);
-
- shell_view_extract_actions (
- shell_view, &new_source_actions, &list);
-
- /* Convert the actions to menu item proxy widgets. */
-
- for (iter = list; iter != NULL; iter = iter->next)
- iter->data = gtk_action_create_menu_item (iter->data);
-
- for (iter = new_item_actions; iter != NULL; iter = iter->next)
- iter->data = gtk_action_create_menu_item (iter->data);
-
- for (iter = new_source_actions; iter != NULL; iter = iter->next)
- iter->data = gtk_action_create_menu_item (iter->data);
-
- /* Add menu separators. */
-
- separator = gtk_separator_menu_item_new ();
- new_item_actions = g_list_prepend (new_item_actions, separator);
-
- separator = gtk_separator_menu_item_new ();
- new_source_actions = g_list_prepend (new_source_actions, separator);
-
- /* Merge everything into one list, reflecting the menu layout. */
-
- list = g_list_concat (list, new_item_actions);
- new_item_actions = NULL; /* just for clarity */
-
- list = g_list_concat (list, new_source_actions);
- new_source_actions = NULL; /* just for clarity */
-
- /* And finally, build the menu. */
-
- menu = gtk_menu_new ();
-
- for (iter = list; iter != NULL; iter = iter->next)
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), iter->data);
-
- g_list_free (list);
-
- return menu;
-}
-
static void
shell_view_class_init (EShellViewClass *class)
{
@@ -314,8 +144,6 @@ shell_view_class_init (EShellViewClass *class)
object_class->dispose = shell_view_dispose;
object_class->finalize = shell_view_finalize;
- class->create_new_menu = shell_view_create_new_menu;
-
g_object_class_install_property (
object_class,
PROP_TITLE,
@@ -373,6 +201,23 @@ e_shell_view_get_type (void)
}
const gchar *
+e_shell_view_get_name (EShellView *shell_view)
+{
+ EShellViewClass *class;
+
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ /* A shell view's name is taken from the name of the
+ * module that registered the shell view subclass. */
+
+ class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ g_return_val_if_fail (class->module != NULL, NULL);
+ g_return_val_if_fail (class->module->name != NULL, NULL);
+
+ return class->module->name;
+}
+
+const gchar *
e_shell_view_get_title (EShellView *shell_view)
{
g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
@@ -401,19 +246,6 @@ e_shell_view_get_window (EShellView *shell_view)
}
GtkWidget *
-e_shell_view_create_new_menu (EShellView *shell_view)
-{
- EShellViewClass *class;
-
- g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
-
- class = E_SHELL_VIEW_CLASS (shell_view);
- g_return_val_if_fail (class->create_new_menu != NULL, NULL);
-
- return class->create_new_menu (shell_view);
-}
-
-GtkWidget *
e_shell_view_get_content_widget (EShellView *shell_view)
{
EShellViewClass *class;
@@ -451,39 +283,3 @@ e_shell_view_get_status_widget (EShellView *shell_view)
return class->get_status_widget (shell_view);
}
-
-void
-e_shell_view_register_new_item_actions (EShellView *shell_view,
- const GtkActionEntry *entries,
- guint n_entries)
-{
- GtkWidget *window;
- GtkActionGroup *action_group;
-
- g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
- g_return_if_fail (entries != NULL);
-
- window = e_shell_view_get_window (shell_view);
- action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM (window);
-
- shell_view_register_new_actions (
- shell_view, action_group, entries, n_entries);
-}
-
-void
-e_shell_view_register_new_source_actions (EShellView *shell_view,
- const GtkActionEntry *entries,
- guint n_entries)
-{
- GtkWidget *window;
- GtkActionGroup *action_group;
-
- g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
- g_return_if_fail (entries != NULL);
-
- window = e_shell_view_get_window (shell_view);
- action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE (window);
-
- shell_view_register_new_actions (
- shell_view, action_group, entries, n_entries);
-}
diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h
index 5f1be6fa7d..433c02f01a 100644
--- a/shell/e-shell-view.h
+++ b/shell/e-shell-view.h
@@ -60,31 +60,25 @@ struct _EShellViewClass {
const gchar *label;
const gchar *icon_name;
- GtkWidget * (*create_new_menu) (EShellView *shell_view);
+ /* Subclasses should set this via the "class_data" field in
+ * the GTypeInfo they pass to g_type_module_register_type(). */
+ GTypeModule *module;
+
GtkWidget * (*get_content_widget) (EShellView *shell_view);
GtkWidget * (*get_sidebar_widget) (EShellView *shell_view);
GtkWidget * (*get_status_widget) (EShellView *shell_view);
};
GType e_shell_view_get_type (void);
+const gchar * e_shell_view_get_name (EShellView *shell_view);
const gchar * e_shell_view_get_title (EShellView *shell_view);
void e_shell_view_set_title (EShellView *shell_view,
const gchar *title);
GtkWidget * e_shell_view_get_window (EShellView *shell_view);
-GtkWidget * e_shell_view_create_new_menu (EShellView *shell_view);
GtkWidget * e_shell_view_get_content_widget (EShellView *shell_view);
GtkWidget * e_shell_view_get_sidebar_widget (EShellView *shell_view);
GtkWidget * e_shell_view_get_status_widget (EShellView *shell_view);
-void e_shell_view_register_new_item_actions
- (EShellView *shell_view,
- const GtkActionEntry *entries,
- guint n_entries);
-void e_shell_view_register_new_source_actions
- (EShellView *shell_view,
- const GtkActionEntry *entries,
- guint n_entries);
-
G_END_DECLS
#endif /* E_SHELL_VIEW_H */
diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c
index 85bdf445d9..a176a202b5 100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@ -799,12 +799,10 @@ action_shell_view_cb (GtkRadioAction *action,
GtkRadioAction *current,
EShellWindow *window)
{
- gint value;
+ const gchar *view_name;
- if (action != current)
- return;
-
- value = gtk_radio_action_get_current_value (action);
+ view_name = g_object_get_data (G_OBJECT (current), "view-name");
+ e_shell_window_set_current_view (window, view_name);
}
static void
@@ -1188,6 +1186,77 @@ static GtkRadioActionEntry shell_switcher_style_entries[] = {
-1 }
};
+static gint
+shell_window_compare_actions (GtkAction *action1,
+ GtkAction *action2)
+{
+ gchar *label1, *label2;
+ gint result;
+
+ /* XXX This is really inefficient, but we're only sorting
+ * a small number of actions (repeatedly, though). */
+
+ g_object_get (action1, "label", &label1, NULL);
+ g_object_get (action2, "label", &label2, NULL);
+
+ result = g_utf8_collate (label1, label2);
+
+ g_free (label1);
+ g_free (label2);
+
+ return result;
+}
+
+static void
+shell_window_extract_actions (EShellWindow *window,
+ GList **source_list,
+ GList **destination_list)
+{
+ const gchar *current_view;
+ GList *match_list = NULL;
+ GList *iter;
+
+ /* Pick out the actions from the source list that are tagged
+ * as belonging to the current EShellView and move them to the
+ * destination list. */
+
+ current_view = e_shell_window_get_current_view (window);
+
+ /* Example: Suppose [A] and [C] are tagged for this EShellView.
+ *
+ * source_list = [A] -> [B] -> [C]
+ * ^ ^
+ * | |
+ * match_list = [ ] --------> [ ]
+ *
+ *
+ * destination_list = [1] -> [2] (other actions)
+ */
+ for (iter = *source_list; iter != NULL; iter = iter->next) {
+ GtkAction *action = iter->data;
+ const gchar *view_name;
+
+ view_name = g_object_get_data (
+ G_OBJECT (action), "view-name");
+
+ if (view_name != current_view)
+ continue;
+
+ match_list = g_list_append (match_list, iter);
+ }
+
+ /* source_list = [B] match_list = [A] -> [C] */
+ for (iter = match_list; iter != NULL; iter = iter->next) {
+ GList *link = iter->data;
+
+ iter->data = link->data;
+ *source_list = g_list_delete_link (*source_list, link);
+ }
+
+ /* destination_list = [1] -> [2] -> [A] -> [C] */
+ *destination_list = g_list_concat (*destination_list, match_list);
+}
+
void
e_shell_window_actions_init (EShellWindow *window)
{
@@ -1231,20 +1300,91 @@ e_shell_window_actions_init (EShellWindow *window)
gtk_ui_manager_insert_action_group (manager, action_group, 0);
}
+GtkWidget *
+e_shell_window_create_new_menu (EShellWindow *window)
+{
+ GtkActionGroup *action_group;
+ GList *new_item_actions;
+ GList *new_source_actions;
+ GList *iter, *list = NULL;
+ GtkWidget *menu;
+ GtkWidget *separator;
+
+ /* Get sorted lists of "new item" and "new source" actions. */
+
+ action_group = window->priv->new_item_actions;
+
+ new_item_actions = g_list_sort (
+ gtk_action_group_list_actions (action_group),
+ (GCompareFunc) shell_window_compare_actions);
+
+ action_group = window->priv->new_source_actions;
+
+ new_source_actions = g_list_sort (
+ gtk_action_group_list_actions (action_group),
+ (GCompareFunc) shell_window_compare_actions);
+
+ /* Give priority to actions that belong to this shell view. */
+
+ shell_window_extract_actions (
+ window, &new_item_actions, &list);
+
+ shell_window_extract_actions (
+ window, &new_source_actions, &list);
+
+ /* Convert the actions to menu item proxy widgets. */
+
+ for (iter = list; iter != NULL; iter = iter->next)
+ iter->data = gtk_action_create_menu_item (iter->data);
+
+ for (iter = new_item_actions; iter != NULL; iter = iter->next)
+ iter->data = gtk_action_create_menu_item (iter->data);
+
+ for (iter = new_source_actions; iter != NULL; iter = iter->next)
+ iter->data = gtk_action_create_menu_item (iter->data);
+
+ /* Add menu separators. */
+
+ separator = gtk_separator_menu_item_new ();
+ new_item_actions = g_list_prepend (new_item_actions, separator);
+
+ separator = gtk_separator_menu_item_new ();
+ new_source_actions = g_list_prepend (new_source_actions, separator);
+
+ /* Merge everything into one list, reflecting the menu layout. */
+
+ list = g_list_concat (list, new_item_actions);
+ new_item_actions = NULL; /* just for clarity */
+
+ list = g_list_concat (list, new_source_actions);
+ new_source_actions = NULL; /* just for clarity */
+
+ /* And finally, build the menu. */
+
+ menu = gtk_menu_new ();
+
+ for (iter = list; iter != NULL; iter = iter->next)
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), iter->data);
+
+ g_list_free (list);
+
+ return menu;
+}
+
void
e_shell_window_create_shell_view_actions (EShellWindow *window)
{
- GType *types;
+ GType *children;
GSList *group = NULL;
GtkActionGroup *action_group;
GtkUIManager *manager;
- guint n_types, ii;
+ guint n_children, ii;
guint merge_id;
g_return_if_fail (E_IS_SHELL_WINDOW (window));
action_group = window->priv->shell_view_actions;
- types = e_shell_registry_get_view_types (&n_types);
+ children = g_type_children (E_TYPE_SHELL_VIEW, &n_children);
manager = e_shell_window_get_ui_manager (window);
merge_id = gtk_ui_manager_new_merge_id (manager);
@@ -1252,22 +1392,31 @@ e_shell_window_create_shell_view_actions (EShellWindow *window)
* subclasses and register them with our ESidebar. These actions
* are manifested as switcher buttons and View->Window menu items. */
- for (ii = 0; ii < n_types; ii++) {
+ for (ii = 0; ii < n_children; ii++) {
EShellViewClass *class;
GtkRadioAction *action;
- const gchar *type_name;
+ const gchar *view_name;
gchar *action_name;
gchar *tooltip;
- class = g_type_class_ref (types[ii]);
- type_name = g_type_name (types[ii]);
+ class = g_type_class_ref (children[ii]);
if (class->label == NULL) {
- g_critical ("Label member not set on %s", type_name);
+ g_critical (
+ "Label member not set on %s",
+ G_OBJECT_CLASS_NAME (class));
+ continue;
+ }
+
+ if (class->module == NULL) {
+ g_critical (
+ "Module member not set on %s",
+ G_OBJECT_CLASS_NAME (class));
continue;
}
- action_name = g_strdup_printf ("shell-view-%s", type_name);
+ view_name = class->module->name;
+ action_name = g_strdup_printf ("shell-view-%s", view_name);
tooltip = g_strdup_printf (_("Switch to %s"), class->label);
/* Note, we have to set "icon-name" separately because
@@ -1282,9 +1431,20 @@ e_shell_window_create_shell_view_actions (EShellWindow *window)
G_OBJECT (action),
"icon-name", class->icon_name, NULL);
- g_signal_connect (
- action, "changed",
- G_CALLBACK (action_shell_view_cb), window);
+ g_object_set_data (
+ G_OBJECT (action),
+ "view-name", (gpointer) view_name);
+
+ if (group == NULL) {
+
+ /* First view is the default. */
+ window->priv->default_view = view_name;
+
+ /* Only listen to the first action. */
+ g_signal_connect (
+ action, "changed",
+ G_CALLBACK (action_shell_view_cb), window);
+ }
gtk_radio_action_set_group (action, group);
group = gtk_radio_action_get_group (action);
@@ -1308,5 +1468,5 @@ e_shell_window_create_shell_view_actions (EShellWindow *window)
g_type_class_unref (class);
}
- g_free (types);
+ g_free (children);
}
diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c
index 1db8652cfa..5e750cfcf4 100644
--- a/shell/e-shell-window-private.c
+++ b/shell/e-shell-window-private.c
@@ -98,6 +98,7 @@ void
e_shell_window_private_init (EShellWindow *window)
{
EShellWindowPrivate *priv = window->priv;
+ GHashTable *loaded_views;
GConfBridge *bridge;
GtkWidget *container;
GtkWidget *widget;
@@ -105,13 +106,17 @@ e_shell_window_private_init (EShellWindow *window)
const gchar *key;
gint height;
+ loaded_views = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) g_object_unref);
+
priv->manager = gtk_ui_manager_new ();
priv->shell_actions = gtk_action_group_new ("shell");
priv->new_item_actions = gtk_action_group_new ("new-item");
priv->new_source_actions = gtk_action_group_new ("new-source");
priv->shell_view_actions = gtk_action_group_new ("shell-view");
-
- priv->shell_views = g_ptr_array_new ();
+ priv->loaded_views = loaded_views;
e_load_ui_definition (priv->manager, "evolution-shell.ui");
@@ -255,6 +260,8 @@ e_shell_window_private_dispose (EShellWindow *window)
DISPOSE (priv->new_source_actions);
DISPOSE (priv->shell_view_actions);
+ g_hash_table_remove_all (priv->loaded_views);
+
DISPOSE (priv->main_menu);
DISPOSE (priv->main_toolbar);
DISPOSE (priv->content_pane);
@@ -280,6 +287,5 @@ e_shell_window_private_finalize (EShellWindow *window)
{
EShellWindowPrivate *priv = window->priv;
- g_ptr_array_foreach (priv->shell_views, (GFunc) g_object_unref, NULL);
- g_ptr_array_free (priv->shell_views, TRUE);
+ g_hash_table_destroy (priv->loaded_views);
}
diff --git a/shell/e-shell-window-private.h b/shell/e-shell-window-private.h
index e8287fc23d..bc5fbc7645 100644
--- a/shell/e-shell-window-private.h
+++ b/shell/e-shell-window-private.h
@@ -61,7 +61,9 @@ struct _EShellWindowPrivate {
/*** Shell Views ***/
- GPtrArray *shell_views;
+ GHashTable *loaded_views;
+ const gchar *current_view;
+ const gchar *default_view;
/*** Widgetry ***/
@@ -89,6 +91,7 @@ void e_shell_window_private_finalize (EShellWindow *window);
/* Private Utilities */
void e_shell_window_actions_init (EShellWindow *window);
+GtkWidget * e_shell_window_create_new_menu (EShellWindow *window);
void e_shell_window_create_shell_view_actions
(EShellWindow *window);
diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c
index 45c1fa2637..ca7776c201 100644
--- a/shell/e-shell-window.c
+++ b/shell/e-shell-window.c
@@ -41,6 +41,7 @@
enum {
PROP_0,
+ PROP_CURRENT_VIEW,
PROP_SAFE_MODE
};
@@ -53,11 +54,17 @@ shell_window_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_CURRENT_VIEW:
+ e_shell_window_set_current_view (
+ E_SHELL_WINDOW (object),
+ g_value_get_string (value));
+ return;
+
case PROP_SAFE_MODE:
e_shell_window_set_safe_mode (
E_SHELL_WINDOW (object),
g_value_get_boolean (value));
- break;
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -70,11 +77,17 @@ shell_window_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_CURRENT_VIEW:
+ g_value_set_string (
+ value, e_shell_window_get_current_view (
+ E_SHELL_WINDOW (object)));
+ return;
+
case PROP_SAFE_MODE:
g_value_set_boolean (
value, e_shell_window_get_safe_mode (
E_SHELL_WINDOW (object)));
- break;
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -114,6 +127,17 @@ shell_window_class_init (EShellWindowClass *class)
g_object_class_install_property (
object_class,
+ PROP_CURRENT_VIEW,
+ g_param_spec_string (
+ "current-view",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
PROP_SAFE_MODE,
g_param_spec_boolean (
"safe-mode",
@@ -125,18 +149,18 @@ shell_window_class_init (EShellWindowClass *class)
}
static void
-shell_window_init (EShellWindow *window)
+shell_window_init (EShellWindow *shell_window)
{
GtkUIManager *manager;
- window->priv = E_SHELL_WINDOW_GET_PRIVATE (window);
+ shell_window->priv = E_SHELL_WINDOW_GET_PRIVATE (shell_window);
- e_shell_window_private_init (window);
+ e_shell_window_private_init (shell_window);
- manager = e_shell_window_get_ui_manager (window);
+ manager = e_shell_window_get_ui_manager (shell_window);
e_plugin_ui_register_manager (
- "org.gnome.evolution.shell", manager, window);
+ "org.gnome.evolution.shell", manager, shell_window);
}
GType
@@ -173,25 +197,25 @@ e_shell_window_new (gboolean safe_mode)
}
GtkUIManager *
-e_shell_window_get_ui_manager (EShellWindow *window)
+e_shell_window_get_ui_manager (EShellWindow *shell_window)
{
- g_return_val_if_fail (E_IS_SHELL_WINDOW (window), NULL);
+ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
- return window->priv->manager;
+ return shell_window->priv->manager;
}
GtkAction *
-e_shell_window_get_action (EShellWindow *window,
+e_shell_window_get_action (EShellWindow *shell_window,
const gchar *action_name)
{
GtkUIManager *manager;
GtkAction *action = NULL;
GList *iter;
- g_return_val_if_fail (E_IS_SHELL_WINDOW (window), NULL);
+ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
g_return_val_if_fail (action_name != NULL, NULL);
- manager = e_shell_window_get_ui_manager (window);
+ manager = e_shell_window_get_ui_manager (shell_window);
iter = gtk_ui_manager_get_action_groups (manager);
while (iter != NULL && action == NULL) {
@@ -208,16 +232,16 @@ e_shell_window_get_action (EShellWindow *window,
}
GtkActionGroup *
-e_shell_window_get_action_group (EShellWindow *window,
+e_shell_window_get_action_group (EShellWindow *shell_window,
const gchar *group_name)
{
GtkUIManager *manager;
GList *iter;
- g_return_val_if_fail (E_IS_SHELL_WINDOW (window), NULL);
+ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
g_return_val_if_fail (group_name != NULL, NULL);
- manager = e_shell_window_get_ui_manager (window);
+ manager = e_shell_window_get_ui_manager (shell_window);
iter = gtk_ui_manager_get_action_groups (manager);
while (iter != NULL) {
@@ -235,16 +259,16 @@ e_shell_window_get_action_group (EShellWindow *window,
}
GtkWidget *
-e_shell_window_get_managed_widget (EShellWindow *window,
+e_shell_window_get_managed_widget (EShellWindow *shell_window,
const gchar *widget_path)
{
GtkUIManager *manager;
GtkWidget *widget;
- g_return_val_if_fail (E_IS_SHELL_WINDOW (window), NULL);
+ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
g_return_val_if_fail (widget_path != NULL, NULL);
- manager = e_shell_window_get_ui_manager (window);
+ manager = e_shell_window_get_ui_manager (shell_window);
widget = gtk_ui_manager_get_widget (manager, widget_path);
g_return_val_if_fail (widget != NULL, NULL);
@@ -252,21 +276,125 @@ e_shell_window_get_managed_widget (EShellWindow *window,
return widget;
}
+const gchar *
+e_shell_window_get_current_view (EShellWindow *shell_window)
+{
+ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL);
+
+ return shell_window->priv->current_view;
+}
+
+void
+e_shell_window_set_current_view (EShellWindow *shell_window,
+ const gchar *name_or_alias)
+{
+ const gchar *current_view;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+
+ if (name_or_alias != NULL)
+ current_view =
+ e_shell_registry_get_canonical_name (name_or_alias);
+
+ if (current_view == NULL)
+ current_view = shell_window->priv->default_view;
+
+ shell_window->priv->current_view = current_view;
+
+ g_object_notify (G_OBJECT (shell_window), "current-view");
+}
+
gboolean
-e_shell_window_get_safe_mode (EShellWindow *window)
+e_shell_window_get_safe_mode (EShellWindow *shell_window)
{
- g_return_val_if_fail (E_IS_SHELL_WINDOW (window), FALSE);
+ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
- return window->priv->safe_mode;
+ return shell_window->priv->safe_mode;
}
void
-e_shell_window_set_safe_mode (EShellWindow *window,
+e_shell_window_set_safe_mode (EShellWindow *shell_window,
gboolean safe_mode)
{
- g_return_if_fail (E_IS_SHELL_WINDOW (window));
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
- window->priv->safe_mode = safe_mode;
+ shell_window->priv->safe_mode = safe_mode;
- g_object_notify (G_OBJECT (window), "safe-mode");
+ g_object_notify (G_OBJECT (shell_window), "safe-mode");
+}
+
+void
+e_shell_window_register_new_item_actions (EShellWindow *shell_window,
+ const gchar *module_name,
+ const GtkActionEntry *entries,
+ guint n_entries)
+{
+ GtkActionGroup *action_group;
+ guint ii;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+ g_return_if_fail (module_name != NULL);
+ g_return_if_fail (entries != NULL);
+
+ action_group = shell_window->priv->new_item_actions;
+ module_name = g_intern_string (module_name);
+
+ gtk_action_group_add_actions (
+ action_group, entries, n_entries, shell_window);
+
+ /* Tag each action with the name of the shell module that
+ * registered it. This is used to help sort actions in the
+ * "New" menu. */
+
+ for (ii = 0; ii < n_entries; ii++) {
+ const gchar *action_name;
+ GtkAction *action;
+
+ action_name = entries[ii].name;
+
+ action = gtk_action_group_get_action (
+ action_group, action_name);
+
+ g_object_set_data (
+ G_OBJECT (action),
+ "module-name", (gpointer) module_name);
+ }
+}
+
+void
+e_shell_window_register_new_source_actions (EShellWindow *shell_window,
+ const gchar *module_name,
+ const GtkActionEntry *entries,
+ guint n_entries)
+{
+ GtkActionGroup *action_group;
+ guint ii;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+ g_return_if_fail (module_name != NULL);
+ g_return_if_fail (entries != NULL);
+
+ action_group = shell_window->priv->new_source_actions;
+ module_name = g_intern_string (module_name);
+
+ gtk_action_group_add_actions (
+ action_group, entries, n_entries, shell_window);
+
+ /* Tag each action with the name of the shell module that
+ * registered it. This is used to help sort actions in the
+ * "New" menu. */
+
+ for (ii = 0; ii < n_entries; ii++) {
+ const gchar *action_name;
+ GtkAction *action;
+
+ action_name = entries[ii].name;
+
+ action = gtk_action_group_get_action (
+ action_group, action_name);
+
+ g_object_set_data (
+ G_OBJECT (action),
+ "module-name", (gpointer) module_name);
+ }
}
diff --git a/shell/e-shell-window.h b/shell/e-shell-window.h
index e7b0d9da8d..2ff65138a8 100644
--- a/shell/e-shell-window.h
+++ b/shell/e-shell-window.h
@@ -22,7 +22,6 @@
#define E_SHELL_WINDOW_H
#include "e-shell-common.h"
-#include "e-shell-view.h"
/* Standard GObject macros */
#define E_TYPE_SHELL_WINDOW \
@@ -60,18 +59,34 @@ struct _EShellWindowClass {
GType e_shell_window_get_type (void);
GtkWidget * e_shell_window_new (gboolean safe_mode);
-GtkUIManager * e_shell_window_get_ui_manager (EShellWindow *window);
-GtkAction * e_shell_window_get_action (EShellWindow *window,
+GtkUIManager * e_shell_window_get_ui_manager (EShellWindow *shell_window);
+GtkAction * e_shell_window_get_action (EShellWindow *shell_window,
const gchar *action_name);
-GtkActionGroup *e_shell_window_get_action_group (EShellWindow *window,
+GtkActionGroup *e_shell_window_get_action_group (EShellWindow *shell_window,
const gchar *group_name);
GtkWidget * e_shell_window_get_managed_widget
- (EShellWindow *window,
+ (EShellWindow *shell_window,
const gchar *widget_path);
-gboolean e_shell_window_get_safe_mode (EShellWindow *window);
-void e_shell_window_set_safe_mode (EShellWindow *window,
+const gchar * e_shell_window_get_current_view (EShellWindow *shell_window);
+void e_shell_window_set_current_view (EShellWindow *shell_window,
+ const gchar *name_or_alias);
+gboolean e_shell_window_get_safe_mode (EShellWindow *shell_window);
+void e_shell_window_set_safe_mode (EShellWindow *shell_window,
gboolean safe_mode);
+/* These should be called from the shell module's window_created() method. */
+
+void e_shell_window_register_new_item_actions
+ (EShellWindow *shell_window,
+ const gchar *module_name,
+ const GtkActionEntry *entries,
+ guint n_entries);
+void e_shell_window_register_new_source_actions
+ (EShellWindow *shell_window,
+ const gchar *module_name,
+ const GtkActionEntry *entries,
+ guint n_entries);
+
G_END_DECLS
#endif /* E_SHELL_WINDOW_H */
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 1d2d68b57e..9678790d72 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -22,6 +22,7 @@
#include <glib/gi18n.h>
#include <e-preferences-window.h>
+#include <e-util/e-util.h>
#include "e-shell-module.h"
#include "e-shell-registry.h"
diff --git a/shell/test/e-test-shell-module.c b/shell/test/e-test-shell-module.c
index 16515c1e30..de6210f654 100644
--- a/shell/test/e-test-shell-module.c
+++ b/shell/test/e-test-shell-module.c
@@ -22,15 +22,16 @@
#include "e-test-shell-view.h"
-#define MODULE_SORT_ORDER 100
-#define MODULE_ALIASES "test"
+#define MODULE_NAME "test"
+#define MODULE_ALIASES "monkey"
#define MODULE_SCHEMES ""
+#define MODULE_SORT_ORDER 100
/* Module Entry Point */
void e_shell_module_init (GTypeModule *module);
static gboolean
-test_module_is_busy (void)
+test_module_is_busy (EShellModule *shell_module)
{
g_debug ("%s", G_STRFUNC);
@@ -38,7 +39,7 @@ test_module_is_busy (void)
}
static gboolean
-test_module_shutdown (void)
+test_module_shutdown (EShellModule *shell_module)
{
g_debug ("%s", G_STRFUNC);
@@ -46,7 +47,8 @@ test_module_shutdown (void)
}
static gboolean
-test_module_handle_uri (const gchar *uri)
+test_module_handle_uri (EShellModule *shell_module,
+ const gchar *uri)
{
g_debug ("%s (uri=%s)", G_STRFUNC, uri);
@@ -54,23 +56,24 @@ test_module_handle_uri (const gchar *uri)
}
static void
-test_module_send_and_receive (void)
+test_module_send_and_receive (EShellModule *shell_module)
{
g_debug ("%s", G_STRFUNC);
}
static void
-test_module_window_created (EShellWindow *window)
+test_module_window_created (EShellModule *shell_module,
+ EShellWindow *shell_window)
{
- g_debug ("%s (window=%p)", G_STRFUNC, window);
+ g_debug ("%s (window=%p)", G_STRFUNC, shell_window);
}
static EShellModuleInfo module_info = {
- MODULE_SORT_ORDER,
+ MODULE_NAME,
MODULE_ALIASES,
MODULE_SCHEMES,
- G_TYPE_INVALID,
+ MODULE_SORT_ORDER,
/* Methods */
test_module_is_busy,
@@ -83,7 +86,6 @@ static EShellModuleInfo module_info = {
void
e_shell_module_init (GTypeModule *module)
{
- g_type_module_set_name (module, "name");
- module_info.shell_view_type = e_test_shell_view_get_type (module);
+ e_test_shell_view_get_type (module);
e_shell_module_set_info (E_SHELL_MODULE (module), &module_info);
}
diff --git a/shell/test/e-test-shell-view.c b/shell/test/e-test-shell-view.c
index 7b2ff9a251..c76d459160 100644
--- a/shell/test/e-test-shell-view.c
+++ b/shell/test/e-test-shell-view.c
@@ -34,7 +34,8 @@ GType e_test_shell_view_type = 0;
static gpointer parent_class;
static void
-test_shell_view_class_init (ETestShellViewClass *class)
+test_shell_view_class_init (ETestShellViewClass *class,
+ GTypeModule *module)
{
EShellViewClass *shell_view_class;
@@ -44,6 +45,7 @@ test_shell_view_class_init (ETestShellViewClass *class)
shell_view_class = E_SHELL_VIEW_CLASS (class);
shell_view_class->label = N_("Test");
shell_view_class->icon_name = "face-monkey";
+ shell_view_class->module = module;
}
static void
@@ -62,11 +64,11 @@ e_test_shell_view_get_type (GTypeModule *module)
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) test_shell_view_class_init,
(GClassFinalizeFunc) NULL,
- NULL, /* class_data */
+ module, /* class_data */
sizeof (ETestShellView),
- 0, /* n_preallocs */
+ 0, /* n_preallocs */
(GInstanceInitFunc) test_shell_view_init,
- NULL /* value_table */
+ NULL /* value_table */
};
e_test_shell_view_type =