[glib] GDBusProxy: Add G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES flag



commit a067df5d720096a62736d26c9e971363c0843d91
Author: David Zeuthen <davidz redhat com>
Date:   Wed Feb 8 12:46:04 2012 -0500

    GDBusProxy: Add G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES flag
    
    This is useful when using certain D-Bus services where the
    PropertiesChanged signal does not include the property value such as
    e.g. various systemd mechanisms, see e.g.
    
     https://bugs.freedesktop.org/show_bug.cgi?id=37632
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 gio/gdbusproxy.c              |  108 ++++++++++++++++++++++++++++++++++++++---
 gio/gioenums.h                |    4 +-
 gio/tests/gdbus-proxy.c       |   47 +++++++++++++++++-
 gio/tests/gdbus-testserver.py |    6 +-
 4 files changed, 153 insertions(+), 12 deletions(-)
---
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c
index 52b222b..ee9be82 100644
--- a/gio/gdbusproxy.c
+++ b/gio/gdbusproxy.c
@@ -587,6 +587,10 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass)
    * that both @changed_properties and @invalidated_properties are
    * guaranteed to never be %NULL (either may be empty though).
    *
+   * If the proxy has the flag
+   * %G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES set, then
+   * @invalidated_properties will always be empty.
+   *
    * This signal corresponds to the
    * <literal>PropertiesChanged</literal> D-Bus signal on the
    * <literal>org.freedesktop.DBus.Properties</literal> interface.
@@ -971,6 +975,63 @@ insert_property_checked (GDBusProxy  *proxy,
   g_free (property_name);
 }
 
+typedef struct
+{
+  GDBusProxy *proxy;
+  gchar *prop_name;
+} InvalidatedPropGetData;
+
+static void
+invalidated_property_get_cb (GDBusConnection *connection,
+                             GAsyncResult    *res,
+                             gpointer         user_data)
+{
+  InvalidatedPropGetData *data = user_data;
+  const gchar *invalidated_properties[] = {NULL};
+  GVariantBuilder builder;
+  GVariant *value = NULL;
+  GVariant *unpacked_value = NULL;
+
+  /* errors are fine, the other end could have disconnected */
+  value = g_dbus_connection_call_finish (connection, res, NULL);
+  if (value == NULL)
+    {
+      goto out;
+    }
+
+  if (!g_variant_is_of_type (value, G_VARIANT_TYPE ("(v)")))
+    {
+      g_warning ("Expected type `(v)' for Get() reply, got `%s'", g_variant_get_type_string (value));
+      goto out;
+    }
+
+  g_variant_get (value, "(v)", &unpacked_value);
+
+  /* synthesize the a{sv} in the PropertiesChanged signal */
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+  g_variant_builder_add (&builder, "{sv}", data->prop_name, unpacked_value);
+
+  G_LOCK (properties_lock);
+  insert_property_checked (data->proxy,
+                           data->prop_name,  /* adopts string */
+                           unpacked_value);  /* adopts value */
+  data->prop_name = NULL;
+  G_UNLOCK (properties_lock);
+
+  g_signal_emit (data->proxy,
+                 signals[PROPERTIES_CHANGED_SIGNAL], 0,
+                 g_variant_builder_end (&builder), /* consumed */
+                 invalidated_properties);
+
+
+ out:
+  if (value != NULL)
+    g_variant_unref (value);
+  g_object_unref (data->proxy);
+  g_free (data->prop_name);
+  g_slice_free (InvalidatedPropGetData, data);
+}
+
 static void
 on_properties_changed (GDBusConnection *connection,
                        const gchar     *sender_name,
@@ -981,6 +1042,7 @@ on_properties_changed (GDBusConnection *connection,
                        gpointer         user_data)
 {
   SignalSubscriptionData *data = user_data;
+  gboolean emit_g_signal = FALSE;
   GDBusProxy *proxy;
   const gchar *interface_name_for_signal;
   GVariant *changed_properties;
@@ -1043,20 +1105,52 @@ on_properties_changed (GDBusConnection *connection,
       insert_property_checked (proxy,
 			       key, /* adopts string */
 			       value); /* adopts value */
+      emit_g_signal = TRUE;
     }
 
-  for (n = 0; invalidated_properties[n] != NULL; n++)
+  if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES)
+    {
+      if (proxy->priv->name_owner != NULL)
+        {
+          for (n = 0; invalidated_properties[n] != NULL; n++)
+            {
+              InvalidatedPropGetData *data;
+              data = g_slice_new0 (InvalidatedPropGetData);
+              data->proxy = g_object_ref (proxy);
+              data->prop_name = g_strdup (invalidated_properties[n]);
+              g_dbus_connection_call (proxy->priv->connection,
+                                      proxy->priv->name_owner,
+                                      proxy->priv->object_path,
+                                      "org.freedesktop.DBus.Properties",
+                                      "Get",
+                                      g_variant_new ("(ss)", proxy->priv->interface_name, data->prop_name),
+                                      G_VARIANT_TYPE ("(v)"),
+                                      G_DBUS_CALL_FLAGS_NONE,
+                                      -1,           /* timeout */
+                                      NULL,         /* GCancellable */
+                                      (GAsyncReadyCallback) invalidated_property_get_cb,
+                                      data);
+            }
+        }
+    }
+  else
     {
-      g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
+      emit_g_signal = TRUE;
+      for (n = 0; invalidated_properties[n] != NULL; n++)
+        {
+          g_hash_table_remove (proxy->priv->properties, invalidated_properties[n]);
+        }
     }
 
   G_UNLOCK (properties_lock);
 
-  /* emit signal */
-  g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
-                 0,
-                 changed_properties,
-                 invalidated_properties);
+  if (emit_g_signal)
+    {
+      g_signal_emit (proxy, signals[PROPERTIES_CHANGED_SIGNAL],
+                     0,
+                     changed_properties,
+                     invalidated_properties);
+    }
 
  out:
   if (changed_properties != NULL)
