[gnome-initial-setup] assistant: Add async mechanism for applying page changes



commit f5decfa6c1030336508e81aa545c3f08ef55e1ef
Author: Stef Walter <stefw redhat com>
Date:   Sun May 26 13:33:44 2013 +0200

    assistant: Add async mechanism for applying page changes
    
    This kicks in when 'Next' is pressed. If applying fails, then stays on
    the same page. Cancellation of apply will be further expanded in later
    commits.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=701039

 gnome-initial-setup/gis-assistant.c                |   20 ++++-
 gnome-initial-setup/gis-page.c                     |   92 ++++++++++++++++++++
 gnome-initial-setup/gis-page.h                     |   10 ++
 .../pages/account/gis-account-page.c               |   21 +++--
 4 files changed, 134 insertions(+), 9 deletions(-)
---
diff --git a/gnome-initial-setup/gis-assistant.c b/gnome-initial-setup/gis-assistant.c
index ecf2932..b3e8345 100644
--- a/gnome-initial-setup/gis-assistant.c
+++ b/gnome-initial-setup/gis-assistant.c
@@ -94,12 +94,28 @@ gis_assistant_switch_to (GisAssistant          *assistant,
   GIS_ASSISTANT_GET_CLASS (assistant)->switch_to (assistant, direction, page);
 }
 
+static void
+on_apply_done (GisPage *page,
+               gboolean valid,
+               gpointer user_data)
+{
+  GisAssistant *assistant = GIS_ASSISTANT (user_data);
+  if (valid)
+    g_signal_emit (assistant, signals[NEXT_PAGE], 0,
+                   assistant->priv->current_page);
+  g_object_unref (assistant);
+}
+
 void
 gis_assistant_next_page (GisAssistant *assistant)
 {
   GisAssistantPrivate *priv = assistant->priv;
-  g_signal_emit (assistant, signals[NEXT_PAGE], 0,
-                 priv->current_page);
+  if (priv->current_page)
+    gis_page_apply_begin (priv->current_page, on_apply_done,
+                          g_object_ref (assistant));
+  else
+    g_signal_emit (assistant, signals[NEXT_PAGE], 0,
+                   priv->current_page);
 }
 
 static inline gboolean
diff --git a/gnome-initial-setup/gis-page.c b/gnome-initial-setup/gis-page.c
index fc05d08..d222d59 100644
--- a/gnome-initial-setup/gis-page.c
+++ b/gnome-initial-setup/gis-page.c
@@ -35,6 +35,11 @@ struct _GisPagePrivate
 {
   char *title;
 
+  gboolean applying;
+  GCancellable *apply_cancel;
+  GisPageApplyCallback apply_cb;
+  gpointer apply_data;
+
   guint complete : 1;
   guint padding : 6;
 };
@@ -45,6 +50,7 @@ enum
   PROP_DRIVER,
   PROP_TITLE,
   PROP_COMPLETE,
+  PROP_APPLYING,
   PROP_LAST,
 };
 
@@ -68,6 +74,9 @@ gis_page_get_property (GObject    *object,
     case PROP_COMPLETE:
       g_value_set_boolean (value, page->priv->complete);
       break;
+    case PROP_APPLYING:
+      g_value_set_boolean (value, gis_page_get_applying (page));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -104,6 +113,9 @@ gis_page_finalize (GObject *object)
   GisPage *page = GIS_PAGE (object);
 
   g_free (page->priv->title);
+  g_assert (!page->priv->applying);
+  g_assert (page->priv->apply_cb == NULL);
+  g_assert (page->priv->apply_cancel == NULL);
 
   G_OBJECT_CLASS (gis_page_parent_class)->finalize (object);
 }
