From e9f7d5d0215011d289c2a376548b7f86c22f3cc2 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sun, 30 Jan 2011 23:11:14 -0500 Subject: Port EShell to GtkApplication. --- shell/e-shell.c | 306 +++++++++++++++++++++++++++++--------------------------- shell/e-shell.h | 7 +- shell/main.c | 32 ++++-- 3 files changed, 182 insertions(+), 163 deletions(-) (limited to 'shell') diff --git a/shell/e-shell.c b/shell/e-shell.c index f3402dd101..d9dcb5de9a 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -47,6 +47,7 @@ struct _EShellPrivate { GList *watched_windows; EShellSettings *settings; GConfClient *gconf_client; + GActionGroup *action_group; GtkWidget *preferences_window; /* Shell Backends */ @@ -109,10 +110,15 @@ static GDebugKey debug_keys[] = { static gpointer default_shell; static guint signals[LAST_SIGNAL]; +/* Forward Declarations */ +static void e_shell_initable_init (GInitableIface *interface); + G_DEFINE_TYPE_WITH_CODE ( EShell, e_shell, - UNIQUE_TYPE_APP, + GTK_TYPE_APPLICATION, + G_IMPLEMENT_INTERFACE ( + G_TYPE_INITABLE, e_shell_initable_init) G_IMPLEMENT_INTERFACE ( E_TYPE_EXTENSIBLE, NULL)) @@ -218,6 +224,57 @@ shell_window_weak_notify_cb (EShell *shell, g_object_ref (shell)); } +static void +shell_action_new_window_cb (GSimpleAction *action, + GVariant *parameter, + EShell *shell) +{ + const gchar *view_name; + + view_name = g_variant_get_string (parameter, NULL); + e_shell_create_shell_window (shell, view_name); +} + +static void +shell_action_quit_cb (GSimpleAction *action, + GVariant *parameter, + EShell *shell) +{ + e_shell_quit (shell, E_SHELL_QUIT_REMOTE_REQUEST); +} + +static void +shell_add_actions (GApplication *application) +{ + EShell *shell; + GSimpleActionGroup *action_group; + GSimpleAction *action; + + /* Add actions that remote instances can invoke. */ + + action_group = g_simple_action_group_new (); + + action = g_simple_action_new ("new-window", G_VARIANT_TYPE_STRING); + g_signal_connect ( + action, "activate", + G_CALLBACK (shell_action_new_window_cb), application); + g_simple_action_group_insert (action_group, G_ACTION (action)); + g_object_unref (action); + + action = g_simple_action_new ("quit", NULL); + g_signal_connect ( + action, "activate", + G_CALLBACK (shell_action_quit_cb), application); + g_simple_action_group_insert (action_group, G_ACTION (action)); + g_object_unref (action); + + shell = E_SHELL (application); + shell->priv->action_group = G_ACTION_GROUP (action_group); + + g_application_set_action_group ( + application, shell->priv->action_group); +} + static void shell_ready_for_offline (EShell *shell, EActivity *activity, @@ -658,6 +715,11 @@ shell_dispose (GObject *object) priv->gconf_client = NULL; } + if (priv->action_group != NULL) { + g_object_unref (priv->action_group); + priv->action_group = NULL; + } + if (priv->preferences_window != NULL) { g_object_unref (priv->preferences_window); priv->preferences_window = NULL; @@ -683,10 +745,6 @@ shell_finalize (GObject *object) 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))) - e_file_lock_destroy (); - g_list_foreach (priv->loaded_backends, (GFunc) g_object_unref, NULL); g_list_free (priv->loaded_backends); @@ -706,21 +764,34 @@ shell_constructed (GObject *object) g_object_add_weak_pointer (object, &default_shell); } - if (!unique_app_is_running (UNIQUE_APP (object))) - e_file_lock_create (); - /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_shell_parent_class)->constructed (object); } -static UniqueResponse -shell_message_handle_activate (EShell *shell, - UniqueMessageData *data) +static void +shell_startup (GApplication *application) +{ + e_file_lock_create (); + + /* Destroy the lock file when the EShell is finalized + * to indicate a clean shut down to the next session. */ + g_object_weak_ref ( + G_OBJECT (application), + (GWeakNotify) e_file_lock_destroy, NULL); + + /* Chain up to parent's startup() method. */ + G_APPLICATION_CLASS (e_shell_parent_class)->startup (application); +} + +static void +shell_activate (GApplication *application) { + EShell *shell; GList *watched_windows; - GdkScreen *screen; - screen = unique_message_data_get_screen (data); + /* Do not chain up. Default method just emits a warning. */ + + shell = E_SHELL (application); watched_windows = e_shell_get_watched_windows (shell); /* Present the first EShellWindow, if found. */ @@ -728,9 +799,8 @@ shell_message_handle_activate (EShell *shell, GtkWindow *window = GTK_WINDOW (watched_windows->data); if (E_IS_SHELL_WINDOW (window)) { - gtk_window_set_screen (window, screen); gtk_window_present (window); - return UNIQUE_RESPONSE_OK; + return; } watched_windows = g_list_next (watched_windows); @@ -738,108 +808,55 @@ shell_message_handle_activate (EShell *shell, /* No EShellWindow found, so create one. */ e_shell_create_shell_window (shell, NULL); - - return UNIQUE_RESPONSE_OK; } -static UniqueResponse -shell_message_handle_new (EShell *shell, - UniqueMessageData *data) -{ - gchar *view_name; - - view_name = unique_message_data_get_text (data); - e_shell_create_shell_window (shell, view_name); - g_free (view_name); - - return UNIQUE_RESPONSE_OK; -} - -static UniqueResponse -shell_message_handle_open (EShell *shell, - UniqueMessageData *data) +static void +shell_open (GApplication *application, + GFile **files, + gint n_files, + const gchar *hint) { + EShell *shell; gchar **uris; + gint ii; - uris = unique_message_data_get_uris (data); - if (uris && uris[0] && g_str_equal (uris[0], "--import")) { - gint ii; - GPtrArray *arr = g_ptr_array_new (); + /* Do not chain up. Default method just emits a warning. */ - /* skip the first argument */ - for (ii = 1; uris[ii] != NULL; ii++) { - g_ptr_array_add (arr, uris[ii]); - } + shell = E_SHELL (application); + uris = g_new0 (gchar *, n_files + 1); - g_ptr_array_add (arr, NULL); + for (ii = 0; ii < n_files; ii++) + uris[ii] = g_file_get_uri (files[ii]); - e_shell_handle_uris (shell, (gchar **)arr->pdata, TRUE); + e_shell_handle_uris (shell, uris, FALSE); - g_ptr_array_free (arr, TRUE); - } else { - e_shell_handle_uris (shell, uris, FALSE); - } g_strfreev (uris); - - return UNIQUE_RESPONSE_OK; } -static UniqueResponse -shell_message_handle_close (EShell *shell, - UniqueMessageData *data) +static void +shell_window_destroyed (EShell *shell) { - UniqueResponse response; - - if (e_shell_quit (shell, E_SHELL_QUIT_REMOTE_REQUEST)) - response = UNIQUE_RESPONSE_OK; - else - response = UNIQUE_RESPONSE_CANCEL; - - return response; + if (e_shell_get_watched_windows (shell) == NULL) + gtk_main_quit (); } -static UniqueResponse -shell_message_received (UniqueApp *app, - gint command, - UniqueMessageData *data, - guint time_) +static gboolean +shell_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) { - EShell *shell = E_SHELL (app); - - switch (command) { - case UNIQUE_ACTIVATE: - return shell_message_handle_activate (shell, data); - - case UNIQUE_NEW: - return shell_message_handle_new (shell, data); + GApplication *application = G_APPLICATION (initable); - case UNIQUE_OPEN: - return shell_message_handle_open (shell, data); - - case UNIQUE_CLOSE: - return shell_message_handle_close (shell, data); - - default: - break; - } + shell_add_actions (application); - /* Chain up to parent's message_received() method. */ - return UNIQUE_APP_CLASS (e_shell_parent_class)-> - message_received (app, command, data, time_); -} - -static void -shell_window_destroyed (EShell *shell) -{ - if (e_shell_get_watched_windows (shell) == NULL) - gtk_main_quit (); + return g_application_register (application, cancellable, error); } static void e_shell_class_init (EShellClass *class) { GObjectClass *object_class; - UniqueAppClass *unique_app_class; + GApplicationClass *application_class; g_type_class_add_private (class, sizeof (EShellPrivate)); @@ -850,8 +867,10 @@ e_shell_class_init (EShellClass *class) object_class->finalize = shell_finalize; object_class->constructed = shell_constructed; - unique_app_class = UNIQUE_APP_CLASS (class); - unique_app_class->message_received = shell_message_received; + application_class = G_APPLICATION_CLASS (class); + application_class->startup = shell_startup; + application_class->activate = shell_activate; + application_class->open = shell_open; class->window_destroyed = shell_window_destroyed; @@ -1161,6 +1180,12 @@ e_shell_class_init (EShellClass *class) G_TYPE_NONE, 0); } +static void +e_shell_initable_init (GInitableIface *interface) +{ + interface->init = shell_initable_init; +} + static void e_shell_init (EShell *shell) { @@ -1347,8 +1372,8 @@ e_shell_get_canonical_name (EShell *shell, g_return_val_if_fail (E_IS_SHELL (shell), NULL); - /* Handle NULL name arguments silently. */ - if (name == NULL) + /* Handle NULL or empty name arguments silently. */ + if (name == NULL || *name == '\0') return NULL; shell_backend = e_shell_get_backend_by_name (shell, name); @@ -1455,16 +1480,12 @@ e_shell_create_shell_window (EShell *shell, const gchar *view_name) { GtkWidget *shell_window; - UniqueMessageData *data; - UniqueApp *app; GList *link; g_return_val_if_fail (E_IS_SHELL (shell), NULL); - app = UNIQUE_APP (shell); - - if (unique_app_is_running (app)) - goto unique; + if (g_application_get_is_remote (G_APPLICATION (shell))) + goto remote; view_name = e_shell_get_canonical_name (shell, view_name); @@ -1508,17 +1529,14 @@ e_shell_create_shell_window (EShell *shell, return shell_window; -unique: /* Send a message to the other Evolution process. */ - - /* XXX Do something with UniqueResponse? */ +remote: /* Send a message to the other Evolution process. */ if (view_name != NULL) { - data = unique_message_data_new (); - unique_message_data_set_text (data, view_name, -1); - unique_app_send_message (app, UNIQUE_NEW, data); - unique_message_data_free (data); + g_action_group_activate_action ( + shell->priv->action_group, "new-window", + g_variant_new_string (view_name)); } else - unique_app_send_message (app, UNIQUE_ACTIVATE, NULL); + g_application_activate (G_APPLICATION (shell)); return NULL; } @@ -1538,18 +1556,15 @@ e_shell_handle_uris (EShell *shell, gchar **uris, gboolean do_import) { - UniqueApp *app; - UniqueMessageData *data; + GFile **files; guint n_handled = 0; - gint ii; + guint length, ii; g_return_val_if_fail (E_IS_SHELL (shell), FALSE); g_return_val_if_fail (uris != NULL, FALSE); - app = UNIQUE_APP (shell); - - if (unique_app_is_running (app)) - goto unique; + if (g_application_get_is_remote (G_APPLICATION (shell))) + goto remote; if (do_import) { n_handled = e_shell_utils_import_uris (shell, uris); @@ -1569,34 +1584,23 @@ e_shell_handle_uris (EShell *shell, return n_handled; -unique: /* Send a message to the other Evolution process. */ +remote: /* Send a message to the other Evolution process. */ - /* XXX Do something with UniqueResponse? */ + length = g_strv_length (uris); - data = unique_message_data_new (); - if (do_import) { - GPtrArray *arr = g_ptr_array_new (); + files = g_new0 (GFile *, length + 1); + for (ii = 0; ii < length; ii++) + files[ii] = g_file_new_for_uri (uris[ii]); - g_ptr_array_add (arr, (gpointer)"--import"); + g_application_open (G_APPLICATION (shell), files, length, ""); - for (ii = 0; uris[ii] != NULL; ii++) { - g_ptr_array_add (arr, uris[ii]); - } - - g_ptr_array_add (arr, NULL); - - unique_message_data_set_uris (data, (gchar **)arr->pdata); - - g_ptr_array_free (arr, TRUE); - } else { - unique_message_data_set_uris (data, uris); - } - unique_app_send_message (app, UNIQUE_OPEN, data); - unique_message_data_free (data); + for (ii = 0; ii < length; ii++) + g_object_unref (files[ii]); + g_free (files); /* As far as we're concerned, all URIs have been handled. */ - return g_strv_length (uris); + return length; } /** @@ -1655,6 +1659,12 @@ e_shell_watch_window (EShell *shell, list = shell->priv->watched_windows; + /* XXX If my suggestion in [1] is accepted for GtkApplication + * then we can get rid of our own watched_windows list. + * + * [1] https://bugzilla.gnome.org/show_bug.cgi?id=624539 + */ + /* Ignore duplicates. */ if (g_list_find (list, window) != NULL) return; @@ -1662,7 +1672,7 @@ e_shell_watch_window (EShell *shell, list = g_list_prepend (list, window); shell->priv->watched_windows = list; - unique_app_watch_window (UNIQUE_APP (shell), window); + gtk_application_add_window (GTK_APPLICATION (shell), window); /* We use the window's own type name and memory * address to form a unique window role for X11. */ @@ -1987,15 +1997,10 @@ gboolean e_shell_quit (EShell *shell, EShellQuitReason reason) { - UniqueApp *app; - UniqueResponse response; - g_return_val_if_fail (E_IS_SHELL (shell), FALSE); - app = UNIQUE_APP (shell); - - if (unique_app_is_running (app)) - goto unique; + if (g_application_get_is_remote (G_APPLICATION (shell))) + goto remote; if (!shell_request_quit (shell, reason)) return FALSE; @@ -2004,11 +2009,12 @@ e_shell_quit (EShell *shell, return TRUE; -unique: /* Send a message to the other Evolution process. */ +remote: /* Send a message to the other Evolution process. */ - response = unique_app_send_message (app, UNIQUE_CLOSE, NULL); + g_action_group_activate_action ( + shell->priv->action_group, "quit", NULL); - return (response == UNIQUE_RESPONSE_OK); + return TRUE; } /** diff --git a/shell/e-shell.h b/shell/e-shell.h index 22aef9252f..bbb11467fc 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -22,7 +22,6 @@ #ifndef E_SHELL_H #define E_SHELL_H -#include #include #include @@ -90,12 +89,12 @@ typedef enum { * functions below. **/ struct _EShell { - UniqueApp parent; + GtkApplication parent; EShellPrivate *priv; }; struct _EShellClass { - UniqueAppClass parent_class; + GtkApplicationClass parent_class; gboolean (*handle_uri) (EShell *shell, const gchar *uri); @@ -154,7 +153,7 @@ gboolean e_shell_quit (EShell *shell, EShellQuitReason reason); void e_shell_cancel_quit (EShell *shell); -void e_shell_adapt_window_size (EShell *shell, +void e_shell_adapt_window_size (EShell *shell, GtkWindow *window); void e_shell_set_startup_view (EShell *shell, const gchar *view); diff --git a/shell/main.c b/shell/main.c index f9c9651e49..a27b6b9495 100644 --- a/shell/main.c +++ b/shell/main.c @@ -84,6 +84,8 @@ #include #endif +#define APPLICATION_ID "org.gnome.Evolution" + #define SKIP_WARNING_DIALOG_KEY \ "/apps/evolution/shell/skip_warning_dialog" @@ -257,7 +259,7 @@ idle_cb (gchar **uris) } /* If another Evolution process is running, we're done. */ - if (unique_app_is_running (UNIQUE_APP (shell))) + if (g_application_get_is_remote (G_APPLICATION (shell))) gtk_main_quit (); return FALSE; @@ -324,7 +326,8 @@ quit_signal (gint sig) g_print ("Received quit signal...\n"); shell = e_shell_get_default (); - if (shell) + + if (shell != NULL) e_shell_quit (shell, E_SHELL_QUIT_OPTION); } @@ -411,10 +414,12 @@ create_default_shell (void) { EShell *shell; GConfClient *client; - gboolean online = TRUE; + GApplicationFlags flags; const gchar *key; + gboolean online = TRUE; + gboolean is_meego = FALSE; + gboolean small_screen = FALSE; GError *error = NULL; - gboolean is_meego = FALSE, small_screen = FALSE; client = gconf_client_get_default (); @@ -457,9 +462,13 @@ create_default_shell (void) g_clear_error (&error); } - shell = g_object_new ( - E_TYPE_SHELL, - "name", "org.gnome.Evolution", + flags = G_APPLICATION_HANDLES_OPEN | + G_APPLICATION_HANDLES_COMMAND_LINE; + + shell = g_initable_new ( + E_TYPE_SHELL, NULL, &error, + "application-id", APPLICATION_ID, + "flags", flags, "geometry", geometry, "module-directory", EVOLUTION_MODULEDIR, "meego-mode", is_meego, @@ -468,6 +477,10 @@ create_default_shell (void) "online", online, NULL); + /* Failure to register is fatal. */ + if (error != NULL) + g_error ("%s", error->message); + if (force_online) e_shell_lock_network_available (shell); @@ -571,9 +584,9 @@ main (gint argc, gchar **argv) exit (1); } - #ifdef HAVE_ICAL_UNKNOWN_TOKEN_HANDLING +#ifdef HAVE_ICAL_UNKNOWN_TOKEN_HANDLING ical_set_unknown_token_handling_setting (ICAL_DISCARD_TOKEN); - #endif +#endif #ifdef G_OS_WIN32 path = g_build_path (";", _e_get_bindir (), g_getenv ("PATH"), NULL); @@ -622,6 +635,7 @@ main (gint argc, gchar **argv) setlocale (LC_ALL, "C"); } #endif + if (start_online && start_offline) { g_printerr ( _("%s: --online and --offline cannot be used " -- cgit v1.2.3