[glib/gdbus-merge] GDBusProxy: Remove error in get_cached_property() and add set_cached_property()



commit f909cb5b2713c8cd5f587c7a70e468d29bdcd429
Author: David Zeuthen <davidz redhat com>
Date:   Wed May 12 20:43:40 2010 -0400

    GDBusProxy: Remove error in get_cached_property() and add set_cached_property()
    
    This makes it possible to use the cached properties mechanism even if
    constructing the proxy with the DO_NOT_LOAD_PROPERTIES flag.
    
    This is useful for cases where you obtain the and track object
    properties out-of-band. For example, in udisks, the plan is to have
    something like this
    
     Manager.GetObjects    (out ao paths, out aa{sa{sv}} all_properties);
     Manager.ObjectAdded   (o path, a{sa{sv}} all_properties);
     Manager.ObjectChanged (o path, a{sa{sv}} all_properties);
     Manager.ObjectRemoved (o path, a{sa{sv}} all_properties);
    
    E.g. the first GetObjects() call will return *all* data about *all*
    exported objects. Further, this way a client will only need to listen
    these three signals (three AddMatch) on the Manager object and it will
    never need to do GetAll() etc (e.g. can use DO_NOT_LOAD_PROPERTIES).
    
    (Of course this only works if the client is interested in all
    objects... while this is true for udisks it is generally not true for
    other D-Bus services).
    
    Also use expected_interface to check for programming errors.

 docs/reference/gio/gio-sections.txt      |    3 +-
 gio/gdbusproxy.c                         |  162 +++++++++++++++++++++++-------
 gio/gdbusproxy.h                         |    4 +-
 gio/gio.symbols                          |    1 +
 gio/tests/gdbus-example-proxy-subclass.c |    6 +-
 gio/tests/gdbus-example-watch-proxy.c    |    2 +-
 gio/tests/gdbus-peer.c                   |    3 +-
 gio/tests/gdbus-proxy.c                  |   44 +++++++-
 8 files changed, 174 insertions(+), 51 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 001217e..1085674 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -2490,8 +2490,9 @@ g_dbus_proxy_get_object_path
 g_dbus_proxy_get_interface_name
 g_dbus_proxy_get_default_timeout
 g_dbus_proxy_set_default_timeout
-g_dbus_proxy_get_cached_property_names
 g_dbus_proxy_get_cached_property
+g_dbus_proxy_set_cached_property
+g_dbus_proxy_get_cached_property_names
 g_dbus_proxy_set_interface_info
 g_dbus_proxy_get_interface_info
 g_dbus_proxy_call
diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c
index 9d1d653..c1c97d2 100644
--- a/gio/gdbusproxy.c
+++ b/gio/gdbusproxy.c
@@ -490,66 +490,149 @@ g_dbus_proxy_get_cached_property_names (GDBusProxy  *proxy,
   return names;
 }
 
+static const GDBusPropertyInfo *
+lookup_property_info_or_warn (GDBusProxy  *proxy,
+                              const gchar *property_name)
+{
+  const GDBusPropertyInfo *info;
+
+  if (proxy->priv->expected_interface == NULL)
+    return NULL;
+
+  info = g_dbus_interface_info_lookup_property (proxy->priv->expected_interface, property_name);
+  if (info == NULL)
+    {
+      g_warning ("Trying to lookup property %s which isn't in expected interface %s",
+                 property_name,
+                 proxy->priv->expected_interface->name);
+    }
+
+  return info;
+}
+
 /**
  * g_dbus_proxy_get_cached_property:
  * @proxy: A #GDBusProxy.
  * @property_name: Property name.
- * @error: Return location for error or %NULL.
- *
- * Looks up the value for a property from the cache. This call does no blocking IO.
  *
- * Normally you will not need to modify the returned variant since it is updated automatically
- * in response to <literal>org.freedesktop.DBus.Properties.PropertiesChanged</literal>
- * D-Bus signals (which also causes #GDBusProxy::g-properties-changed to be emitted).
+ * Looks up the value for a property from the cache. This call does no
+ * blocking IO.
  *
- * However, for properties for which said D-Bus signal is not emitted, you
- * can catch other signals and modify the returned variant accordingly (remember to emit
- * #GDBusProxy::g-properties-changed yourself).
+ * If @proxy has an expected interface (see
+ * #GDBusProxy:g-interface-info), then @property_name (for existence)
+ * is checked against it.
  *
- * Returns: A reference to the #GVariant instance that holds the value for @property_name or
- * %NULL if @error is set. Free the reference with g_variant_unref().
+ * Returns: A reference to the #GVariant instance that holds the value
+ * for @property_name or %NULL if the value is not in the cache. The
+ * returned reference must be freed with g_variant_unref().
  *
  * Since: 2.26
  */
 GVariant *
 g_dbus_proxy_get_cached_property (GDBusProxy   *proxy,
-                                  const gchar  *property_name,
-                                  GError      **error)
+                                  const gchar  *property_name)
 {
   GVariant *value;
 
   g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
   g_return_val_if_fail (property_name != NULL, NULL);
 
-  value = NULL;
-
-  if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_FAILED,
-                   _("Properties are not available (proxy created with G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)"));
-      goto out;
-    }
-
   value = g_hash_table_lookup (proxy->priv->properties, property_name);
   if (value == NULL)
     {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_FAILED,
-                   _("No property with name %s"),
-                   property_name);
+      const GDBusPropertyInfo *info;
+      info = lookup_property_info_or_warn (proxy, property_name);
+      /* no difference */
       goto out;
     }
 
   g_variant_ref (value);
 
  out:
