[Xfce4-commits] <xfce4-mixer:gber/improvements> Handle GST_MIXER_MESSAGE_MIXER_CHANGED messages

Guido Berhoerster noreply at xfce.org
Fri Sep 21 17:18:32 CEST 2012


Updating branch refs/heads/gber/improvements
         to fb97549cd34ed3fdc3f8a9d5b1d58a0e9facf65e (commit)
       from 1cc5a806d513be3e3424ea270342ed72e0a18739 (commit)

commit fb97549cd34ed3fdc3f8a9d5b1d58a0e9facf65e
Author: Guido Berhoerster <guido+xfce at berhoerster.name>
Date:   Fri Sep 21 12:00:36 2012 +0200

    Handle GST_MIXER_MESSAGE_MIXER_CHANGED messages
    
    Connect every mixer to a GstBus in libxfce4mixer and add a signal handler for messages that handles GST_MIXER_MESSAGE_MIXER_CHANGED messages for every card and adds labels to all tracks.
    Refactor XfceMixer in order to allow updating itself in case the tracks have changed, preserving the currently active tab if possible; handle GST_MIXER_MESSAGE_MIXER_CHANGED messages accordingly and allow the card property to be changed.
    Make XfceMixerTrackCombo and XfceMixerControlsDialog listen to the bus and handle GST_MIXER_MESSAGE_MIXER_CHANGED messages for the current sound card by rebuilding the track list.
    Let XfceMixerPlugin refresh the track and attemt to retain the currently selected one when receiving a GST_MIXER_MESSAGE_MIXER_CHANGED for the currently selected card.

 NEWS                                     |    2 +
 libxfce4mixer/libxfce4mixer.c            |   57 ++++-
 libxfce4mixer/xfce-mixer-track-combo.c   |   78 ++++--
 panel-plugin/xfce-mixer-plugin.c         |   17 +-
 xfce4-mixer/xfce-mixer-controls-dialog.c |   40 +++-
 xfce4-mixer/xfce-mixer-window.c          |   51 ++--
 xfce4-mixer/xfce-mixer.c                 |  432 +++++++++++++++++-------------
 xfce4-mixer/xfce-mixer.h                 |    4 +-
 8 files changed, 430 insertions(+), 251 deletions(-)

diff --git a/NEWS b/NEWS
index 9798e77..eedf761 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,8 @@
 - Handle tracks which are marked read-only by GStreamer or which have no mute
   or record functionality by making the corresponding widgets insensitive.
   Prevent read-only tracks from being selected in the panel-plugin.
+- Handle mixer changed messages which indicate that the tracks of a mixer have
+  changed.
 
 
 4.8.0
diff --git a/libxfce4mixer/libxfce4mixer.c b/libxfce4mixer/libxfce4mixer.c
index 451e1d8..244196c 100644
--- a/libxfce4mixer/libxfce4mixer.c
+++ b/libxfce4mixer/libxfce4mixer.c
@@ -40,11 +40,16 @@
 
 
 
-static gboolean _xfce_mixer_filter_mixer     (GstMixer *mixer,
-                                              gpointer  user_data);
-static void     _xfce_mixer_add_track_labels (gpointer  data,
-                                              gpointer  user_data);
-static void     _xfce_mixer_destroy_mixer    (GstMixer *mixer);
+static gboolean _xfce_mixer_filter_mixer     (GstMixer   *mixer,
+                                              gpointer    user_data);
+static void     _xfce_mixer_add_track_labels (gpointer    data,
+                                              gpointer    user_data);
+static void     _xfce_mixer_init_mixer       (gpointer    data,
+                                              gpointer    user_data);
+static void     _xfce_mixer_destroy_mixer    (GstMixer   *mixer);
+static void     _xfce_mixer_bus_message      (GstBus     *bus,
+                                              GstMessage *message,
+                                              gpointer    user_data);
 
 
 
@@ -85,12 +90,16 @@ xfce_mixer_init (void)
       /* Get list of all available mixer devices */
       mixers = gst_audio_default_registry_mixer_filter (_xfce_mixer_filter_mixer, FALSE, &counter);
 
-      /* Add custom labels to all tracks of all mixers */
-      g_list_foreach (mixers, (GFunc) _xfce_mixer_add_track_labels, NULL);
-
       /* Create a GstBus for notifications */
       bus = gst_bus_new ();
       gst_bus_add_signal_watch (bus);
+
+      /*
+       * Add custom labels to all tracks of all mixers and create a GstBus for
+       * each mixer device and connect an internal signal handler to receive
+       * notifications about track list changes
+       */
+      g_list_foreach (mixers, (GFunc) _xfce_mixer_init_mixer, NULL);
     }
 }
 
@@ -188,7 +197,6 @@ xfce_mixer_select_card (GstElement *card)
 {
   g_return_if_fail (GST_IS_MIXER (card));
 
-  gst_element_set_bus (card, bus);
   selected_card = card;
 }
 
@@ -361,6 +369,7 @@ void
 xfce_mixer_bus_disconnect (guint signal_handler_id)
 {
   g_return_if_fail (refcount > 0);
+
   if (signal_handler_id != 0)
     g_signal_handler_disconnect (bus, signal_handler_id);
 }