@@ -113,6 +125,9 @@ gis_page_dispose (GObject *object)
 {
   GisPage *page = GIS_PAGE (object);
 
+  if (page->priv->apply_cancel)
+    g_cancellable_cancel (page->priv->apply_cancel);
+
   g_clear_object (&page->driver);
   g_clear_object (&page->builder);
 
@@ -187,6 +202,9 @@ gis_page_class_init (GisPageClass *klass)
   obj_props[PROP_COMPLETE] =
     g_param_spec_boolean ("complete", "", "", FALSE,
                           G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+  obj_props[PROP_APPLYING] =
+    g_param_spec_boolean ("applying", "", "", FALSE,
+                          G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 
   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
 
@@ -243,3 +261,77 @@ gis_page_locale_changed (GisPage *page)
   if (GIS_PAGE_GET_CLASS (page)->locale_changed)
     return GIS_PAGE_GET_CLASS (page)->locale_changed (page);
 }
+
+void
+gis_page_apply_begin (GisPage                *page,
+                      GisPageApplyCallback callback,
+                      gpointer                user_data)
+{
+  GisPageClass *klass;
+
+  g_return_if_fail (GIS_IS_PAGE (page));
+  g_return_if_fail (page->priv->applying == FALSE);
+
+  klass = GIS_PAGE_GET_CLASS (page);
+
+  /* Shortcut case where no apply vfunc, to avoid flicker */
+  if (!klass->apply) {
+    if (callback)
+      (callback) (page, TRUE, user_data);
+    return;
+  }
+
+  /* Unrefs in gis_page_apply_complete() */
+  g_object_ref (page);
+
+  page->priv->apply_cb = callback;
+  page->priv->apply_data = user_data;
+  page->priv->apply_cancel = g_cancellable_new ();
+  page->priv->applying = TRUE;
+  g_object_notify (G_OBJECT (page), "applying");
+
+  (klass->apply) (page, page->priv->apply_cancel);
+}
+
+void
+gis_page_apply_complete (GisPage *page,
+                         gboolean valid)
+{
+  GisPageApplyCallback callback;
+  gpointer user_data;
+
+  g_return_if_fail (GIS_IS_PAGE (page));
+  g_return_if_fail (page->priv->applying == TRUE);
+
+  callback = page->priv->apply_cb;
+  page->priv->apply_cb = NULL;
+  user_data = page->priv->apply_data;
+  page->priv->apply_data = NULL;
+
+  g_clear_object (&page->priv->apply_cancel);
+  page->priv->applying = FALSE;
+  g_object_notify (G_OBJECT (page), "applying");
+
+  if (callback)
+    (callback) (page, valid, user_data);
+
+  /* Matches ref in gis_page_apply_begin() */
+  g_object_unref (page);
+}
+
+gboolean
+gis_page_get_applying (GisPage *page)
+{
+  g_return_val_if_fail (GIS_IS_PAGE (page), FALSE);
+
+  return page->priv->applying;
+}
+
+void
+gis_page_apply_cancel (GisPage *page)
+{
+  g_return_if_fail (GIS_IS_PAGE (page));
+  g_return_if_fail (page->priv->applying == TRUE);
+
+  g_cancellable_cancel (page->priv->apply_cancel);
+}
diff --git a/gnome-initial-setup/gis-page.h b/gnome-initial-setup/gis-page.h
index 2b28b69..8d287c6 100644
--- a/gnome-initial-setup/gis-page.h
+++ b/gnome-initial-setup/gis-page.h
@@ -40,6 +40,10 @@ typedef struct _GisPageClass   GisPageClass;
 typedef struct _GisPagePrivate GisPagePrivate;
 typedef struct _GisAssistantPagePrivate GisAssistantPagePrivate;
 
+typedef void (* GisPageApplyCallback) (GisPage *page,
+                                       gboolean valid,
+                                       gpointer user_data);
+
 struct _GisPage
 {
   GtkBin parent;
@@ -59,6 +63,8 @@ struct _GisPageClass
   GtkBuilder * (*get_builder) (GisPage *page);
   GtkWidget  * (*get_action_widget) (GisPage *page);
   void         (*locale_changed) (GisPage *page);
+  void         (*apply) (GisPage *page,
+                         GCancellable *cancellable);
 };
 
 GType gis_page_get_type (void);
@@ -69,6 +75,10 @@ gboolean     gis_page_get_complete (GisPage *page);
 void         gis_page_set_complete (GisPage *page, gboolean complete);
 GtkWidget *  gis_page_get_action_widget (GisPage *page);
 void         gis_page_locale_changed (GisPage *page);
+void         gis_page_apply_begin (GisPage *page, GisPageApplyCallback callback, gpointer user_data);
+void         gis_page_apply_cancel (GisPage *page);
+void         gis_page_apply_complete (GisPage *page, gboolean valid);
+gboolean     gis_page_get_applying (GisPage *page);
 
 G_END_DECLS
 
diff --git a/gnome-initial-setup/pages/account/gis-account-page.c 
b/gnome-initial-setup/pages/account/gis-account-page.c
index a60803a..74c0fc6 100644
--- a/gnome-initial-setup/pages/account/gis-account-page.c
+++ b/gnome-initial-setup/pages/account/gis-account-page.c
@@ -556,12 +556,14 @@ on_permit_user_login (GObject *source,
     g_debug ("Caching remote user: %s", login);
 
     priv->act_user = act_user_manager_cache_user (priv->act_client, login, NULL);
+    gis_page_apply_complete (GIS_PAGE (page), TRUE);
 
     g_free (login);
   } else {
     show_error_dialog (page, _("Failed to register account"), error);
     g_message ("Couldn't permit logins on account: %s", error->message);
     g_error_free (error);
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
   }
 }
 
@@ -619,11 +621,13 @@ on_realm_joined (GObject *source,
 
     /* XXX */
     /* join_show_prompt (self, error); */
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
 
     /* Other failure */
   } else {
     show_error_dialog (page, _("Failed to join domain"), error);
     g_message ("Failed to join the domain: %s", error->message);
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
   }
 
   g_clear_error (&error);
@@ -671,6 +675,7 @@ on_realm_login (GObject *source,
 
       /* XXX: creds */
       /* join_show_prompt (self, NULL); */
+      gis_page_apply_complete (GIS_PAGE (page), FALSE);
     }
 
     g_bytes_unref (creds);
@@ -680,16 +685,19 @@ on_realm_login (GObject *source,
     g_debug ("Problem with the user's login: %s", error->message);
     set_entry_validation_error (OBJ (GtkEntry *, "enterprise-login"), error->message);
     gtk_widget_grab_focus (WID ("enterprise-login"));
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
 
   } else if (g_error_matches (error, UM_REALM_ERROR, UM_REALM_ERROR_BAD_PASSWORD)) {
     g_debug ("Problem with the user's password: %s", error->message);
     set_entry_validation_error (OBJ (GtkEntry *, "enterprise-password"), error->message);
     gtk_widget_grab_focus (WID ("enterprise-password"));
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
 
     /* Other login failure */
   } else {
     show_error_dialog (page, _("Failed to log into domain"), error);
     g_message ("Couldn't log in as user: %s", error->message);
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
   }
 
   g_clear_error (&error);
@@ -735,6 +743,7 @@ on_realm_discover_input (GObject *source,
     g_message ("Couldn't discover domain: %s", error->message);
     gtk_widget_grab_focus (WID ("enterprise-domain-entry"));
     set_entry_validation_error (OBJ (GtkEntry*, "enterprise-domain-entry"), error->message);
+    gis_page_apply_complete (GIS_PAGE (page), FALSE);
     g_error_free (error);
   }
 }