-
   return value;
 }
 
+/**
+ * g_dbus_proxy_set_cached_property:
+ * @proxy: A #GDBusProxy
+ * @property_name: Property name.
+ * @value: Value for the property or %NULL to remove it from the cache.
+ *
+ * If @value is not %NULL, sets the cached value for the property with
+ * name @property_name to the value in @value.
+ *
+ * If @value is %NULL, then the cached value is removed from the
+ * property cache.
+ *
+ * If @proxy has an expected interface (see
+ * #GDBusProxy:g-interface-info), then @property_name (for existence)
+ * and @value (for the type) is checked against it.
+ *
+ * If the @value #GVariant is floating, it is consumed. This allows
+ * convenient 'inline' use of g_variant_new(), e.g.
+ * |[
+ *  g_dbus_proxy_set_cached_property (proxy,
+ *                                    "SomeProperty",
+ *                                    g_variant_new ("(si)",
+ *                                                  "A String",
+ *                                                  42));
+ * ]|
+ *
+ * Normally you will not need to use this method since @proxy is
+ * tracking changes using the
+ * <literal>org.freedesktop.DBus.Properties.PropertiesChanged</literal>
+ * D-Bus signal. However, for performance reasons an object may decide
+ * to not use this signal for some properties and instead use a
+ * proprietary out-of-band mechanism to transmit changes.
+ *
+ * As a concrete example, consider an object with a property
+ * <literal>ChatroomParticipants</literal> which is an array of
+ * strings. Instead of transmitting the same (long) array every time
+ * the property changes, it is more efficient to only transmit the
+ * delta using e.g. signals <literal>ChatroomParticipantJoined(String
+ * name)</literal> and <literal>ChatroomParticipantParted(String
+ * name)</literal>.
+ *
+ * Since: 2.26
+ */
+void
+g_dbus_proxy_set_cached_property (GDBusProxy   *proxy,
+                                  const gchar  *property_name,
+                                  GVariant     *value)
+{
+  const GDBusPropertyInfo *info;
+
+  g_return_if_fail (G_IS_DBUS_PROXY (proxy));
+  g_return_if_fail (property_name != NULL);
+
+  if (value != NULL)
+    {
+      info = lookup_property_info_or_warn (proxy, property_name);
+      if (info != NULL)
+        {
+          if (g_strcmp0 (info->signature, g_variant_get_type_string (value)) != 0)
+            {
+              g_warning (_("Trying to set property %s of type %s but according to the expected "
+                           "interface the type is %s"),
+                         property_name,
+                         g_variant_get_type_string (value),
+                         info->signature);
+              goto out;
+            }
+        }
+      g_hash_table_insert (proxy->priv->properties,
+                           g_strdup (property_name),
+                           g_variant_ref_sink (value));
+    }
+  else
+    {
+      g_hash_table_remove (proxy->priv->properties, property_name);
+    }
+
+ out:
+  ;
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
@@ -1306,13 +1389,15 @@ lookup_method_info_or_warn (GDBusProxy  *proxy,
 {
   const GDBusMethodInfo *info;
 
-  if (!proxy->priv->expected_interface)
+  if (proxy->priv->expected_interface == NULL)
     return NULL;
 
   info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, method_name);
-  if (!info)
-    g_warning ("Trying to invoke method %s which isn't in expected interface %s",
-               method_name, proxy->priv->expected_interface->name);
+  if (info == NULL)
+    {
+      g_warning ("Trying to invoke method %s which isn't in expected interface %s",
+                 method_name, proxy->priv->expected_interface->name);
+    }
 
   return info;
 }
@@ -1586,9 +1671,12 @@ g_dbus_proxy_call_sync (GDBusProxy      *proxy,
   if (proxy->priv->expected_interface)
     {
       expected_method_info = g_dbus_interface_info_lookup_method (proxy->priv->expected_interface, target_method_name);
-      if (!expected_method_info)
-        g_warning ("Trying to invoke method %s which isn't in expected interface %s",
-                   target_method_name, target_interface_name);
+      if (expected_method_info == NULL)
+        {
+          g_warning ("Trying to invoke method `%s' which isn't in expected interface `%s'",
+                     target_method_name,
+                     target_interface_name);
+        }
     }
   else
     {
diff --git a/gio/gdbusproxy.h b/gio/gdbusproxy.h
index ee9f62e..fcf3f96 100644
--- a/gio/gdbusproxy.h
+++ b/gio/gdbusproxy.h
@@ -122,8 +122,10 @@ GDBusInterfaceInfo *g_dbus_proxy_get_interface_info     (GDBusProxy          *pr
 void             g_dbus_proxy_set_interface_info        (GDBusProxy           *proxy,
                                                          GDBusInterfaceInfo   *info);
 GVariant        *g_dbus_proxy_get_cached_property       (GDBusProxy          *proxy,
+                                                         const gchar         *property_name);
+void             g_dbus_proxy_set_cached_property       (GDBusProxy          *proxy,
                                                          const gchar         *property_name,
-                                                         GError             **error);
+                                                         GVariant            *value);
 gchar          **g_dbus_proxy_get_cached_property_names (GDBusProxy          *proxy,
                                                          GError             **error);
 void             g_dbus_proxy_call                      (GDBusProxy          *proxy,
diff --git a/gio/gio.symbols b/gio/gio.symbols
index e772748..7f1302e 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1663,6 +1663,7 @@ g_dbus_proxy_new
 g_dbus_proxy_new_finish
 g_dbus_proxy_new_sync
 g_dbus_proxy_get_cached_property
+g_dbus_proxy_set_cached_property
 g_dbus_proxy_get_cached_property_names
 g_dbus_proxy_get_connection
 g_dbus_proxy_get_default_timeout
diff --git a/gio/tests/gdbus-example-proxy-subclass.c b/gio/tests/gdbus-example-proxy-subclass.c
index 6c09909..110cbdb 100644
--- a/gio/tests/gdbus-example-proxy-subclass.c
+++ b/gio/tests/gdbus-example-proxy-subclass.c
@@ -160,7 +160,7 @@ accounts_user_get_user_name (AccountsUser *user)
   GVariant *value;
   const gchar *ret;
   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
-  value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "UserName", NULL);
+  value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "UserName");
   ret = g_variant_get_string (value, NULL);
   g_variant_unref (value);
   return ret;
@@ -172,7 +172,7 @@ accounts_user_get_real_name (AccountsUser *user)
   GVariant *value;
   const gchar *ret;
   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
-  value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "RealName", NULL);
+  value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "RealName");
   ret = g_variant_get_string (value, NULL);
   g_variant_unref (value);
   return ret;
