diff options
-rw-r--r-- | shell/e-shell-module.c | 74 | ||||
-rw-r--r-- | shell/e-shell-module.h | 17 | ||||
-rw-r--r-- | shell/e-shell-registry.c | 31 | ||||
-rw-r--r-- | shell/e-shell-registry.h | 2 | ||||
-rw-r--r-- | shell/e-shell-view.c | 238 | ||||
-rw-r--r-- | shell/e-shell-view.h | 16 | ||||
-rw-r--r-- | shell/e-shell-window-actions.c | 196 | ||||
-rw-r--r-- | shell/e-shell-window-private.c | 14 | ||||
-rw-r--r-- | shell/e-shell-window-private.h | 5 | ||||
-rw-r--r-- | shell/e-shell-window.c | 180 | ||||
-rw-r--r-- | shell/e-shell-window.h | 29 | ||||
-rw-r--r-- | shell/e-shell.c | 1 | ||||
-rw-r--r-- | shell/test/e-test-shell-module.c | 26 | ||||
-rw-r--r-- | shell/test/e-test-shell-view.c | 10 |
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 = |