[ekiga/ds-gtk-application] Main Window: Properly populate dynamic menu when actions change.



commit 377f19a7a2e44b0992e767faeb8bf5f97616aafa
Author: Damien Sandras <dsandras seconix com>
Date:   Sun Oct 12 13:07:50 2014 +0200

    Main Window: Properly populate dynamic menu when actions change.
    
    A new signal was added to the RosterViewGtk GObject in order to allow
    this.
    
    The signal is emitted when new actions are available (depending on the
    active selection). The GMenuModel passed as signal argument helps
    rebuilding the menu.

 lib/engine/gui/gtk-frontend/main_window.cpp     |   44 ++++++++++++++---------
 lib/engine/gui/gtk-frontend/roster-view-gtk.cpp |   28 ++++++++------
 lib/engine/gui/gtk-frontend/roster-view-gtk.h   |    5 ++-
 3 files changed, 46 insertions(+), 31 deletions(-)
---
diff --git a/lib/engine/gui/gtk-frontend/main_window.cpp b/lib/engine/gui/gtk-frontend/main_window.cpp
index 6d10264..57760bd 100644
--- a/lib/engine/gui/gtk-frontend/main_window.cpp
+++ b/lib/engine/gui/gtk-frontend/main_window.cpp
@@ -153,6 +153,9 @@ struct _EkigaMainWindowPrivate
 
   Ekiga::scoped_connections connections;
 
+  /* Menu Dynamic Section */
+  unsigned menu_dynamic_section_n_items;
+
   /* GSettings */
   boost::shared_ptr<Ekiga::Settings> user_interface_settings;
   boost::shared_ptr<Ekiga::Settings> sound_events_settings;
@@ -174,12 +177,6 @@ static const char* win_menu =
   "  <menu id='menubar'>"
   "    <section>"
   "      <item>"
-  "        <attribute name='label' translatable='yes'>_Call</attribute>"
-  "        <attribute name='action'>win.call</attribute>"
-  "      </item>"
-  "    </section>"
-  "    <section>"
-  "      <item>"
   "        <attribute name='label' translatable='yes'>_Add Contact</attribute>"
   "        <attribute name='action'>win.local-cluster-new</attribute>"
   "      </item>"
@@ -236,6 +233,15 @@ static void close_activated (G_GNUC_UNUSED GSimpleAction *action,
                              gpointer data);
 
 
+/* DESCRIPTION  :  This callback is called when a contact is selected
+ *                 in the roster or call history views.
+ * BEHAVIOR     :  Updates the window menu with new actions.
+ * PRE          :  A valid pointer to the main window GMObject.
+ */
+static void actions_changed_cb (G_GNUC_UNUSED GtkWidget *widget,
+                                GMenuModel *model,
+                                gpointer data);
+
 /* DESCRIPTION  :  This callback is called when the status bar is clicked.
  * BEHAVIOR     :  Clear all info message, not normal messages.
  * PRE          :  The main window GMObject.
@@ -599,24 +605,26 @@ statusbar_clicked_cb (G_GNUC_UNUSED GtkWidget *widget,
 
 
 static void
-menu_button_toggled_cb (GtkToggleButton *togglebutton,
-                        gpointer data)
+actions_changed_cb (G_GNUC_UNUSED GtkWidget *widget,
+                    GMenuModel *model,
+                    gpointer data)
 {
   GMenu *menu = NULL;
 
   g_return_if_fail (EKIGA_IS_MAIN_WINDOW (data));
   EkigaMainWindow *mw = EKIGA_MAIN_WINDOW (data);
 
-  if (!gtk_toggle_button_get_active (togglebutton))
-    return;
-
   menu = G_MENU (gtk_builder_get_object (mw->priv->builder, "menubar"));
- /* if (mw->priv->contact_menu->size () > 0)
+
+  while (mw->priv->menu_dynamic_section_n_items-- > 0) {
     g_menu_remove (menu, 0);
+  }
+  mw->priv->menu_dynamic_section_n_items = 0;
 
-  contact_menu = mw->priv->contact_menu->get ();
-  if (contact_menu)
-    g_menu_insert_section (menu, 0, NULL, contact_menu);*/
+  if (model) {
+    g_menu_insert_section (menu, 0, NULL, model);
+    mw->priv->menu_dynamic_section_n_items = g_menu_model_get_n_items (model);
+  }
 }
 
 
@@ -763,8 +771,6 @@ ekiga_main_window_init_actions_toolbar (EkigaMainWindow *mw)
   gtk_button_set_image (GTK_BUTTON (button), image);
   gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button),
                                   G_MENU_MODEL (gtk_builder_get_object (mw->priv->builder, "menubar")));
-  g_signal_connect (GTK_TOGGLE_BUTTON (button), "toggled",
-                    G_CALLBACK (menu_button_toggled_cb), mw);
   gtk_header_bar_pack_end (GTK_HEADER_BAR (mw->priv->actions_toolbar), button);
   gtk_widget_show_all (mw->priv->actions_toolbar);
 
@@ -823,6 +829,9 @@ ekiga_main_window_init_contact_list (EkigaMainWindow *mw)
                            "icon-name", "avatar-default-symbolic", NULL);
 
   g_object_ref (mw->priv->roster_view);
+
+  g_signal_connect (mw->priv->roster_view, "actions-changed",
+                    G_CALLBACK (actions_changed_cb), mw);
 }
 
 