@@ -184,7 +184,7 @@ accounts_user_get_automatic_login (AccountsUser *user)
   GVariant *value;
   gboolean ret;
   g_return_val_if_fail (ACCOUNTS_IS_USER (user), FALSE);
-  value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "AutomaticLogin", NULL);
+  value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "AutomaticLogin");
   ret = g_variant_get_boolean (value);
   g_variant_unref (value);
   return ret;
diff --git a/gio/tests/gdbus-example-watch-proxy.c b/gio/tests/gdbus-example-watch-proxy.c
index db543a8..00768bc 100644
--- a/gio/tests/gdbus-example-watch-proxy.c
+++ b/gio/tests/gdbus-example-watch-proxy.c
@@ -32,7 +32,7 @@ print_properties (GDBusProxy *proxy)
       const gchar *key = property_names[n];
       GVariant *value;
       gchar *value_str;
-      value = g_dbus_proxy_get_cached_property (proxy, key, NULL);
+      value = g_dbus_proxy_get_cached_property (proxy, key);
       value_str = g_variant_print (value, TRUE);
       g_print ("      %s -> %s\n", key, value_str);
       g_variant_unref (value);
diff --git a/gio/tests/gdbus-peer.c b/gio/tests/gdbus-peer.c
index e96666a..8571e73 100644
--- a/gio/tests/gdbus-peer.c
+++ b/gio/tests/gdbus-peer.c
@@ -531,8 +531,7 @@ test_peer (void)
   g_assert_no_error (error);
   g_assert (proxy != NULL);
   error = NULL;
