childproxy: Implement a new ::get_child_by_name_recurse() API
authorMichael Gruner <michael.gruner@ridgerun.com>
Tue, 18 Oct 2022 16:15:12 +0000 (18:15 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 2 Nov 2022 13:21:09 +0000 (13:21 +0000)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2908>

subprojects/gstreamer/gst/gstchildproxy.c
subprojects/gstreamer/gst/gstchildproxy.h

index 77ef181..f229045 100644 (file)
@@ -55,6 +55,69 @@ enum
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
+/**
+ * gst_child_proxy_get_child_by_name_recurse:
+ * @parent: the parent object to get the child from
+ * @name: the full-path child's name
+ *
+ * Looks up a child element by the given full-path name.
+ *
+ * Similar to gst_child_proxy_get_child_by_name(), this method
+ * searches and returns a child given a name. The difference is that
+ * this method allows a hierarchical path in the form of
+ * child1::child2::child3. In the later example this method would
+ * return a reference to child3, if found. The name should be made of
+ * element names only and should not contain any property names.
+ *
+ * Returns: (transfer full) (nullable): the child object or %NULL if
+ *     not found.
+ *
+ * Since: 1.22
+ */
+GObject *
+gst_child_proxy_get_child_by_name_recurse (GstChildProxy * child_proxy,
+    const gchar * name)
+{
+  gchar **names = NULL, **current = NULL;
+  GObject *obj = NULL, *next = NULL;
+
+  g_return_val_if_fail (child_proxy != NULL, NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  current = names = g_strsplit (name, "::", -1);
+  if (current[0]) {
+    obj = G_OBJECT (g_object_ref (child_proxy));
+  }
+
+  /* walk through the children hierarchy until the requested one is found */
+  while (current[0]) {
+
+    /* Cannot ask for the child of a non-childproxy */
+    if (!GST_IS_CHILD_PROXY (obj)) {
+      gst_object_unref (obj);
+      next = NULL;
+      break;
+    }
+
+    next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (obj),
+        current[0]);
+    gst_object_unref (obj);
+
+    /* The child does not exist */
+    if (!next) {
+      GST_INFO ("Unable to find child %s", current[0]);
+      break;
+    }
+
+    obj = next;
+    current++;
+  }
+
+  g_strfreev (names);
+
+  return next;
+}
+
 static GObject *
 gst_child_proxy_default_get_child_by_name (GstChildProxy * parent,
     const gchar * name)
@@ -194,55 +257,54 @@ gboolean
 gst_child_proxy_lookup (GstChildProxy * object, const gchar * name,
     GObject ** target, GParamSpec ** pspec)
 {
-  GObject *obj;
   gboolean res = FALSE;
-  gchar **names, **current;
+  gchar *children = NULL;
+  const gchar *prop = NULL;
+  GObject *child = NULL;
+  static const gchar *separator = "::";
 
   g_return_val_if_fail (GST_IS_CHILD_PROXY (object), FALSE);
   g_return_val_if_fail (name != NULL, FALSE);
 
-  obj = G_OBJECT (g_object_ref (object));
-
-  current = names = g_strsplit (name, "::", -1);
-  /* find the owner of the property */
-  while (current[1]) {
-    GObject *next;
-
-    if (!GST_IS_CHILD_PROXY (obj)) {
-      GST_INFO
-          ("object %s is not a parent, so you cannot request a child by name %s",
-          (GST_IS_OBJECT (obj) ? GST_OBJECT_NAME (obj) : ""), current[0]);
-      break;
+  /* If the requested name does not include a "::" then it is not a
+     child proxy path, but the property name directly */
+  prop = g_strrstr (name, separator);
+  if (!prop) {
+    child = gst_object_ref (G_OBJECT (object));
+    prop = name;
+  } else {
+    /* Skip "::" */
+    prop += 2;
+
+    /* Extract "child1::child2" from "child1::child2::prop" */
+    children = g_strndup (name, prop - name - 2);
+    GST_INFO ("Looking for property %s in %s", prop, children);
+
+    child = gst_child_proxy_get_child_by_name_recurse (object, children);
+    g_free (children);
+
+    if (!child) {
+      GST_INFO ("Child not found");
+      goto out;
     }
-    next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (obj),
-        current[0]);
-    if (!next) {
-      GST_INFO ("no such object %s", current[0]);
-      break;
-    }
-    gst_object_unref (obj);
-    obj = next;
-    current++;
   }
 
-  /* look for psec */
-  if (current[1] == NULL) {
-    GParamSpec *spec =
-        g_object_class_find_property (G_OBJECT_GET_CLASS (obj), current[0]);
-    if (spec == NULL) {
-      GST_INFO ("no param spec named %s", current[0]);
-    } else {
-      if (pspec)
-        *pspec = spec;
-      if (target) {
-        g_object_ref (obj);
-        *target = obj;
-      }
-      res = TRUE;
+  GParamSpec *spec =
+      g_object_class_find_property (G_OBJECT_GET_CLASS (child), prop);
+  if (spec == NULL) {
+    GST_INFO ("no param spec named %s", prop);
+  } else {
+    if (pspec)
+      *pspec = spec;
+    if (target) {
+      g_object_ref (child);
+      *target = child;
     }
+    res = TRUE;
   }
-  gst_object_unref (obj);
-  g_strfreev (names);
+  gst_object_unref (child);
+
+out:
   return res;
 }
 
index deb8f21..407a4f5 100644 (file)
@@ -119,6 +119,10 @@ GST_API
 GObject * gst_child_proxy_get_child_by_name  (GstChildProxy * parent, const gchar * name);
 
 GST_API
+GObject * gst_child_proxy_get_child_by_name_recurse (GstChildProxy * child_proxy,
+                                                     const gchar *name);
+
+GST_API
 guint     gst_child_proxy_get_children_count (GstChildProxy * parent);
 
 GST_API