[ekiga/ds-gtk-application] GmInfoBar: Add the ability to display several messages.



commit a04f4a211e16c6032d56d2aebba494e995655bd6
Author: Damien Sandras <dsandras seconix com>
Date:   Sun Nov 16 12:46:34 2014 +0100

    GmInfoBar: Add the ability to display several messages.
    
    It often happens that the application generates several messages that
    the user needs to acknowledge. The previous implementation was able to
    display one message at a time, overriding older messages without
    allowing the user to acknowledge or read them. This is now fixed by the
    implementation of a stack of messages.

 lib/engine/gui/gtk-frontend/call-window.cpp |   38 ++++----
 lib/engine/gui/gtk-frontend/main_window.cpp |   14 ++--
 lib/gui/gm-info-bar.c                       |  120 ++++++++++++++++++++++++---
 lib/gui/gm-info-bar.h                       |    8 +-
 4 files changed, 138 insertions(+), 42 deletions(-)
---
diff --git a/lib/engine/gui/gtk-frontend/call-window.cpp b/lib/engine/gui/gtk-frontend/call-window.cpp
index 11f6cc0..684674b 100644
--- a/lib/engine/gui/gtk-frontend/call-window.cpp
+++ b/lib/engine/gui/gtk-frontend/call-window.cpp
@@ -527,9 +527,9 @@ on_videooutput_device_error_cb (Ekiga::VideoOutputManager & /* manager */,
 {
   EkigaCallWindow *self = EKIGA_CALL_WINDOW (data);
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_ERROR,
-                           _("There was an error opening or initializing the video output. Please verify 
that no other application is using the accelerated video output."));
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_ERROR,
+                            _("There was an error opening or initializing the video output. Please verify 
that no other application is using the accelerated video output."));
 }
 
 
@@ -627,9 +627,9 @@ on_videoinput_device_error_cb (Ekiga::VideoInputManager & /* manager */,
     break;
   }
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_ERROR,
-                           message);
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_ERROR,
+                            message);
 
   g_free (message);
 }
@@ -683,8 +683,8 @@ on_audioinput_device_error_cb (Ekiga::AudioInputManager & /* manager */,
     break;
   }
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_ERROR, message);
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_ERROR, message);
   g_free (message);
 }
 
@@ -751,8 +751,8 @@ on_audiooutput_device_error_cb (Ekiga::AudioOutputManager & /*manager */,
     break;
   }
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_ERROR, message);
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_ERROR, message);
 
   g_free (message);
 }
@@ -844,8 +844,8 @@ on_cleared_call_cb (G_GNUC_UNUSED boost::shared_ptr<Ekiga::CallManager> manager,
 
   ekiga_call_window_clear_signal_levels (self);
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_INFO, reason.c_str ());
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_INFO, reason.c_str ());
 }
 
 static void on_missed_call_cb (boost::shared_ptr<Ekiga::CallManager>  /*manager*/,
@@ -870,8 +870,8 @@ on_held_call_cb (boost::shared_ptr<Ekiga::CallManager>  /*manager*/,
 {
   EkigaCallWindow *self = EKIGA_CALL_WINDOW (data);
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_INFO, _("Call on hold"));
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_INFO, _("Call on hold"));
 }
 
 
@@ -882,8 +882,8 @@ on_retrieved_call_cb (boost::shared_ptr<Ekiga::CallManager>  /*manager*/,
 {
   EkigaCallWindow *self = EKIGA_CALL_WINDOW (data);
 
-  gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                           GTK_MESSAGE_INFO, _("Call retrieved"));
+  gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                            GTK_MESSAGE_INFO, _("Call retrieved"));
 }
 
 
@@ -1218,9 +1218,9 @@ ekiga_call_window_update_stats (EkigaCallWindow *self,
   g_free (stats_msg);
 
   if (jitter > 150 || lost > 0.02 || late > 0.02 || out_of_order > 0.02)
-    gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                             GTK_MESSAGE_WARNING,
-                             _("The call quality is rather bad. Please check your Internet connection."));
+    gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                              GTK_MESSAGE_WARNING,
+                              _("The call quality is rather bad. Please check your Internet connection."));
 }
 
 