-  value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty", &error);
-  g_assert_no_error (error);
+  value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
   g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
 
   /* try invoking a method */
diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c
index 5df6ad5..a0fabd8 100644
--- a/gio/tests/gdbus-proxy.c
+++ b/gio/tests/gdbus-proxy.c
@@ -150,13 +150,11 @@ test_properties (GDBusConnection *connection,
    *
    * No need to test all properties - GVariant has already been tested
    */
-  variant = g_dbus_proxy_get_cached_property (proxy, "y", &error);
-  g_assert_no_error (error);
+  variant = g_dbus_proxy_get_cached_property (proxy, "y");
   g_assert (variant != NULL);
   g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
   g_variant_unref (variant);
-  variant = g_dbus_proxy_get_cached_property (proxy, "o", &error);
-  g_assert_no_error (error);
+  variant = g_dbus_proxy_get_cached_property (proxy, "o");
   g_assert (variant != NULL);
   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
   g_variant_unref (variant);
@@ -180,11 +178,20 @@ test_properties (GDBusConnection *connection,
   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
   g_variant_unref (result);
   _g_assert_signal_received (proxy, "g-properties-changed");
-  variant = g_dbus_proxy_get_cached_property (proxy, "y", &error);
-  g_assert_no_error (error);
+  variant = g_dbus_proxy_get_cached_property (proxy, "y");
   g_assert (variant != NULL);
   g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
   g_variant_unref (variant);
+
+  g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (142));
+  variant = g_dbus_proxy_get_cached_property (proxy, "y");
+  g_assert (variant != NULL);
+  g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
+  g_variant_unref (variant);
+
+  g_dbus_proxy_set_cached_property (proxy, "y", NULL);
+  variant = g_dbus_proxy_get_cached_property (proxy, "y");
+  g_assert (variant == NULL);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -352,6 +359,7 @@ static const gchar *frob_dbus_interface_xml =
   "    <method name='Sleep'>"
   "      <arg type='i' name='timeout' direction='in'/>"
   "    </method>"
+  "    <property name='y' type='y' access='readwrite'/>"
   "  </interface>"
   "</node>";
 static GDBusInterfaceInfo *frob_dbus_interface_info;
@@ -367,6 +375,12 @@ on_proxy_appeared (GDBusConnection *connection,
   test_properties (connection, name, name_owner, proxy);
   test_signals (connection, name, name_owner, proxy);
 
+  /* This is obviously wrong but expected interface is not set so we don't fail... */
+  g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
+  g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
+  g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
+  g_dbus_proxy_set_cached_property (proxy, "does-not-exist", NULL);
+
   /* Now repeat the method tests, with an expected interface set */
   g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info);
   test_methods (connection, name, name_owner, proxy);
@@ -376,6 +390,24 @@ on_proxy_appeared (GDBusConnection *connection,
    */
   test_bogus_method_return (connection, name, name_owner, proxy);
 
+  /* Also check that we complain if setting a cached property of the wrong type */
+  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
+    {
+      g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
+    }
+  g_test_trap_assert_stderr ("*Trying to set property y of type s but according to the expected interface the type is y*");
+  g_test_trap_assert_failed();
+
+  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
+    {
+      g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
+    }
+  g_test_trap_assert_stderr ("*Trying to lookup property does-not-exist which isn't in expected interface com.example.Frob*");
+  g_test_trap_assert_failed();
+
+  /* this should work, however (since the type is correct) */
+  g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
+
   g_main_loop_quit (loop);
 }
 



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