@@ -478,14 +487,44 @@ _xfce_mixer_add_track_labels (gpointer data,
 
 
 static void
+_xfce_mixer_init_mixer (gpointer data,
+                        gpointer user_data)
+{
+  GstMixer *card = GST_MIXER (data);
+
+  /* Add custom labels to all tracks */
+  _xfce_mixer_add_track_labels (card, NULL);
+
+  /* Add bus to every card and connect to internal signal handler */
+  gst_element_set_bus (GST_ELEMENT (card), bus);
+  g_signal_connect (bus, "message::element", G_CALLBACK (_xfce_mixer_bus_message), NULL);
+}
+
+
+
+static void
 _xfce_mixer_destroy_mixer (GstMixer *mixer)
 {
+  g_signal_handlers_disconnect_by_func (bus, _xfce_mixer_bus_message, NULL);
+
   gst_element_set_state (GST_ELEMENT (mixer), GST_STATE_NULL);
   gst_object_unref (GST_OBJECT (mixer));
 }
 
 
 
+static void
+_xfce_mixer_bus_message (GstBus     *bus,
+                         GstMessage *message,
+                         gpointer    user_data)
+{
+  /* Add labels in case the tracks have changed */
+  if (gst_mixer_message_get_type (message) == GST_MIXER_MESSAGE_MIXER_CHANGED)
+    _xfce_mixer_add_track_labels (GST_MIXER (GST_MESSAGE_SRC (message)), NULL);
+}
+
+
+
 int
 xfce_mixer_utf8_cmp (const gchar *s1, const gchar *s2)
 {
diff --git a/libxfce4mixer/xfce-mixer-track-combo.c b/libxfce4mixer/xfce-mixer-track-combo.c
index 15fafcc..d0c52d1 100644
--- a/libxfce4mixer/xfce-mixer-track-combo.c
+++ b/libxfce4mixer/xfce-mixer-track-combo.c
@@ -53,10 +53,14 @@ static guint combo_signals[LAST_SIGNAL];
 
 
 
-static void  xfce_mixer_track_combo_class_init (XfceMixerTrackComboClass *klass);
-static void  xfce_mixer_track_combo_init       (XfceMixerTrackCombo      *combo);
-static void  xfce_mixer_track_combo_finalize   (GObject                  *object);
-static void  xfce_mixer_track_combo_changed    (XfceMixerTrackCombo      *combo);
+static void  xfce_mixer_track_combo_class_init        (XfceMixerTrackComboClass *klass);
+static void  xfce_mixer_track_combo_init              (XfceMixerTrackCombo      *combo);
+static void  xfce_mixer_track_combo_finalize          (GObject                  *object);
+static void  xfce_mixer_track_combo_update_track_list (XfceMixerTrackCombo      *combo);
+static void  xfce_mixer_track_combo_bus_message       (GstBus                   *bus,
+                                                       GstMessage               *message,
+                                                       XfceMixerTrackCombo      *combo);
+static void  xfce_mixer_track_combo_changed           (XfceMixerTrackCombo      *combo);
 
 
 
@@ -73,6 +77,7 @@ struct _XfceMixerTrackCombo
 
   GstElement    *card;
   GstMixerTrack *track;
+  guint          signal_handler_id;
 };
 
 
@@ -140,6 +145,8 @@ xfce_mixer_track_combo_init (XfceMixerTrackCombo *combo)
 {
   GtkCellRenderer *renderer;
 
+  combo->signal_handler_id = xfce_mixer_bus_connect (G_CALLBACK (xfce_mixer_track_combo_bus_message), combo);
+
   combo->card = NULL;
 
   combo->list_store = gtk_list_store_new (2, G_TYPE_STRING, GST_TYPE_MIXER_TRACK);
@@ -159,6 +166,12 @@ xfce_mixer_track_combo_finalize (GObject *object)
 {
   XfceMixerTrackCombo *combo = XFCE_MIXER_TRACK_COMBO (object);
 
+  if (combo->signal_handler_id > 0)
+    {
+      xfce_mixer_bus_disconnect (combo->signal_handler_id);
+      combo->signal_handler_id = 0;
+    }
+
   gtk_list_store_clear (combo->list_store);
   g_object_unref (combo->list_store);
 
@@ -185,9 +198,8 @@ xfce_mixer_track_combo_new (GstElement    *card,
 
 
 
-void
-xfce_mixer_track_combo_set_soundcard (XfceMixerTrackCombo *combo,
-                                      GstElement          *card)
+static void
+xfce_mixer_track_combo_update_track_list (XfceMixerTrackCombo *combo)
 {
   XfceMixerTrackType type;
   GtkTreeIter        tree_iter;
@@ -197,18 +209,7 @@ xfce_mixer_track_combo_set_soundcard (XfceMixerTrackCombo *combo,
   GstMixerTrack     *track;
   GstMixerTrack     *track_new;
 
-  g_return_if_fail (IS_XFCE_MIXER_TRACK_COMBO (combo));
-
-  /* Remember card. If the card is invalid, use the first one available */
-  if (GST_IS_MIXER (card))
-    combo->card = card;
-  else
-    {
-      card = xfce_mixer_get_default_card ();
-
-      if (GST_IS_MIXER (card))
-        combo->card = card;
-    }
+  g_return_if_fail (GST_IS_MIXER (combo->card));
 
   /* Try to re-use the current track */
   track = xfce_mixer_track_combo_get_active_track (combo);
@@ -244,6 +245,30 @@ xfce_mixer_track_combo_set_soundcard (XfceMixerTrackCombo *combo,
 
 
 
+void
+xfce_mixer_track_combo_set_soundcard (XfceMixerTrackCombo *combo,
+                                      GstElement          *card)
+{
+  g_return_if_fail (IS_XFCE_MIXER_TRACK_COMBO (combo));
+
+  /* Remember card. If the card is invalid, use the first one available */
+  if (GST_IS_MIXER (card))
+    combo->card = card;
+  else
+    {
+      card = xfce_mixer_get_default_card ();
+
+      if (GST_IS_MIXER (card))
+        combo->card = card;
+      else
+        return;
+    }
+
+  xfce_mixer_track_combo_update_track_list (combo);
+}
+
+
+
 static void
 xfce_mixer_track_combo_changed (XfceMixerTrackCombo *combo)
 {
@@ -308,3 +333,18 @@ xfce_mixer_track_combo_set_active_track (XfceMixerTrackCombo *combo,
   else
     gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
 }
+
+
+
+static void
+xfce_mixer_track_combo_bus_message (GstBus              *bus,
+                                    GstMessage          *message,
+                                    XfceMixerTrackCombo *combo)
+{
+  if (!GST_IS_MIXER (combo->card) || GST_MESSAGE_SRC (message) != GST_OBJECT (combo->card))
+    return;
+
+  /* Rebuild track list if the tracks for this card have changed */
+  if (gst_mixer_message_get_type (message) == GST_MIXER_MESSAGE_MIXER_CHANGED)
+    xfce_mixer_track_combo_update_track_list (combo);
+}
diff --git a/panel-plugin/xfce-mixer-plugin.c b/panel-plugin/xfce-mixer-plugin.c
index 5b8ee60..57b227f 100644
--- a/panel-plugin/xfce-mixer-plugin.c
+++ b/panel-plugin/xfce-mixer-plugin.c
@@ -780,10 +780,10 @@ xfce_mixer_plugin_bus_message (GstBus          *bus,
                                GstMessage      *message,
                                XfceMixerPlugin *mixer_plugin)
 {
-  GstMixerTrack      *track = NULL;
-  gboolean            mute;
-  gboolean            record;
-  const gchar        *label;
+  GstMixerTrack *track = NULL;
+  gboolean      mute;
+  gboolean      record;
+  const gchar   *label;
 
   /* Don't do anything if GstBus messages are to be ignored */
   if (G_UNLIKELY (mixer_plugin->ignore_bus_messages))
@@ -833,6 +833,15 @@ xfce_mixer_plugin_bus_message (GstBus          *bus,
           }
 
         break;
+      case GST_MIXER_MESSAGE_MIXER_CHANGED:
+        /*
+         * If the mixer tracks have changed, try to keep the current track by
+         * selecting a track based on the current track name; if there is no
+         * track with such name any more, the property setter will handle the
+         * situation in a sane way
+         */
+        g_object_set (mixer_plugin, "track", mixer_plugin->track_label, NULL);
+        break;
       default:
         break;
     }
diff --git a/xfce4-mixer/xfce-mixer-controls-dialog.c b/xfce4-mixer/xfce-mixer-controls-dialog.c
index 9b2fbff..716abd5 100644
--- a/xfce4-mixer/xfce-mixer-controls-dialog.c
+++ b/xfce4-mixer/xfce-mixer-controls-dialog.c
@@ -53,6 +53,9 @@ static void   xfce_mixer_controls_dialog_update_preferences   (XfceMixerControls
 static void   xfce_mixer_controls_dialog_control_toggled      (GtkCellRendererToggle        *renderer,
                                                                gchar                        *path,
                                                                XfceMixerControlsDialog      *dialog);
+static void  xfce_mixer_controls_dialog_bus_message           (GstBus                       *bus,
+                                                               GstMessage                   *message,
+                                                               XfceMixerControlsDialog      *dialog);
 
 
 
@@ -68,6 +71,7 @@ struct _XfceMixerControlsDialog
   XfceMixerWindow      *parent;
   XfceMixerPreferences *preferences;
   GstElement           *card;
+  guint                 signal_handler_id;
 
   GtkWidget            *frame;
   GtkListStore         *store;
@@ -134,6 +138,8 @@ xfce_mixer_controls_dialog_init (XfceMixerControlsDialog *dialog)
 
   dialog->preferences = xfce_mixer_preferences_get ();
 
+  dialog->signal_handler_id = xfce_mixer_bus_connect (G_CALLBACK (xfce_mixer_controls_dialog_bus_message), dialog);
+
   dialog->card = NULL;
 
   dialog->frame = NULL;
@@ -164,6 +170,12 @@ xfce_mixer_controls_dialog_finalize (GObject *object)
 {
   XfceMixerControlsDialog *dialog = XFCE_MIXER_CONTROLS_DIALOG (object);
 
+  if (dialog->signal_handler_id > 0)
+    {
+      xfce_mixer_bus_disconnect (dialog->signal_handler_id);
+      dialog->signal_handler_id = 0;
+    }
+
   g_object_unref (G_OBJECT (dialog->preferences));
 
   (*G_OBJECT_CLASS (xfce_mixer_controls_dialog_parent_class)->finalize) (object);
@@ -241,6 +253,17 @@ xfce_mixer_controls_dialog_create_contents (XfceMixerControlsDialog *dialog)
 
 
 
+static void
+xfce_mixer_controls_dialog_update_contents (XfceMixerControlsDialog *dialog)
+{
+  g_return_if_fail (IS_XFCE_MIXER_CONTROLS_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog->frame);
+  xfce_mixer_controls_dialog_create_contents (dialog);
+}
+
+
+
 void
 xfce_mixer_controls_dialog_update_dialog (XfceMixerControlsDialog *dialog)
 {
@@ -350,7 +373,20 @@ xfce_mixer_controls_dialog_set_soundcard (XfceMixerControlsDialog *dialog,
   dialog->card = card;
 
   /* Recreate contents corresponding to the new card */
-  gtk_widget_destroy (dialog->frame);
-  xfce_mixer_controls_dialog_create_contents (dialog);
+  xfce_mixer_controls_dialog_update_contents (dialog);
 }
 
+
+
+static void
+xfce_mixer_controls_dialog_bus_message (GstBus                  *bus,
+                                        GstMessage              *message,
+                                        XfceMixerControlsDialog *dialog)
+{
+  if (!GST_IS_MIXER (dialog->card) || GST_MESSAGE_SRC (message) != GST_OBJECT (dialog->card))
+    return;
+
+  /* Rebuild track list if the tracks for this card have changed */
+  if (gst_mixer_message_get_type (message) == GST_MIXER_MESSAGE_MIXER_CHANGED)
+    xfce_mixer_controls_dialog_update_contents (dialog);
+}
diff --git a/xfce4-mixer/xfce-mixer-window.c b/xfce4-mixer/xfce-mixer-window.c
index a21afd6..f8dec5b 100644
--- a/xfce4-mixer/xfce-mixer-window.c
+++ b/xfce4-mixer/xfce-mixer-window.c
@@ -168,8 +168,6 @@ xfce_mixer_window_init (XfceMixerWindow *window)
   gint           width;
   gint           height;
 
-  window->mixer = NULL;
-
   window->controls_dialog = NULL;
 
   window->preferences = xfce_mixer_preferences_get ();
@@ -242,6 +240,10 @@ xfce_mixer_window_init (XfceMixerWindow *window)
   gtk_container_add (GTK_CONTAINER (vbox), window->mixer_frame);
   gtk_widget_show (window->mixer_frame);
 
+  window->mixer = xfce_mixer_new (NULL);
+  gtk_container_add (GTK_CONTAINER (window->mixer_frame), window->mixer);
+  gtk_widget_show (window->mixer);
+
   bbox = gtk_dialog_get_action_area (GTK_DIALOG (window));
   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_EDGE);
   gtk_container_set_border_width (GTK_CONTAINER (bbox), 6);
@@ -266,7 +268,7 @@ xfce_mixer_window_init (XfceMixerWindow *window)
 
   g_signal_connect_swapped (G_OBJECT (window->preferences), "notify::controls", G_CALLBACK (xfce_mixer_window_controls_property_changed), window);
 
-  /* Re-generate mixer controls for the active sound card */
+  /* Update mixer controls for the active sound card */
   xfce_mixer_window_update_contents (window);
 }
 
@@ -314,7 +316,7 @@ xfce_mixer_window_soundcard_changed (XfceMixerCardCombo *combo,
   g_object_set (G_OBJECT (window->preferences), "sound-card", xfce_mixer_get_card_internal_name (card), NULL);
   g_signal_handlers_unblock_by_func (G_OBJECT (window->preferences), G_CALLBACK (xfce_mixer_window_soundcard_property_changed), window);
 
-  /* Re-generate mixer controls for the active sound card */
+  /* Update mixer controls for the active sound card */
   xfce_mixer_window_update_contents (window);
 
   /* Update the controls dialog */
@@ -362,7 +364,7 @@ xfce_mixer_window_soundcard_property_changed (XfceMixerWindow *window,
       xfce_mixer_card_combo_set_active_card (XFCE_MIXER_CARD_COMBO (window->soundcard_combo), new_card);
       g_signal_handlers_unblock_by_func (G_OBJECT (window->soundcard_combo), G_CALLBACK (xfce_mixer_window_soundcard_changed), window);
 
-      /* Re-generate mixer controls for the active sound card */
+      /* Update mixer controls for the active sound card */
       xfce_mixer_window_update_contents (window);
 
       /* Update the controls dialog */
@@ -393,7 +395,7 @@ xfce_mixer_window_controls_property_changed (XfceMixerWindow *window,
                                              GParamSpec      *pspec,
                                              GObject         *object)
 {
-  xfce_mixer_window_update_contents (window);
+  xfce_mixer_update_contents (XFCE_MIXER (window->mixer));
 
   /* Update the controls dialog */
   if (window->controls_dialog != NULL)
@@ -448,27 +450,28 @@ xfce_mixer_window_update_contents (XfceMixerWindow *window)
   g_return_if_fail (IS_XFCE_MIXER_WINDOW (window));
 
   card = xfce_mixer_card_combo_get_active_card (XFCE_MIXER_CARD_COMBO (window->soundcard_combo));
+  if (G_LIKELY (GST_IS_MIXER (card)))
+    {
+      title = g_strdup_printf ("%s - %s", _("Audio Mixer"), xfce_mixer_get_card_display_name (card));
+      gtk_window_set_title (GTK_WINDOW (window), title);
+      g_free (title);
 
-  if (G_UNLIKELY (!GST_IS_MIXER (card)))
-    return;
-
-  title = g_strdup_printf ("%s - %s", _("Audio Mixer"), xfce_mixer_get_card_display_name (card));
-  gtk_window_set_title (GTK_WINDOW (window), title);
-  g_free (title);
-
-  /* Destroy the current mixer */
-  if (G_LIKELY (window->mixer != NULL))
-    gtk_widget_destroy (window->mixer);
+      xfce_mixer_select_card (card);
 
-  xfce_mixer_select_card (card);
+      /* Update the XfceMixer containing the controls */
+      g_object_set (window->mixer, "card", card, NULL);
 
-  /* Create a new XfceMixer for the active sound card */
-  window->mixer = xfce_mixer_new (card);
+      /* Make the "Select Controls..." button sensitive */
+      gtk_widget_set_sensitive (window->select_controls_button, TRUE);
+    }
+  else
+    {
+      gtk_window_set_title (GTK_WINDOW (window), _("Audio Mixer"));
 
-  /* Add the XfceMixer to the window */
-  gtk_container_add (GTK_CONTAINER (window->mixer_frame), window->mixer);
-  gtk_widget_show (window->mixer);
+      /* Update the XfceMixer containing the controls */
+      g_object_set (window->mixer, "card", NULL, NULL);
 
-  /* Make the "Select Controls..." button sensitive */
-  gtk_widget_set_sensitive (window->select_controls_button, TRUE);
+      /* Make the "Select Controls..." button insensitive */
+      gtk_widget_set_sensitive (window->select_controls_button, FALSE);
+    }
 }
diff --git a/xfce4-mixer/xfce-mixer.c b/xfce4-mixer/xfce-mixer.c
index 773f27b..dd6f5f6 100644
--- a/xfce4-mixer/xfce-mixer.c
+++ b/xfce4-mixer/xfce-mixer.c
@@ -58,6 +58,7 @@ static void xfce_mixer_set_property    (GObject        *object,
                                         guint           prop_id,
                                         const GValue   *value,
                                         GParamSpec     *pspec);
+static void xfce_mixer_create_contents (XfceMixer      *mixer);
 static void xfce_mixer_bus_message     (GstBus         *bus,
                                         GstMessage     *message,
                                         XfceMixer      *mixer);
@@ -135,8 +136,7 @@ xfce_mixer_class_init (XfceMixerClass *klass)
                                                         "card",
                                                         "card",
                                                         GST_TYPE_ELEMENT,
-                                                        G_PARAM_CONSTRUCT_ONLY | 
-                                                        G_PARAM_READWRITE));
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
 }
 
 
@@ -144,6 +144,7 @@ xfce_mixer_class_init (XfceMixerClass *klass)
 static void
 xfce_mixer_instance_init (XfceMixer *mixer)
 {
+  mixer->card = NULL;
   mixer->widgets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
   mixer->message_handler_id = 0;
 }
@@ -153,7 +154,95 @@ xfce_mixer_instance_init (XfceMixer *mixer)
 static void
 xfce_mixer_constructed (GObject *object)
 {
-  XfceMixer            *mixer = XFCE_MIXER (object);
+  XfceMixer *mixer = XFCE_MIXER (object);
+
+  /* Create the content */
+  xfce_mixer_create_contents (XFCE_MIXER (mixer));
+
+  mixer->message_handler_id = xfce_mixer_bus_connect (G_CALLBACK (xfce_mixer_bus_message), mixer);
+}
+
+
+
+static void
+xfce_mixer_finalize (GObject *object)
+{
+  XfceMixer *mixer = XFCE_MIXER (object);
+
+  xfce_mixer_bus_disconnect (mixer->message_handler_id);
+
+  g_object_unref (mixer->card);
+  g_hash_table_unref (mixer->widgets);
+
+  (*G_OBJECT_CLASS (xfce_mixer_parent_class)->finalize) (object);
+}
+
+
+
+static void
+xfce_mixer_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  XfceMixer *mixer = XFCE_MIXER (object);
+
+  switch (prop_id)
+    {
+    case PROP_CARD:
+      g_value_set_object (value, mixer->card);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+static void
+xfce_mixer_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  XfceMixer *mixer = XFCE_MIXER (object);
+
+  switch (prop_id)
+    {
+    case PROP_CARD:
+      if (mixer->message_handler_id != 0)
+        xfce_mixer_bus_disconnect (mixer->message_handler_id);
+      mixer->card = g_value_dup_object (value);
+      xfce_mixer_update_contents (mixer);
+      if (GST_IS_MIXER (mixer->card))
+        mixer->message_handler_id = xfce_mixer_bus_connect (G_CALLBACK (xfce_mixer_bus_message), mixer);
+      else
+        mixer->message_handler_id = 0;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+GtkWidget *
+xfce_mixer_new (GstElement *card)
+{
+  GObject *object = NULL;
+
+  object = g_object_new (TYPE_XFCE_MIXER, "card", card, NULL);
+
+  return GTK_WIDGET (object);
+}
+
+
+
+static void
+xfce_mixer_create_contents (XfceMixer *mixer)
+{
   XfceMixerPreferences *preferences;
   XfceMixerTrackType    type;
   GstMixerTrack        *track;
@@ -168,9 +257,10 @@ xfce_mixer_constructed (GObject *object)
   GtkWidget            *label2;
   const gchar          *track_label;
   guint                 num_children[4] = { 0, 0, 0, 0 };
+  gboolean              no_controls_visible = TRUE;
   gint                  i;
 
-  g_hash_table_remove_all (mixer->widgets);
+  g_return_if_fail (IS_XFCE_MIXER (mixer));
 
   preferences = xfce_mixer_preferences_get ();
 
@@ -200,77 +290,82 @@ xfce_mixer_constructed (GObject *object)
     }
 
   /* Create controls for all mixer tracks */
-  for (iter = gst_mixer_list_tracks (GST_MIXER (mixer->card)); iter != NULL; iter = g_list_next (iter))
+  if (GST_IS_MIXER (mixer->card))
     {
-      track = GST_MIXER_TRACK (iter->data);
-
-      track_label = xfce_mixer_get_track_label (track);
-
-      if (!xfce_mixer_preferences_get_control_visible (preferences, track_label))
-        continue;
-
-      /* Determine the type of the mixer track */
-      type = xfce_mixer_track_type_new (track);
-
-      switch (type) 
+      for (iter = gst_mixer_list_tracks (GST_MIXER (mixer->card)); iter != NULL; iter = g_list_next (iter))
         {
-        case XFCE_MIXER_TRACK_TYPE_PLAYBACK:
-          /* Create a regular volume control for this track */
-          track_widget = xfce_mixer_track_new (mixer->card, track);
-          gtk_table_attach (GTK_TABLE (views[0]), track_widget, 
-                            num_children[0], num_children[0] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
-          gtk_widget_show (track_widget);
-          num_children[0]++;
-
-          /* Append a separator. The last one will be destroyed later */
-          last_separator[0] = gtk_vseparator_new ();
-          gtk_table_attach (GTK_TABLE (views[0]), last_separator[0], 
-                            num_children[0], num_children[0] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
-          gtk_widget_show (last_separator[0]);
-          num_children[0]++;
-
-          /* Add the track to the hash table */
-          g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
-          break;
-
-        case XFCE_MIXER_TRACK_TYPE_CAPTURE:
-          /* Create a regular volume control for this track */
-          track_widget = xfce_mixer_track_new (mixer->card, track);
-          gtk_table_attach (GTK_TABLE (views[1]), track_widget, 
-                            num_children[1], num_children[1] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
-          gtk_widget_show (track_widget);
-          num_children[1]++;
-
-          /* Append a separator. The last one will be destroyed later */
-          last_separator[1] = gtk_vseparator_new ();
-          gtk_table_attach (GTK_TABLE (views[1]), last_separator[1], 
-                            num_children[1], num_children[1] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
-          gtk_widget_show (last_separator[1]);
-          num_children[1]++;
-
-          /* Add the track to the hash table */
-          g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
-          break;
-
-        case XFCE_MIXER_TRACK_TYPE_SWITCH:
-          track_widget = xfce_mixer_switch_new (mixer->card, track);
-          gtk_box_pack_start (GTK_BOX (views[2]), track_widget, FALSE, FALSE, 0);
-          gtk_widget_show (track_widget);
-          num_children[2]++;
-
-          /* Add the track to the hash table */
-          g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
-          break;
-
-        case XFCE_MIXER_TRACK_TYPE_OPTIONS:
-          track_widget = xfce_mixer_option_new (mixer->card, track);
-          gtk_box_pack_start (GTK_BOX (views[3]), track_widget, FALSE, FALSE, 0);
-          gtk_widget_show (track_widget);
-          num_children[3]++;
-
-          /* Add the track to the hash table */
-          g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
-          break;
+          track = GST_MIXER_TRACK (iter->data);
+
+          track_label = xfce_mixer_get_track_label (track);
+
+          if (!xfce_mixer_preferences_get_control_visible (preferences, track_label))
+            continue;
+
+          /* Determine the type of the mixer track */
+          type = xfce_mixer_track_type_new (track);
+
+          switch (type) 
+            {
+            case XFCE_MIXER_TRACK_TYPE_PLAYBACK:
+              /* Create a regular volume control for this track */
+              track_widget = xfce_mixer_track_new (mixer->card, track);
+              gtk_table_attach (GTK_TABLE (views[0]), track_widget, 
+                                num_children[0], num_children[0] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
+              gtk_widget_show (track_widget);
+              num_children[0]++;
+
+              /* Append a separator. The last one will be destroyed later */
+              last_separator[0] = gtk_vseparator_new ();
+              gtk_table_attach (GTK_TABLE (views[0]), last_separator[0], 
+                                num_children[0], num_children[0] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
+              gtk_widget_show (last_separator[0]);
+              num_children[0]++;
+
+              /* Add the track to the hash table */
+              g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
+              break;
+
+            case XFCE_MIXER_TRACK_TYPE_CAPTURE:
+              /* Create a regular volume control for this track */
+              track_widget = xfce_mixer_track_new (mixer->card, track);
+              gtk_table_attach (GTK_TABLE (views[1]), track_widget, 
+                                num_children[1], num_children[1] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
+              gtk_widget_show (track_widget);
+              num_children[1]++;
+
+              /* Append a separator. The last one will be destroyed later */
+              last_separator[1] = gtk_vseparator_new ();
+              gtk_table_attach (GTK_TABLE (views[1]), last_separator[1], 
+                                num_children[1], num_children[1] + 1, 0, 1, GTK_SHRINK, GTK_FILL|GTK_EXPAND, 0, 0);
+              gtk_widget_show (last_separator[1]);
+              num_children[1]++;
+
+              /* Add the track to the hash table */
+              g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
+              break;
+
+            case XFCE_MIXER_TRACK_TYPE_SWITCH:
+              track_widget = xfce_mixer_switch_new (mixer->card, track);
+              gtk_box_pack_start (GTK_BOX (views[2]), track_widget, FALSE, FALSE, 0);
+              gtk_widget_show (track_widget);
+              num_children[2]++;
+
+              /* Add the track to the hash table */
+              g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
+              break;
+
+            case XFCE_MIXER_TRACK_TYPE_OPTIONS:
+              track_widget = xfce_mixer_option_new (mixer->card, track);
+              gtk_box_pack_start (GTK_BOX (views[3]), track_widget, FALSE, FALSE, 0);
+              gtk_widget_show (track_widget);
+              num_children[3]++;
+
+              /* Add the track to the hash table */
+              g_hash_table_insert (mixer->widgets, g_strdup (track_label), track_widget);
+              break;
+            default:
+              break;
+            }
         }
     }
 
@@ -281,21 +376,17 @@ xfce_mixer_constructed (GObject *object)
       if (G_LIKELY (last_separator[i] != NULL))
         gtk_widget_destroy (last_separator[i]);
 
-      /* Check if there are controls at all for this tab */
-      if (G_LIKELY (num_children[i] > 0))
-        {
-          /* If there are controls, create the notebook tab */
-          gtk_notebook_append_page (GTK_NOTEBOOK (mixer), scrollwins[i], labels[i]);
-        }
+      gtk_notebook_append_page (GTK_NOTEBOOK (mixer), scrollwins[i], labels[i]);
+
+      /* Hide tabs with no visible controls */
+      if (num_children[i] > 0)
+        no_controls_visible = FALSE;
       else
-        {
-          /* Otherwise, destroy all created widgets */
-          gtk_widget_destroy (labels[i]);
-          gtk_widget_destroy (scrollwins[i]);
-        }
+        gtk_widget_hide (gtk_notebook_get_nth_page (GTK_NOTEBOOK (mixer), i));
     }
 
-  if (G_UNLIKELY (gtk_notebook_get_n_pages (GTK_NOTEBOOK (mixer)) == 0))
+  /* Show informational message if no controls are visible */
+  if (G_UNLIKELY (no_controls_visible))
     {
       label1 = gtk_label_new (_("No controls visible"));
       gtk_widget_show (label1);
@@ -308,80 +399,35 @@ xfce_mixer_constructed (GObject *object)
       gtk_notebook_append_page (GTK_NOTEBOOK (mixer), label2, label1);
     }
 
-  mixer->message_handler_id = xfce_mixer_bus_connect (G_CALLBACK (xfce_mixer_bus_message), mixer);
-
   g_object_unref (preferences);
 }
 
 
 
-static void
-xfce_mixer_finalize (GObject *object)
+void
+xfce_mixer_update_contents (XfceMixer *mixer)
 {
-  XfceMixer *mixer = XFCE_MIXER (object);
-
-  xfce_mixer_bus_disconnect (mixer->message_handler_id);
+  gint current_tab;
+  gint i;
 
-  g_object_unref (mixer->card);
-  g_hash_table_unref (mixer->widgets);
-
-  (*G_OBJECT_CLASS (xfce_mixer_parent_class)->finalize) (object);
-}
-
-
-
-static void
-xfce_mixer_get_property (GObject    *object,
-                         guint       prop_id,
-                         GValue     *value,
-                         GParamSpec *pspec)
-{
-  XfceMixer *mixer = XFCE_MIXER (object);
-
-  switch (prop_id)
-    {
-    case PROP_CARD:
-      g_value_set_object (value, mixer->card);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-static void
-xfce_mixer_set_property (GObject      *object,
-                         guint         prop_id,
-                         const GValue *value,
-                         GParamSpec   *pspec)
-{
-  XfceMixer *mixer = XFCE_MIXER (object);
-
-  switch (prop_id)
-    {
-    case PROP_CARD:
-      mixer->card = g_value_dup_object (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
+  g_return_if_fail (IS_XFCE_MIXER (mixer));
+  g_return_if_fail (mixer->widgets != NULL);
 
+  g_hash_table_remove_all (mixer->widgets);
 
+  /* Remember active tab */
+  current_tab = gtk_notebook_get_current_page (GTK_NOTEBOOK (mixer));
 
-GtkWidget *
-xfce_mixer_new (GstElement *card)
-{
-  GObject *object = NULL;
+  /* Destroy all tabs */
+  for (i = gtk_notebook_get_n_pages (GTK_NOTEBOOK (mixer)); i >= 0; i--)
+    gtk_notebook_remove_page (GTK_NOTEBOOK (mixer), i);
 
-  g_return_val_if_fail (GST_IS_MIXER (card), NULL);
- 
-  object = g_object_new (TYPE_XFCE_MIXER, "card", card, NULL);
+  /* Re-create contents */
+  xfce_mixer_create_contents (mixer);
 
-  return GTK_WIDGET (object);
+  /* Restore previously active tab if possible */
+  if (current_tab > 0 && current_tab < 4)
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (mixer), current_tab);
 }
 
 
@@ -391,7 +437,6 @@ xfce_mixer_bus_message (GstBus     *bus,
                         GstMessage *message,
                         XfceMixer  *mixer)
 {
-  GstMixerMessageType type;
   GstMixerOptions    *options = NULL;
   GstMixerTrack      *track = NULL;
   GtkWidget          *widget;
@@ -407,50 +452,53 @@ xfce_mixer_bus_message (GstBus     *bus,
   if (G_UNLIKELY (GST_MESSAGE_SRC (message) != GST_OBJECT (mixer->card)))
     return;
 
-  type = gst_mixer_message_get_type (message);
-
-  if (type == GST_MIXER_MESSAGE_MUTE_TOGGLED)
-    {
-      gst_mixer_message_parse_mute_toggled (message, &track, &muted);
-      label = xfce_mixer_get_track_label (track);
-      xfce_mixer_debug ("Track '%s' was %s", label, muted ? "muted" : "unmuted");
-      widget = g_hash_table_lookup (mixer->widgets, label);
-
-      if (IS_XFCE_MIXER_TRACK (widget))
-        xfce_mixer_track_update_mute (XFCE_MIXER_TRACK (widget));
-      else if (IS_XFCE_MIXER_SWITCH (widget))
-        xfce_mixer_switch_update (XFCE_MIXER_SWITCH (widget));
-    }
-  else if (type == GST_MIXER_MESSAGE_RECORD_TOGGLED)
-    {
-      gst_mixer_message_parse_record_toggled (message, &track, &record);
-      label = xfce_mixer_get_track_label (track);
-      xfce_mixer_debug ("Recording on track '%s' was %s", label, record ? "turned on" : "turned off");
-      widget = g_hash_table_lookup (mixer->widgets, label);
-
-      if (IS_XFCE_MIXER_TRACK (widget))
-        xfce_mixer_track_update_record (XFCE_MIXER_TRACK (widget));
-      else if (IS_XFCE_MIXER_SWITCH (widget))
-        xfce_mixer_switch_update (XFCE_MIXER_SWITCH (widget));
-    }
-  else if (type == GST_MIXER_MESSAGE_VOLUME_CHANGED)
-    {
-      gst_mixer_message_parse_volume_changed (message, &track, &volumes, &num_channels);
-      label = xfce_mixer_get_track_label (track);
-      xfce_mixer_debug ("Volume on track '%s' changed to %i", label, volumes[0]);
-      widget = g_hash_table_lookup (mixer->widgets, label);
-
-      if (IS_XFCE_MIXER_TRACK (widget))
-        xfce_mixer_track_update_volume (XFCE_MIXER_TRACK (widget));
-    }
-  else if (type == GST_MIXER_MESSAGE_OPTION_CHANGED)
+  switch (gst_mixer_message_get_type (message))
     {
-      gst_mixer_message_parse_option_changed (message, &options, &option);
-      label = xfce_mixer_get_track_label (GST_MIXER_TRACK (options));
-      xfce_mixer_debug ("Option '%s' was set to '%s'", label, option);
-      widget = g_hash_table_lookup (mixer->widgets, label);
-
-      if (IS_XFCE_MIXER_OPTION (widget))
-        xfce_mixer_option_update (XFCE_MIXER_OPTION (widget));
+      case GST_MIXER_MESSAGE_MUTE_TOGGLED:
+        gst_mixer_message_parse_mute_toggled (message, &track, &muted);
+        label = xfce_mixer_get_track_label (track);
+        xfce_mixer_debug ("Track '%s' was %s", label, muted ? "muted" : "unmuted");
+        widget = g_hash_table_lookup (mixer->widgets, label);
+
+        if (IS_XFCE_MIXER_TRACK (widget))
+          xfce_mixer_track_update_mute (XFCE_MIXER_TRACK (widget));
+        else if (IS_XFCE_MIXER_SWITCH (widget))
+          xfce_mixer_switch_update (XFCE_MIXER_SWITCH (widget));
+        break;
+      case GST_MIXER_MESSAGE_RECORD_TOGGLED:
+        gst_mixer_message_parse_record_toggled (message, &track, &record);
+        label = xfce_mixer_get_track_label (track);
+        xfce_mixer_debug ("Recording on track '%s' was %s", label, record ? "turned on" : "turned off");
+        widget = g_hash_table_lookup (mixer->widgets, label);
+
+        if (IS_XFCE_MIXER_TRACK (widget))
+          xfce_mixer_track_update_record (XFCE_MIXER_TRACK (widget));
+        else if (IS_XFCE_MIXER_SWITCH (widget))
+          xfce_mixer_switch_update (XFCE_MIXER_SWITCH (widget));
+        break;
+      case GST_MIXER_MESSAGE_VOLUME_CHANGED:
+        gst_mixer_message_parse_volume_changed (message, &track, &volumes, &num_channels);
+        label = xfce_mixer_get_track_label (track);
+        xfce_mixer_debug ("Volume on track '%s' changed to %i", label, volumes[0]);
+        widget = g_hash_table_lookup (mixer->widgets, label);
+
+        if (IS_XFCE_MIXER_TRACK (widget))
+          xfce_mixer_track_update_volume (XFCE_MIXER_TRACK (widget));
+        break;
+      case GST_MIXER_MESSAGE_OPTION_CHANGED:
+        gst_mixer_message_parse_option_changed (message, &options, &option);
+        label = xfce_mixer_get_track_label (GST_MIXER_TRACK (options));
+        xfce_mixer_debug ("Option '%s' was set to '%s'", label, option);
+        widget = g_hash_table_lookup (mixer->widgets, label);
+
+        if (IS_XFCE_MIXER_OPTION (widget))
+          xfce_mixer_option_update (XFCE_MIXER_OPTION (widget));
+        break;
+      case GST_MIXER_MESSAGE_MIXER_CHANGED:
+        xfce_mixer_debug ("Mixer tracks have changed");
+        xfce_mixer_update_contents (mixer);
+        break;
+      default:
+        break;
     }
 }
diff --git a/xfce4-mixer/xfce-mixer.h b/xfce4-mixer/xfce-mixer.h
index 00186fa..2aeab9e 100644
--- a/xfce4-mixer/xfce-mixer.h
+++ b/xfce4-mixer/xfce-mixer.h
@@ -1,6 +1,7 @@
 /* vi:set expandtab sw=2 sts=2: */
 /*-
  * Copyright (c) 2008 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2012 Guido Berhoerster <guido+xfce at berhoerster.name>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,7 +39,8 @@ typedef struct _XfceMixer      XfceMixer;
 
 GType      xfce_mixer_get_type (void) G_GNUC_CONST;
 
-GtkWidget *xfce_mixer_new      (GstElement *card);
+GtkWidget  *xfce_mixer_new             (GstElement *card);
+void        xfce_mixer_update_contents (XfceMixer  *mixer);
 
 G_END_DECLS;
 


More information about the Xfce4-commits mailing list