@@ -939,6 +948,7 @@ ekiga_main_window_init (EkigaMainWindow *mw)
 
   mw->priv->current_call = boost::shared_ptr<Ekiga::Call>();
   mw->priv->calling_state = Standby;
+  mw->priv->menu_dynamic_section_n_items = 0;
   mw->priv->call_window = NULL;
 
   mw->priv->user_interface_settings =
diff --git a/lib/engine/gui/gtk-frontend/roster-view-gtk.cpp b/lib/engine/gui/gtk-frontend/roster-view-gtk.cpp
index 8b89268..5049cdf 100644
--- a/lib/engine/gui/gtk-frontend/roster-view-gtk.cpp
+++ b/lib/engine/gui/gtk-frontend/roster-view-gtk.cpp
@@ -85,7 +85,7 @@ enum {
 };
 
 enum {
-  SELECTION_CHANGED_SIGNAL,
+  ACTIONS_CHANGED_SIGNAL,
   LAST_SIGNAL
 };
 
@@ -177,8 +177,8 @@ static void show_offline_contacts_changed_cb (GSettings *settings,
  * BEHAVIOR     : Emit the presentity-selected signal
  * PRE          : The gpointer must point to the RosterViewGtk GObject.
  */
-static void on_selection_changed (GtkTreeSelection* selection,
-                                 gpointer data);
+static void on_actions_changed (GtkTreeSelection* actions,
+                                gpointer data);
 
 /* DESCRIPTION  : Called when the user clicks or presses Enter
  *                on a heap, group or presentity.
@@ -707,16 +707,18 @@ on_selection_changed (GtkTreeSelection* selection,
       if (heap != NULL) {
         self->priv->selected_heap = heap;
         self->priv->heap_menu = Ekiga::GActorMenuPtr (new Ekiga::GActorMenu (*self->priv->selected_heap));
+        g_signal_emit (self, signals[ACTIONS_CHANGED_SIGNAL], 0, self->priv->heap_menu->get_model ());
       }
       break;
     case TYPE_GROUP:
-
+        g_signal_emit (self, signals[ACTIONS_CHANGED_SIGNAL], 0, NULL);
       break;
     case TYPE_PRESENTITY:
 
       if (presentity != NULL) {
         self->priv->selected_presentity = presentity;
         self->priv->presentity_menu = Ekiga::GActorMenuPtr (new Ekiga::GActorMenu 
(*self->priv->selected_presentity));
+        g_signal_emit (self, signals[ACTIONS_CHANGED_SIGNAL], 0, self->priv->presentity_menu->get_model ());
       }
       break;
     default:
@@ -727,8 +729,8 @@ on_selection_changed (GtkTreeSelection* selection,
     g_free (group_name);
     g_free (name);
   }
-
-  g_signal_emit (self, signals[SELECTION_CHANGED_SIGNAL], 0);
+  else
+    g_signal_emit (self, signals[ACTIONS_CHANGED_SIGNAL], 0, NULL);
 }
 
 static gint
@@ -991,6 +993,8 @@ on_heap_updated (RosterViewGtk* self,
   GtkTreeSelection* selection = NULL;
   gboolean should_emit = FALSE;
 
+  // FIXME???
+  //
   roster_view_gtk_find_iter_for_heap (self, heap, &iter);
 
   selection = gtk_tree_view_get_selection (self->priv->tree_view);
@@ -1006,7 +1010,7 @@ on_heap_updated (RosterViewGtk* self,
                      COLUMN_NAME, heap->get_name ().c_str (), -1);
 
   if (should_emit)
-    g_signal_emit (self, signals[SELECTION_CHANGED_SIGNAL], 0);
+    g_signal_emit (self, signals[ACTIONS_CHANGED_SIGNAL], 0);
 }
 
 
@@ -1156,7 +1160,7 @@ on_presentity_added (RosterViewGtk* self,
   roster_view_gtk_update_groups (self, &heap_iter);
 
   if (should_emit)
-    g_signal_emit (self, signals[SELECTION_CHANGED_SIGNAL], 0);
+    g_signal_emit (self, signals[ACTIONS_CHANGED_SIGNAL], 0);
 }
 
 
@@ -1585,14 +1589,14 @@ roster_view_gtk_class_init (RosterViewGtkClass* klass)
 
   gobject_class->finalize = roster_view_gtk_finalize;
 
-  signals[SELECTION_CHANGED_SIGNAL] =
-    g_signal_new ("selection-changed",
+  signals[ACTIONS_CHANGED_SIGNAL] =
+    g_signal_new ("actions-changed",
                  G_OBJECT_CLASS_TYPE (gobject_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (RosterViewGtkClass, selection_changed),
                  NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 1, G_TYPE_MENU_MODEL);
 }
 
 /*
diff --git a/lib/engine/gui/gtk-frontend/roster-view-gtk.h b/lib/engine/gui/gtk-frontend/roster-view-gtk.h
index 2622b0e..ec2f0f7 100644
--- a/lib/engine/gui/gtk-frontend/roster-view-gtk.h
+++ b/lib/engine/gui/gtk-frontend/roster-view-gtk.h
@@ -62,8 +62,9 @@ bool roster_view_gtk_populate_menu_for_selected (RosterViewGtk* self,
 
 /* Signals emitted by that widget :
  *
- * - "selection-changed", comes with nothing, and notifies whether either the
- * selection changed, or the selected object changed.
+ * - "actions-changed", comes with nothing, and notifies when new
+ * actions are available (wrt the active selection). The GMenuModel
+ * signal callback argument details available actions.
  */
 
 


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