diff --git a/lib/engine/gui/gtk-frontend/main_window.cpp b/lib/engine/gui/gtk-frontend/main_window.cpp
index 9824e5b..21dcfac 100644
--- a/lib/engine/gui/gtk-frontend/main_window.cpp
+++ b/lib/engine/gui/gtk-frontend/main_window.cpp
@@ -315,9 +315,9 @@ place_call_cb (GtkWidget * /*widget*/,
 
     // Dial
     if (!mw->priv->call_core->dial (uri))
-      gm_info_bar_set_message (GM_INFO_BAR (mw->priv->info_bar),
-                               GTK_MESSAGE_ERROR,
-                               _("Could not connect to remote host"));
+      gm_info_bar_push_message (GM_INFO_BAR (mw->priv->info_bar),
+                                GTK_MESSAGE_ERROR,
+                                _("Could not connect to remote host"));
   }
 }
 
@@ -358,8 +358,8 @@ on_account_updated (Ekiga::BankPtr /*bank*/,
                           account->get_name ().c_str (),
                           account->get_status ().c_str ());
 
-    gm_info_bar_set_message (GM_INFO_BAR (self->priv->info_bar),
-                             GTK_MESSAGE_ERROR, msg);
+    gm_info_bar_push_message (GM_INFO_BAR (self->priv->info_bar),
+                              GTK_MESSAGE_ERROR, msg);
 
     g_free (msg);
     break;
@@ -468,8 +468,8 @@ static void on_missed_call_cb (boost::shared_ptr<Ekiga::CallManager>  /*manager*
   gchar* info = NULL;
   info = g_strdup_printf (_("Missed call from %s"),
                           call->get_remote_party_name ().c_str ());
-  gm_info_bar_set_message (GM_INFO_BAR (mw->priv->info_bar),
-                           GTK_MESSAGE_INFO, info);
+  gm_info_bar_push_message (GM_INFO_BAR (mw->priv->info_bar),
+                            GTK_MESSAGE_INFO, info);
   g_free (info);
 
   // FIXME: the engine should take care of this
diff --git a/lib/gui/gm-info-bar.c b/lib/gui/gm-info-bar.c
index 5583e0f..166f9dc 100644
--- a/lib/gui/gm-info-bar.c
+++ b/lib/gui/gm-info-bar.c
@@ -44,8 +44,16 @@ struct _GmInfoBarPrivate {
 
   GtkWidget *label;
   guint timeout;
+  GSList *messages;
 };
 
+typedef struct _GmMessage {
+
+  GtkMessageType type;
+  gchar *message;
+} GmMessage;
+
+
 G_DEFINE_TYPE (GmInfoBar, gm_info_bar, GTK_TYPE_INFO_BAR);
 
 
@@ -65,15 +73,29 @@ static void gm_info_bar_class_init (GmInfoBarClass *);
 static void gm_info_bar_init (GmInfoBar *);
 
 
+/* Static helpers */
+static void gm_info_bar_pop_message (GmInfoBar *self);
+
+static gboolean gm_info_bar_display_last_message (GmInfoBar *self);
+
+static void gm_info_bar_display_message (GmInfoBar *self,
+                                         GtkMessageType type,
+                                         const char *message);
+
+
 /* Callbacks */
 static gboolean
 on_info_bar_delayed_hide (gpointer self)
 {
-  gtk_widget_hide (GTK_WIDGET (self));
+  g_return_if_fail (GM_IS_INFO_BAR (self));
+  /* Display (again) the new last element or hide the infobar */
+  if (!gm_info_bar_display_last_message (self))
+    gtk_widget_hide (GTK_WIDGET (self));
 
   return FALSE;
 }
 
+
 static void
 on_info_bar_response (GmInfoBar *self,
                       gint response_id,
@@ -81,8 +103,9 @@ on_info_bar_response (GmInfoBar *self,
 {
   g_return_if_fail (GM_IS_INFO_BAR (self));
 
-  if (response_id == GTK_RESPONSE_CLOSE)
-    gtk_widget_hide (GTK_WIDGET (self));
+  if (response_id == GTK_RESPONSE_CLOSE) {
+      gm_info_bar_pop_message (self);
+  }
 }
 
 
@@ -121,6 +144,7 @@ gm_info_bar_init (GmInfoBar* self)
 
   self->priv->timeout = 0;
   self->priv->label = gtk_label_new (NULL);
+  self->priv->messages = NULL;
   gtk_label_set_line_wrap (GTK_LABEL (self->priv->label), TRUE);
 
   gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (self))),
@@ -131,21 +155,57 @@ gm_info_bar_init (GmInfoBar* self)
 }
 
 