@@ -770,6 +779,7 @@ save_account_data (GisAccountPage *page)
   switch (priv->mode) {
   case UM_LOCAL:
     local_create_user (page);
+    gis_page_apply_complete (GIS_PAGE (page), TRUE);
     break;
   case UM_ENTERPRISE:
     enterprise_add_user (page);
@@ -953,12 +963,10 @@ toggle_mode (GtkToggleButton *button,
 }
 
 static void
-next_page_cb (GisAssistant *assistant,
-              GisPage      *which_page,
-              GisPage      *this_page)
+gis_account_page_apply (GisPage *page,
+                           GCancellable *cancellable)
 {
-  if (which_page == this_page)
-    save_account_data (GIS_ACCOUNT_PAGE (this_page));
+  save_account_data (GIS_ACCOUNT_PAGE (page));
 }
 
 static void
@@ -1007,8 +1015,6 @@ gis_account_page_constructed (GObject *object)
 
   priv->act_client = act_user_manager_get_default ();
 
-  g_signal_connect (assistant, "next-page", G_CALLBACK (next_page_cb), page);
-
   clear_account_page (page);
   update_account_page_status (page);
 
@@ -1061,6 +1067,7 @@ gis_account_page_class_init (GisAccountPageClass *klass)
   page_class->page_id = PAGE_ID;
   page_class->locale_changed = gis_account_page_locale_changed;
   page_class->get_action_widget = gis_account_page_get_action_widget;
+  page_class->apply = gis_account_page_apply;
   object_class->constructed = gis_account_page_constructed;
   object_class->dispose = gis_account_page_dispose;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]