From 8dd50ff5e07c449e6cdca0abfd868826673fcba5 Mon Sep 17 00:00:00 2001 From: Jose Dapena Paz Date: Mon, 26 May 2008 16:29:18 +0000 Subject: [PATCH] Fix for bug NB#83343 * src/modest-mail-operation-queue.[ch]: * Add the special handling for shutdown sync mail operation. This operation should be requested everytime we decide that modest should be finished (mail operation queue is empty, and no windows displayed). If queue exhaust again, and the last operation finished was that shutdown sync, then we can close modest safely. This way we don't have to sync on shutdown process itself. * src/modest-main.c: * On (on_idle_exit_modest) handler implement checking for last operation. If last operation was the shutdown sync then we close silently. If not then we have to run the operation. * src/modest-init.c: * Move to the last shutdown step the gnome vfs shutdown. * src/modest-mail-operation.[ch]: * Add shutdown mail operation. This simply syncs all accounts * src/modest-tny-account-store.[ch]: * New async method that shutdowns all accounts in a store. * Now the finalize of the account store does not shutdown the accounts as this step should have happened before. pmo-trunk-r4572 --- src/modest-init.c | 6 +-- src/modest-mail-operation-queue.c | 26 ++++++++++++ src/modest-mail-operation-queue.h | 22 ++++++++++ src/modest-mail-operation.c | 37 +++++++++++++++++ src/modest-mail-operation.h | 12 ++++++ src/modest-main.c | 44 ++++++++++++-------- src/modest-tny-account-store.c | 80 +++++++++++++++++++++++++++++-------- src/modest-tny-account-store.h | 15 +++++++ 8 files changed, 207 insertions(+), 35 deletions(-) diff --git a/src/modest-init.c b/src/modest-init.c index e3f54de..c06fae9 100644 --- a/src/modest-init.c +++ b/src/modest-init.c @@ -297,15 +297,15 @@ modest_init_uninit (void) if (!_is_initialized) return TRUE; - if (gnome_vfs_initialized()) /* apparently, this returns TRUE, even after a shutdown */ - gnome_vfs_shutdown (); - if (!modest_runtime_uninit()) g_printerr ("modest: failed to uninit runtime\n"); if (!modest_platform_uninit()) g_printerr ("modest: failed to uninit platform\n"); + if (gnome_vfs_initialized()) /* apparently, this returns TRUE, even after a shutdown */ + gnome_vfs_shutdown (); + _is_initialized = FALSE; return TRUE; } diff --git a/src/modest-mail-operation-queue.c b/src/modest-mail-operation-queue.c index aadb3b8..804a656 100644 --- a/src/modest-mail-operation-queue.c +++ b/src/modest-mail-operation-queue.c @@ -55,6 +55,7 @@ struct _ModestMailOperationQueuePrivate { GMutex *queue_lock; guint op_id; guint queue_empty_handler; + gboolean running_final_sync; }; #define MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_MAIL_OPERATION_QUEUE, \ @@ -148,6 +149,7 @@ modest_mail_operation_queue_init (ModestMailOperationQueue *obj) priv->queue_lock = g_mutex_new (); priv->op_id = 0; priv->queue_empty_handler = 0; + priv->running_final_sync = FALSE; } static void @@ -246,6 +248,8 @@ modest_mail_operation_queue_add (ModestMailOperationQueue *self, priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + priv->running_final_sync = (modest_mail_operation_get_type_operation (mail_op) == MODEST_MAIL_OPERATION_TYPE_SHUTDOWN); + g_mutex_lock (priv->queue_lock); g_queue_push_tail (priv->op_queue, g_object_ref (mail_op)); g_mutex_unlock (priv->queue_lock); @@ -512,3 +516,25 @@ modest_mail_operation_queue_to_string (ModestMailOperationQueue *self) return str; } + +gboolean +modest_mail_operation_queue_running_shutdown (ModestMailOperationQueue *self) +{ + ModestMailOperationQueuePrivate *priv; + + g_return_val_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self), FALSE); + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + return priv->running_final_sync; +} + +void +modest_mail_operation_queue_set_running_shutdown (ModestMailOperationQueue *self) +{ + ModestMailOperationQueuePrivate *priv; + + g_return_if_fail (MODEST_IS_MAIL_OPERATION_QUEUE (self)); + + priv = MODEST_MAIL_OPERATION_QUEUE_GET_PRIVATE(self); + priv->running_final_sync = TRUE; +} diff --git a/src/modest-mail-operation-queue.h b/src/modest-mail-operation-queue.h index 0a1e08f..4171306 100644 --- a/src/modest-mail-operation-queue.h +++ b/src/modest-mail-operation-queue.h @@ -142,6 +142,28 @@ GSList* modest_mail_operation_queue_get_by_source (ModestMailOperationQueue *op_ **/ gchar* modest_mail_operation_queue_to_string (ModestMailOperationQueue *self); +/** + * modest_mail_operation_queue_set_running_shutdown: + * @self: a #ModestMailOperationQueue + * + * Mark the queue as running the final sync. + * + */ +void +modest_mail_operation_queue_set_running_shutdown (ModestMailOperationQueue *self); + +/** + * modest_mail_operation_queue_running_shutdown: + * @self: a #ModestMailOperationQueue + * + * Is the last operation queued a shutdown operation? + * + * Returns: a #gboolean, %TRUE if the last queued operation is + * a shutdown, %FALSE otherwise + */ +gboolean +modest_mail_operation_queue_running_shutdown (ModestMailOperationQueue *self); + G_END_DECLS #endif /* __MODEST_MAIL_OPERATION_QUEUE_H__ */ diff --git a/src/modest-mail-operation.c b/src/modest-mail-operation.c index 7c518d4..64afda8 100644 --- a/src/modest-mail-operation.c +++ b/src/modest-mail-operation.c @@ -3132,6 +3132,7 @@ run_queue_stop (ModestTnySendQueue *queue, g_signal_handlers_disconnect_by_func (queue, run_queue_stop, self); g_object_unref (self); } + void modest_mail_operation_run_queue (ModestMailOperation *self, ModestTnySendQueue *queue) @@ -3152,6 +3153,42 @@ modest_mail_operation_run_queue (ModestMailOperation *self, } static void +shutdown_callback (ModestTnyAccountStore *account_store, gpointer userdata) +{ + ModestMailOperation *self = (ModestMailOperation *) userdata; + ModestMailOperationPrivate *priv; + + g_return_if_fail (MODEST_IS_MAIL_OPERATION (self)); + g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store)); + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self); + + priv->status = MODEST_MAIL_OPERATION_STATUS_SUCCESS; + + modest_mail_operation_notify_end (self); + g_object_unref (self); +} + +void +modest_mail_operation_shutdown (ModestMailOperation *self, ModestTnyAccountStore *account_store) +{ + ModestMailOperationPrivate *priv; + + g_return_if_fail (MODEST_IS_MAIL_OPERATION (self)); + g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (account_store)); + priv = MODEST_MAIL_OPERATION_GET_PRIVATE (self); + + modest_mail_operation_queue_set_running_shutdown (modest_runtime_get_mail_operation_queue ()); + + priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS; + priv->account = NULL; + priv->op_type = MODEST_MAIL_OPERATION_TYPE_SHUTDOWN; + + modest_mail_operation_notify_start (self); + g_object_ref (self); + modest_tny_account_store_shutdown (account_store, shutdown_callback, self); +} + +static void sync_folder_finish_callback (TnyFolder *self, gboolean cancelled, GError *err, diff --git a/src/modest-mail-operation.h b/src/modest-mail-operation.h index 7c43ac0..9017847 100644 --- a/src/modest-mail-operation.h +++ b/src/modest-mail-operation.h @@ -34,6 +34,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -76,6 +77,7 @@ typedef enum { MODEST_MAIL_OPERATION_TYPE_INFO, MODEST_MAIL_OPERATION_TYPE_RUN_QUEUE, MODEST_MAIL_OPERATION_TYPE_SYNC_FOLDER, + MODEST_MAIL_OPERATION_TYPE_SHUTDOWN, MODEST_MAIL_OPERATION_TYPE_UNKNOWN, } ModestMailOperationTypeOperation; @@ -647,6 +649,16 @@ void modest_mail_operation_run_queue (ModestMailOperation *self, void modest_mail_operation_sync_folder (ModestMailOperation *self, TnyFolder *folder, gboolean expunge); +/** + * modest_mail_operation_shutdown: + * @self: a #ModestMailOperation + * @account_store: a #ModestTnyAccountStore + * + * disconnects all accounts in the account store (doing the proper syncs). + */ +void modest_mail_operation_shutdown (ModestMailOperation *self, + ModestTnyAccountStore *account_store); + /* Functions to control mail operations */ /** * modest_mail_operation_get_task_done: diff --git a/src/modest-main.c b/src/modest-main.c index b330ca2..3214858 100644 --- a/src/modest-main.c +++ b/src/modest-main.c @@ -46,23 +46,35 @@ static gboolean on_idle_exit_modest (gpointer data) { MainSignalHandlers *handlers; + ModestMailOperationQueue *mail_op_queue; /* Protect the Gtk calls */ gdk_threads_enter (); - - /* Disconnect signals. Will be freed by the destroy notify */ - handlers = (MainSignalHandlers *) data; - g_signal_handler_disconnect (modest_runtime_get_mail_operation_queue (), - handlers->queue_handler); - g_signal_handler_disconnect (modest_runtime_get_window_mgr (), - handlers->window_list_handler); - - /* Wait for remaining tasks */ - while (gtk_events_pending ()) - gtk_main_iteration (); - - gtk_main_quit (); - + mail_op_queue = modest_runtime_get_mail_operation_queue (); + + if (modest_mail_operation_queue_running_shutdown (mail_op_queue)) { + + /* Disconnect signals. Will be freed by the destroy notify */ + handlers = (MainSignalHandlers *) data; + g_signal_handler_disconnect (modest_runtime_get_mail_operation_queue (), + handlers->queue_handler); + g_signal_handler_disconnect (modest_runtime_get_window_mgr (), + handlers->window_list_handler); + /* Wait for remaining tasks */ + while (gtk_events_pending ()) + gtk_main_iteration (); + + g_free (handlers); + + gtk_main_quit (); + } else { + ModestMailOperation *mail_op; + mail_op = modest_mail_operation_new (NULL); + modest_mail_operation_queue_add (mail_op_queue, mail_op); + modest_mail_operation_shutdown (mail_op, modest_runtime_get_account_store ()); + g_object_unref (mail_op); + } + gdk_threads_leave (); return FALSE; @@ -78,7 +90,7 @@ on_queue_empty (ModestMailOperationQueue *queue, windows. We can exit as well if the main window is hidden and it's the only one */ if (modest_window_mgr_num_windows (mgr) == 0) - g_idle_add_full (G_PRIORITY_LOW, on_idle_exit_modest, user_data, g_free); + g_idle_add_full (G_PRIORITY_LOW, on_idle_exit_modest, user_data, NULL); } static void @@ -89,7 +101,7 @@ on_window_list_empty (ModestWindowMgr *window_mgr, /* Exit if there are no more windows and the queue is empty */ if (modest_mail_operation_queue_num_elements (queue) == 0) - g_idle_add_full (G_PRIORITY_LOW, on_idle_exit_modest, user_data, g_free); + g_idle_add_full (G_PRIORITY_LOW, on_idle_exit_modest, user_data, NULL); } int diff --git a/src/modest-tny-account-store.c b/src/modest-tny-account-store.c index f086183..f26d516 100644 --- a/src/modest-tny-account-store.c +++ b/src/modest-tny-account-store.c @@ -301,20 +301,6 @@ modest_tny_account_store_instance_init (ModestTnyAccountStore *obj) /* disconnect the list of TnyAccounts */ static void -account_disconnect (TnyAccount *account) -{ - g_return_if_fail (account && TNY_IS_ACCOUNT(account)); - - if (TNY_IS_STORE_ACCOUNT (account) && - !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) - return; - - tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL); -} - - -/* disconnect the list of TnyAccounts */ -static void account_verify_last_ref (TnyAccount *account, const gchar *str) { gchar *txt; @@ -838,14 +824,12 @@ modest_tny_account_store_finalize (GObject *obj) /* Destroy all accounts. Disconnect all accounts before they are destroyed */ if (priv->store_accounts) { - tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL); tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store"); g_object_unref (priv->store_accounts); priv->store_accounts = NULL; } if (priv->transport_accounts) { - tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL); tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport"); g_object_unref (priv->transport_accounts); priv->transport_accounts = NULL; @@ -2188,3 +2172,67 @@ modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *se } } + +typedef struct { + ModestTnyAccountStore *account_store; + ModestTnyAccountStoreShutdownCallback callback; + gpointer userdata; + gint pending; +} ShutdownOpData; + +static void +account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata) +{ + ShutdownOpData *op_data = (ShutdownOpData *) userdata; + op_data->pending--; + if (op_data->pending == 0) { + if (op_data->callback) + op_data->callback (op_data->account_store, op_data->userdata); + g_object_unref (op_data->account_store); + g_free (op_data); + } +} + +static void +account_shutdown (TnyAccount *account, ShutdownOpData *op_data) +{ + g_return_if_fail (account && TNY_IS_ACCOUNT(account)); + + if (TNY_IS_STORE_ACCOUNT (account) && + !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) + return; + + op_data->pending++; + + tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, account_shutdown_callback, op_data); +} + + +void +modest_tny_account_store_shutdown (ModestTnyAccountStore *self, + ModestTnyAccountStoreShutdownCallback callback, + gpointer userdata) +{ + ShutdownOpData *op_data = g_new0 (ShutdownOpData, 1); + ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self); + op_data->callback = callback; + op_data->userdata = userdata; + op_data->pending = 0; + op_data->account_store = g_object_ref (self); + + /* Destroy all accounts. Disconnect all accounts before they are destroyed */ + if (priv->store_accounts) { + tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data); + } + + if (priv->transport_accounts) { + tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data); + } + + if (op_data->pending == 0) { + if (op_data->callback) + op_data->callback (op_data->account_store, op_data->userdata); + g_object_unref (op_data->account_store); + g_free (op_data); + } +} diff --git a/src/modest-tny-account-store.h b/src/modest-tny-account-store.h index 1ed6d50..ccdb108 100644 --- a/src/modest-tny-account-store.h +++ b/src/modest-tny-account-store.h @@ -247,6 +247,21 @@ TnyTransportAccount * modest_tny_account_store_new_connection_specific_transport GtkWidget *modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *self, const gchar *account_name); +typedef void (*ModestTnyAccountStoreShutdownCallback) (ModestTnyAccountStore *account_store, gpointer userdata); + +/** + * modest_tny_account_store_shutdown: + * @self: a #ModestTnyAccountStore + * @callback: a #ModestTnyAccountStoreShutdownCallback + * @userdata: a #gpointer + * + * Disconnects all registered accounts (forcing syncs for all of them). + */ +void modest_tny_account_store_shutdown (ModestTnyAccountStore *self, + ModestTnyAccountStoreShutdownCallback callback, + gpointer userdata); + + G_END_DECLS #endif /* __MODEST_TNY_ACCOUNT_STORE_H__ */ -- 1.7.9.5