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