Git init
[external/dbus-glib.git] / dbus / dbus-gproxy.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gproxy.c Proxy for remote objects
3  *
4  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
5  * Copyright (C) 2005 Nokia
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 #include <dbus/dbus-glib.h>
25 #include <dbus/dbus-glib-lowlevel.h>
26 #include <dbus/dbus-signature.h>
27 #include "dbus-gutils.h"
28 #include "dbus-gsignature.h"
29 #include "dbus-gvalue.h"
30 #include "dbus-gvalue-utils.h"
31 #include "dbus-gobject.h"
32 #include <string.h>
33 #include <glib/gi18n.h>
34 #include <gobject/gvaluecollector.h>
35
36 #define DBUS_G_PROXY_CALL_TO_ID(x) (GPOINTER_TO_UINT(x))
37 #define DBUS_G_PROXY_ID_TO_CALL(x) (GUINT_TO_POINTER(x))
38 #define DBUS_G_PROXY_GET_PRIVATE(o)  \
39        (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUS_TYPE_G_PROXY, DBusGProxyPrivate))
40
41
42 /**
43  * @addtogroup DBusGLibInternals
44  *
45  * @{
46  */
47
48 /**
49  * DBusGProxyManager typedef
50  */
51
52 typedef struct _DBusGProxyManager DBusGProxyManager;
53
54 typedef struct _DBusGProxyPrivate DBusGProxyPrivate;
55
56 /**
57  * Internals of DBusGProxy
58  */
59 struct _DBusGProxyPrivate
60 {
61   DBusGProxyManager *manager; /**< Proxy manager */
62   char *name;                 /**< Name messages go to or NULL */
63   char *path;                 /**< Path messages go to or NULL */
64   char *interface;            /**< Interface messages go to or NULL */
65
66   DBusGProxyCall *name_call;  /**< Pending call id to retrieve name owner */
67   guint for_owner : 1;        /**< Whether or not this proxy is for a name owner */
68   guint associated : 1;       /**< Whether or not this proxy is associated (for name proxies) */
69
70   /* FIXME: make threadsafe? */
71   guint call_id_counter;      /**< Integer counter for pending calls */
72
73   GData *signal_signatures;   /**< D-BUS signatures for each signal */
74
75   GHashTable *pending_calls;  /**< Calls made on this proxy which have not yet returned */
76
77   int default_timeout; /**< Default timeout to use, see dbus_g_proxy_set_default_timeout */
78 };
79
80 static void dbus_g_proxy_init               (DBusGProxy      *proxy);
81 static void dbus_g_proxy_class_init         (DBusGProxyClass *klass);
82 static GObject *dbus_g_proxy_constructor    (GType                  type,
83                                              guint                  n_construct_properties,
84                                              GObjectConstructParam *construct_properties);
85 static void     dbus_g_proxy_set_property       (GObject               *object,
86                                                  guint                  prop_id,
87                                                  const GValue          *value,
88                                                  GParamSpec            *pspec);
89 static void     dbus_g_proxy_get_property       (GObject               *object,
90                                                  guint                  prop_id,
91                                                  GValue                *value,
92                                                  GParamSpec            *pspec);
93
94 static void dbus_g_proxy_finalize           (GObject         *object);
95 static void dbus_g_proxy_dispose            (GObject         *object);
96 static void dbus_g_proxy_destroy            (DBusGProxy      *proxy);
97 static void dbus_g_proxy_emit_remote_signal (DBusGProxy      *proxy,
98                                              DBusMessage     *message);
99
100 static DBusGProxyCall *manager_begin_bus_call (DBusGProxyManager    *manager,
101                                                const char          *method,
102                                                DBusGProxyCallNotify notify,
103                                                gpointer             data,
104                                                GDestroyNotify       destroy,
105                                                GType                first_arg_type,
106                                                ...);
107 static guint dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
108                                                const char          *method,
109                                                DBusGProxyCallNotify notify,
110                                                gpointer             data,
111                                                GDestroyNotify       destroy,
112                                                GValueArray         *args,
113                                                int timeout );
114 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
115                                                 guint              call_id,
116                                                 GError           **error,
117                                                 GType              first_arg_type,
118                                                 va_list            args);
119
120 /**
121  * A list of proxies with a given name+path+interface, used to
122  * route incoming signals.
123  */
124 typedef struct
125 {
126   GSList *proxies; /**< The list of proxies */
127
128   char name[4]; /**< name (empty string for none), nul byte,
129                  *   path, nul byte,
130                  *   interface, nul byte
131                  */
132   
133 } DBusGProxyList;
134
135 /**
136  * DBusGProxyManager's primary task is to route signals to the proxies
137  * those signals are emitted on. In order to do this it also has to
138  * track the owners of the names proxies are bound to.
139  */
140 struct _DBusGProxyManager
141 {
142   GStaticMutex lock; /**< Thread lock */
143   int refcount;      /**< Reference count */
144   DBusConnection *connection; /**< Connection we're associated with. */
145
146   DBusGProxy *bus_proxy; /**< Special internal proxy used to talk to the bus */
147
148   GHashTable *proxy_lists; /**< Hash used to route incoming signals
149                             *   and iterate over proxies
150                             */
151   GHashTable *owner_names; /**< Hash to keep track of mapping from
152                             *   base name -> [name,name,...] for proxies which
153                             *   are for names.
154                             */
155   GSList *unassociated_proxies;     /**< List of name proxies for which
156                                      *   there was no result for
157                                      *   GetNameOwner
158                                      */
159 };
160
161 static DBusGProxyManager *dbus_g_proxy_manager_ref    (DBusGProxyManager *manager);
162 static DBusHandlerResult  dbus_g_proxy_manager_filter (DBusConnection    *connection,
163                                                        DBusMessage       *message,
164                                                        void              *user_data);
165
166
167 /** Lock the DBusGProxyManager */
168 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
169 /** Unlock the DBusGProxyManager */
170 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
171
172 static int g_proxy_manager_slot = -1;
173
174 /* Lock controlling get/set manager as data on each connection */
175 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
176
177 static DBusGProxyManager*
178 dbus_g_proxy_manager_get (DBusConnection *connection)
179 {
180   DBusGProxyManager *manager;
181
182   dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
183   if (g_proxy_manager_slot < 0)
184     g_error ("out of memory");
185   
186   g_static_mutex_lock (&connection_g_proxy_lock);
187   
188   manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
189   if (manager != NULL)
190     {
191       dbus_connection_free_data_slot (&g_proxy_manager_slot);
192       dbus_g_proxy_manager_ref (manager);
193       g_static_mutex_unlock (&connection_g_proxy_lock);
194       return manager;
195     }
196   
197   manager = g_new0 (DBusGProxyManager, 1);
198
199   manager->refcount = 1;
200   manager->connection = connection;
201
202   g_static_mutex_init (&manager->lock);
203
204   /* Proxy managers keep the connection alive, which means that
205    * DBusGProxy indirectly does. To free a connection you have to free
206    * all the proxies referring to it.
207    */
208   dbus_connection_ref (manager->connection);
209
210   dbus_connection_set_data (connection, g_proxy_manager_slot,
211                             manager, NULL);
212
213   dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
214                               manager, NULL);
215   
216   g_static_mutex_unlock (&connection_g_proxy_lock);
217   
218   return manager;
219 }
220
221 static DBusGProxyManager * 
222 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
223 {
224   g_assert (manager != NULL);
225   g_assert (manager->refcount > 0);
226
227   LOCK_MANAGER (manager);
228   
229   manager->refcount += 1;
230
231   UNLOCK_MANAGER (manager);
232
233   return manager;
234 }
235
236 static void
237 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
238 {
239   g_assert (manager != NULL);
240   g_assert (manager->refcount > 0);
241
242   LOCK_MANAGER (manager);
243   manager->refcount -= 1;
244   if (manager->refcount == 0)
245     {
246       UNLOCK_MANAGER (manager);
247
248       if (manager->bus_proxy)
249         g_object_unref (manager->bus_proxy);
250
251       if (manager->proxy_lists)
252         {
253           /* can't have any proxies left since they hold
254            * a reference to the proxy manager.
255            */
256           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
257           
258           g_hash_table_destroy (manager->proxy_lists);
259           manager->proxy_lists = NULL;
260
261         }
262
263       if (manager->owner_names)
264         {
265           /* Since we destroyed all proxies, none can be tracking
266            * name owners
267            */
268           g_assert (g_hash_table_size (manager->owner_names) == 0);
269
270           g_hash_table_destroy (manager->owner_names);
271           manager->owner_names = NULL;
272         }
273
274       g_assert (manager->unassociated_proxies == NULL);
275       
276       g_static_mutex_free (&manager->lock);
277
278       g_static_mutex_lock (&connection_g_proxy_lock);
279
280       dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
281                                      manager);
282       
283       dbus_connection_set_data (manager->connection,
284                                 g_proxy_manager_slot,
285                                 NULL, NULL);
286
287       g_static_mutex_unlock (&connection_g_proxy_lock);
288       
289       dbus_connection_unref (manager->connection);
290       g_free (manager);
291
292       dbus_connection_free_data_slot (&g_proxy_manager_slot);
293     }
294   else
295     {
296       UNLOCK_MANAGER (manager);
297     }
298 }
299
300 static guint
301 tristring_hash (gconstpointer key)
302 {
303   const char *p = key;
304   guint h = *p;
305
306   if (h)
307     {
308       for (p += 1; *p != '\0'; p++)
309         h = (h << 5) - h + *p;
310     }
311
312   /* skip nul and do the next substring */
313   for (p += 1; *p != '\0'; p++)
314     h = (h << 5) - h + *p;
315
316   /* skip nul again and another substring */
317   for (p += 1; *p != '\0'; p++)
318     h = (h << 5) - h + *p;
319   
320   return h;
321 }
322
323 static gboolean
324 strequal_len (const char *a,
325               const char *b,
326               size_t     *lenp)
327 {
328   size_t a_len;
329   size_t b_len;
330
331   a_len = strlen (a);
332   b_len = strlen (b);
333
334   if (a_len != b_len)
335     return FALSE;
336
337   if (memcmp (a, b, a_len) != 0)
338     return FALSE;
339   
340   *lenp = a_len;
341
342   return TRUE;
343 }
344
345 static gboolean
346 tristring_equal (gconstpointer  a,
347                  gconstpointer  b)
348 {
349   const char *ap = a;
350   const char *bp = b;
351   size_t len;
352
353   if (!strequal_len (ap, bp, &len))
354     return FALSE;
355
356   ap += len + 1;
357   bp += len + 1;
358
359   if (!strequal_len (ap, bp, &len))
360     return FALSE;
361
362   ap += len + 1;
363   bp += len + 1;
364
365   if (strcmp (ap, bp) != 0)
366     return FALSE;
367   
368   return TRUE;
369 }
370
371 static char*
372 tristring_alloc_from_strings (size_t      padding_before,
373                               const char *name,
374                               const char *path,
375                               const char *interface)
376 {
377   size_t name_len, iface_len, path_len, len;
378   char *tri;
379   
380   if (name)
381     name_len = strlen (name);
382   else
383     name_len = 0;
384
385   path_len = strlen (path);
386   
387   iface_len = strlen (interface);
388
389   tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
390
391   len = padding_before;
392   
393   if (name)
394     memcpy (&tri[len], name, name_len);
395
396   len += name_len;
397   tri[len] = '\0';
398   len += 1;
399
400   g_assert (len == (padding_before + name_len + 1));
401   
402   memcpy (&tri[len], path, path_len);
403   len += path_len;
404   tri[len] = '\0';
405   len += 1;
406
407   g_assert (len == (padding_before + name_len + path_len + 2));
408   
409   memcpy (&tri[len], interface, iface_len);
410   len += iface_len;
411   tri[len] = '\0';
412   len += 1;
413
414   g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
415
416   return tri;
417 }
418
419 static char*
420 tristring_from_proxy (DBusGProxy *proxy)
421 {
422   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
423
424   return tristring_alloc_from_strings (0,
425                                        priv->name,
426                                        priv->path,
427                                        priv->interface);
428 }
429
430 static char*
431 tristring_from_message (DBusMessage *message)
432 {
433   const char *path;
434   const char *interface;
435
436   path = dbus_message_get_path (message);
437   interface = dbus_message_get_interface (message);
438
439   g_assert (path);
440   g_assert (interface);
441   
442   return tristring_alloc_from_strings (0,
443                                        dbus_message_get_sender (message),
444                                        path, interface);
445 }
446
447 static DBusGProxyList*
448 g_proxy_list_new (DBusGProxy *first_proxy)
449 {
450   DBusGProxyList *list;
451   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(first_proxy);
452   
453   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
454                                                priv->name,
455                                                priv->path,
456                                                priv->interface);
457   list->proxies = NULL;
458
459   return list;
460 }
461
462 static void
463 g_proxy_list_free (DBusGProxyList *list)
464 {
465   /* we don't hold a reference to the proxies in the list,
466    * as they ref the GProxyManager
467    */
468   g_slist_free (list->proxies);  
469
470   g_free (list);
471 }
472
473 static char*
474 g_proxy_get_signal_match_rule (DBusGProxy *proxy)
475 {
476   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
477   /* FIXME Escaping is required here */
478   
479   if (priv->name)
480     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
481                             priv->name, priv->path, priv->interface);
482   else
483     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
484                             priv->path, priv->interface);
485 }
486
487 static char *
488 g_proxy_get_owner_match_rule (DBusGProxy *proxy)
489 {
490   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
491   if (priv->name) 
492     {
493       return g_strdup_printf ("type='signal',sender='" DBUS_SERVICE_DBUS
494         "',path='" DBUS_PATH_DBUS
495         "',interface='" DBUS_INTERFACE_DBUS
496         "',member='NameOwnerChanged'"
497         ",arg0='%s'", priv->name);
498     }
499   return NULL;
500 }
501
502 typedef struct
503 {
504   char *name;
505   guint refcount;
506 } DBusGProxyNameOwnerInfo;
507
508 static gint
509 find_name_in_info (gconstpointer a, gconstpointer b)
510 {
511   const DBusGProxyNameOwnerInfo *info = a;
512   const char *name = b;
513
514   return strcmp (info->name, name);
515 }
516
517 typedef struct
518 {
519   const char *name;
520   const char *owner;
521   DBusGProxyNameOwnerInfo *info;
522 } DBusGProxyNameOwnerForeachData;
523
524 static void
525 name_owner_foreach (gpointer key, gpointer val, gpointer data)
526 {
527   const char *owner;
528   DBusGProxyNameOwnerForeachData *foreach_data;
529   GSList *names;
530   GSList *link;
531
532   owner = key;
533   names = val;
534   foreach_data = data;
535
536   if (foreach_data->owner != NULL)
537     return;
538
539   g_assert (foreach_data->info == NULL);
540
541   link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
542   if (link)
543     {
544       foreach_data->owner = owner;
545       foreach_data->info = link->data;
546     }
547 }
548
549 static gboolean
550 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager        *manager,
551                                         const char               *name,
552                                         DBusGProxyNameOwnerInfo **info,
553                                         const char              **owner)
554 {
555   DBusGProxyNameOwnerForeachData foreach_data;
556
557   foreach_data.name = name;
558   foreach_data.owner = NULL;
559   foreach_data.info = NULL;
560   
561   g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
562
563   *info = foreach_data.info;
564   *owner = foreach_data.owner;
565   return *info != NULL;
566 }
567
568 static void
569 insert_nameinfo (DBusGProxyManager       *manager,
570                  const char              *owner,
571                  DBusGProxyNameOwnerInfo *info)
572 {
573   GSList *names;
574   gboolean insert;
575
576   names = g_hash_table_lookup (manager->owner_names, owner);
577
578   /* Only need to g_hash_table_insert the first time */
579   insert = (names == NULL);
580
581   names = g_slist_append (names, info); 
582
583   if (insert)
584     g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
585 }
586
587 static void
588 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager  *manager,
589                                          const char         *owner,
590                                          const char         *name)
591 {
592   GSList *names;
593   GSList *link;
594   DBusGProxyNameOwnerInfo *nameinfo;
595
596   names = g_hash_table_lookup (manager->owner_names, owner);
597   link = g_slist_find_custom (names, name, find_name_in_info);
598   
599   if (!link)
600     {
601       nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
602       nameinfo->name = g_strdup (name);
603       nameinfo->refcount = 1;
604
605       insert_nameinfo (manager, owner, nameinfo);
606     }
607   else
608     {
609       nameinfo = link->data;
610       nameinfo->refcount++;
611     }
612 }
613
614 static void
615 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager  *manager,
616                                            const char         *name)
617 {
618   DBusGProxyNameOwnerInfo *info;
619   const char *owner;
620   gboolean ret;
621
622   ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
623   g_assert (ret);
624   g_assert (info != NULL);
625   g_assert (owner != NULL);
626
627   info->refcount--;
628   if (info->refcount == 0)
629     {
630       GSList *names;
631       GSList *link;
632
633       names = g_hash_table_lookup (manager->owner_names, owner);
634       link = g_slist_find_custom (names, name, find_name_in_info);
635       names = g_slist_delete_link (names, link);
636       if (names != NULL)
637         g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
638       else
639         g_hash_table_remove (manager->owner_names, owner);
640
641       g_free (info->name);
642       g_free (info);
643     }
644 }
645
646 typedef struct
647 {
648   const char *name;
649   GSList *destroyed;
650 } DBusGProxyUnassociateData;
651
652 static void
653 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
654 {
655   DBusGProxyList *list;
656   const char *name;
657   GSList *tmp;
658   DBusGProxyUnassociateData *data;
659
660   list = val;
661   data = user_data;
662   name = data->name;
663   
664   for (tmp = list->proxies; tmp; tmp = tmp->next)
665     {
666       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
667       DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
668       DBusGProxyManager *manager;
669
670       manager = priv->manager;
671
672       if (!strcmp (priv->name, name))
673         {
674           if (!priv->for_owner)
675             {
676               /* If a service appeared and then vanished very quickly,
677                * it's conceivable we have an inflight request for
678                * GetNameOwner here.  Cancel it.
679                * https://bugs.freedesktop.org/show_bug.cgi?id=18573
680                */
681               if (priv->name_call)
682                 dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
683
684               priv->name_call = NULL;
685
686               priv->associated = FALSE;
687               manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
688             }
689           else
690             {
691               data->destroyed = g_slist_prepend (data->destroyed, proxy);
692               /* make contents of list into weak pointers in case the objects
693                * unref each other when disposing */
694               g_object_add_weak_pointer (G_OBJECT (proxy),
695                   &(data->destroyed->data));
696             }
697         }
698     }
699 }
700
701 static void
702 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
703                                          const char         *name,
704                                          const char         *prev_owner,
705                                          const char         *new_owner)
706 {
707   GSList *names;
708           
709   if (prev_owner[0] == '\0')
710     {
711       GSList *tmp;
712       GSList *removed;
713
714       /* We have a new service, look at unassociated proxies */
715
716       removed = NULL;
717
718       for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
719         {
720           DBusGProxy *proxy = tmp->data;
721           DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
722
723           if (!strcmp (priv->name, name))
724             {
725               removed = g_slist_prepend (removed, tmp);
726               
727               dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
728               priv->associated = TRUE;
729             }
730         }
731
732       for (tmp = removed; tmp; tmp = tmp->next)
733         manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
734       g_slist_free (removed);
735     }
736   else
737     {
738       DBusGProxyNameOwnerInfo *info;
739       GSList *link;
740
741       /* Name owner changed or deleted */ 
742
743       names = g_hash_table_lookup (manager->owner_names, prev_owner);
744
745       info = NULL;
746       if (names != NULL)
747         {
748           link = g_slist_find_custom (names, name, find_name_in_info);
749
750           if (link != NULL)
751             {
752               info = link->data;
753           
754               names = g_slist_delete_link (names, link);
755
756               if (names == NULL)
757                 {
758                   g_hash_table_remove (manager->owner_names, prev_owner);
759                 }
760               else
761                 {
762                   g_hash_table_insert (manager->owner_names,
763                                        g_strdup (prev_owner), names);
764                 }
765             }
766         }
767
768       if (new_owner[0] == '\0')
769         {
770           DBusGProxyUnassociateData data;
771           GSList *tmp;
772
773           data.name = name;
774           data.destroyed = NULL;
775
776           /* A service went away, we need to unassociate proxies */
777           g_hash_table_foreach (manager->proxy_lists,
778                                 unassociate_proxies, &data);
779
780           UNLOCK_MANAGER (manager);
781
782           /* the destroyed list's data pointers are weak pointers, so that we
783            * don't end up calling destroy on proxies which have already been
784            * freed up as a result of other ones being destroyed */
785           for (tmp = data.destroyed; tmp; tmp = tmp->next)
786             if (tmp->data != NULL)
787               {
788                 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
789                     &(tmp->data));
790                 dbus_g_proxy_destroy (tmp->data);
791               }
792           g_slist_free (data.destroyed);
793
794           LOCK_MANAGER (manager);
795
796           if (info)
797             {
798               g_free (info->name);
799               g_free (info);
800             }
801         }
802       else if (info)
803         {
804           insert_nameinfo (manager, new_owner, info);
805         }
806     }
807 }
808
809 static void
810 got_name_owner_cb (DBusGProxy       *bus_proxy,
811                    DBusGProxyCall   *call,
812                    void             *user_data)
813 {
814   DBusGProxy *proxy = user_data;
815   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
816   GError *error;
817   char *owner;
818
819   error = NULL;
820   owner = NULL;
821
822   LOCK_MANAGER (priv->manager);
823
824   if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
825                               G_TYPE_STRING, &owner,
826                               G_TYPE_INVALID))
827     {
828       if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
829         {
830           priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
831         }
832       else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
833         g_warning ("Couldn't get name owner (%s): %s",
834                    dbus_g_error_get_name (error),
835                    error->message);
836       else
837         g_warning ("Couldn't get name owner (code %d): %s",
838                    error->code, error->message);
839       g_clear_error (&error);
840       goto out;
841     }
842   else
843     {
844       dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
845       priv->associated = TRUE;
846     }
847
848  out:
849   priv->name_call = NULL;
850   UNLOCK_MANAGER (priv->manager);
851   g_free (owner);
852 }
853
854 static char *
855 get_name_owner (DBusConnection     *connection,
856                 const char         *name,
857                 GError            **error)
858 {
859   DBusError derror;
860   DBusMessage *request, *reply;
861   char *base_name;
862   
863   dbus_error_init (&derror);
864
865   base_name = NULL;
866   reply = NULL;
867
868   request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
869                                           DBUS_PATH_DBUS,
870                                           DBUS_INTERFACE_DBUS,
871                                           "GetNameOwner");
872   if (request == NULL)
873     g_error ("Out of memory");
874   
875   if (!dbus_message_append_args (request, 
876                                  DBUS_TYPE_STRING, &name, 
877                                  DBUS_TYPE_INVALID))
878     g_error ("Out of memory");
879
880   reply =
881     dbus_connection_send_with_reply_and_block (connection,
882                                                request,
883                                                2000, &derror);
884   if (reply == NULL)
885     goto error;
886
887   if (dbus_set_error_from_message (&derror, reply))
888     goto error;
889
890   if (!dbus_message_get_args (reply, &derror, 
891                               DBUS_TYPE_STRING, &base_name, 
892                               DBUS_TYPE_INVALID))
893     goto error;
894
895   base_name = g_strdup (base_name);
896   goto out;
897
898  error:
899   g_assert (dbus_error_is_set (&derror));
900   dbus_set_g_error (error, &derror);
901   dbus_error_free (&derror);
902
903  out:
904   if (request)
905     dbus_message_unref (request);
906   if (reply)
907     dbus_message_unref (reply);
908
909   return base_name;
910 }
911
912
913 static void
914 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
915                                DBusGProxy        *proxy)
916 {
917   DBusGProxyList *list;
918   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
919
920   LOCK_MANAGER (manager);
921
922   if (manager->proxy_lists == NULL)
923     {
924       g_assert (manager->owner_names == NULL);
925
926       list = NULL;
927       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
928                                                     tristring_equal,
929                                                     NULL,
930                                                     (GFreeFunc) g_proxy_list_free);
931       manager->owner_names = g_hash_table_new_full (g_str_hash,
932                                                     g_str_equal,
933                                                     g_free,
934                                                     NULL);
935     }
936   else
937     {
938       char *tri;
939
940       tri = tristring_from_proxy (proxy);
941       
942       list = g_hash_table_lookup (manager->proxy_lists, tri);
943
944       g_free (tri);
945     }
946       
947   if (list == NULL)
948     {
949       list = g_proxy_list_new (proxy);
950       
951       g_hash_table_replace (manager->proxy_lists,
952                             list->name, list);
953     }
954
955   if (list->proxies == NULL && priv->name)
956     {
957       /* We have to add match rules to the server,
958        * but only if the server is a message bus,
959        * not if it's a peer.
960        */
961        char *rule;
962        
963        rule = g_proxy_get_signal_match_rule (proxy);
964        /* We don't check for errors; it's not like anyone would handle them, and
965         * we don't want a round trip here.
966         */
967        dbus_bus_add_match (manager->connection,
968                            rule, NULL);
969        g_free (rule);
970        
971        rule = g_proxy_get_owner_match_rule (proxy);
972        if (rule)
973          dbus_bus_add_match (manager->connection,
974                              rule, NULL);
975        g_free (rule);
976     }
977
978   g_assert (g_slist_find (list->proxies, proxy) == NULL);
979   
980   list->proxies = g_slist_prepend (list->proxies, proxy);
981
982   if (!priv->for_owner)
983     {
984       const char *owner;
985       DBusGProxyNameOwnerInfo *info;
986
987       if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
988         {
989           priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
990                                                      got_name_owner_cb,
991                                                      proxy, NULL,
992                                                      G_TYPE_STRING,
993                                                      priv->name, 
994                                                      G_TYPE_INVALID);
995           
996           priv->associated = FALSE;
997         }
998       else
999         {
1000           info->refcount++;
1001           priv->associated = TRUE;
1002         }
1003     }
1004   
1005   UNLOCK_MANAGER (manager);
1006 }
1007
1008 static void
1009 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
1010                                 DBusGProxy        *proxy)
1011 {
1012   DBusGProxyList *list;
1013   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1014   char *tri;
1015   
1016   LOCK_MANAGER (manager);
1017
1018 #ifndef G_DISABLE_CHECKS
1019   if (manager->proxy_lists == NULL)
1020     {
1021       g_warning ("Trying to unregister a proxy but there aren't any registered");
1022       return;
1023     }
1024 #endif
1025
1026   tri = tristring_from_proxy (proxy);
1027   
1028   list = g_hash_table_lookup (manager->proxy_lists, tri);
1029
1030 #ifndef G_DISABLE_CHECKS
1031   if (list == NULL)
1032     {
1033       g_warning ("Trying to unregister a proxy but it isn't registered");
1034       return;
1035     }
1036 #endif
1037
1038   g_assert (g_slist_find (list->proxies, proxy) != NULL);
1039   
1040   list->proxies = g_slist_remove (list->proxies, proxy);
1041
1042   g_assert (g_slist_find (list->proxies, proxy) == NULL);
1043
1044   if (!priv->for_owner)
1045     {
1046       if (!priv->associated)
1047         {
1048           GSList *link;
1049
1050           if (priv->name_call != 0)
1051             {
1052               dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
1053               priv->name_call = 0;
1054             }
1055           else
1056             {
1057               link = g_slist_find (manager->unassociated_proxies, proxy);
1058               g_assert (link != NULL);
1059
1060               manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
1061             }
1062         }
1063       else
1064         {
1065           g_assert (priv->name_call == 0);
1066           
1067           dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
1068         }
1069     }
1070
1071   if (list->proxies == NULL)
1072     {
1073       char *rule;
1074       g_hash_table_remove (manager->proxy_lists,
1075                            tri);
1076       list = NULL;
1077
1078       rule = g_proxy_get_signal_match_rule (proxy);
1079       dbus_bus_remove_match (manager->connection,
1080                              rule, NULL);
1081       g_free (rule);
1082       rule = g_proxy_get_owner_match_rule (proxy);
1083       if (rule)
1084         dbus_bus_remove_match (manager->connection,
1085                                rule, NULL);
1086       g_free (rule);      
1087     }
1088   
1089   if (g_hash_table_size (manager->proxy_lists) == 0)
1090     {
1091       g_hash_table_destroy (manager->proxy_lists);
1092       manager->proxy_lists = NULL;
1093     }
1094
1095   g_free (tri);
1096       
1097   UNLOCK_MANAGER (manager);
1098 }
1099
1100 static void
1101 list_proxies_foreach (gpointer key,
1102                       gpointer value,
1103                       gpointer user_data)
1104 {
1105   DBusGProxyList *list;
1106   GSList **ret;
1107   GSList *tmp;
1108   
1109   list = value;
1110   ret = user_data;
1111
1112   tmp = list->proxies;
1113   while (tmp != NULL)
1114     {
1115       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
1116
1117       g_object_ref (proxy);
1118       *ret = g_slist_prepend (*ret, proxy);
1119       
1120       tmp = tmp->next;
1121     }
1122 }
1123
1124 static GSList*
1125 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
1126 {
1127   GSList *ret;
1128
1129   ret = NULL;
1130
1131   if (manager->proxy_lists)
1132     {
1133       g_hash_table_foreach (manager->proxy_lists,
1134                             list_proxies_foreach,
1135                             &ret);
1136     }
1137
1138   return ret;
1139 }
1140
1141 static DBusHandlerResult
1142 dbus_g_proxy_manager_filter (DBusConnection    *connection,
1143                              DBusMessage       *message,
1144                              void              *user_data)
1145 {
1146   DBusGProxyManager *manager;
1147   
1148   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
1149     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1150
1151   manager = user_data;
1152
1153   dbus_g_proxy_manager_ref (manager);
1154   
1155   LOCK_MANAGER (manager);
1156   
1157   if (dbus_message_is_signal (message,
1158                               DBUS_INTERFACE_LOCAL,
1159                               "Disconnected"))
1160     {
1161       /* Destroy all the proxies, quite possibly resulting in unreferencing
1162        * the proxy manager and the connection as well.
1163        */
1164       GSList *all;
1165       GSList *tmp;
1166
1167       all = dbus_g_proxy_manager_list_all (manager);
1168
1169       tmp = all;
1170       while (tmp != NULL)
1171         {
1172           DBusGProxy *proxy;
1173
1174           proxy = DBUS_G_PROXY (tmp->data);
1175
1176           UNLOCK_MANAGER (manager);
1177           dbus_g_proxy_destroy (proxy);
1178           g_object_unref (G_OBJECT (proxy));
1179           LOCK_MANAGER (manager);
1180           
1181           tmp = tmp->next;
1182         }
1183
1184       g_slist_free (all);
1185
1186 #ifndef G_DISABLE_CHECKS
1187       if (manager->proxy_lists != NULL)
1188         g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
1189 #endif
1190     }
1191   else
1192     {
1193       char *tri;
1194       GSList *full_list;
1195       GSList *owned_names;
1196       GSList *tmp;
1197       const char *sender;
1198
1199       /* First we handle NameOwnerChanged internally */
1200       if (dbus_message_is_signal (message,
1201                                   DBUS_INTERFACE_DBUS,
1202                                   "NameOwnerChanged"))
1203         {
1204           const char *name;
1205           const char *prev_owner;
1206           const char *new_owner;
1207           DBusError derr;
1208
1209           dbus_error_init (&derr);
1210           if (!dbus_message_get_args (message,
1211                                       &derr,
1212                                       DBUS_TYPE_STRING,
1213                                       &name,
1214                                       DBUS_TYPE_STRING,
1215                                       &prev_owner,
1216                                       DBUS_TYPE_STRING,
1217                                       &new_owner,
1218                                       DBUS_TYPE_INVALID))
1219             {
1220               /* Ignore this error */
1221               dbus_error_free (&derr);
1222             }
1223           else if (manager->owner_names != NULL)
1224             {
1225               dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
1226             }
1227         }
1228
1229       sender = dbus_message_get_sender (message);
1230
1231       /* dbus spec requires these, libdbus validates */
1232       g_assert (dbus_message_get_path (message) != NULL);
1233       g_assert (dbus_message_get_interface (message) != NULL);
1234       g_assert (dbus_message_get_member (message) != NULL);
1235       
1236       tri = tristring_from_message (message);
1237
1238       if (manager->proxy_lists)
1239         {
1240           DBusGProxyList *owner_list;
1241           owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
1242           if (owner_list)
1243             full_list = g_slist_copy (owner_list->proxies);
1244           else
1245             full_list = NULL;
1246         }
1247       else
1248         full_list = NULL;
1249
1250       g_free (tri);
1251
1252       if (manager->owner_names && sender)
1253         {
1254           owned_names = g_hash_table_lookup (manager->owner_names, sender);
1255           for (tmp = owned_names; tmp; tmp = tmp->next)
1256             {
1257               DBusGProxyList *owner_list;
1258               DBusGProxyNameOwnerInfo *nameinfo;
1259
1260               nameinfo = tmp->data;
1261               g_assert (nameinfo->refcount > 0);
1262               tri = tristring_alloc_from_strings (0, nameinfo->name,
1263                                                   dbus_message_get_path (message),
1264                                                   dbus_message_get_interface (message));
1265
1266               owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
1267               if (owner_list != NULL) 
1268                 {
1269                   GSList *elt;
1270
1271                   /* Ignore duplicates when adding to full_list */
1272                   for (elt = owner_list->proxies; elt; elt = g_slist_next (elt)) 
1273                     {
1274                       if (!g_slist_find (full_list, elt->data))
1275                         full_list = g_slist_append (full_list, elt->data);
1276                     }
1277                 }
1278               g_free (tri);
1279             }
1280         }
1281
1282 #if 0
1283       g_print ("proxy got %s,%s,%s = list %p\n",
1284                tri,
1285                tri + strlen (tri) + 1,
1286                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
1287                list);
1288 #endif
1289       
1290       /* Emit the signal */
1291       
1292       g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
1293       
1294       for (tmp = full_list; tmp; tmp = tmp->next)
1295         {
1296           DBusGProxy *proxy;
1297           
1298           proxy = DBUS_G_PROXY (tmp->data);
1299           
1300           UNLOCK_MANAGER (manager);
1301           dbus_g_proxy_emit_remote_signal (proxy, message);
1302           g_object_unref (G_OBJECT (proxy));
1303           LOCK_MANAGER (manager);
1304         }
1305       g_slist_free (full_list);
1306     }
1307
1308   UNLOCK_MANAGER (manager);
1309   dbus_g_proxy_manager_unref (manager);
1310   
1311   /* "Handling" signals doesn't make sense, they are for everyone
1312    * who cares
1313    */
1314   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1315 }
1316
1317
1318
1319 /*      ---------- DBusGProxy --------------   */
1320 #define DBUS_G_PROXY_DESTROYED(proxy)  (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
1321
1322 static void
1323 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
1324                                       GValue       *return_value,
1325                                       guint         n_param_values,
1326                                       const GValue *param_values,
1327                                       gpointer      invocation_hint,
1328                                       gpointer      marshal_data);
1329 enum
1330 {
1331   PROP_0,
1332   PROP_NAME,
1333   PROP_PATH,
1334   PROP_INTERFACE,
1335   PROP_CONNECTION
1336 };
1337
1338 enum
1339 {
1340   DESTROY,
1341   RECEIVED,
1342   LAST_SIGNAL
1343 };
1344
1345 static void *parent_class;
1346 static guint signals[LAST_SIGNAL] = { 0 };
1347
1348 static void
1349 dbus_g_proxy_init (DBusGProxy *proxy)
1350 {
1351   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1352   
1353   g_datalist_init (&priv->signal_signatures);
1354   priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
1355                                 (GDestroyNotify) dbus_pending_call_unref);
1356   priv->name_call = 0;
1357   priv->associated = FALSE;
1358   priv->default_timeout = -1;
1359 }
1360
1361 static GObject *
1362 dbus_g_proxy_constructor (GType                  type,
1363                           guint                  n_construct_properties,
1364                           GObjectConstructParam *construct_properties)
1365 {
1366   DBusGProxy *proxy;
1367   DBusGProxyClass *klass;
1368   GObjectClass *parent_class;
1369   DBusGProxyPrivate *priv;
1370
1371   klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
1372
1373   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
1374
1375   proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
1376                                                     construct_properties));
1377
1378   priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
1379
1380   /* if these assertions fail, a deriving class has not set our required
1381    * parameters - our own public constructors do return_if_fail checks
1382    * on these parameters being provided. unfortunately we can't assert
1383    * for manager because it's allowed to be NULL when tha mangager is
1384    * setting up a bus proxy for its own calls */
1385   g_assert (priv->path != NULL);
1386   g_assert (priv->interface != NULL);
1387
1388   if (priv->manager != NULL)
1389     {
1390       dbus_g_proxy_manager_register (priv->manager, proxy);
1391     }
1392
1393   return G_OBJECT (proxy);
1394 }
1395
1396 static void
1397 dbus_g_proxy_class_init (DBusGProxyClass *klass)
1398 {
1399   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1400   
1401   parent_class = g_type_class_peek_parent (klass);
1402
1403   g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
1404
1405   object_class->set_property = dbus_g_proxy_set_property;
1406   object_class->get_property = dbus_g_proxy_get_property;
1407
1408   g_object_class_install_property (object_class,
1409                                    PROP_NAME,
1410                                    g_param_spec_string ("name",
1411                                                         "name",
1412                                                         "name",
1413                                                         NULL,
1414                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1415
1416   g_object_class_install_property (object_class,
1417                                    PROP_PATH,
1418                                    g_param_spec_string ("path",
1419                                                         "path",
1420                                                         "path",
1421                                                         NULL,
1422                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1423
1424   g_object_class_install_property (object_class,
1425                                    PROP_INTERFACE,
1426                                    g_param_spec_string ("interface",
1427                                                         "interface",
1428                                                         "interface",
1429                                                         NULL,
1430                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1431   
1432   g_object_class_install_property (object_class,
1433                                    PROP_CONNECTION,
1434                                    g_param_spec_boxed ("connection",
1435                                                         "connection",
1436                                                         "connection",
1437                                                         DBUS_TYPE_G_CONNECTION,
1438                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1439   
1440   object_class->finalize = dbus_g_proxy_finalize;
1441   object_class->dispose = dbus_g_proxy_dispose;
1442   object_class->constructor = dbus_g_proxy_constructor;
1443   
1444   signals[DESTROY] =
1445     g_signal_new ("destroy",
1446                   G_OBJECT_CLASS_TYPE (object_class),
1447                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
1448                   0,
1449                   NULL, NULL,
1450                   g_cclosure_marshal_VOID__VOID,
1451                   G_TYPE_NONE, 0);
1452
1453   signals[RECEIVED] =
1454     g_signal_new ("received",
1455                   G_OBJECT_CLASS_TYPE (object_class),
1456                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
1457                   0,
1458                   NULL, NULL,
1459                   marshal_dbus_message_to_g_marshaller,
1460                   G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
1461 }
1462
1463 static gboolean
1464 cancel_pending_call (gpointer key, gpointer val, gpointer data)
1465 {
1466   DBusPendingCall *pending = val;
1467
1468   dbus_pending_call_cancel (pending);
1469
1470   return TRUE;
1471 }
1472
1473 static void
1474 dbus_g_proxy_dispose (GObject *object)
1475 {
1476   DBusGProxy *proxy = DBUS_G_PROXY (object);
1477   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1478
1479   if (priv->pending_calls == NULL) 
1480     {
1481       return;
1482     }
1483
1484   /* Cancel outgoing pending calls */
1485   g_hash_table_foreach_remove (priv->pending_calls, cancel_pending_call, NULL);
1486   g_hash_table_destroy (priv->pending_calls);
1487   priv->pending_calls = NULL;
1488
1489   if (priv->manager && proxy != priv->manager->bus_proxy)
1490     {
1491       dbus_g_proxy_manager_unregister (priv->manager, proxy);
1492       dbus_g_proxy_manager_unref (priv->manager);
1493     }
1494   priv->manager = NULL;
1495   
1496   g_datalist_clear (&priv->signal_signatures);
1497   
1498   g_signal_emit (object, signals[DESTROY], 0);
1499   
1500   G_OBJECT_CLASS (parent_class)->dispose (object);
1501 }
1502
1503 static void
1504 dbus_g_proxy_finalize (GObject *object)
1505 {
1506   DBusGProxy *proxy = DBUS_G_PROXY (object);
1507   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1508   
1509   g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
1510   
1511   g_free (priv->name);
1512   g_free (priv->path);
1513   g_free (priv->interface);
1514   
1515   G_OBJECT_CLASS (parent_class)->finalize (object);
1516 }
1517
1518 static void
1519 dbus_g_proxy_destroy (DBusGProxy *proxy)
1520 {
1521   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
1522    * from GtkObject?
1523    */
1524   g_object_run_dispose (G_OBJECT (proxy));
1525 }
1526
1527 static void
1528 dbus_g_proxy_set_property (GObject *object,
1529                            guint prop_id,
1530                            const GValue *value,
1531                            GParamSpec *pspec)
1532 {
1533   DBusGProxy *proxy = DBUS_G_PROXY (object);
1534   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1535   DBusGConnection *connection;
1536
1537   switch (prop_id)
1538     {
1539     case PROP_NAME:
1540       priv->name = g_strdup (g_value_get_string (value));
1541       if (priv->name)
1542         priv->for_owner = (priv->name[0] == ':');
1543       else
1544         priv->for_owner = TRUE;
1545       break;
1546     case PROP_PATH:
1547       priv->path = g_strdup (g_value_get_string (value));
1548       break;
1549     case PROP_INTERFACE:
1550       priv->interface = g_strdup (g_value_get_string (value));
1551       break;
1552     case PROP_CONNECTION:
1553       connection = g_value_get_boxed (value);
1554       if (connection != NULL)
1555         {
1556           priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
1557         }
1558       break;
1559     default:
1560       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1561       break;
1562     }
1563 }
1564
1565 static void 
1566 dbus_g_proxy_get_property (GObject *object,
1567                            guint prop_id,
1568                            GValue *value,
1569                            GParamSpec *pspec)
1570 {
1571   DBusGProxy *proxy = DBUS_G_PROXY (object);
1572   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1573
1574   switch (prop_id)
1575     {
1576     case PROP_NAME:
1577       g_value_set_string (value, priv->name);
1578       break;
1579     case PROP_PATH:
1580       g_value_set_string (value, priv->path);
1581       break;
1582     case PROP_INTERFACE:
1583       g_value_set_string (value, priv->interface);
1584       break;
1585     case PROP_CONNECTION:
1586       g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
1587       break;
1588     default:
1589       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1590       break;
1591     }
1592 }
1593
1594 /* this is to avoid people using g_signal_connect() directly,
1595  * to avoid confusion with local signal names, and because
1596  * of the horribly broken current setup (signals are added
1597  * globally to all proxies)
1598  */
1599 static char*
1600 create_signal_name (const char *interface,
1601                     const char *signal)
1602 {
1603   GString *str;
1604   char *p;
1605
1606   str = g_string_new (interface);
1607
1608   g_string_append (str, "-");
1609   
1610   g_string_append (str, signal);
1611
1612   /* GLib will silently barf on '.' in signal names */
1613   p = str->str;
1614   while (*p)
1615     {
1616       if (*p == '.')
1617         *p = '-';
1618       ++p;
1619     }
1620   
1621   return g_string_free (str, FALSE);
1622 }
1623
1624 static void
1625 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
1626                                       GValue       *return_value,
1627                                       guint         n_param_values,
1628                                       const GValue *param_values,
1629                                       gpointer      invocation_hint,
1630                                       gpointer      marshal_data)
1631 {
1632   /* Incoming here we have three params, the instance (Proxy), the
1633    * DBusMessage, the signature. We want to convert that to an
1634    * expanded GValue array, then call an appropriate normal GLib
1635    * marshaller.
1636    */
1637 #define MAX_SIGNATURE_ARGS 20
1638   GValueArray *value_array;
1639   GSignalCMarshaller c_marshaller;
1640   DBusGProxy *proxy;
1641   DBusMessage *message;
1642   GArray *gsignature;
1643   const GType *types;
1644   DBusGProxyPrivate *priv;
1645
1646   g_assert (n_param_values == 3);
1647
1648   proxy = g_value_get_object (&param_values[0]);
1649   message = g_value_get_boxed (&param_values[1]);
1650   gsignature = g_value_get_pointer (&param_values[2]);
1651
1652   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
1653   g_return_if_fail (message != NULL);
1654   g_return_if_fail (gsignature != NULL);
1655
1656   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1657
1658   c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
1659                                                   (GType*) gsignature->data);
1660
1661   g_return_if_fail (c_marshaller != NULL);
1662   
1663   {
1664     DBusGValueMarshalCtx context;
1665     context.recursion_depth = 0;
1666     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
1667     context.proxy = proxy;
1668
1669     types = (const GType*) gsignature->data;
1670     value_array = _dbus_gvalue_demarshal_message (&context, message,
1671                                                  gsignature->len, types, NULL);
1672   }
1673
1674   if (value_array == NULL)
1675     return;
1676   
1677   g_value_array_prepend (value_array, NULL);
1678   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
1679   g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
1680
1681   (* c_marshaller) (closure, return_value, value_array->n_values,
1682                     value_array->values, invocation_hint, marshal_data);
1683   
1684   g_value_array_free (value_array);
1685 }
1686
1687 static void
1688 dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
1689                                  DBusMessage *message)
1690 {
1691   const char *interface;
1692   const char *signal;
1693   char *name;
1694   GQuark q;
1695   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1696   GArray *msg_gsignature = NULL;
1697
1698   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
1699
1700   interface = dbus_message_get_interface (message);
1701   signal = dbus_message_get_member (message);
1702
1703   g_assert (interface != NULL);
1704   g_assert (signal != NULL);
1705
1706   name = create_signal_name (interface, signal);
1707
1708   /* If the quark isn't preexisting, there's no way there
1709    * are any handlers connected. We don't want to create
1710    * extra quarks for every possible signal.
1711    */
1712   q = g_quark_try_string (name);
1713
1714   if (q != 0)
1715     {
1716       GArray *gsignature;
1717       guint i;
1718       
1719       gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
1720       if (gsignature == NULL)
1721         goto out;
1722       
1723       msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
1724                                                        TRUE);
1725       for (i = 0; i < gsignature->len; i++)
1726         {
1727           if (msg_gsignature->len == i
1728               || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
1729             goto mismatch;
1730         }
1731       if (msg_gsignature->len != i)
1732         goto mismatch;
1733       
1734       g_signal_emit (proxy,
1735                      signals[RECEIVED],
1736                      q,
1737                      message,
1738                      msg_gsignature);
1739     }
1740
1741  out:
1742   g_free (name);
1743   if (msg_gsignature)
1744     g_array_free (msg_gsignature, TRUE);
1745   return;
1746  mismatch:
1747 #if 0
1748   /* Don't spew on remote errors */
1749   g_warning ("Unexpected message signature '%s' for signal '%s'\n",
1750              dbus_message_get_signature (message),
1751              name);
1752 #endif
1753   goto out;
1754 }
1755
1756 typedef struct
1757 {
1758   DBusGProxy *proxy;
1759   guint call_id;
1760   DBusGProxyCallNotify func;
1761   void *data;
1762   GDestroyNotify free_data_func;
1763 } GPendingNotifyClosure;
1764
1765 static void
1766 d_pending_call_notify (DBusPendingCall *dcall,
1767                        void            *data)
1768 {
1769   GPendingNotifyClosure *closure = data;
1770
1771   (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
1772 }
1773
1774 static void
1775 d_pending_call_free (void *data)
1776 {
1777   GPendingNotifyClosure *closure = data;
1778   
1779   if (closure->free_data_func)
1780     (* closure->free_data_func) (closure->data);
1781
1782   g_free (closure);
1783 }
1784   
1785 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
1786 do { \
1787   GType valtype; \
1788   int i = 0; \
1789   VALARRAY = g_value_array_new (6); \
1790   valtype = FIRST_ARG_TYPE; \
1791   while (valtype != G_TYPE_INVALID) \
1792     { \
1793       const char *collect_err; \
1794       GValue *val; \
1795       g_value_array_append (VALARRAY, NULL); \
1796       val = g_value_array_get_nth (VALARRAY, i); \
1797       g_value_init (val, valtype); \
1798       collect_err = NULL; \
1799       G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
1800       valtype = va_arg (ARGS, GType); \
1801       i++; \
1802     } \
1803 } while (0)
1804
1805 DBusGProxyCall *
1806 manager_begin_bus_call (DBusGProxyManager    *manager,
1807                         const char           *method,
1808                         DBusGProxyCallNotify  notify,
1809                         gpointer              user_data,
1810                         GDestroyNotify        destroy,
1811                         GType                 first_arg_type,
1812                         ...)
1813 {
1814   DBusGProxyCall *call;
1815   DBusGProxyPrivate *priv;
1816   va_list args;
1817   GValueArray *arg_values;
1818   
1819   va_start (args, first_arg_type);
1820
1821   if (!manager->bus_proxy)
1822     {
1823       manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
1824                                          "name", DBUS_SERVICE_DBUS,
1825                                          "path", DBUS_PATH_DBUS,
1826                                          "interface", DBUS_INTERFACE_DBUS,
1827                                          NULL);
1828       priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
1829       priv->manager = manager;
1830     }
1831
1832   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
1833   
1834   call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values,-1));
1835
1836   g_value_array_free (arg_values);
1837
1838   va_end (args);
1839
1840   return call;
1841 }
1842
1843 /** @} End of DBusGLibInternals */
1844
1845 /** @addtogroup DBusGLib
1846  * @{
1847  */
1848
1849 /**
1850  * SECTION:dbus-gproxy
1851  * @short_description: DBus Proxy
1852  * @see_also: #DBusProxy
1853  * @stability: Stable
1854  *
1855  * A #DBusGProxy is a boxed type abstracting a #DBusProxy.
1856  */
1857
1858 /**
1859  * dbus_g_proxy_get_type:
1860  * Standard GObject get_type() function for DBusGProxy.
1861  *
1862  * Returns: type ID for DBusGProxy class
1863  */
1864 GType
1865 dbus_g_proxy_get_type (void)
1866 {
1867   static GType object_type = 0;
1868
1869   if (!object_type)
1870     {
1871       static const GTypeInfo object_info =
1872         {
1873           sizeof (DBusGProxyClass),
1874           (GBaseInitFunc) NULL,
1875           (GBaseFinalizeFunc) NULL,
1876           (GClassInitFunc) dbus_g_proxy_class_init,
1877           NULL,           /* class_finalize */
1878           NULL,           /* class_data */
1879           sizeof (DBusGProxy),
1880           0,              /* n_preallocs */
1881           (GInstanceInitFunc) dbus_g_proxy_init,
1882         };
1883       
1884       object_type = g_type_register_static (G_TYPE_OBJECT,
1885                                             "DBusGProxy",
1886                                             &object_info, 0);
1887     }
1888   
1889   return object_type;
1890 }
1891
1892 static DBusGProxy*
1893 dbus_g_proxy_new (DBusGConnection *connection,
1894                   const char      *name,
1895                   const char      *path_name,
1896                   const char      *interface_name)
1897 {
1898   DBusGProxy *proxy;
1899
1900   g_assert (connection != NULL);
1901   
1902   proxy = g_object_new (DBUS_TYPE_G_PROXY, 
1903                         "name", name, 
1904                         "path", path_name, 
1905                         "interface", interface_name, 
1906                         "connection", connection, NULL);
1907
1908   return proxy;
1909 }
1910
1911 /**
1912  * dbus_g_proxy_new_for_name:
1913  * @connection: the connection to the remote bus
1914  * @name: any name on the message bus
1915  * @path_name: name of the object instance to call methods on
1916  * @interface_name: name of the interface to call methods on
1917  *
1918  * Creates a new proxy for a remote interface exported by a connection
1919  * on a message bus. Method calls and signal connections over this
1920  * proxy will go to the name owner; the name's owner is expected to
1921  * support the given interface name. THE NAME OWNER MAY CHANGE OVER
1922  * TIME, for example between two different method calls, unless the
1923  * name is a unique name. If you need a fixed owner, you need to
1924  * request the current owner and bind a proxy to its unique name
1925  * rather than to the generic name; see
1926  * dbus_g_proxy_new_for_name_owner().
1927  *
1928  * A name-associated proxy only makes sense with a message bus, not
1929  * for app-to-app direct dbus connections.
1930  *
1931  * This proxy will only emit the "destroy" signal if the
1932  * #DBusConnection is disconnected, the proxy has no remaining
1933  * references, or the name is a unique name and its owner
1934  * disappears. If a well-known name changes owner, the proxy will
1935  * still be alive.
1936  *
1937  * Returns: new proxy object
1938  */
1939 DBusGProxy*
1940 dbus_g_proxy_new_for_name (DBusGConnection *connection,
1941                            const char      *name,
1942                            const char      *path_name,
1943                            const char      *interface_name)
1944 {
1945   g_return_val_if_fail (connection != NULL, NULL);
1946   g_return_val_if_fail (name != NULL, NULL);
1947   g_return_val_if_fail (path_name != NULL, NULL);
1948   g_return_val_if_fail (interface_name != NULL, NULL);
1949
1950   return dbus_g_proxy_new (connection, name,
1951                            path_name, interface_name);
1952 }
1953
1954 /**
1955  * dbus_g_proxy_new_for_name_owner:
1956  * @connection: the connection to the remote bus
1957  * @name: any name on the message bus
1958  * @path_name: name of the object inside the service to call methods on
1959  * @interface_name: name of the interface to call methods on
1960  * @error: return location for an error
1961  *
1962  * Similar to dbus_g_proxy_new_for_name(), but makes a round-trip
1963  * request to the message bus to get the current name owner, then
1964  * binds the proxy to the unique name of the current owner, rather
1965  * than to the well-known name. As a result, the name owner will
1966  * not change over time, and the proxy will emit the "destroy" signal
1967  * when the owner disappears from the message bus.
1968  *
1969  * An example of the difference between dbus_g_proxy_new_for_name()
1970  * and dbus_g_proxy_new_for_name_owner(): if you provide the well-known name
1971  * "org.freedesktop.Database" dbus_g_proxy_new_for_name() remains bound
1972  * to that name as it changes owner. dbus_g_proxy_new_for_name_owner()
1973  * will fail if the name has no owner. If the name has an owner,
1974  * dbus_g_proxy_new_for_name_owner() will bind to the unique name
1975  * of that owner rather than the generic name.
1976  * 
1977  * Returns: new proxy object, or #NULL on error
1978  */
1979 DBusGProxy*
1980 dbus_g_proxy_new_for_name_owner (DBusGConnection          *connection,
1981                                  const char               *name,
1982                                  const char               *path_name,
1983                                  const char               *interface_name,
1984                                  GError                  **error)
1985 {
1986   DBusGProxy *proxy;
1987   char *unique_name;
1988
1989   g_return_val_if_fail (connection != NULL, NULL);
1990   g_return_val_if_fail (name != NULL, NULL);
1991   g_return_val_if_fail (path_name != NULL, NULL);
1992   g_return_val_if_fail (interface_name != NULL, NULL);
1993
1994   if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
1995     return NULL;
1996
1997   proxy = dbus_g_proxy_new (connection, unique_name,
1998                             path_name, interface_name);
1999   g_free (unique_name);
2000   return proxy;
2001 }
2002
2003 /**
2004  * dbus_g_proxy_new_from_proxy:
2005  * @proxy: the proxy to use as a template
2006  * @path: of the object inside the peer to call methods on
2007  * @interface: name of the interface to call methods on
2008  *
2009  * Creates a proxy using an existing proxy as a template, substituting
2010  * the specified interface and path.  Either or both may be NULL.
2011  *
2012  * Returns: new proxy object
2013  */
2014 DBusGProxy*
2015 dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
2016                              const char        *interface,
2017                              const char        *path)
2018 {
2019   DBusGProxyPrivate *priv;
2020
2021   g_return_val_if_fail (proxy != NULL, NULL);
2022
2023   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2024   
2025   if (interface == NULL)
2026     interface = priv->interface;
2027   if (path == NULL)
2028     path = priv->path;
2029
2030   return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
2031                            priv->name,
2032                            path, interface);
2033 }
2034
2035 /**
2036  * dbus_g_proxy_new_for_peer:
2037  * @connection: the connection to the peer
2038  * @path_name: name of the object inside the peer to call methods on
2039  * @interface_name: name of the interface to call methods on
2040  *
2041  * Creates a proxy for an object in peer application (one
2042  * we're directly connected to). That is, this function is
2043  * intended for use when there's no message bus involved,
2044  * we're doing a simple 1-to-1 communication between two
2045  * applications.
2046  *
2047  * Returns: new proxy object
2048  */
2049 DBusGProxy*
2050 dbus_g_proxy_new_for_peer (DBusGConnection          *connection,
2051                            const char               *path_name,
2052                            const char               *interface_name)
2053 {
2054   DBusGProxy *proxy;
2055   
2056   g_return_val_if_fail (connection != NULL, NULL);
2057   g_return_val_if_fail (path_name != NULL, NULL);
2058   g_return_val_if_fail (interface_name != NULL, NULL);
2059
2060   proxy = dbus_g_proxy_new (connection, NULL,
2061                             path_name, interface_name);
2062
2063   return proxy;
2064 }
2065
2066 /**
2067  * dbus_g_proxy_get_bus_name:
2068  * @proxy: the proxy
2069  *
2070  * Gets the bus name a proxy is bound to (may be #NULL in some cases).
2071  * If you created the proxy with dbus_g_proxy_new_for_name(), then
2072  * the name you passed to that will be returned.
2073  * If you created it with dbus_g_proxy_new_for_name_owner(), then the
2074  * unique connection name will be returned. If you created it
2075  * with dbus_g_proxy_new_for_peer() then #NULL will be returned.
2076  *
2077  * Returns: the bus name the proxy sends messages to
2078  */
2079 const char*
2080 dbus_g_proxy_get_bus_name (DBusGProxy        *proxy)
2081 {
2082   DBusGProxyPrivate *priv;
2083
2084   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2085   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2086
2087   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2088
2089   return priv->name;
2090 }
2091
2092 /**
2093  * dbus_g_proxy_get_interface:
2094  * @proxy: the proxy
2095  *
2096  * Gets the object interface proxy is bound to (may be #NULL in some cases).
2097  *
2098  * Returns: an object interface 
2099  */
2100 const char*
2101 dbus_g_proxy_get_interface (DBusGProxy        *proxy)
2102 {
2103   DBusGProxyPrivate *priv;
2104   
2105   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2106   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2107
2108   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2109
2110   return priv->interface;
2111 }
2112
2113 /**
2114  * dbus_g_proxy_set_interface:
2115  * @proxy: the proxy
2116  * @interface_name: an object interface 
2117  *
2118  * Sets the object interface proxy is bound to
2119  */
2120 void
2121 dbus_g_proxy_set_interface (DBusGProxy        *proxy,
2122                             const char        *interface_name)
2123 {
2124   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2125   /* FIXME - need to unregister when we switch interface for now
2126    * later should support idea of unset interface
2127    */
2128   dbus_g_proxy_manager_unregister (priv->manager, proxy);
2129   g_free (priv->interface);
2130   priv->interface = g_strdup (interface_name);
2131   dbus_g_proxy_manager_register (priv->manager, proxy);
2132 }
2133
2134 /**
2135  * dbus_g_proxy_get_path:
2136  * Gets the path this proxy is bound to
2137  * @proxy: the proxy
2138  *
2139  * Returns: an object path
2140  */
2141 const char*
2142 dbus_g_proxy_get_path (DBusGProxy        *proxy)
2143 {
2144   DBusGProxyPrivate *priv;
2145   
2146   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2147   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2148
2149   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2150
2151   return priv->path;
2152 }
2153
2154 static DBusMessage *
2155 dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
2156                                       const char  *method,
2157                                       GValueArray *args)
2158 {
2159   DBusMessage *message;
2160   DBusMessageIter msgiter;
2161   guint i;
2162   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2163
2164   message = dbus_message_new_method_call (priv->name,
2165                                           priv->path,
2166                                           priv->interface,
2167                                           method);
2168   if (message == NULL)
2169     goto oom;
2170
2171   dbus_message_iter_init_append (message, &msgiter);
2172   for (i = 0; i < args->n_values; i++)
2173     {
2174       GValue *gvalue;
2175
2176       gvalue = g_value_array_get_nth (args, i);
2177
2178       if (!_dbus_gvalue_marshal (&msgiter, gvalue))
2179         g_assert_not_reached ();
2180     }
2181   return message;
2182  oom:
2183   return NULL;
2184 }
2185
2186 static guint
2187 dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
2188                                   const char          *method,
2189                                   DBusGProxyCallNotify notify,
2190                                   gpointer             user_data,
2191                                   GDestroyNotify       destroy,
2192                                   GValueArray         *args,
2193                                   int timeout)
2194 {
2195   DBusMessage *message;
2196   DBusPendingCall *pending;
2197   GPendingNotifyClosure *closure;
2198   guint call_id;
2199   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2200
2201   pending = NULL;
2202
2203   message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
2204   if (!message)
2205     goto oom;
2206
2207   if (!dbus_connection_send_with_reply (priv->manager->connection,
2208                                         message,
2209                                         &pending,
2210                                         timeout))
2211     goto oom;
2212   dbus_message_unref (message);
2213   
2214   /* If we got a NULL pending, that means the connection was disconnected,
2215    * and we need to abort this call.  
2216    * https://bugs.freedesktop.org/show_bug.cgi?id=12675
2217    */
2218   if (pending == NULL)
2219     return 0;
2220
2221   call_id = ++priv->call_id_counter;
2222
2223   if (notify != NULL)
2224     {
2225       closure = g_new (GPendingNotifyClosure, 1);
2226       closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
2227       closure->call_id = call_id;
2228       closure->func = notify;
2229       closure->data = user_data;
2230       closure->free_data_func = destroy;
2231       dbus_pending_call_set_notify (pending, d_pending_call_notify,
2232                                     closure,
2233                                     d_pending_call_free);
2234     }
2235
2236   g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
2237
2238   return call_id;
2239  oom:
2240   g_error ("Out of memory");
2241   return 0;
2242 }
2243
2244 static gboolean
2245 dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
2246                                 guint              call_id,
2247                                 GError           **error,
2248                                 GType              first_arg_type,
2249                                 va_list            args)
2250 {
2251   DBusMessage *reply;
2252   DBusMessageIter msgiter;
2253   DBusError derror;
2254   va_list args_unwind;
2255   guint over;
2256   int n_retvals_processed;
2257   gboolean ret;
2258   GType valtype;
2259   DBusPendingCall *pending;
2260   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2261
2262   reply = NULL;
2263   ret = FALSE;
2264   n_retvals_processed = 0;
2265   over = 0;
2266
2267   /* Keep around a copy of output arguments so we can free on error. */
2268   G_VA_COPY(args_unwind, args);
2269
2270   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
2271   
2272   dbus_pending_call_block (pending);
2273   reply = dbus_pending_call_steal_reply (pending);
2274
2275   g_assert (reply != NULL);
2276
2277   dbus_error_init (&derror);
2278
2279   switch (dbus_message_get_type (reply))
2280     {
2281     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
2282       dbus_message_iter_init (reply, &msgiter);
2283       valtype = first_arg_type;
2284       while (valtype != G_TYPE_INVALID)
2285         {
2286           int arg_type;
2287           gpointer return_storage;
2288           GValue gvalue = { 0, };
2289           DBusGValueMarshalCtx context;
2290
2291           context.recursion_depth = 0;
2292           context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
2293           context.proxy = proxy;
2294
2295           arg_type = dbus_message_iter_get_arg_type (&msgiter);
2296           if (arg_type == DBUS_TYPE_INVALID)
2297             {
2298               g_set_error (error, DBUS_GERROR,
2299                            DBUS_GERROR_INVALID_ARGS,
2300                            _("Too few arguments in reply"));
2301               goto out;
2302             }
2303
2304           return_storage = va_arg (args, gpointer);
2305           if (return_storage == NULL)
2306             goto next;
2307
2308           /* We handle variants specially; the caller is expected
2309            * to have already allocated storage for them.
2310            */
2311           if (arg_type == DBUS_TYPE_VARIANT
2312               && g_type_is_a (valtype, G_TYPE_VALUE))
2313             {
2314               if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
2315                 {
2316                   g_set_error (error,
2317                                DBUS_GERROR,
2318                                DBUS_GERROR_INVALID_ARGS,
2319                                _("Couldn't convert argument, expected \"%s\""),
2320                                g_type_name (valtype));
2321                   goto out;
2322                 }
2323             }
2324           else
2325             {
2326               g_value_init (&gvalue, valtype);
2327
2328               if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
2329                 goto out;
2330
2331               /* Anything that can be demarshaled must be storable */
2332               if (!_dbus_gvalue_store (&gvalue, return_storage))
2333                 g_assert_not_reached ();
2334               /* Ownership of the value passes to the client, don't unset */
2335             }
2336           
2337         next:
2338           n_retvals_processed++;
2339           dbus_message_iter_next (&msgiter);
2340           valtype = va_arg (args, GType);
2341         }
2342       
2343       while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
2344         {
2345           over++;
2346           dbus_message_iter_next (&msgiter);
2347         }
2348
2349       if (over > 0)
2350         {
2351           g_set_error (error, DBUS_GERROR,
2352                        DBUS_GERROR_INVALID_ARGS,
2353                        _("Too many arguments in reply; expected %d, got %d"),
2354                        n_retvals_processed, over);
2355           goto out;
2356         }
2357       break;
2358     case DBUS_MESSAGE_TYPE_ERROR:
2359       dbus_set_error_from_message (&derror, reply);
2360       dbus_set_g_error (error, &derror);
2361       dbus_error_free (&derror);
2362       goto out;
2363       break;
2364     default:
2365       dbus_set_error (&derror, DBUS_ERROR_FAILED,
2366                       "Reply was neither a method return nor an exception");
2367       dbus_set_g_error (error, &derror);
2368       dbus_error_free (&derror);
2369       goto out;
2370       break;
2371     }
2372
2373   ret = TRUE;
2374  out:
2375   if (ret == FALSE)
2376     {
2377       int i;
2378
2379       valtype = first_arg_type;
2380       for (i = 0; i < n_retvals_processed; i++)
2381         {
2382           GValue value = {0,};
2383           gpointer retval;
2384
2385           g_value_init (&value, valtype);
2386
2387           retval = va_arg (args_unwind, gpointer);
2388           if (retval == NULL)
2389             {
2390               i--;
2391               continue;
2392             }
2393             
2394           _dbus_gvalue_take (&value, retval);
2395           g_value_unset (&value);
2396
2397           valtype = va_arg (args_unwind, GType);
2398         }
2399     }
2400   va_end (args_unwind);
2401   va_end (args);
2402
2403   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
2404
2405   if (reply)
2406     dbus_message_unref (reply);
2407   return ret;
2408 }
2409
2410 /**
2411  * dbus_g_proxy_begin_call:
2412  * @proxy: a proxy for a remote interface
2413  * @method: the name of the method to invoke
2414  * @notify: callback to be invoked when method returns
2415  * @user_data: user data passed to callback
2416  * @destroy: function called to destroy user_data
2417  * @first_arg_type: type of the first argument
2418  *
2419  * Asynchronously invokes a method on a remote interface. The method
2420  * call will not be sent over the wire until the application returns
2421  * to the main loop, or blocks in dbus_g_connection_flush() to write out
2422  * pending data.  The call will be completed after a timeout, or when
2423  * a reply is received.  When the call returns, the callback specified
2424  * will be invoked; you can then collect the results of the call
2425  * (which may be an error, or a reply), use dbus_g_proxy_end_call().
2426  *
2427  * TODO this particular function shouldn't die on out of memory,
2428  * since you should be able to do a call with large arguments.
2429  * 
2430  * Returns: call identifier.
2431  */
2432 DBusGProxyCall *
2433 dbus_g_proxy_begin_call (DBusGProxy          *proxy,
2434                          const char          *method,
2435                          DBusGProxyCallNotify notify,
2436                          gpointer             user_data,
2437                          GDestroyNotify       destroy,
2438                          GType                first_arg_type,
2439                          ...)
2440 {
2441   guint call_id;
2442   va_list args;
2443   GValueArray *arg_values;
2444   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2445   
2446   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2447   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2448
2449   va_start (args, first_arg_type);
2450
2451   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
2452   
2453   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values, priv->default_timeout);
2454
2455   g_value_array_free (arg_values);
2456
2457   va_end (args);
2458
2459   return DBUS_G_PROXY_ID_TO_CALL (call_id);
2460 }
2461
2462 /**
2463  * dbus_g_proxy_begin_call_with_timeout:
2464  * @proxy: a proxy for a remote interface
2465  * @method: the name of the method to invoke
2466  * @notify: callback to be invoked when method returns
2467  * @user_data: user data passed to callback
2468  * @destroy: function called to destroy user_data
2469  * @timeout: specify the timeout in milliseconds
2470  * @first_arg_type: type of the first argument
2471  *
2472  * Asynchronously invokes a method on a remote interface. The method
2473  * call will not be sent over the wire until the application returns
2474  * to the main loop, or blocks in dbus_g_connection_flush() to write out
2475  * pending data.  The call will be completed after a timeout, or when
2476  * a reply is received.  When the call returns, the callback specified
2477  * will be invoked; you can then collect the results of the call
2478  * (which may be an error, or a reply), use dbus_g_proxy_end_call().
2479  *
2480  * TODO this particular function shouldn't die on out of memory,
2481  * since you should be able to do a call with large arguments.
2482  *
2483  * Returns: call identifier.
2484  */
2485 DBusGProxyCall *
2486 dbus_g_proxy_begin_call_with_timeout (DBusGProxy          *proxy,
2487                          const char          *method,
2488                          DBusGProxyCallNotify notify,
2489                          gpointer             user_data,
2490                          GDestroyNotify       destroy,
2491                          int timeout,
2492                          GType                first_arg_type,
2493                          ...)
2494 {
2495   guint call_id;
2496   va_list args;
2497   GValueArray *arg_values;
2498
2499   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2500   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2501
2502   va_start (args, first_arg_type);
2503
2504   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
2505
2506   call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values,timeout);
2507
2508   g_value_array_free (arg_values);
2509
2510   va_end (args);
2511
2512   return DBUS_G_PROXY_ID_TO_CALL (call_id);
2513 }
2514
2515 /**
2516  * dbus_g_proxy_end_call:
2517  * @proxy: a proxy for a remote interface
2518  * @call: the pending call ID from dbus_g_proxy_begin_call()
2519  * @error: return location for an error
2520  * @first_arg_type: type of first "out" argument
2521  *
2522  * Collects the results of a method call. The method call was normally
2523  * initiated with dbus_g_proxy_end_call(). You may use this function
2524  * outside of the callback given to dbus_g_proxy_begin_call; in that
2525  * case this function will block if the results haven't yet been
2526  * received.
2527  *
2528  * If the call results in an error, the error is set as normal for
2529  * GError and the function returns #FALSE.
2530  *
2531  * Otherwise, the "out" parameters and return value of the
2532  * method are stored in the provided varargs list.
2533  * The list should be terminated with G_TYPE_INVALID.
2534  *
2535  * Returns: #FALSE if an error is set.
2536  */
2537 gboolean
2538 dbus_g_proxy_end_call (DBusGProxy          *proxy,
2539                        DBusGProxyCall      *call,
2540                        GError             **error,
2541                        GType                first_arg_type,
2542                        ...)
2543 {
2544   gboolean ret;
2545   va_list args;
2546
2547   va_start (args, first_arg_type);
2548
2549   ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
2550
2551   va_end (args);
2552   
2553   return ret;
2554 }
2555
2556 /**
2557  * dbus_g_proxy_call:
2558  * @proxy: a proxy for a remote interface
2559  * @method: method to invoke
2560  * @error: return location for an error
2561  * @first_arg_type: type of first "in" argument
2562  *
2563  * Function for synchronously invoking a method and receiving reply
2564  * values.  This function is equivalent to dbus_g_proxy_begin_call
2565  * followed by dbus_g_proxy_end_call.  All of the input arguments are
2566  * specified first, followed by G_TYPE_INVALID, followed by all of the
2567  * output values, followed by a second G_TYPE_INVALID.  Note that  
2568  * this means you must always specify G_TYPE_INVALID twice.
2569  *
2570  * Returns: #FALSE if an error is set, #TRUE otherwise.
2571  */
2572 gboolean
2573 dbus_g_proxy_call (DBusGProxy        *proxy,
2574                    const char        *method,
2575                    GError           **error,
2576                    GType              first_arg_type,
2577                    ...)
2578 {
2579   gboolean ret;
2580   guint call_id;
2581   va_list args;
2582   GValueArray *in_args;
2583   DBusGProxyPrivate *priv;
2584
2585   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2586   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
2587
2588   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2589
2590   va_start (args, first_arg_type);
2591
2592   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2593
2594   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args, priv->default_timeout);
2595
2596   g_value_array_free (in_args);
2597
2598   if (call_id > 0)
2599     {
2600       first_arg_type = va_arg (args, GType);
2601       ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
2602     }
2603   else
2604     {
2605       g_set_error (error, DBUS_GERROR,
2606                    DBUS_GERROR_FAILED,
2607                    _("Disconnection or out-of-memory"));
2608       ret = FALSE;
2609     }
2610
2611   va_end (args);
2612
2613   return ret;
2614 }
2615
2616 /**
2617  * dbus_g_proxy_call_with_timeout:
2618  * @proxy: a proxy for a remote interface
2619  * @method: method to invoke
2620  * @timeout: specify the timeout in milliseconds
2621  * @error: return location for an error
2622  * @first_arg_type: type of first "in" argument
2623  *
2624  * Function for synchronously invoking a method and receiving reply
2625  * values.  This function is equivalent to dbus_g_proxy_begin_call
2626  * followed by dbus_g_proxy_end_call.  All of the input arguments are
2627  * specified first, followed by G_TYPE_INVALID, followed by all of the
2628  * output values, followed by a second G_TYPE_INVALID.  Note that
2629  * this means you must always specify G_TYPE_INVALID twice.
2630  *
2631  * Returns: #FALSE if an error is set, #TRUE otherwise.
2632  */
2633 gboolean
2634 dbus_g_proxy_call_with_timeout (DBusGProxy        *proxy,
2635                    const char        *method,
2636                    int timeout,
2637                    GError           **error,
2638                    GType              first_arg_type,
2639                    ...)
2640 {
2641   gboolean ret;
2642   guint call_id;
2643   va_list args;
2644   GValueArray *in_args;
2645
2646   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2647   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
2648
2649   va_start (args, first_arg_type);
2650
2651   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2652
2653   call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args,timeout);
2654
2655   g_value_array_free (in_args);
2656
2657   first_arg_type = va_arg (args, GType);
2658   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
2659
2660   va_end (args);
2661
2662   return ret;
2663 }
2664
2665 /**
2666  * dbus_g_proxy_call_no_reply:
2667  * @proxy: a proxy for a remote interface
2668  * @method: the name of the method to invoke
2669  * @first_arg_type: type of the first argument
2670  *
2671  * Sends a method call message as with dbus_g_proxy_begin_call(), but
2672  * does not ask for a reply or allow you to receive one.
2673  *
2674  * TODO: this particular function shouldn't die on out of memory,
2675  * since you should be able to do a call with large arguments.
2676  */
2677 void
2678 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
2679                             const char               *method,
2680                             GType                     first_arg_type,
2681                             ...)
2682 {
2683   DBusMessage *message;
2684   va_list args;
2685   GValueArray *in_args;
2686   DBusGProxyPrivate *priv;
2687   
2688   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2689   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2690
2691   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2692
2693   va_start (args, first_arg_type);
2694   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2695
2696   message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
2697
2698   g_value_array_free (in_args);
2699   va_end (args);
2700
2701   if (!message)
2702     goto oom;
2703
2704   dbus_message_set_no_reply (message, TRUE);
2705
2706   if (!dbus_connection_send (priv->manager->connection,
2707                              message,
2708                              NULL))
2709     goto oom;
2710   dbus_message_unref (message);
2711   return;
2712   
2713  oom:
2714   g_error ("Out of memory");
2715 }
2716
2717 /**
2718  * dbus_g_proxy_cancel_call
2719  * @proxy: a proxy for a remote interface
2720  * @call: the pending call ID from dbus_g_proxy_begin_call()
2721  *
2722  * Cancels a pending method call. The method call was normally
2723  * initiated with dbus_g_proxy_begin_call().  This function
2724  * may not be used on pending calls that have already been
2725  * ended with dbus_g_proxy_end_call.
2726  */
2727 void
2728 dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
2729                           DBusGProxyCall    *call)
2730 {
2731   guint call_id;
2732   DBusPendingCall *pending;
2733   DBusGProxyPrivate *priv;
2734   
2735   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2736   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2737
2738   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2739
2740   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
2741
2742   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
2743   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
2744   g_return_if_fail (pending != NULL);
2745
2746   dbus_pending_call_cancel (pending);
2747 }
2748
2749 /**
2750  * dbus_g_proxy_send:
2751  * @proxy: a proxy for a remote interface
2752  * @message: the message to address and send
2753  * @client_serial: return location for message's serial, or #NULL 
2754  *
2755  * Sends a message to the interface we're proxying for.  Does not
2756  * block or wait for a reply. The message is only actually written out
2757  * when you return to the main loop or block in
2758  * dbus_g_connection_flush().
2759  *
2760  * The message is modified to be addressed to the target interface.
2761  * That is, a destination name field or whatever is needed will be
2762  * added to the message. The basic point of this function is to add
2763  * the necessary header fields, otherwise it's equivalent to
2764  * dbus_connection_send().
2765  *
2766  * This function adds a reference to the message, so the caller
2767  * still owns its original reference.
2768  */
2769 void
2770 dbus_g_proxy_send (DBusGProxy          *proxy,
2771                    DBusMessage         *message,
2772                    dbus_uint32_t       *client_serial)
2773 {
2774   DBusGProxyPrivate *priv;
2775   
2776   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2777   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2778   
2779   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2780   
2781   if (priv->name)
2782     {
2783       if (!dbus_message_set_destination (message, priv->name))
2784         g_error ("Out of memory");
2785     }
2786   if (priv->path)
2787     {
2788       if (!dbus_message_set_path (message, priv->path))
2789         g_error ("Out of memory");
2790     }
2791   if (priv->interface)
2792     {
2793       if (!dbus_message_set_interface (message, priv->interface))
2794         g_error ("Out of memory");
2795     }
2796   
2797   if (!dbus_connection_send (priv->manager->connection, message, client_serial))
2798     g_error ("Out of memory\n");
2799 }
2800
2801 static void
2802 array_free_all (gpointer array)
2803 {
2804   g_array_free (array, TRUE);
2805 }
2806
2807 /**
2808  * dbus_g_proxy_add_signal:
2809  * @proxy: the proxy for a remote interface
2810  * @signal_name: the name of the signal
2811  * @first_type: the first argument type, or G_TYPE_INVALID if none
2812  *
2813  * Specifies the argument signature of a signal;.only necessary
2814  * if the remote object does not support introspection.  The arguments
2815  * specified are the GLib types expected.
2816  */
2817 void
2818 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
2819                           const char        *signal_name,
2820                           GType              first_type,
2821                           ...)
2822 {
2823   GQuark q;
2824   char *name;
2825   GArray *gtypesig;
2826   GType gtype;
2827   va_list args;
2828   DBusGProxyPrivate *priv;
2829
2830   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2831   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2832   g_return_if_fail (signal_name != NULL);
2833   
2834   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2835
2836   name = create_signal_name (priv->interface, signal_name);
2837   
2838   q = g_quark_from_string (name);
2839   
2840   g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
2841
2842   gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
2843
2844   va_start (args, first_type);
2845   gtype = first_type;
2846   while (gtype != G_TYPE_INVALID)
2847     {
2848       g_array_append_val (gtypesig, gtype);
2849       gtype = va_arg (args, GType);
2850     }
2851   va_end (args);
2852
2853 #ifndef G_DISABLE_CHECKS
2854   if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
2855     g_warning ("No marshaller for signature of signal '%s'", signal_name);
2856 #endif
2857
2858   
2859   g_datalist_id_set_data_full (&priv->signal_signatures,
2860                                q, gtypesig,
2861                                array_free_all);
2862
2863   g_free (name);
2864 }
2865
2866 /**
2867  * dbus_g_proxy_connect_signal:
2868  * @proxy: a proxy for a remote interface
2869  * @signal_name: the DBus signal name to listen for
2870  * @handler: the handler to connect
2871  * @data: data to pass to handler
2872  * @free_data_func: callback function to destroy data
2873  *
2874  * Connect a signal handler to a proxy for a remote interface.  When
2875  * the remote interface emits the specified signal, the proxy will
2876  * emit a corresponding GLib signal.
2877  */
2878 void
2879 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
2880                              const char             *signal_name,
2881                              GCallback               handler,
2882                              void                   *data,
2883                              GClosureNotify          free_data_func)
2884 {
2885   char *name;
2886   GClosure *closure;
2887   GQuark q;
2888   DBusGProxyPrivate *priv;
2889
2890   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2891   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2892   g_return_if_fail (signal_name != NULL);
2893   g_return_if_fail (handler != NULL);
2894   
2895   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2896   name = create_signal_name (priv->interface, signal_name);
2897
2898   q = g_quark_try_string (name);
2899
2900 #ifndef G_DISABLE_CHECKS
2901   if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
2902     {
2903       g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
2904       g_free (name);
2905       return;
2906     }
2907 #endif
2908   
2909   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
2910   
2911   g_signal_connect_closure_by_id (G_OBJECT (proxy),
2912                                   signals[RECEIVED],
2913                                   q,
2914                                   closure, FALSE);
2915   
2916   g_free (name);
2917 }
2918
2919 /**
2920  * dbus_g_proxy_disconnect_signal:
2921  * @proxy: a proxy for a remote interface
2922  * @signal_name: the DBus signal name to disconnect
2923  * @handler: the handler to disconnect
2924  * @data: the data that was registered with handler
2925  *
2926  * Disconnect all signal handlers from a proxy that match the given
2927  * criteria.
2928  */
2929 void
2930 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
2931                                 const char             *signal_name,
2932                                 GCallback               handler,
2933                                 void                   *data)
2934 {
2935   char *name;
2936   GQuark q;
2937   DBusGProxyPrivate *priv;
2938   
2939   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2940   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2941   g_return_if_fail (signal_name != NULL);
2942   g_return_if_fail (handler != NULL);
2943
2944   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2945   name = create_signal_name (priv->interface, signal_name);
2946
2947   q = g_quark_try_string (name);
2948   
2949   if (q != 0)
2950     {
2951       g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
2952                                             G_SIGNAL_MATCH_DETAIL |
2953                                             G_SIGNAL_MATCH_FUNC   |
2954                                             G_SIGNAL_MATCH_DATA,
2955                                             signals[RECEIVED],
2956                                             q,
2957                                             NULL,
2958                                             G_CALLBACK (handler), data);
2959     }
2960   else
2961     {
2962       g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
2963                  name);
2964     }
2965
2966   g_free (name);
2967 }
2968
2969 /**
2970  * dbus_g_proxy_set_default_timeout:
2971  * @proxy: a proxy for a remote interface
2972  * @timeout: specify the timeout in milliseconds
2973  *
2974  * Sets the default timeout to use for a proxy. This timeout will be
2975  * used in calls where the timeout is not specified.
2976  *
2977  * This is useful for long-running operations that takes longer than
2978  * the default timeout (which is a on the order of magnitude of tens
2979  * of seconds). For some applications, consider using a pattern where
2980  * the method returns once the operation is underway
2981  * (e.g. immediately) and emits a signal when the operation terminates
2982  * (though beware of leaking information with/in the signal return value).
2983  *
2984  * Since: 0.75
2985  */
2986 void
2987 dbus_g_proxy_set_default_timeout (DBusGProxy        *proxy,
2988                                   int                timeout)
2989 {
2990   DBusGProxyPrivate *priv;
2991
2992   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2993   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2994
2995   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2996   priv->default_timeout = timeout;
2997 }
2998
2999
3000 /** @} End of DBusGLib public */
3001
3002 #ifdef DBUS_BUILD_TESTS
3003
3004 /**
3005  * @ingroup DBusGLibInternals
3006  * Unit test for GLib proxy functions
3007  * Returns: #TRUE on success.
3008  */
3009 gboolean
3010 _dbus_g_proxy_test (void)
3011 {
3012   
3013   
3014   return TRUE;
3015 }
3016
3017 #endif /* DBUS_BUILD_TESTS */