diff options
-rw-r--r-- | modules/startup-wizard/evolution-startup-wizard.c | 94 |
1 files changed, 93 insertions, 1 deletions
diff --git a/modules/startup-wizard/evolution-startup-wizard.c b/modules/startup-wizard/evolution-startup-wizard.c index 7917557f8d..cd2a363195 100644 --- a/modules/startup-wizard/evolution-startup-wizard.c +++ b/modules/startup-wizard/evolution-startup-wizard.c @@ -534,6 +534,9 @@ startup_wizard_run (EStartupWizard *extension) const gchar *startup_view; gboolean express_mode; + /* Accounts should now be loaded if there were any to load. + * Check, and proceed with the Evolution Setup Assistant. */ + shell = startup_wizard_get_shell (extension); express_mode = e_shell_get_express_mode (shell); startup_view = e_shell_get_startup_view (shell); @@ -560,6 +563,95 @@ startup_wizard_run (EStartupWizard *extension) } static void +startup_wizard_load_accounts_done (GMainLoop *loop, + EActivity *activity, + gboolean is_last_ref) +{ + /* All asynchronous account loading operations should + * be complete now, so we can terminate the main loop. */ + if (is_last_ref) + g_main_loop_quit (loop); +} + +static void +startup_wizard_load_accounts (EStartupWizard *extension) +{ + EShell *shell; + EActivity *activity; + GMainContext *context; + GMainLoop *loop; + GSource *source; + + /* This works similar to the offline and shutdown procedure in + * EShell. We broadcast a "load-accounts" EShell event with an + * EActivity. The EActivity has a toggle reference which we use + * as a counting semaphore. If another module needs to handle + * the event asynchronously, it should reference the EActivity + * until its async operation completes, then drop the reference. + * Once the signal handlers finish and only the toggle reference + * remains, we then proceed with the Evolution Setup Assistant. */ + + shell = startup_wizard_get_shell (extension); + + /* Start a temporary main loop so asynchronous account loading + * operations can signal completion from an idle callback. We push + * our own GMainContext as the thread-default so we don't trigger + * other GSources that have already been attached to the current + * thread-default context, such as the idle callback in main.c. */ + context = g_main_context_new (); + loop = g_main_loop_new (context, TRUE); + g_main_context_push_thread_default (context); + + activity = e_activity_new (); + e_activity_set_text (activity, _("Loading accounts...")); + + /* Drop our normal (non-toggle) EActivity reference from an + * idle callback. If nothing else references the EActivity + * then it will be a very short-lived main loop. */ + source = g_idle_source_new (); + g_source_set_callback ( + source, (GSourceFunc) gtk_false, + activity, (GDestroyNotify) g_object_unref); + g_source_attach (source, context); + g_source_unref (source); + + /* Add a toggle reference to the EActivity which, + * when triggered, will terminate the main loop. */ + g_object_add_toggle_ref ( + G_OBJECT (activity), (GToggleNotify) + startup_wizard_load_accounts_done, loop); + + /* Broadcast the "load-accounts" event. */ + e_shell_event (shell, "load-accounts", activity); + + /* And now we wait... */ + g_main_loop_run (loop); + + /* Increment the reference count so we can safely emit + * a signal without triggering the toggle reference. */ + g_object_ref (activity); + + e_activity_set_state (activity, E_ACTIVITY_COMPLETED); + + g_object_remove_toggle_ref ( + G_OBJECT (activity), (GToggleNotify) + startup_wizard_load_accounts_done, loop); + + /* Finalize the activity. */ + g_object_unref (activity); + + /* Finalize the main loop. */ + g_main_loop_unref (loop); + + /* Pop our GMainContext off the thread-default stack. */ + g_main_context_pop_thread_default (context); + g_main_context_unref (context); + + /* Proceed with the Evolution Setup Assistant. */ + startup_wizard_run (extension); +} + +static void startup_wizard_dispose (GObject *object) { EStartupWizard *extension; @@ -598,7 +690,7 @@ startup_wizard_constructed (GObject *object) g_signal_connect_swapped ( shell, "event::ready-to-start", - G_CALLBACK (startup_wizard_run), extension); + G_CALLBACK (startup_wizard_load_accounts), extension); /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_startup_wizard_parent_class)->constructed (object); |