? gst/.gstmessage.c.swp
? gst/.gstmessage.h.swp
? tests/check/gst/.gstbin.c.swp
? docs/gst/.gstreamer-sections.txt.swp
Index: gst/gstbin.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.c,v
retrieving revision 1.374
diff -u -r1.374 gstbin.c
--- gst/gstbin.c	22 Nov 2007 15:59:00 -0000	1.374
+++ gst/gstbin.c	18 Jan 2008 10:15:49 -0000
@@ -199,6 +199,7 @@
 struct _GstBinPrivate
 {
   gboolean asynchandling;
+  guint32 structure_cookie;
 };
 
 typedef struct
@@ -922,6 +923,7 @@
   bin->children = g_list_prepend (bin->children, element);
   bin->numchildren++;
   bin->children_cookie++;
+  bin->priv->structure_cookie++;
 
   /* distribute the bus */
   gst_element_set_bus (element, bin->child_bus);
@@ -1131,6 +1133,7 @@
    * so that others can detect a change in the children list. */
   bin->numchildren--;
   bin->children_cookie++;
+  bin->priv->structure_cookie++;
 
   if (is_sink && !othersink) {
     /* we're not a sink anymore */
@@ -1820,7 +1823,7 @@
       gst_iterator_new (sizeof (GstBinSortIterator),
       GST_TYPE_ELEMENT,
       GST_OBJECT_GET_LOCK (bin),
-      &bin->children_cookie,
+      &bin->priv->structure_cookie,
       (GstIteratorNextFunction) gst_bin_sort_iterator_next,
       (GstIteratorItemFunction) NULL,
       (GstIteratorResyncFunction) gst_bin_sort_iterator_resync,
@@ -2915,6 +2918,14 @@
         break;
       }
     }
+    case GST_MESSAGE_STRUCTURE_CHANGE:
+    {
+      GST_OBJECT_LOCK (bin);
+      bin->priv->structure_cookie++;
+      GST_OBJECT_UNLOCK (bin);
+      gst_message_unref (message);
+      break;
+    }
     default:
       goto forward;
   }
Index: gst/gstmessage.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstmessage.c,v
retrieving revision 1.62
diff -u -r1.62 gstmessage.c
--- gst/gstmessage.c	1 Nov 2007 21:50:05 -0000	1.62
+++ gst/gstmessage.c	18 Jan 2008 10:15:49 -0000
@@ -593,6 +593,33 @@
 }
 
 /**
+ * gst_message_new_structure_change:
+ * @src: The object originating the message.
+ * @type: The change type.
+ *
+ * Create a new structure change message. This message is posted when the
+ * structure of a pipeline changes, for example when pads are linked or
+ * unlinked.
+ *
+ * Returns: The new structure change message.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.17
+ */
+GstMessage *
+gst_message_new_structure_change (GstObject * src, GstStructureChangeType type)
+{
+  GstMessage *message;
+
+  message = gst_message_new_custom (GST_MESSAGE_STRUCTURE_CHANGE, src,
+      gst_structure_new ("GstMessageStructureChange",
+          "type", GST_TYPE_STRUCTURE_CHANGE_TYPE, type, NULL));
+
+  return message;
+}
+
+/**
  * gst_message_new_segment_start:
  * @src: The object originating the message.
  * @format: The format of the position being played
@@ -967,6 +994,28 @@
 }
 
 /**
+ * gst_message_parse_structure_change:
+ * @message: A valid #GstMessage of type GST_MESSAGE_STRUCTURE_CHANGE.
+ * @type: A pointer to hold the change type
+ *
+ * Extracts the change type from the GstMessage.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.17
+ */
+void
+gst_message_parse_structure_change (GstMessage * message, GstStructureChangeType * type)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STRUCTURE_CHANGE);
+  g_return_if_fail (type != NULL);
+  
+  g_return_if_fail (gst_structure_get_enum (message->structure,
+      "type", GST_TYPE_STRUCTURE_CHANGE_TYPE, (gint *) type));
+}
+
+/**
  * gst_message_parse_error:
  * @message: A valid #GstMessage of type GST_MESSAGE_ERROR.
  * @gerror: Location for the GError
Index: gst/gstmessage.h
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstmessage.h,v
retrieving revision 1.50
diff -u -r1.50 gstmessage.h
--- gst/gstmessage.h	2 Nov 2007 18:35:37 -0000	1.50
+++ gst/gstmessage.h	18 Jan 2008 10:15:49 -0000
@@ -58,8 +58,8 @@
  *                          unusable. The pipeline will select a new clock on
  *                          the next PLAYING state change.
  * @GST_MESSAGE_NEW_CLOCK: a new clock was selected in the pipeline.
- * @GST_MESSAGE_STRUCTURE_CHANGE: the structure of the pipeline changed. Not
- * implemented yet.
+ * @GST_MESSAGE_STRUCTURE_CHANGE: the structure of the pipeline changed. This
+ * message is used internally and never forwarded to the application.
  * @GST_MESSAGE_STREAM_STATUS: status about a stream, emitted when it starts,
  *                             stops, errors, etc.. Not implemented yet.
  * @GST_MESSAGE_APPLICATION: message posted by the application, possibly
@@ -180,6 +180,20 @@
 #define GST_MESSAGE_SRC(message)	(GST_MESSAGE(message)->src)
 
 /**
+ * GstStructureChangeType:
+ * @GST_STRUCTURE_CHANGE_TYPE_PAD_LINKED: Pad was linked.
+ * @GST_STRUCTURE_CHANGE_TYPE_PAD_UNLINKED: Pad was unlinked.
+ *
+ * The type of a #GstMessageStructureChange.
+ *
+ * Since: 0.10.17
+ */
+typedef enum {
+	GST_STRUCTURE_CHANGE_TYPE_PAD_LINKED = 0,
+	GST_STRUCTURE_CHANGE_TYPE_PAD_UNLINKED = 1
+} GstStructureChangeType;
+
+/**
  * GstMessage:
  * @mini_object: the parent structure
  * @type: the #GstMessageType of the message
@@ -290,6 +304,7 @@
 GstMessage *	gst_message_new_async_start	(GstObject * src, gboolean new_base_time);
 GstMessage *	gst_message_new_async_done	(GstObject * src);
 GstMessage *	gst_message_new_latency         (GstObject * src);
+GstMessage *	gst_message_new_structure_change (GstObject * src, GstStructureChangeType type);
 GstMessage *	gst_message_new_custom		(GstMessageType type,
 						 GstObject    * src,
 						 GstStructure * structure);
@@ -308,6 +323,7 @@
 void		gst_message_parse_segment_done	(GstMessage *message, GstFormat *format, gint64 *position);
 void		gst_message_parse_duration	(GstMessage *message, GstFormat *format, gint64 *duration);
 void		gst_message_parse_async_start	(GstMessage *message, gboolean *new_base_time);
+void		gst_message_parse_structure_change	(GstMessage *message, GstStructureChangeType *type);
 
 const GstStructure *  gst_message_get_structure	(GstMessage *message);
 
Index: gst/gstpad.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstpad.c,v
retrieving revision 1.563
diff -u -r1.563 gstpad.c
--- gst/gstpad.c	4 Jan 2008 18:39:15 -0000	1.563
+++ gst/gstpad.c	18 Jan 2008 10:15:50 -0000
@@ -1540,6 +1540,8 @@
 gboolean
 gst_pad_unlink (GstPad * srcpad, GstPad * sinkpad)
 {
+  GstElement *parent;
+
   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
 
@@ -1570,6 +1572,14 @@
   /* first clear peers */
   GST_PAD_PEER (srcpad) = NULL;
   GST_PAD_PEER (sinkpad) = NULL;
