libtelepathy/src/tp-props-iface.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* tp-props-iface.c
       
     2  *
       
     3  * Copyright (C) 2005 Collabora Ltd.
       
     4  * 
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2.1 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General Public
       
    17  * License along with this library; if not, write to the Free Software
       
    18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
       
    19  *
       
    20  */
       
    21 
       
    22 #include <dbus/dbus-glib.h>
       
    23 #include <string.h>
       
    24 #include "tp-interfaces.h"
       
    25 #include "tp-ifaces-signals-marshal.h"
       
    26 #include "tp-props-iface-gen.h"
       
    27 #include "tp-props-iface.h"
       
    28 
       
    29 #ifdef EMULATOR
       
    30 #include "libtelepathy_wsd_solution.h"
       
    31 #endif
       
    32 
       
    33 
       
    34 #define TP_TYPE_PROPERTY_DESCRIPTION (dbus_g_type_get_struct ("GValueArray", \
       
    35       G_TYPE_UINT, \
       
    36       G_TYPE_STRING, \
       
    37       G_TYPE_STRING, \
       
    38       G_TYPE_UINT, \
       
    39       G_TYPE_INVALID))
       
    40 
       
    41 #define TP_TYPE_PROPERTY_CHANGE (dbus_g_type_get_struct ("GValueArray", \
       
    42       G_TYPE_UINT, \
       
    43       G_TYPE_VALUE, \
       
    44       G_TYPE_INVALID))
       
    45 
       
    46 #define TP_TYPE_PROPERTY_FLAGS_CHANGE (dbus_g_type_get_struct ("GValueArray", \
       
    47       G_TYPE_UINT, \
       
    48       G_TYPE_UINT, \
       
    49       G_TYPE_INVALID))
       
    50 
       
    51 
       
    52 
       
    53 
       
    54 /*signal enum*/
       
    55 enum
       
    56 {
       
    57   PROPERTIES_READY,
       
    58   PROPERTY_CHANGED,
       
    59   LAST_SIGNAL 
       
    60 #ifdef EMULATOR  
       
    61   = LAST_SIGNAL_TP_PROPS_IFACE
       
    62 #endif
       
    63   
       
    64 };
       
    65 
       
    66 #ifndef EMULATOR
       
    67 	static guint signals[LAST_SIGNAL] = {0};
       
    68 #endif
       
    69 
       
    70 /* looking up properties is linear time on the grounds that number of properties
       
    71  * will always be small, so this will be more cache-friendly
       
    72  */
       
    73 typedef struct _PropertyMapping PropertyMapping;
       
    74 struct _PropertyMapping
       
    75 {
       
    76   guint user_id;
       
    77   guint32 server_id;
       
    78   gchar *name;
       
    79   GValue *value;
       
    80   guint32 flags;
       
    81 };
       
    82 
       
    83 typedef struct _TpPropsPrivate TpPropsPrivate;
       
    84 
       
    85 struct _TpPropsPrivate
       
    86 {
       
    87   gboolean properties_ready;
       
    88 
       
    89   int mappings_len;
       
    90   PropertyMapping *mappings;
       
    91 };
       
    92 
       
    93 #ifndef EMULATOR
       
    94 	static GObjectClass *parent_class = NULL;
       
    95 #endif
       
    96 
       
    97 
       
    98 #ifdef EMULATOR
       
    99 	
       
   100 	GET_STATIC_ARRAY_FROM_TLS(signals,tp_props_iface,guint)
       
   101 	#define signals (GET_WSD_VAR_NAME(signals,tp_props_iface, s)())	
       
   102 	
       
   103 	GET_STATIC_VAR_FROM_TLS(parent_class,tp_props_iface,GObjectClass *)
       
   104 	#define parent_class (*GET_WSD_VAR_NAME(parent_class,tp_props_iface,s)())
       
   105 	
       
   106 	GET_STATIC_VAR_FROM_TLS(type1,tp_props_iface,GType)
       
   107 	#define type1 (*GET_WSD_VAR_NAME(type1,tp_props_iface,s)())
       
   108 	
       
   109 	GET_STATIC_VAR_FROM_TLS(ret,tp_props_iface,GQuark)
       
   110 	#define ret (*GET_WSD_VAR_NAME(ret,tp_props_iface,s)())
       
   111 	
       
   112 #endif
       
   113 	
       
   114 
       
   115 #define PRIV(o) ((TpPropsPrivate*)(o->priv))
       
   116 
       
   117 static void properties_listed_cb (DBusGProxy *proxy, GPtrArray *properties, GError *error, gpointer user_data);
       
   118 
       
   119 static void tp_props_iface_init(GTypeInstance *instance, gpointer g_class)
       
   120 {
       
   121   TpPropsIface *self = TELEPATHY_PROPS_IFACE(instance);
       
   122 
       
   123   self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
       
   124                  TELEPATHY_PROPS_IFACE_TYPE, TpPropsPrivate);
       
   125 
       
   126 }
       
   127 
       
   128 static GObject *
       
   129 tp_props_iface_constructor (GType type, guint n_props,
       
   130                              GObjectConstructParam *props)
       
   131 {
       
   132   GObject *obj;
       
   133 
       
   134   obj = G_OBJECT_CLASS (parent_class)->
       
   135            constructor (type, n_props, props);
       
   136 
       
   137   dbus_g_proxy_add_signal(DBUS_G_PROXY(obj), "PropertiesChanged",
       
   138       dbus_g_type_get_collection ("GPtrArray", TP_TYPE_PROPERTY_CHANGE),
       
   139                                   G_TYPE_INVALID);
       
   140   dbus_g_proxy_add_signal(DBUS_G_PROXY(obj), "PropertyFlagsChanged",
       
   141       dbus_g_type_get_collection ("GPtrArray", TP_TYPE_PROPERTY_FLAGS_CHANGE),
       
   142                                   G_TYPE_INVALID);
       
   143 
       
   144   return obj;
       
   145 }
       
   146 
       
   147 static void tp_props_iface_dispose(GObject *obj)
       
   148 {
       
   149 
       
   150   /* Call parent class dispose method */
       
   151   if (G_OBJECT_CLASS(parent_class)->dispose)
       
   152   {
       
   153     G_OBJECT_CLASS(parent_class)->dispose(obj);
       
   154   }
       
   155 
       
   156 }
       
   157 
       
   158 
       
   159 static void tp_props_iface_finalize(GObject *obj)
       
   160 {
       
   161   TpPropsIface *self = TELEPATHY_PROPS_IFACE(obj);
       
   162   int i;
       
   163   for (i=0; i < PRIV(self)->mappings_len; i++)
       
   164     {
       
   165       if (PRIV(self)->mappings[i].value)
       
   166         {
       
   167           g_value_unset (PRIV(self)->mappings[i].value);
       
   168           g_free (PRIV(self)->mappings[i].value);
       
   169         }
       
   170       if (PRIV(self)->mappings[i].name)
       
   171         g_free (PRIV(self)->mappings[i].name);
       
   172     }
       
   173   
       
   174   g_free (PRIV(self)->mappings);
       
   175 
       
   176   if (G_OBJECT_CLASS(parent_class)->finalize)
       
   177     {
       
   178       G_OBJECT_CLASS(parent_class)->finalize(obj);
       
   179     }
       
   180 }
       
   181 
       
   182 
       
   183 static void tp_props_iface_class_init(TpPropsIfaceClass *klass)
       
   184 {
       
   185   GObjectClass *obj = G_OBJECT_CLASS(klass);
       
   186   parent_class = g_type_class_peek_parent(klass);
       
   187 
       
   188   obj->set_property = parent_class->set_property;
       
   189   obj->get_property = parent_class->get_property;
       
   190 
       
   191   obj->constructor = tp_props_iface_constructor;
       
   192   obj->dispose = tp_props_iface_dispose;
       
   193   obj->finalize = tp_props_iface_finalize;
       
   194 
       
   195   g_type_class_add_private (klass, sizeof (TpPropsPrivate));
       
   196   /**
       
   197    * TpPropsIface::properties-ready:
       
   198    * @self: #TpPropsIface that emmitted the signal
       
   199    * @property_id: property that changed
       
   200    * @change_flags: #TpPropsChanged for what changed on the property
       
   201    *
       
   202    * This signal is emitted when the properties 1st become avaible for
       
   203    * reading or writing.
       
   204    */
       
   205 
       
   206   signals[PROPERTIES_READY] =
       
   207   g_signal_new ("properties-ready",
       
   208                 G_OBJECT_CLASS_TYPE (klass),
       
   209                 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   210                 0,
       
   211                 NULL, NULL,
       
   212                 g_cclosure_marshal_VOID__VOID,
       
   213                 G_TYPE_NONE, 0);
       
   214 
       
   215 
       
   216 
       
   217   /**
       
   218    * TpPropsIface::properties-changed:
       
   219    * @self: #TpPropsIface that emmitted the signal
       
   220    * @property_id: property that changed
       
   221    * @change_flags: #TpPropsChanged for what changed on the property
       
   222    *
       
   223    * This signal is emitted when a property changes.
       
   224    */
       
   225 
       
   226   signals[PROPERTY_CHANGED] =
       
   227   g_signal_new ("properties-changed",
       
   228                 G_OBJECT_CLASS_TYPE (klass),
       
   229                 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   230                 0,
       
   231                 NULL, NULL,
       
   232                 tp_ifaces_signals_marshal_VOID__UINT_UINT,
       
   233                 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
       
   234 
       
   235 
       
   236   /* register marshaller for  PropertiesChanged and PropertyFlagsChanged*/
       
   237   dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT_UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
       
   238 
       
   239 }
       
   240 
       
   241 #ifdef SYMBIAN
       
   242 EXPORT_C
       
   243 #endif
       
   244 GType tp_props_iface_get_type(void)
       
   245 {
       
   246 #ifndef EMULATOR
       
   247   static GType type1 = 0;
       
   248 #endif
       
   249   
       
   250   if (type1 == 0)
       
   251     {
       
   252       static const GTypeInfo info =
       
   253         {
       
   254           sizeof(TpPropsIfaceClass),
       
   255           NULL,
       
   256           NULL,
       
   257           (GClassInitFunc)tp_props_iface_class_init,
       
   258           NULL,
       
   259           NULL,
       
   260           sizeof(TpPropsIface),
       
   261           0,
       
   262           (GInstanceInitFunc)tp_props_iface_init
       
   263         };
       
   264       type1 = g_type_register_static(DBUS_TYPE_G_PROXY,
       
   265                                     "TpPropsIface", &info, 0);
       
   266     }
       
   267   return type1;
       
   268 }
       
   269 
       
   270 /* The interface name getters */
       
   271 #ifdef SYMBIAN
       
   272 EXPORT_C
       
   273 #endif
       
   274 GQuark
       
   275 tp_get_props_interface (void)
       
   276 {
       
   277 #ifndef EMULATOR
       
   278   static GQuark ret = 0;
       
   279 #endif
       
   280 
       
   281   if (ret == 0)
       
   282   {
       
   283     ret = g_quark_from_static_string(TP_IFACE_PROPERTIES);
       
   284   }
       
   285 
       
   286   return ret;
       
   287 }
       
   288 
       
   289 TpPropsIface *
       
   290 tp_props_iface_new (DBusGConnection *connection,
       
   291                    const char      *name,
       
   292                    const char      *path_name)
       
   293 {
       
   294   /* The properties are order dependant in dbus <= 0.61. Thanks dbus*/
       
   295   return g_object_new (TELEPATHY_PROPS_IFACE_TYPE,
       
   296                        "name", name,
       
   297                        "path", path_name,
       
   298                        "interface",TP_IFACE_PROPERTIES,
       
   299                        "connection", connection,
       
   300                        NULL);
       
   301 }
       
   302 
       
   303 static void properties_changed_cb (DBusGProxy *proxy, GPtrArray *properties, gpointer user_data);
       
   304 static void property_flags_changed_cb (DBusGProxy *proxy, GPtrArray *properties, gpointer user_data);
       
   305 
       
   306 /**
       
   307  * tp_props_iface_set_mapping:
       
   308  * @iface: #TpPropsIface on which to set mapping
       
   309  * @first_name: First name in list to set a mapping for
       
   310  *
       
   311  * Set a mapping between propery names and your chosen ID's for these
       
   312  * names. Takes a list of property name, id pairs, terminated by NULL.
       
   313  *
       
   314  * Typically the user will define an enum of properties that they're
       
   315  * interested in, and set a mapping like:
       
   316  *   tp_props_iface_set_mapping (props, "foo", FOO,
       
   317  *                                     "bar", BAR,
       
   318  *                                     "baz", BAZ,
       
   319  *                                     NULL);
       
   320  * the user should bind to the
       
   321  * <link linkend="TpPropsIface-properties-ready">properties-ready signal</link>
       
   322  * before calling this. Property queries will only be possible *after* this
       
   323  * signal has been emitted.
       
   324  */
       
   325 void tp_props_iface_set_mapping (TpPropsIface *self,
       
   326                                 const gchar *first_property_name,
       
   327                                 ...)
       
   328 {
       
   329   va_list var_args;
       
   330   const gchar *name = first_property_name;
       
   331   guint id;
       
   332   GArray *array;
       
   333   PropertyMapping map = {0,0,NULL,NULL,0};
       
   334 
       
   335   g_return_if_fail (TELEPATHY_IS_PROPS_IFACE (self));
       
   336   g_return_if_fail (PRIV(self)->mappings == NULL);
       
   337 
       
   338   va_start (var_args, first_property_name);
       
   339 
       
   340   array = g_array_new (FALSE, FALSE, sizeof (PropertyMapping));
       
   341 
       
   342   while (name)
       
   343     {
       
   344       id = va_arg (var_args, guint);
       
   345       map.user_id = id;
       
   346       map.name = g_strdup (name);
       
   347       g_array_append_val (array, map);
       
   348       name = va_arg (var_args, gchar *);
       
   349     }
       
   350 
       
   351   va_end (var_args);
       
   352 
       
   353   PRIV (self)->mappings_len = array->len;
       
   354   PRIV (self)->mappings = (PropertyMapping*) g_array_free (array, FALSE);
       
   355 
       
   356   dbus_g_proxy_connect_signal (DBUS_G_PROXY (self), "PropertiesChanged",
       
   357                                G_CALLBACK(properties_changed_cb), self, NULL);
       
   358   dbus_g_proxy_connect_signal (DBUS_G_PROXY (self), "PropertyFlagsChanged",
       
   359                                G_CALLBACK(property_flags_changed_cb),
       
   360                                self, NULL);
       
   361 
       
   362   tp_props_iface_list_properties_async (DBUS_G_PROXY (self),
       
   363                                         properties_listed_cb, self);
       
   364 }
       
   365 
       
   366 /**
       
   367  * tp_props_iface_get_value:
       
   368  * @self: #TpPropsIface on which to get a property value
       
   369  * @prop_id: Identifier for property as set in #tp_props_iface_set_mapping
       
   370  * @value: GValue to return the property's value in.
       
   371  *
       
   372  * Get the value of a property on this interface
       
   373  */
       
   374 gboolean tp_props_iface_get_value (TpPropsIface* self, guint prop_id,
       
   375                                   GValue *return_value)
       
   376 {
       
   377   int i;
       
   378 
       
   379   if (!PRIV (self)->properties_ready)
       
   380     return FALSE;
       
   381 
       
   382   for (i = 0; i < PRIV (self)->mappings_len; i++)
       
   383     {
       
   384       if (PRIV (self)->mappings[i].user_id == prop_id)
       
   385         {
       
   386           if (PRIV (self)->mappings[i].value)
       
   387             {
       
   388               g_value_copy (PRIV (self)->mappings[i].value, return_value);
       
   389               return TRUE;
       
   390             }
       
   391           else
       
   392             {
       
   393               return FALSE;
       
   394             }
       
   395         }
       
   396     }
       
   397 
       
   398   return FALSE;
       
   399 }
       
   400 
       
   401 /* dummy callback handler for async calling calls with no return values */
       
   402 static void
       
   403 dummy_callback (DBusGProxy *proxy, GError *error, gpointer user_data)
       
   404 {
       
   405   if (error)
       
   406     {
       
   407       g_warning ("%s calling %s", error->message, (char*)user_data);
       
   408       g_error_free (error);
       
   409     }
       
   410 }
       
   411 
       
   412 /**
       
   413  * tp_props_iface_set_value:
       
   414  * @self: #TpPropsIface on which to set a property value
       
   415  * @prop_id: Identifier for property as set in #tp_props_iface_set_mapping
       
   416  * @value: GValue to use to set the property's value
       
   417  *
       
   418  * Set the value of a property on this interface
       
   419  */
       
   420 gboolean tp_props_iface_set_value (TpPropsIface* self, guint prop_id,
       
   421                                   const GValue *value)
       
   422 {
       
   423   /*TODO add option for an error callback*/
       
   424   int i;
       
   425   GPtrArray *props;
       
   426 
       
   427   if (!PRIV(self)->properties_ready)
       
   428     return FALSE;
       
   429 
       
   430   for (i=0; i < PRIV(self)->mappings_len; i++)
       
   431     {
       
   432       if (PRIV(self)->mappings[i].user_id == prop_id)
       
   433         {
       
   434           GValue prop = {0,};
       
   435           g_value_init (&prop, TP_TYPE_PROPERTY_CHANGE);
       
   436           g_value_take_boxed (&prop,
       
   437               dbus_g_type_specialized_construct (TP_TYPE_PROPERTY_CHANGE));
       
   438 
       
   439           dbus_g_type_struct_set (&prop,
       
   440               0, PRIV(self)->mappings[i].server_id,
       
   441               1, value,
       
   442               G_MAXUINT);
       
   443 
       
   444           props = g_ptr_array_sized_new (1);
       
   445           g_ptr_array_add (props, g_value_get_boxed (&prop));
       
   446           tp_props_iface_set_properties_async (DBUS_G_PROXY(self), props,
       
   447                                                dummy_callback, "SetProperties");
       
   448           g_value_unset (&prop);
       
   449           g_ptr_array_free (props, TRUE);
       
   450           return TRUE;
       
   451         }
       
   452     }
       
   453   return FALSE;
       
   454 }
       
   455 
       
   456 
       
   457 static void
       
   458 set_properties_values (TpPropsIface *self, GPtrArray *properties)
       
   459 {
       
   460   int i,j;
       
   461 
       
   462   for (i = 0; i < properties->len; i++)
       
   463     {
       
   464       GValue property = {0};
       
   465       guint32 id;
       
   466       GValue *value;
       
   467 
       
   468       g_value_init (&property, TP_TYPE_PROPERTY_CHANGE);
       
   469       g_value_set_static_boxed (&property, g_ptr_array_index (properties, i));
       
   470       dbus_g_type_struct_get (&property, 0, &id, G_MAXUINT);
       
   471 
       
   472       for (j = 0; j < PRIV(self)->mappings_len; j++)
       
   473         {
       
   474           PropertyMapping *mapping = &(PRIV (self)->mappings[j]);
       
   475 
       
   476           if (mapping->server_id == id)
       
   477             {
       
   478               dbus_g_type_struct_get (&property, 1, &value, G_MAXUINT);
       
   479               g_assert (value);
       
   480 
       
   481               if (mapping->value)
       
   482                 {
       
   483                   g_value_unset (mapping->value);
       
   484                   g_free (mapping->value);
       
   485                 }
       
   486 
       
   487               mapping->value = value;
       
   488               value = NULL; /* just to be on the safe side... */
       
   489 
       
   490               if (PRIV (self)->properties_ready)
       
   491                 g_signal_emit (self, signals[PROPERTY_CHANGED], 0,
       
   492                                mapping->user_id, TP_PROPS_CHANGED_VALUE);
       
   493 
       
   494               break;
       
   495             }
       
   496         }
       
   497     }
       
   498 
       
   499 }
       
   500 
       
   501 static void
       
   502 properties_changed_cb (DBusGProxy *proxy, GPtrArray *properties,
       
   503                        gpointer user_data)
       
   504 {
       
   505   TpPropsIface *self = TELEPATHY_PROPS_IFACE (user_data);
       
   506   if (!PRIV(self)->properties_ready)
       
   507     return;
       
   508   set_properties_values (self, properties);
       
   509 }
       
   510 
       
   511 static void
       
   512 properties_got_cb (DBusGProxy *proxy, GPtrArray *properties, GError *error, gpointer user_data)
       
   513 {
       
   514   TpPropsIface *self = TELEPATHY_PROPS_IFACE (user_data);
       
   515 
       
   516   if (error)
       
   517     {
       
   518       g_debug ("getting properties failed: %s (%s)", error->message,
       
   519         dbus_g_error_get_name (error));
       
   520       g_error_free (error);
       
   521       return;
       
   522     }
       
   523 
       
   524   set_properties_values (self, properties);
       
   525 
       
   526   if (!PRIV (self)->properties_ready)
       
   527     {
       
   528       PRIV (self)->properties_ready = TRUE;
       
   529       g_signal_emit (self, signals[PROPERTIES_READY], 0);
       
   530     }
       
   531 }
       
   532 
       
   533 static void
       
   534 property_flags_changed_cb (DBusGProxy *proxy, GPtrArray *properties,
       
   535                        gpointer user_data)
       
   536 {
       
   537   TpPropsIface *self = TELEPATHY_PROPS_IFACE (user_data);
       
   538   GArray *get_props;
       
   539   int i, j;
       
   540 
       
   541   if (!PRIV(self)->properties_ready)
       
   542     return;
       
   543 
       
   544   get_props = g_array_sized_new (FALSE, FALSE, sizeof (guint32),
       
   545                                  properties->len);
       
   546 
       
   547   for (i = 0; i < properties->len; i++)
       
   548     {
       
   549       GValue property = {0};
       
   550       guint32 id, flags;
       
   551 
       
   552       g_value_init (&property, TP_TYPE_PROPERTY_CHANGE);
       
   553       g_value_set_static_boxed (&property, g_ptr_array_index (properties, i));
       
   554       dbus_g_type_struct_get (&property, 0, &id, G_MAXUINT);
       
   555 
       
   556       for (j = 0; j < PRIV (self)->mappings_len; j++)
       
   557         {
       
   558           PropertyMapping *mapping = &(PRIV (self)->mappings[j]);
       
   559 
       
   560           if (mapping->server_id == id)
       
   561             {
       
   562               dbus_g_type_struct_get (&property, 1, &flags, G_MAXUINT);
       
   563 
       
   564               if (!(mapping->flags & TP_PROPERTY_FLAG_READ) &&
       
   565                   flags & TP_PROPERTY_FLAG_READ)
       
   566                 /* property has become readable; fetch it */
       
   567                 g_array_append_val (get_props, mapping->server_id);
       
   568 
       
   569               mapping->flags = flags;
       
   570               g_signal_emit (self, signals[PROPERTY_CHANGED], 0,
       
   571                 mapping->user_id, TP_PROPS_CHANGED_FLAGS);
       
   572               break;
       
   573             }
       
   574         }
       
   575     }
       
   576 
       
   577   tp_props_iface_get_properties_async (DBUS_G_PROXY (self), get_props,
       
   578                                        properties_got_cb, self);
       
   579   g_array_free (get_props, TRUE);
       
   580 }
       
   581 
       
   582 static void
       
   583 properties_listed_cb (DBusGProxy *proxy, GPtrArray *properties, GError *error, gpointer user_data)
       
   584 {
       
   585   TpPropsIface *self = TELEPATHY_PROPS_IFACE (user_data);
       
   586   int i,j;
       
   587   guint32 id, flags;
       
   588   gchar *name;
       
   589   GArray *get_props;
       
   590 
       
   591   if (error)
       
   592     {
       
   593       g_debug ("listing properties failed: %s (%s)", error->message,
       
   594         dbus_g_error_get_name (error));
       
   595       g_error_free (error);
       
   596       return;
       
   597     }
       
   598 
       
   599   for (i = 0; i < properties->len; i++)
       
   600     {
       
   601       GValue property = {0};
       
   602       g_value_init (&property, TP_TYPE_PROPERTY_DESCRIPTION);
       
   603       g_value_set_static_boxed (&property, g_ptr_array_index (properties, i));
       
   604 
       
   605       dbus_g_type_struct_get (&property,
       
   606           0, &id,
       
   607           1, &name,
       
   608           3, &flags,
       
   609           G_MAXUINT);
       
   610 
       
   611       for (j = 0; j < PRIV (self)->mappings_len; j++)
       
   612         {
       
   613           if (0 == strcmp (PRIV (self)->mappings[j].name, name))
       
   614             {
       
   615               PRIV (self)->mappings[j].server_id = id;
       
   616               PRIV (self)->mappings[j].flags = flags;
       
   617             }
       
   618         }
       
   619 
       
   620       g_free (name);
       
   621     }
       
   622 
       
   623   get_props = g_array_sized_new (FALSE, FALSE, sizeof (guint32),
       
   624                                  properties->len);
       
   625 
       
   626   for (i = 0; i < PRIV(self)->mappings_len; i++)
       
   627     {
       
   628       PropertyMapping *mapping = &(PRIV(self)->mappings[i]);
       
   629 
       
   630       if (mapping->flags & TP_PROPERTY_FLAG_READ)
       
   631         g_array_append_val (get_props, mapping->server_id);
       
   632     }
       
   633 
       
   634   tp_props_iface_get_properties_async (DBUS_G_PROXY (self), get_props,
       
   635                                        properties_got_cb, self);
       
   636   g_array_free (get_props, TRUE);
       
   637 }
       
   638 
       
   639 void
       
   640 tp_props_interface_set_signatures (DBusGProxy *proxy)
       
   641 {
       
   642   dbus_g_proxy_add_signal(proxy, "PropertiesChanged",
       
   643       dbus_g_type_get_collection ("GPtrArray",
       
   644           dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT,
       
   645                                    G_TYPE_VALUE, G_TYPE_INVALID)),
       
   646       G_TYPE_INVALID);
       
   647   dbus_g_proxy_add_signal(proxy, "PropertyFlagsChanged",
       
   648       dbus_g_type_get_collection ("GPtrArray",
       
   649           dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT,
       
   650                                    G_TYPE_UINT, G_TYPE_INVALID)),
       
   651       G_TYPE_INVALID);
       
   652 }
       
   653