Index: seek.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/tests/examples/seek/seek.c,v
retrieving revision 1.59
diff -u -3 -p -b -B -d -r1.59 seek.c
--- seek.c	29 Mar 2006 13:54:24 -0000	1.59
+++ seek.c	2 Apr 2006 18:38:57 -0000
@@ -7,6 +7,9 @@
 GST_DEBUG_CATEGORY (seek_debug);
 #define GST_CAT_DEFAULT (seek_debug)
 
+static GstObject *seek_object = NULL;
+static GstObject *seek_object_stream = NULL;
+
 static GList *seekable_pads = NULL;
 static GList *rate_pads = NULL;
 static GList *seekable_elements = NULL;
@@ -17,11 +20,13 @@ static gboolean loop_seek = FALSE;
 static gboolean flush_seek = TRUE;
 static gboolean scrub = FALSE;
 
+static GstFormat format = GST_FORMAT_DEFAULT;
+static GstFormat format_stream = GST_FORMAT_DEFAULT;
+
 static GstElement *pipeline;
-static gint64 position;
-static gint64 duration;
-static GtkAdjustment *adjustment;
-static GtkWidget *hscale;
+static gint64 duration = 0, duration_stream = 0, stream = 0;
+static GtkAdjustment *adjustment, *adjustment_stream;
+static GtkWidget *hscale, *hscale_stream;
 static gboolean stats = FALSE;
 static gboolean elem_seek = FALSE;
 static gboolean verbose = FALSE;
@@ -829,18 +834,39 @@ make_parselaunch_pipeline (const gchar *
 }
 
 static gchar *
-format_value (GtkScale * scale, gdouble value)
+format_value_common (gdouble value, GstFormat format, gdouble duration)
 {
-  gint64 real;
+  gint64 real = value * duration / 100;
   gint64 seconds;
   gint64 subseconds;
 
-  real = value * duration / 100;
+  switch (format) {
+  case GST_FORMAT_TIME:
   seconds = (gint64) real / GST_SECOND;
   subseconds = (gint64) real / (GST_SECOND / 100);
+    return g_strdup_printf ("%02" G_GINT64_FORMAT
+        ":%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT,
+        seconds / 60, seconds % 60, subseconds % 100);
+  case GST_FORMAT_PERCENT:
+    return g_strdup_printf ("%.02f%%", (gdouble) real / GST_FORMAT_PERCENT_MAX);
+  case GST_FORMAT_STREAMS:
+    return g_strdup_printf ("%" G_GINT64_FORMAT, real + 1);
+  case GST_FORMAT_BYTES:
+  default:
+    return g_strdup_printf ("%" G_GINT64_FORMAT, real);
+  }
+}
 
-  return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
-      G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
+static gchar *
+format_value (GtkScale * scale, gdouble value)
+{
+  return format_value_common (value, format, duration);
+}
+
+static gchar *
+format_value_stream (GtkScale * scale, gdouble value)
+{
+  return format_value_common (value, format_stream, duration_stream);
 }
 
 typedef struct
@@ -955,29 +981,105 @@ query_positions_pads ()
 }
 
 static gboolean