diff --git a/gio/gioenums.h b/gio/gioenums.h
index d1fadf1..b2b7861 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -880,6 +880,7 @@ typedef enum
  * @G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START: If not set and the proxy if for a well-known name,
  * then request the bus to launch an owner for the name if no-one owns the name. This flag can
  * only be used in proxies for well-known names.
+ * @G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES: If set, the property value for any <emphasis>invalidated property</emphasis> will be (asynchronously) retrieved upon receiving the <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties";>PropertiesChanged</ulink> D-Bus signal and the property will not cause emission of the #GDBusProxy::g-properties-changed signal. When the value is received the #GDBusProxy::g-properties-changed signal is emitted for the property along with the retrieved value. Since 2.32.
  *
  * Flags used when constructing an instance of a #GDBusProxy derived class.
  *
@@ -890,7 +891,8 @@ typedef enum
   G_DBUS_PROXY_FLAGS_NONE = 0,
   G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0),
   G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1),
-  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2)
+  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2),
+  G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES = (1<<3)
 } GDBusProxyFlags;
 
 /**
diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c
index 0b2905c..00e6274 100644
--- a/gio/tests/gdbus-proxy.c
+++ b/gio/tests/gdbus-proxy.c
@@ -280,7 +280,7 @@ test_properties (GDBusProxy *proxy)
    */
   result = g_dbus_proxy_call_sync (proxy,
                                    "FrobInvalidateProperty",
-                                   NULL,
+                                   g_variant_new ("(s)", "OMGInvalidated"),
                                    G_DBUS_CALL_FLAGS_NONE,
                                    -1,
                                    NULL,
@@ -294,6 +294,51 @@ test_properties (GDBusProxy *proxy)
   /* ... and now we finally, check that the cached value has been invalidated */
   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
   g_assert (variant == NULL);
+
+  /* Now test that G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES works - we need a new proxy for that */
+  gchar *name_owner;
+  GDBusProxy *proxy2;
+  error = NULL;
+  proxy2 = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy),
+                                  G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
+                                  NULL,                      /* GDBusInterfaceInfo */
+                                  "com.example.TestService", /* name */
+                                  "/com/example/TestObject", /* object path */
+                                  "com.example.Frob",        /* interface */
+                                  NULL, /* GCancellable */
+                                  &error);
+  g_assert_no_error (error);
+
+  name_owner = g_dbus_proxy_get_name_owner (proxy2);
+  g_assert (name_owner != NULL);
+  g_free (name_owner);
+
+  variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated");
+  g_assert (variant != NULL);
+  g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated"); /* from previous test */
+  g_variant_unref (variant);
+
+  result = g_dbus_proxy_call_sync (proxy2,
+                                   "FrobInvalidateProperty",
+                                   g_variant_new ("(s)", "OMGInvalidated2"),
+                                   G_DBUS_CALL_FLAGS_NONE,
+                                   -1,
+                                   NULL,
+                                   &error);
+  g_assert_no_error (error);
+  g_assert (result != NULL);
+  g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
+  g_variant_unref (result);
+
+  /* this time we should get the ::g-properties-changed _with_ the value */
+  _g_assert_signal_received (proxy2, "g-properties-changed");
+
+  variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated");
+  g_assert (variant != NULL);
+  g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated2");
+  g_variant_unref (variant);
+
+  g_object_unref (proxy2);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/gio/tests/gdbus-testserver.py b/gio/tests/gdbus-testserver.py
index 6b2b64b..645a7e4 100755
--- a/gio/tests/gdbus-testserver.py
+++ b/gio/tests/gdbus-testserver.py
@@ -193,9 +193,9 @@ class TestService(dbus.service.Object):
     # ----------------------------------------------------------------------------------------------------
 
     @dbus.service.method("com.example.Frob",
-                          in_signature='', out_signature='')
-    def FrobInvalidateProperty(self):
-        self.frob_props["PropertyThatWillBeInvalidated"] = "OMGInvalidated"
+                          in_signature='s', out_signature='')
+    def FrobInvalidateProperty(self, new_value):
+        self.frob_props["PropertyThatWillBeInvalidated"] = new_value
         message = dbus.lowlevel.SignalMessage("/com/example/TestObject",
                                               "org.freedesktop.DBus.Properties",
                                               "PropertiesChanged")



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