-/* public api */
-GtkWidget *
-gm_info_bar_new ()
+/* Helpers */
+static void
+gm_info_bar_pop_message (GmInfoBar *self)
 {
-  return GTK_WIDGET (g_object_new (GM_TYPE_INFO_BAR, NULL));
+  GmInfoBarPrivate *priv = GM_INFO_BAR (self)->priv;
+
+  if (!priv->messages)
+    return;
+
+  /* Display the oldest message */
+  GSList *last = g_slist_last (priv->messages);
+  if (last) {
+    /* Free the last element */
+    GmMessage *m = (GmMessage *) last->data;
+    priv->messages = g_slist_remove_link (priv->messages, last);
+    g_free (m->message);
+    g_slist_free_1 (last);
+
+    /* Display the new last element or hide the infobar */
+    if (!gm_info_bar_display_last_message (self))
+      gtk_widget_hide (GTK_WIDGET (self));
+  }
 }
 
 
-void
-gm_info_bar_set_message (GmInfoBar *self,
-                         GtkMessageType type,
-                         const char *message)
+static gboolean
+gm_info_bar_display_last_message (GmInfoBar *self)
 {
-  g_return_if_fail (GM_IS_INFO_BAR (self) || !message || !g_strcmp0 (message, ""));
+  GmInfoBarPrivate *priv = GM_INFO_BAR (self)->priv;
+  GSList *last = NULL;
+
+  if (!priv->messages)
+    return FALSE;
+
+  /* Display the new last element or hide the infobar */
+  last = g_slist_last (priv->messages);
+  if (last) {
+    GmMessage *m = (GmMessage *) last->data;
+    gm_info_bar_display_message (self, m->type, m->message);
+    return TRUE;
+  }
+
+  return FALSE;
+}
 
+
+static void
+gm_info_bar_display_message (GmInfoBar *self,
+                             GtkMessageType type,
+                             const char *message)
+{
   gtk_info_bar_set_message_type (GTK_INFO_BAR (self), type);
   gtk_label_set_text (GTK_LABEL (self->priv->label), message);
   gtk_info_bar_set_show_close_button (GTK_INFO_BAR (self), (type != GTK_MESSAGE_INFO));
@@ -157,3 +217,39 @@ gm_info_bar_set_message (GmInfoBar *self,
     self->priv->timeout = g_timeout_add_seconds (4, on_info_bar_delayed_hide, self);
   }
 }
+
+
+/* public api */
+GtkWidget *
+gm_info_bar_new ()
+{
+  return GTK_WIDGET (g_object_new (GM_TYPE_INFO_BAR, NULL));
+}
+
+
+void
+gm_info_bar_push_message (GmInfoBar *self,
+                          GtkMessageType type,
+                          const char *message)
+{
+  GmMessage *m = NULL;
+  gboolean was_empty = FALSE;
+  g_return_if_fail (GM_IS_INFO_BAR (self) || !message || !g_strcmp0 (message, ""));
+
+  was_empty = (g_slist_length (self->priv->messages) == 0);
+
+  if (type == GTK_MESSAGE_INFO) {
+    gm_info_bar_display_message (self, type, message);
+    return;
+  }
+
+  m = g_malloc0 (sizeof (GmMessage));
+  m->type = type;
+  m->message = g_strdup (message);
+
+  /* Last message first */
+  self->priv->messages = g_slist_prepend (self->priv->messages, m);
+
+  if (was_empty)
+    gm_info_bar_display_message (self, type, message);
+}
diff --git a/lib/gui/gm-info-bar.h b/lib/gui/gm-info-bar.h
index b980786..1cf8c4b 100644
--- a/lib/gui/gm-info-bar.h
+++ b/lib/gui/gm-info-bar.h
@@ -63,11 +63,11 @@ GtkWidget *gm_info_bar_new ();
 /** Update the GmInfoBar content.
  * @param self:    A GmInfoBar
  * @param type:    The message type.
- * @param message: The non empty information message to display.
+ * @param message: The non empty information message to push for display.
  */
-void gm_info_bar_set_message (GmInfoBar *self,
-                              GtkMessageType type,
-                              const char *message);
+void gm_info_bar_push_message (GmInfoBar *self,
+                               GtkMessageType type,
+                               const char *message);
 
 
 /* GObject thingies */


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