+_gst_element_query_duration_stream (GstElement * element, guint stream,
+    GstFormat * format, gint64 * duration)
+{
+  GstQuery *query;
+
+  query = gst_query_new_duration (*format);
+  gst_query_set_stream (query, stream);
+  if (!gst_element_query (element, query)) {
+    gst_query_unref (query);
+    return FALSE;
+  }
+  gst_query_parse_duration (query, NULL, duration);
+  gst_query_unref (query);
+  return TRUE;
+}
+
+static gboolean
+_gst_element_query_position_stream (GstElement * element, guint stream,
+    GstFormat * format, gint64 * position)
+{
+  GstQuery *query;
+
+  query = gst_query_new_position (*format);
+  gst_query_set_stream (query, stream);
+  if (!gst_element_query (element, query)) {
+    gst_query_unref (query);
+    return FALSE;
+  }
+  gst_query_parse_position (query, NULL, position);
+  gst_query_unref (query);
+  return TRUE;
+}
+
+static gboolean
+_gst_pad_query_duration_stream (GstPad * pad, guint stream,
+    GstFormat * format, gint64 * duration)
+{
+  GstQuery *query;
+
+  query = gst_query_new_duration (*format);
+  gst_query_set_stream (query, stream);
+  if (!gst_pad_query (pad, query)) {
+    gst_query_unref (query);
+    return FALSE;
+  }
+  gst_query_parse_duration (query, NULL, duration);
+  gst_query_unref (query);
+  return TRUE;
+}
+
+static gboolean
+_gst_pad_query_position_stream (GstPad * pad, guint stream,
+    GstFormat * format, gint64 * position)
+{
+  GstQuery *query;
+
+  query = gst_query_new_position (*format);
+  gst_query_set_stream (query, stream);
+  if (!gst_pad_query (pad, query)) {
+    gst_query_unref (query);
+    return FALSE;
+  }
+  gst_query_parse_position (query, NULL, position);
+  gst_query_unref (query);
+  return TRUE;
+}
+
+static gboolean
 update_scale (gpointer data)
 {
-  GstFormat format;
+  GstFormat format_streams = GST_FORMAT_STREAMS;
+  gint64 position = 0, position_stream = 0;
 
-  position = 0;
   duration = 0;
 
-  format = GST_FORMAT_TIME;
-
-  if (elem_seek) {
-    if (seekable_elements) {
-      GstElement *element = GST_ELEMENT (seekable_elements->data);
+  if (GST_IS_ELEMENT (seek_object)) {
+    GstElement *element = GST_ELEMENT (seek_object);
 
+    gst_element_query_position (GST_ELEMENT (seek_object),
+        &format_streams, &stream);
       gst_element_query_position (element, &format, &position);
       gst_element_query_duration (element, &format, &duration);
-    }
-  } else {
-    if (seekable_pads) {
-      GstPad *pad = GST_PAD (seekable_pads->data);
+  } else if (GST_IS_PAD (seek_object)) {
+    GstPad *pad = GST_PAD (seek_object);
 
+    gst_pad_query_position (GST_PAD (seek_object), &format_streams, &stream);
       gst_pad_query_position (pad, &format, &position);
       gst_pad_query_duration (pad, &format, &duration);
     }
+  if (GST_IS_ELEMENT (seek_object_stream)) {
+    GstElement *element = GST_ELEMENT (seek_object_stream);
+
+    _gst_element_query_position_stream (element, stream, &format_stream, &position_stream);
+    _gst_element_query_duration_stream (element, stream, &format_stream, &duration_stream);
+  } else if (GST_IS_PAD (seek_object_stream)) {
+    GstPad *pad = GST_PAD (seek_object_stream);
+
+    _gst_pad_query_position_stream (pad, stream, &format_stream, &position_stream);
+    _gst_pad_query_duration_stream (pad, stream, &format_stream, &duration_stream);
   }
 
   if (stats) {
@@ -988,19 +1090,23 @@ update_scale (gpointer data)
     }
     query_rates ();
   }
-  if (position >= duration)
-    duration = position;
+
+  duration = MAX (duration, position);
+  duration_stream = MAX (duration_stream, position_stream);
 
   if (duration > 0) {
     gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
     gtk_widget_queue_draw (hscale);
   }
+  if (duration_stream > 0) {
+    gtk_adjustment_set_value (adjustment_stream,
+        position_stream * 100. / duration_stream);
+    gtk_widget_queue_draw (hscale_stream);
+  }
 
   return TRUE;
 }
 
-static void do_seek (GtkWidget * widget);
-
 static gboolean
 end_scrub (GtkWidget * widget)
 {
@@ -1012,10 +1118,17 @@ end_scrub (GtkWidget * widget)
 }
 
 static gboolean
-send_event (GstEvent * event)
+send_event (GstEvent * event, GstObject * seek_object)
 {
   gboolean res = FALSE;
 
+  if (seek_object) {
+    if (GST_IS_PAD (seek_object))
+      return gst_pad_send_event (GST_PAD (seek_object), event);
+    else
+      return gst_element_send_event (GST_ELEMENT (seek_object), event);
+  }
+
   if (!elem_seek) {
     GList *walk = seekable_pads;
 
@@ -1054,8 +1167,32 @@ do_seek (GtkWidget * widget)
   gboolean res = FALSE;
   GstEvent *s_event;
   GstSeekFlags flags;
+  GstObject *seek_obj;
+  GstFormat fmt;
+  gdouble val;
 
-  real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
+  val = gtk_range_get_value (GTK_RANGE (widget));
+  if (widget == hscale_stream) {
+    gint64 i, dur = 0;
+
+    fmt = format_stream;
+    seek_obj = seek_object_stream;
+    real = val * duration_stream / 100;
+    for (i = 0; i < stream; i++) {
+      if (GST_IS_ELEMENT (seek_object))
+        _gst_element_query_duration_stream (GST_ELEMENT (seek_object),
+            i, &format_stream, &dur);
+      else if (GST_IS_PAD (seek_object))
+        _gst_pad_query_duration_stream (GST_PAD (seek_object),
+            i, &format_stream, &dur);
+      real += dur;
+    }
+  } else {
+    fmt = format;
+    seek_obj = seek_object;
+    real = val * duration / 100;
+    g_message ("ELEMENT_SEEK on %p to %lld", seek_object, real);
+  }
 
   flags = 0;
   if (flush_seek)
@@ -1068,11 +1205,9 @@ do_seek (GtkWidget * widget)
     flags |= GST_SEEK_FLAG_SEGMENT;
 
   s_event = gst_event_new_seek (1.0,
-      GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_NONE, 0);
-
-  GST_DEBUG ("seek to %" GST_TIME_FORMAT, GST_TIME_ARGS (real));
+      fmt, flags, GST_SEEK_TYPE_SET, real, GST_SEEK_TYPE_NONE, 0);
 
-  res = send_event (s_event);
+  res = send_event (s_event, seek_obj);
 
   if (res) {
     if (flush_seek) {
@@ -1080,7 +1215,7 @@ do_seek (GtkWidget * widget)
       gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
     }
   } else
-    g_print ("seek failed\n");
+    g_print ("seek on object %s failed\n", G_OBJECT_TYPE_NAME (seek_obj));
 }
 
 static void
@@ -1136,7 +1271,7 @@ start_seek (GtkWidget * widget, GdkEvent
   set_update_scale (FALSE);
 
   if (changed_id == 0 && flush_seek) {
-    changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
+    changed_id = gtk_signal_connect (GTK_OBJECT (widget),
         "value_changed", G_CALLBACK (seek_cb), pipeline);
   }
 
@@ -1147,7 +1282,7 @@ static gboolean
 stop_seek (GtkWidget * widget, gpointer user_data)
 {
   if (changed_id) {
-    g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
+    g_signal_handler_disconnect (GTK_OBJECT (widget), changed_id);
     changed_id = 0;
   }
 
@@ -1281,11 +1416,11 @@ segment_done (GstBus * bus, GstMessage *
     flags |= GST_SEEK_FLAG_SEGMENT;
 
   event = gst_event_new_seek (1.0,
-      GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0);
+      format, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0);
 
   GST_DEBUG ("segmeent seek to start");
 
-  res = send_event (event);
+  res = send_event (event, NULL);
   if (!res) {
     g_print ("segment seek failed\n");
   }
@@ -1311,6 +1446,171 @@ message_received (GstBus * bus, GstMessa
   }
 }
 
+enum {
+  COL_NAME,
+  COL_FORMAT,
+  NUM_COLS
+};
+
+static void
+foreach_format_func (gpointer data, gpointer user_data)
+{
+  GtkTreeIter iter;
+  GtkComboBox *combo = GTK_COMBO_BOX (user_data);
+  GtkListStore *list = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+  GstFormatDefinition *def = (GstFormatDefinition *) data;
+  GstFormat *format = g_object_get_data (G_OBJECT (combo), "format");
+
+  gtk_list_store_append (list, &iter);
+  gtk_list_store_set (list, &iter, COL_NAME, g_strdup (def->nick),
+      COL_FORMAT, def->value, -1);
+  if (def->value == *format)
+    gtk_combo_box_set_active_iter (combo, &iter);
+}
+
+static GtkWidget *
+get_format_combo (GstFormat *format, GstObject **seek_object)
+{
+  GtkListStore *list;
+  GtkWidget *combo;
+  GtkCellRenderer *r;
+  GstIterator *it;
+
+  list = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_UINT);
+  combo = g_object_new (GTK_TYPE_COMBO_BOX, "model", list, NULL);
+  g_object_set_data (G_OBJECT (combo), "format", format);
+  g_object_set_data (G_OBJECT (combo), "seek_object", seek_object);
+  r = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), r, FALSE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), r, "text",
+      0, NULL);
+  it = gst_format_iterate_definitions ();
+  gst_iterator_foreach (it, foreach_format_func, combo);
+  gst_iterator_free (it);
+
+  return GTK_WIDGET (combo);
+}
+
+enum {
+  OBJECT_COL_NAME,
+  OBJECT_COL_OBJECT,
+  OBJECT_NUM_COLS
+};
+
+static GtkWidget *
+get_object_combo (GstFormat *format)
+{
+  GtkListStore *list;
+  GtkWidget *combo;
+  GtkCellRenderer *r;
+
+  list = gtk_list_store_new (OBJECT_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
+  combo = g_object_new (GTK_TYPE_COMBO_BOX, "model", list, NULL);
+  g_object_set_data (G_OBJECT (combo), "format", format);
+  r = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), r, FALSE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), r, "text",
+      0, NULL);
+
+  return GTK_WIDGET (combo);
+}
+
+static void
+foreach_element_func (gpointer data, gpointer user_data)
+{
+  GstElement *e = GST_ELEMENT (data);
+  GstQuery *query;
+  guint i, n = 0;
+  GstFormat f;
+  GtkComboBox *combo = GTK_COMBO_BOX (user_data);
+  GtkListStore *model = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+  GtkTreeIter iter;
+  GstFormat *format = g_object_get_data (G_OBJECT (combo), "format");
+
+  query = gst_query_new_formats ();
+  if (gst_element_query (e, query)) {
+    gst_query_parse_formats_length (query, &n);
+    for (i = 0; i < n; i++) {
+      gst_query_parse_formats_nth (query, i, &f);
+      if (f != *format)
+        continue;
+      gtk_list_store_append (model, &iter);
+      gtk_list_store_set (model, &iter,
+          OBJECT_COL_NAME, g_strdup (G_OBJECT_TYPE_NAME (e)),
+          OBJECT_COL_OBJECT, e, -1);
+    }
+  }
+  gst_query_unref (query);
+}
+
+void
+object_changed_cb (GtkComboBox *combo, GstObject **seek_object)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  GValue v = {0,};
+
+  model = gtk_combo_box_get_model (combo);
+  if (gtk_combo_box_get_active_iter (combo, &iter)) {
+    gtk_tree_model_get_value (model, &iter, OBJECT_COL_OBJECT, &v);
+    *seek_object = g_value_get_pointer (&v);
+    g_value_unset (&v);
+  }
+}
+
+void
+format_changed_cb (GtkComboBox *combo, GtkComboBox *obj_combo)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  GValue v = {0,};
+  GstIterator *it;
+  GstFormat *format;
+  GstObject **seek_object;
+
+  format = g_object_get_data (G_OBJECT (combo), "format");
+  seek_object = g_object_get_data (G_OBJECT (combo), "seek_object");
+
+  model = gtk_combo_box_get_model (combo);
+  if (gtk_combo_box_get_active_iter (combo, &iter)) {
+    gtk_tree_model_get_value (model, &iter, COL_FORMAT, &v);
+    *format = g_value_get_uint (&v);
+    g_value_unset (&v);
+  }
+
+  model = gtk_combo_box_get_model (obj_combo);
+  gtk_list_store_clear (GTK_LIST_STORE (model));
+  it = gst_bin_iterate_elements (GST_BIN (pipeline));
+  gst_iterator_foreach (it, foreach_element_func, obj_combo);
+  gst_iterator_free (it);
+
+  if (gtk_tree_model_get_iter_first (model, &iter)) {
+    while (TRUE) {
+      gtk_tree_model_get_value (model, &iter, OBJECT_COL_OBJECT, &v);
+      if (!seek_object) {
+        gtk_combo_box_set_active_iter (obj_combo, &iter);
+        *seek_object = g_value_get_pointer (&v);
+        g_value_unset (&v);
+        break;
+      }
+      if (g_value_get_pointer (&v) == seek_object) {
+        g_value_unset (&v);
+        gtk_combo_box_set_active_iter (obj_combo, &iter);
+        break;
+      }
+      g_value_unset (&v);
+      if (!gtk_tree_model_iter_next (model, &iter)) {
+        gtk_tree_model_get_iter_first (model, &iter);
+        gtk_combo_box_set_active_iter (obj_combo, &iter);
+        gtk_tree_model_get_value (model, &iter, OBJECT_COL_OBJECT, &v);
+        *seek_object = g_value_get_pointer (&v);
+        g_value_unset (&v);
+        break;
+      }
+    }
+  } else
+    *seek_object = NULL;
+}
 
 typedef struct
 {
@@ -1359,7 +1659,9 @@ main (int argc, char **argv)
 {
   GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button;
   GtkWidget *accurate_checkbox, *key_checkbox, *loop_checkbox, *flush_checkbox;
-  GtkWidget *scrub_checkbox;
+  GtkWidget *scrub_checkbox, *format_combo, *format_stream_combo;
+  GtkWidget *hb, *hb_stream;
+  GtkWidget *object_combo, *object_stream_combo;
   GOptionEntry options[] = {
     {"stats", 's', 0, G_OPTION_ARG_NONE, &stats,
         "Show pad stats", NULL},
@@ -1405,6 +1707,8 @@ main (int argc, char **argv)
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   hbox = gtk_hbox_new (FALSE, 0);
   vbox = gtk_vbox_new (FALSE, 0);
+  hb = gtk_hbox_new (FALSE, 0);
+  hb_stream = gtk_hbox_new (FALSE, 0);
   play_button = gtk_button_new_with_label ("play");
   pause_button = gtk_button_new_with_label ("pause");
   stop_button = gtk_button_new_with_label ("stop");
@@ -1414,6 +1718,10 @@ main (int argc, char **argv)
   loop_checkbox = gtk_check_button_new_with_label ("Loop");
   flush_checkbox = gtk_check_button_new_with_label ("Flush");
   scrub_checkbox = gtk_check_button_new_with_label ("Scrub");
+  format_combo = get_format_combo (&format, &seek_object);
+  format_stream_combo = get_format_combo (&format_stream, &seek_object_stream);
+  object_combo = get_object_combo (&format);
+  object_stream_combo = get_object_combo (&format_stream);
 
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (flush_checkbox), TRUE);
 
@@ -1423,17 +1731,31 @@ main (int argc, char **argv)
   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
   gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
 
+  adjustment_stream =
+    GTK_ADJUSTMENT (gtk_adjustment_new (0., 0., 100., 0.1, 1., 1.));
+  hscale_stream = gtk_hscale_new (adjustment_stream);
+  gtk_scale_set_digits (GTK_SCALE (hscale_stream), 2);
+  gtk_range_set_update_policy (GTK_RANGE (hscale_stream), GTK_UPDATE_CONTINUOUS);
+
   gtk_signal_connect (GTK_OBJECT (hscale),
       "button_press_event", G_CALLBACK (start_seek), pipeline);
   gtk_signal_connect (GTK_OBJECT (hscale),
       "button_release_event", G_CALLBACK (stop_seek), pipeline);
   gtk_signal_connect (GTK_OBJECT (hscale),
       "format_value", G_CALLBACK (format_value), pipeline);
+  gtk_signal_connect (GTK_OBJECT (hscale_stream),
+      "button_press_event", G_CALLBACK (start_seek), pipeline);
+  gtk_signal_connect (GTK_OBJECT (hscale_stream),
+      "button_release_event", G_CALLBACK (stop_seek), pipeline);
+  gtk_signal_connect (GTK_OBJECT (hscale_stream),
+      "format_value", G_CALLBACK (format_value_stream), pipeline);
 
   /* do the packing stuff ... */
   gtk_window_set_default_size (GTK_WINDOW (window), 250, 96);
   gtk_container_add (GTK_CONTAINER (window), vbox);
   gtk_container_add (GTK_CONTAINER (vbox), hbox);
+  gtk_container_add (GTK_CONTAINER (vbox), hb);
+  gtk_container_add (GTK_CONTAINER (vbox), hb_stream);
   gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
   gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
   gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
@@ -1442,7 +1764,12 @@ main (int argc, char **argv)
   gtk_box_pack_start (GTK_BOX (hbox), loop_checkbox, FALSE, FALSE, 2);
   gtk_box_pack_start (GTK_BOX (hbox), flush_checkbox, FALSE, FALSE, 2);
   gtk_box_pack_start (GTK_BOX (hbox), scrub_checkbox, FALSE, FALSE, 2);
-  gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
+  gtk_box_pack_start (GTK_BOX (hb), hscale, TRUE, TRUE, 2);
+  gtk_box_pack_start (GTK_BOX (hb), format_combo, FALSE, FALSE, 2);
+  gtk_box_pack_start (GTK_BOX (hb), object_combo, FALSE, FALSE, 2);
+  gtk_box_pack_start (GTK_BOX (hb_stream), hscale_stream, TRUE, TRUE, 2);
+  gtk_box_pack_start (GTK_BOX (hb_stream), format_stream_combo, FALSE, FALSE, 2);
+  gtk_box_pack_start (GTK_BOX (hb_stream), object_stream_combo, FALSE, FALSE, 2);
 
   /* connect things ... */
   g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
@@ -1461,6 +1788,14 @@ main (int argc, char **argv)
       G_CALLBACK (flush_toggle_cb), pipeline);
   g_signal_connect (G_OBJECT (scrub_checkbox), "toggled",
       G_CALLBACK (scrub_toggle_cb), pipeline);
+  g_signal_connect (G_OBJECT (format_combo), "changed",
+      G_CALLBACK (format_changed_cb), object_combo);
+  g_signal_connect (G_OBJECT (format_stream_combo), "changed",
+      G_CALLBACK (format_changed_cb), object_stream_combo);
+  g_signal_connect (G_OBJECT (object_combo), "changed",
+      G_CALLBACK (object_changed_cb), &seek_object);
+  g_signal_connect (G_OBJECT (object_stream_combo), "changed",
+      G_CALLBACK (object_changed_cb), &seek_object_stream);
 
   g_signal_connect (G_OBJECT (window), "destroy", gtk_main_quit, NULL);
 
