From b7333387e8bd19299794e6485e3407d03c2eb73f Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sun, 14 Dec 2008 02:14:41 +0000 Subject: - Fix NetworkManager connection tracking. - Implement offline preparation as an EActivity that gets broadcast in a signal to shell modules. Offline preparations are complete when the last EActivity reference is dropped. - Bind some of the composer preferences to EShellSettings properties. svn path=/branches/kill-bonobo/; revision=36875 --- shell/e-shell-nm.c | 41 ++++---- shell/e-shell-window-actions.c | 4 +- shell/e-shell.c | 229 +++++++++++++++++++++++++++++++++++++---- shell/e-shell.h | 14 +-- 4 files changed, 237 insertions(+), 51 deletions(-) (limited to 'shell') diff --git a/shell/e-shell-nm.c b/shell/e-shell-nm.c index c0cae505dc..48652501da 100644 --- a/shell/e-shell-nm.c +++ b/shell/e-shell-nm.c @@ -52,15 +52,14 @@ e_shell_network_monitor (DBusConnection *connection G_GNUC_UNUSED, gpointer user_data) { DBusError error = DBUS_ERROR_INIT; - const gchar *object; EShell *shell = user_data; - EShellLineStatus line_status; - gboolean device_active; + const gchar *path; + guint32 state; - object = dbus_message_get_path (message); + path = dbus_message_get_path (message); if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") && - object != NULL && strcmp (object, DBUS_PATH_LOCAL) == 0) { + path != NULL && strcmp (path, DBUS_PATH_LOCAL) == 0) { dbus_connection_unref (dbus_connection); dbus_connection = NULL; @@ -69,23 +68,29 @@ e_shell_network_monitor (DBusConnection *connection G_GNUC_UNUSED, return DBUS_HANDLER_RESULT_HANDLED; } - if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNoLongerActive")) - device_active = FALSE; - else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNowActive")) - device_active = TRUE; - else + if (!dbus_message_is_signal (message, NM_DBUS_INTERFACE, "StateChanged")) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (!dbus_message_get_args (message, &error, DBUS_TYPE_OBJECT_PATH, - &object, DBUS_TYPE_INVALID)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + dbus_message_get_args ( + message, &error, + DBUS_TYPE_UINT32, &state, + DBUS_TYPE_INVALID); - line_status = e_shell_get_line_status (shell); + if (dbus_error_is_set (&error)) { + g_warning ("%s", error.message); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } - if (line_status == E_SHELL_LINE_STATUS_ONLINE && !device_active) - e_shell_set_line_status (shell, E_SHELL_LINE_STATUS_FORCED_OFFLINE); - else if (line_status == E_SHELL_LINE_STATUS_FORCED_OFFLINE && device_active) - e_shell_set_line_status (shell, E_SHELL_LINE_STATUS_ONLINE); + switch (state) { + case NM_STATE_CONNECTED: + e_shell_set_network_available (shell, TRUE); + break; + case NM_STATE_DISCONNECTED: + e_shell_set_network_available (shell, FALSE); + break; + default: + break; + } return DBUS_HANDLER_RESULT_HANDLED; } diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c index 38f33d99e9..707edd8439 100644 --- a/shell/e-shell-window-actions.c +++ b/shell/e-shell-window-actions.c @@ -1365,7 +1365,7 @@ action_work_offline_cb (GtkAction *action, EShell *shell; shell = e_shell_window_get_shell (shell_window); - e_shell_set_line_status (shell, E_SHELL_LINE_STATUS_OFFLINE); + e_shell_set_online_mode (shell, FALSE); } /** @@ -1383,7 +1383,7 @@ action_work_online_cb (GtkAction *action, EShell *shell; shell = e_shell_window_get_shell (shell_window); - e_shell_set_line_status (shell, E_SHELL_LINE_STATUS_ONLINE); + e_shell_set_online_mode (shell, TRUE); } /** diff --git a/shell/e-shell.c b/shell/e-shell.c index 6e92750eb9..57118a4e14 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -22,12 +22,14 @@ #include "e-shell.h" #include -#include -#include +#include -#include -#include -#include +#include "e-util/e-util.h" +#include "widgets/misc/e-preferences-window.h" + +#include "e-shell-migrate.h" +#include "e-shell-module.h" +#include "e-shell-window.h" #define SHUTDOWN_TIMEOUT 500 /* milliseconds */ @@ -38,19 +40,23 @@ struct _EShellPrivate { GList *active_windows; EShellSettings *settings; - EShellLineStatus line_status; /* Shell Modules */ GList *loaded_modules; GHashTable *modules_by_name; GHashTable *modules_by_scheme; - guint online_mode : 1; - guint safe_mode : 1; + gpointer preparing_for_offline; /* weak pointer */ + + guint auto_reconnect : 1; + guint network_available : 1; + guint online_mode : 1; + guint safe_mode : 1; }; enum { PROP_0, + PROP_NETWORK_AVAILABLE, PROP_ONLINE_MODE, PROP_SETTINGS }; @@ -58,6 +64,7 @@ enum { enum { EVENT, HANDLE_URI, + PREPARE_FOR_OFFLINE, SEND_RECEIVE, WINDOW_CREATED, WINDOW_DESTROYED, @@ -109,6 +116,15 @@ shell_window_focus_in_event_cb (EShell *shell, return FALSE; } +static void +shell_notify_online_mode_cb (EShell *shell) +{ + gboolean online; + + online = e_shell_get_online_mode (shell); + e_passwords_set_online (online); +} + static void shell_window_weak_notify_cb (EShell *shell, GObject *where_the_object_was) @@ -124,6 +140,53 @@ shell_window_weak_notify_cb (EShell *shell, g_signal_emit (shell, signals[WINDOW_DESTROYED], 0, last_window); } +static void +shell_ready_for_offline (EShell *shell, + EActivity *activity, + gboolean is_last_ref) +{ + if (!is_last_ref) + return; + + e_activity_complete (activity); + + g_object_remove_toggle_ref ( + G_OBJECT (activity), (GToggleNotify) + shell_ready_for_offline, shell); + + shell->priv->online_mode = FALSE; + g_object_notify (G_OBJECT (shell), "online-mode"); + + g_message ("Offline preparations complete."); +} + +static void +shell_prepare_for_offline (EShell *shell) +{ + /* Are preparations already in progress? */ + if (shell->priv->preparing_for_offline != NULL) + return; + + g_message ("Preparing for offline mode..."); + + shell->priv->preparing_for_offline = + e_activity_new (_("Preparing to go offline...")); + + g_object_add_toggle_ref ( + G_OBJECT (shell->priv->preparing_for_offline), + (GToggleNotify) shell_ready_for_offline, shell); + + g_object_add_weak_pointer ( + G_OBJECT (shell->priv->preparing_for_offline), + &shell->priv->preparing_for_offline); + + g_signal_emit ( + shell, signals[PREPARE_FOR_OFFLINE], 0, + shell->priv->preparing_for_offline); + + g_object_unref (shell->priv->preparing_for_offline); +} + /* Helper for shell_query_module() */ static void shell_split_and_insert_items (GHashTable *hash_table, @@ -241,6 +304,12 @@ shell_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_NETWORK_AVAILABLE: + e_shell_set_network_available ( + E_SHELL (object), + g_value_get_boolean (value)); + return; + case PROP_ONLINE_MODE: e_shell_set_online_mode ( E_SHELL (object), @@ -258,6 +327,12 @@ shell_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_NETWORK_AVAILABLE: + g_value_set_boolean ( + value, e_shell_get_network_available ( + E_SHELL (object))); + return; + case PROP_ONLINE_MODE: g_value_set_boolean ( value, e_shell_get_online_mode ( @@ -360,6 +435,22 @@ shell_class_init (EShellClass *class) object_class->finalize = shell_finalize; object_class->constructed = shell_constructed; + /** + * EShell:network-available + * + * Whether the network is available. + **/ + g_object_class_install_property ( + object_class, + PROP_NETWORK_AVAILABLE, + g_param_spec_boolean ( + "network-available", + _("Network Available"), + _("Whether the network is available"), + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + /** * EShell:online-mode * @@ -430,6 +521,31 @@ shell_class_init (EShellClass *class) G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + /** + * EShell:prepare-for-offline + * @shell: the #EShell which emitted the signal + * @activity: the #EActivity for offline preparations + * + * Emitted when the user elects to work offline. An #EShellModule + * should listen for this signal and make preparations for working + * in offline mode. + * + * If preparations for working offline cannot immediately be + * completed (such as when synchronizing with a remote server), + * the #EShellModule should reference the @activity until + * preparations are complete, and then unreference the @activity. + * This will delay Evolution from actually going to offline mode + * until the all modules have unreferenced @activity. + */ + signals[PREPARE_FOR_OFFLINE] = g_signal_new ( + "prepare-for-offline", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_ACTIVITY); + /** * EShell:send-receive * @shell: the #EShell which emitted the signal @@ -501,6 +617,10 @@ shell_init (EShell *shell) #endif e_file_lock_create (); + + g_signal_connect ( + shell, "notify::online-mode", + G_CALLBACK (shell_notify_online_mode_cb), NULL); } GType @@ -762,37 +882,106 @@ e_shell_send_receive (EShell *shell, g_signal_emit (shell, signals[SEND_RECEIVE], 0, parent); } +/** + * e_shell_get_network_available: + * @shell: an #EShell + * + * Returns %TRUE if a network is available. + * + * Returns: %TRUE if a network is available + **/ gboolean -e_shell_get_online_mode (EShell *shell) +e_shell_get_network_available (EShell *shell) { g_return_val_if_fail (E_IS_SHELL (shell), FALSE); - return shell->priv->online_mode; + return shell->priv->network_available; } +/** + * e_shell_set_network_available: + * @shell: an #EShell + * @network_available: whether a network is available + * + * Sets whether a network is available. This is usually called in + * response to a status change signal from NetworkManager. If the + * network becomes unavailable while #EShell:online-mode is %TRUE, + * the @shell will force #EShell:online-mode to %FALSE until the + * network becomes available again. + **/ void -e_shell_set_online_mode (EShell *shell, - gboolean online_mode) +e_shell_set_network_available (EShell *shell, + gboolean network_available) { g_return_if_fail (E_IS_SHELL (shell)); - shell->priv->online_mode = online_mode; + if (network_available == shell->priv->network_available) + return; - g_object_notify (G_OBJECT (shell), "online-mode"); + shell->priv->network_available = network_available; + g_object_notify (G_OBJECT (shell), "network-available"); + + /* If we're being forced offline, perhaps due to a network outage, + * reconnect automatically when the network becomes available. */ + if (!network_available && shell->priv->online_mode) { + g_message ("Network disconnected. Forced offline."); + e_shell_set_online_mode (shell, FALSE); + shell->priv->auto_reconnect = TRUE; + } else if (network_available && shell->priv->auto_reconnect) { + g_message ("Connection established. Going online."); + e_shell_set_online_mode (shell, TRUE); + shell->priv->auto_reconnect = FALSE; + } } -EShellLineStatus -e_shell_get_line_status (EShell *shell) +/** + * e_shell_get_online_mode: + * @shell: an #EShell + * + * Returns %TRUE if Evolution is in online mode, %FALSE if Evolution is + * offline. Evolution may be offline because the user elected to work + * offline, or because the network has become unavailable. + * + * Returns: %TRUE if Evolution is in online mode + **/ +gboolean +e_shell_get_online_mode (EShell *shell) { - g_return_val_if_fail (E_IS_SHELL (shell), E_SHELL_LINE_STATUS_OFFLINE); + g_return_val_if_fail (E_IS_SHELL (shell), FALSE); - return shell->priv->line_status; + return shell->priv->online_mode; } +/** + * e_shell_set_online_mode: + * @shell: an #EShell + * @online_mode: whether to put Evolution in online mode + * + * Puts Evolution in online or offline mode. + **/ void -e_shell_set_line_status (EShell *shell, - EShellLineStatus status) +e_shell_set_online_mode (EShell *shell, + gboolean online_mode) { + g_return_if_fail (E_IS_SHELL (shell)); + + if (online_mode == shell->priv->online_mode) + return; + + if (!online_mode && e_shell_get_network_available (shell)) + shell_prepare_for_offline (shell); + else { + EActivity *activity; + + shell->priv->online_mode = online_mode; + g_object_notify (G_OBJECT (shell), "online-mode"); + + /* If we're being forced offline and we've already started + * preparing for offline mode, cancel the preparations. */ + activity = shell->priv->preparing_for_offline; + if (!online_mode && activity != NULL) + e_activity_cancel (activity); + } } GtkWidget * diff --git a/shell/e-shell.h b/shell/e-shell.h index 79ff9c1783..e482f93960 100644 --- a/shell/e-shell.h +++ b/shell/e-shell.h @@ -74,13 +74,6 @@ struct _EShellClass { GObjectClass parent_class; }; -enum _EShellLineStatus { - E_SHELL_LINE_STATUS_ONLINE, - E_SHELL_LINE_STATUS_GOING_OFFLINE, /* NB: really means changing state in either direction */ - E_SHELL_LINE_STATUS_OFFLINE, - E_SHELL_LINE_STATUS_FORCED_OFFLINE -}; - GType e_shell_get_type (void); EShell * e_shell_get_default (void); GList * e_shell_list_modules (EShell *shell); @@ -97,13 +90,12 @@ gboolean e_shell_handle_uri (EShell *shell, const gchar *uri); void e_shell_send_receive (EShell *shell, GtkWindow *parent); +gboolean e_shell_get_network_available (EShell *shell); +void e_shell_set_network_available (EShell *shell, + gboolean network_available); gboolean e_shell_get_online_mode (EShell *shell); void e_shell_set_online_mode (EShell *shell, gboolean online_mode); -EShellLineStatus - e_shell_get_line_status (EShell *shell); -void e_shell_set_line_status (EShell *shell, - EShellLineStatus status); GtkWidget * e_shell_get_preferences_window (void); void e_shell_event (EShell *shell, const gchar *event_name, -- cgit