+  
+  parent = GST_PAD_PARENT (srcpad);
+  if (parent && GST_IS_ELEMENT (parent))
+    /* ref the parent so it doesn't go away if it's unreffed before we post
+     * the message */
+    gst_object_ref (parent);
+  else
+    parent = NULL;
 
   GST_OBJECT_UNLOCK (sinkpad);
   GST_OBJECT_UNLOCK (srcpad);
@@ -1578,6 +1588,13 @@
    * that they've been unlinked */
   g_signal_emit (G_OBJECT (srcpad), gst_pad_signals[PAD_UNLINKED], 0, sinkpad);
   g_signal_emit (G_OBJECT (sinkpad), gst_pad_signals[PAD_UNLINKED], 0, srcpad);
+  
+  if (parent) {
+    gst_element_post_message (parent,
+        gst_message_new_structure_change (GST_OBJECT (srcpad),
+            GST_STRUCTURE_CHANGE_TYPE_PAD_UNLINKED));
+    gst_object_unref (parent);
+  }
 
   GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "unlinked %s:%s and %s:%s",
       GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
@@ -1894,6 +1911,14 @@
   GST_OBJECT_LOCK (sinkpad);
 
   if (result == GST_PAD_LINK_OK) {
+    GstElement *parent = GST_PAD_PARENT (srcpad);
+    if (parent && GST_IS_ELEMENT (parent))
+      /* ref the parent so it doesn't go away if it's unreffed before we post
+       * the message */
+      gst_object_ref (parent);
+    else
+      parent = NULL;
+
     GST_OBJECT_UNLOCK (sinkpad);
     GST_OBJECT_UNLOCK (srcpad);
 
@@ -1902,6 +1927,13 @@
     g_signal_emit (G_OBJECT (srcpad), gst_pad_signals[PAD_LINKED], 0, sinkpad);
     g_signal_emit (G_OBJECT (sinkpad), gst_pad_signals[PAD_LINKED], 0, srcpad);
 
+    if (parent) {
+      gst_element_post_message (parent,
+          gst_message_new_structure_change (GST_OBJECT (srcpad),
+              GST_STRUCTURE_CHANGE_TYPE_PAD_LINKED));
+      gst_object_unref (parent);
+    }
+
     GST_CAT_INFO (GST_CAT_PADS, "linked %s:%s and %s:%s, successful",
         GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
   } else {
Index: tests/check/gst/gstbin.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/tests/check/gst/gstbin.c,v
retrieving revision 1.57
diff -u -r1.57 gstbin.c
--- tests/check/gst/gstbin.c	15 Dec 2007 14:42:25 -0000	1.57
+++ tests/check/gst/gstbin.c	18 Jan 2008 10:15:50 -0000
@@ -891,6 +891,81 @@
 
 GST_END_TEST;
 
+static void
+test_link_structure_change_state_changed_sync_cb (GstBus *bus,
+    GstMessage *message, gpointer data)
+{
+  GstPipeline *pipeline = GST_PIPELINE (data);
+  GstElement *src, *identity, *sink;
+  GstState old, snew, pending; 
+  
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+  fail_unless (sink != NULL, "Could not get sink");
+
+  gst_message_parse_state_changed (message, &old, &snew, &pending);
+  if (message->src != GST_OBJECT (sink) || snew != GST_STATE_READY) {
+    gst_object_unref (sink);
+    return;
+  }
+  
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+  fail_unless (src != NULL, "Could not get src");
+  
+  identity = gst_bin_get_by_name (GST_BIN (pipeline), "identity");
+  fail_unless (identity != NULL, "Could not get identity");
+
+  /* link src to identity, the pipeline should detect the new link and
+   * resync the state change */
+  fail_unless (gst_element_link (src, identity) == TRUE);
+
+  gst_object_unref (src);
+  gst_object_unref (identity);
+  gst_object_unref (sink);
+}
+
+GST_START_TEST (test_link_structure_change)
+{
+  GstElement *src, *identity, *sink, *pipeline;
+  GstBus *bus;
+  GstState state;
+
+  pipeline = gst_pipeline_new (NULL);
+  fail_unless (pipeline != NULL, "Could not create pipeline");
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  fail_unless (bus != NULL, "Could not get bus");
+
+  /* use the sync signal handler to link elements while the pipeline is still
+   * doing the state change */
+  gst_bus_set_sync_handler (bus, gst_bus_sync_signal_handler, pipeline);
+  g_object_connect (bus, "signal::sync-message::state-changed",
+      G_CALLBACK (test_link_structure_change_state_changed_sync_cb), pipeline, NULL);
+
+  src = gst_element_factory_make ("fakesrc", "src");
+  fail_if (src == NULL, "Could not create fakesrc");
+
+  identity = gst_element_factory_make ("identity", "identity");
+  fail_if (identity == NULL, "Could not create identity");
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  fail_if (sink == NULL, "Could not create fakesink1");
+
+  gst_bin_add_many (GST_BIN (pipeline), src, identity, sink, NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_READY);
+  gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+
+  /* the state change will be done on src only if the pipeline correctly resyncs
+   * after that filesrc has been linked to identity */
+  gst_element_get_state (src, &state, NULL, 0);
+  fail_unless_equals_int (state, GST_STATE_READY);
+
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 Suite *
 gst_bin_suite (void)
 {
@@ -911,6 +986,7 @@
   tcase_add_test (tc_chain, test_add_linked);
   tcase_add_test (tc_chain, test_add_self);
   tcase_add_test (tc_chain, test_iterate_sorted);
+  tcase_add_test (tc_chain, test_link_structure_change);
 
   return s;
 }
Index: docs/gst/gstreamer-sections.txt
===================================================================
RCS file: /cvs/gstreamer/gstreamer/docs/gst/gstreamer-sections.txt,v
retrieving revision 1.321
diff -u -r1.321 gstreamer-sections.txt
--- docs/gst/gstreamer-sections.txt	9 Jan 2008 18:23:36 -0000	1.321
+++ docs/gst/gstreamer-sections.txt	18 Jan 2008 10:15:50 -0000
@@ -1006,6 +1006,7 @@
 <TITLE>GstMessage</TITLE>
 GstMessage
 GstMessageType
+GstStructureChangeType
 GST_MESSAGE_SRC
 GST_MESSAGE_TIMESTAMP
 GST_MESSAGE_TYPE
@@ -1036,6 +1037,7 @@
 gst_message_new_async_start
 gst_message_new_async_done
 gst_message_new_latency
+gst_message_new_structure_change
 gst_message_parse_clock_lost
 gst_message_parse_clock_provide
 gst_message_parse_error
@@ -1049,6 +1051,7 @@
 gst_message_parse_warning
 gst_message_parse_duration
 gst_message_parse_async_start
+gst_message_parse_structure_change
 gst_message_ref
 gst_message_unref
 
@@ -1062,9 +1065,11 @@
 GST_IS_MESSAGE_CLASS
 GST_MESSAGE_GET_CLASS
 GST_TYPE_MESSAGE_TYPE
+GST_TYPE_STRUCTURE_CHANGE_TYPE
 <SUBSECTION Private>
 gst_message_get_type
 gst_message_type_get_type
+gst_structure_change_type_get_type
 GST_MESSAGE_COND
 GST_MESSAGE_GET_LOCK
 GST_MESSAGE_LOCK
