00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <dbus/dbus-glib.h>
00025 #include <dbus/dbus-glib-lowlevel.h>
00026 #include <dbus/dbus-signature.h>
00027 #include "dbus-gutils.h"
00028 #include "dbus-gsignature.h"
00029 #include "dbus-gvalue.h"
00030 #include "dbus-gvalue-utils.h"
00031 #include "dbus-gobject.h"
00032 #include <string.h>
00033 #include <glib/gi18n.h>
00034 #include <gobject/gvaluecollector.h>
00035
00036 #define DBUS_G_PROXY_CALL_TO_ID(x) (GPOINTER_TO_UINT(x))
00037 #define DBUS_G_PROXY_ID_TO_CALL(x) (GUINT_TO_POINTER(x))
00038
00049 typedef struct _DBusGProxyManager DBusGProxyManager;
00050
00054 struct _DBusGProxy
00055 {
00056 GObject parent;
00058 DBusGProxyManager *manager;
00059 char *name;
00060 char *path;
00061 char *interface;
00063 DBusGProxyCall *name_call;
00064 guint for_owner : 1;
00065 guint associated : 1;
00067
00068 guint call_id_counter;
00070 GData *signal_signatures;
00072 GHashTable *pending_calls;
00073 };
00074
00078 struct _DBusGProxyClass
00079 {
00080 GObjectClass parent_class;
00081 };
00082
00083 static void dbus_g_proxy_init (DBusGProxy *proxy);
00084 static void dbus_g_proxy_class_init (DBusGProxyClass *klass);
00085 static GObject *dbus_g_proxy_constructor (GType type,
00086 guint n_construct_properties,
00087 GObjectConstructParam *construct_properties);
00088 static void dbus_g_proxy_set_property (GObject *object,
00089 guint prop_id,
00090 const GValue *value,
00091 GParamSpec *pspec);
00092 static void dbus_g_proxy_get_property (GObject *object,
00093 guint prop_id,
00094 GValue *value,
00095 GParamSpec *pspec);
00096
00097 static void dbus_g_proxy_finalize (GObject *object);
00098 static void dbus_g_proxy_dispose (GObject *object);
00099 static void dbus_g_proxy_destroy (DBusGProxy *proxy);
00100 static void dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
00101 DBusMessage *message);
00102
00103 static DBusGProxyCall *manager_begin_bus_call (DBusGProxyManager *manager,
00104 const char *method,
00105 DBusGProxyCallNotify notify,
00106 gpointer data,
00107 GDestroyNotify destroy,
00108 GType first_arg_type,
00109 ...);
00110 static guint dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
00111 const char *method,
00112 DBusGProxyCallNotify notify,
00113 gpointer data,
00114 GDestroyNotify destroy,
00115 GValueArray *args);
00116 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
00117 guint call_id,
00118 GError **error,
00119 GType first_arg_type,
00120 va_list args);
00121
00126 typedef struct
00127 {
00128 GSList *proxies;
00130 char name[4];
00135 } DBusGProxyList;
00136
00142 struct _DBusGProxyManager
00143 {
00144 GStaticMutex lock;
00145 int refcount;
00146 DBusConnection *connection;
00148 DBusGProxy *bus_proxy;
00150 GHashTable *proxy_lists;
00153 GHashTable *owner_names;
00157 GSList *unassociated_proxies;
00161 };
00162
00163 static DBusGProxyManager *dbus_g_proxy_manager_ref (DBusGProxyManager *manager);
00164 static DBusHandlerResult dbus_g_proxy_manager_filter (DBusConnection *connection,
00165 DBusMessage *message,
00166 void *user_data);
00167
00168
00170 #define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock))
00171
00172 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00173
00174 static int g_proxy_manager_slot = -1;
00175
00176
00177 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
00178
00179 static DBusGProxyManager*
00180 dbus_g_proxy_manager_get (DBusConnection *connection)
00181 {
00182 DBusGProxyManager *manager;
00183
00184 dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
00185 if (g_proxy_manager_slot < 0)
00186 g_error ("out of memory");
00187
00188 g_static_mutex_lock (&connection_g_proxy_lock);
00189
00190 manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
00191 if (manager != NULL)
00192 {
00193 dbus_connection_free_data_slot (&g_proxy_manager_slot);
00194 dbus_g_proxy_manager_ref (manager);
00195 g_static_mutex_unlock (&connection_g_proxy_lock);
00196 return manager;
00197 }
00198
00199 manager = g_new0 (DBusGProxyManager, 1);
00200
00201 manager->refcount = 1;
00202 manager->connection = connection;
00203
00204 g_static_mutex_init (&manager->lock);
00205
00206
00207
00208
00209
00210 dbus_connection_ref (manager->connection);
00211
00212 dbus_connection_set_data (connection, g_proxy_manager_slot,
00213 manager, NULL);
00214
00215 dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
00216 manager, NULL);
00217
00218 g_static_mutex_unlock (&connection_g_proxy_lock);
00219
00220 return manager;
00221 }
00222
00223 static DBusGProxyManager *
00224 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
00225 {
00226 g_assert (manager != NULL);
00227 g_assert (manager->refcount > 0);
00228
00229 LOCK_MANAGER (manager);
00230
00231 manager->refcount += 1;
00232
00233 UNLOCK_MANAGER (manager);
00234
00235 return manager;
00236 }
00237
00238 static void
00239 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
00240 {
00241 g_assert (manager != NULL);
00242 g_assert (manager->refcount > 0);
00243
00244 LOCK_MANAGER (manager);
00245 manager->refcount -= 1;
00246 if (manager->refcount == 0)
00247 {
00248 UNLOCK_MANAGER (manager);
00249
00250 if (manager->bus_proxy)
00251 g_object_unref (manager->bus_proxy);
00252
00253 if (manager->proxy_lists)
00254 {
00255
00256
00257
00258 g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00259
00260 g_hash_table_destroy (manager->proxy_lists);
00261 manager->proxy_lists = NULL;
00262
00263 }
00264
00265 if (manager->owner_names)
00266 {
00267
00268
00269
00270 g_assert (g_hash_table_size (manager->owner_names) == 0);
00271
00272 g_hash_table_destroy (manager->owner_names);
00273 manager->owner_names = NULL;
00274 }
00275
00276 g_assert (manager->unassociated_proxies == NULL);
00277
00278 g_static_mutex_free (&manager->lock);
00279
00280 g_static_mutex_lock (&connection_g_proxy_lock);
00281
00282 dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
00283 manager);
00284
00285 dbus_connection_set_data (manager->connection,
00286 g_proxy_manager_slot,
00287 NULL, NULL);
00288
00289 g_static_mutex_unlock (&connection_g_proxy_lock);
00290
00291 dbus_connection_unref (manager->connection);
00292 g_free (manager);
00293
00294 dbus_connection_free_data_slot (&g_proxy_manager_slot);
00295 }
00296 else
00297 {
00298 UNLOCK_MANAGER (manager);
00299 }
00300 }
00301
00302 static guint
00303 tristring_hash (gconstpointer key)
00304 {
00305 const char *p = key;
00306 guint h = *p;
00307
00308 if (h)
00309 {
00310 for (p += 1; *p != '\0'; p++)
00311 h = (h << 5) - h + *p;
00312 }
00313
00314
00315 for (p += 1; *p != '\0'; p++)
00316 h = (h << 5) - h + *p;
00317
00318
00319 for (p += 1; *p != '\0'; p++)
00320 h = (h << 5) - h + *p;
00321
00322 return h;
00323 }
00324
00325 static gboolean
00326 strequal_len (const char *a,
00327 const char *b,
00328 size_t *lenp)
00329 {
00330 size_t a_len;
00331 size_t b_len;
00332
00333 a_len = strlen (a);
00334 b_len = strlen (b);
00335
00336 if (a_len != b_len)
00337 return FALSE;
00338
00339 if (memcmp (a, b, a_len) != 0)
00340 return FALSE;
00341
00342 *lenp = a_len;
00343
00344 return TRUE;
00345 }
00346
00347 static gboolean
00348 tristring_equal (gconstpointer a,
00349 gconstpointer b)
00350 {
00351 const char *ap = a;
00352 const char *bp = b;
00353 size_t len;
00354
00355 if (!strequal_len (ap, bp, &len))
00356 return FALSE;
00357
00358 ap += len + 1;
00359 bp += len + 1;
00360
00361 if (!strequal_len (ap, bp, &len))
00362 return FALSE;
00363
00364 ap += len + 1;
00365 bp += len + 1;
00366
00367 if (strcmp (ap, bp) != 0)
00368 return FALSE;
00369
00370 return TRUE;
00371 }
00372
00373 static char*
00374 tristring_alloc_from_strings (size_t padding_before,
00375 const char *name,
00376 const char *path,
00377 const char *interface)
00378 {
00379 size_t name_len, iface_len, path_len, len;
00380 char *tri;
00381
00382 if (name)
00383 name_len = strlen (name);
00384 else
00385 name_len = 0;
00386
00387 path_len = strlen (path);
00388
00389 iface_len = strlen (interface);
00390
00391 tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
00392
00393 len = padding_before;
00394
00395 if (name)
00396 memcpy (&tri[len], name, name_len);
00397
00398 len += name_len;
00399 tri[len] = '\0';
00400 len += 1;
00401
00402 g_assert (len == (padding_before + name_len + 1));
00403
00404 memcpy (&tri[len], path, path_len);
00405 len += path_len;
00406 tri[len] = '\0';
00407 len += 1;
00408
00409 g_assert (len == (padding_before + name_len + path_len + 2));
00410
00411 memcpy (&tri[len], interface, iface_len);
00412 len += iface_len;
00413 tri[len] = '\0';
00414 len += 1;
00415
00416 g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
00417
00418 return tri;
00419 }
00420
00421 static char*
00422 tristring_from_proxy (DBusGProxy *proxy)
00423 {
00424 return tristring_alloc_from_strings (0,
00425 proxy->name,
00426 proxy->path,
00427 proxy->interface);
00428 }
00429
00430 static char*
00431 tristring_from_message (DBusMessage *message)
00432 {
00433 const char *path;
00434 const char *interface;
00435
00436 path = dbus_message_get_path (message);
00437 interface = dbus_message_get_interface (message);
00438
00439 g_assert (path);
00440 g_assert (interface);
00441
00442 return tristring_alloc_from_strings (0,
00443 dbus_message_get_sender (message),
00444 path, interface);
00445 }
00446
00447 static DBusGProxyList*
00448 g_proxy_list_new (DBusGProxy *first_proxy)
00449 {
00450 DBusGProxyList *list;
00451
00452 list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00453 first_proxy->name,
00454 first_proxy->path,
00455 first_proxy->interface);
00456 list->proxies = NULL;
00457
00458 return list;
00459 }
00460
00461 static void
00462 g_proxy_list_free (DBusGProxyList *list)
00463 {
00464
00465
00466
00467 g_slist_free (list->proxies);
00468
00469 g_free (list);
00470 }
00471
00472 static char*
00473 g_proxy_get_match_rule (DBusGProxy *proxy)
00474 {
00475
00476
00477 if (proxy->name)
00478 return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00479 proxy->name, proxy->path, proxy->interface);
00480 else
00481 return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00482 proxy->path, proxy->interface);
00483 }
00484
00485 typedef struct
00486 {
00487 char *name;
00488 guint refcount;
00489 } DBusGProxyNameOwnerInfo;
00490
00491 static gint
00492 find_name_in_info (gconstpointer a, gconstpointer b)
00493 {
00494 const DBusGProxyNameOwnerInfo *info = a;
00495 const char *name = b;
00496
00497 return strcmp (info->name, name);
00498 }
00499
00500 typedef struct
00501 {
00502 const char *name;
00503 const char *owner;
00504 DBusGProxyNameOwnerInfo *info;
00505 } DBusGProxyNameOwnerForeachData;
00506
00507 static void
00508 name_owner_foreach (gpointer key, gpointer val, gpointer data)
00509 {
00510 const char *owner;
00511 DBusGProxyNameOwnerForeachData *foreach_data;
00512 GSList *names;
00513 GSList *link;
00514
00515 owner = key;
00516 names = val;
00517 foreach_data = data;
00518
00519 if (foreach_data->owner != NULL)
00520 return;
00521
00522 g_assert (foreach_data->info == NULL);
00523
00524 link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
00525 if (link)
00526 {
00527 foreach_data->owner = owner;
00528 foreach_data->info = link->data;
00529 }
00530 }
00531
00532 static gboolean
00533 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager *manager,
00534 const char *name,
00535 DBusGProxyNameOwnerInfo **info,
00536 const char **owner)
00537 {
00538 DBusGProxyNameOwnerForeachData foreach_data;
00539
00540 foreach_data.name = name;
00541 foreach_data.owner = NULL;
00542 foreach_data.info = NULL;
00543
00544 g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
00545
00546 *info = foreach_data.info;
00547 *owner = foreach_data.owner;
00548 return *info != NULL;
00549 }
00550
00551 static void
00552 insert_nameinfo (DBusGProxyManager *manager,
00553 const char *owner,
00554 DBusGProxyNameOwnerInfo *info)
00555 {
00556 GSList *names;
00557 gboolean insert;
00558
00559 names = g_hash_table_lookup (manager->owner_names, owner);
00560
00561
00562 insert = (names == NULL);
00563
00564 names = g_slist_append (names, info);
00565
00566 if (insert)
00567 g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00568 }
00569
00570 static void
00571 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager *manager,
00572 const char *owner,
00573 const char *name)
00574 {
00575 GSList *names;
00576 GSList *link;
00577 DBusGProxyNameOwnerInfo *nameinfo;
00578
00579 names = g_hash_table_lookup (manager->owner_names, owner);
00580 link = g_slist_find_custom (names, name, find_name_in_info);
00581
00582 if (!link)
00583 {
00584 nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
00585 nameinfo->name = g_strdup (name);
00586 nameinfo->refcount = 1;
00587
00588 insert_nameinfo (manager, owner, nameinfo);
00589 }
00590 else
00591 {
00592 nameinfo = link->data;
00593 nameinfo->refcount++;
00594 }
00595 }
00596
00597 static void
00598 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager *manager,
00599 const char *name)
00600 {
00601 DBusGProxyNameOwnerInfo *info;
00602 const char *owner;
00603 gboolean ret;
00604
00605 ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
00606 g_assert (ret);
00607 g_assert (info != NULL);
00608 g_assert (owner != NULL);
00609
00610 info->refcount--;
00611 if (info->refcount == 0)
00612 {
00613 GSList *names;
00614 GSList *link;
00615
00616 names = g_hash_table_lookup (manager->owner_names, owner);
00617 link = g_slist_find_custom (names, name, find_name_in_info);
00618 names = g_slist_delete_link (names, link);
00619 if (names != NULL)
00620 g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
00621 else
00622 g_hash_table_remove (manager->owner_names, owner);
00623
00624 g_free (info->name);
00625 g_free (info);
00626 }
00627 }
00628
00629 typedef struct
00630 {
00631 const char *name;
00632 GSList *destroyed;
00633 } DBusGProxyUnassociateData;
00634
00635 static void
00636 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
00637 {
00638 DBusGProxyList *list;
00639 const char *name;
00640 GSList *tmp;
00641 DBusGProxyUnassociateData *data;
00642
00643 list = val;
00644 data = user_data;
00645 name = data->name;
00646
00647 for (tmp = list->proxies; tmp; tmp = tmp->next)
00648 {
00649 DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
00650 DBusGProxyManager *manager;
00651
00652 manager = proxy->manager;
00653
00654 if (!strcmp (proxy->name, name))
00655 {
00656 if (!proxy->for_owner)
00657 {
00658 g_assert (proxy->associated);
00659 g_assert (proxy->name_call == NULL);
00660
00661 proxy->associated = FALSE;
00662 manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
00663 }
00664 else
00665 {
00666 data->destroyed = g_slist_prepend (data->destroyed, proxy);
00667 }
00668 }
00669 }
00670 }
00671
00672 static void
00673 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager *manager,
00674 const char *name,
00675 const char *prev_owner,
00676 const char *new_owner)
00677 {
00678 GSList *names;
00679
00680 if (prev_owner[0] == '\0')
00681 {
00682 GSList *tmp;
00683 GSList *removed;
00684
00685
00686
00687 removed = NULL;
00688
00689 for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
00690 {
00691 DBusGProxy *proxy;
00692
00693 proxy = tmp->data;
00694
00695 if (!strcmp (proxy->name, name))
00696 {
00697 removed = g_slist_prepend (removed, tmp);
00698
00699 dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
00700 proxy->associated = TRUE;
00701 }
00702 }
00703
00704 for (tmp = removed; tmp; tmp = tmp->next)
00705 manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
00706 g_slist_free (removed);
00707 }
00708 else
00709 {
00710 DBusGProxyNameOwnerInfo *info;
00711 GSList *link;
00712
00713
00714
00715 names = g_hash_table_lookup (manager->owner_names, prev_owner);
00716
00717 link = g_slist_find_custom (names, name, find_name_in_info);
00718
00719 info = NULL;
00720 if (link != NULL)
00721 {
00722 info = link->data;
00723
00724 names = g_slist_delete_link (names, link);
00725
00726 if (names == NULL)
00727 g_hash_table_remove (manager->owner_names, prev_owner);
00728 }
00729
00730 if (new_owner[0] == '\0')
00731 {
00732 DBusGProxyUnassociateData data;
00733 GSList *tmp;
00734
00735 data.name = name;
00736 data.destroyed = NULL;
00737
00738
00739 g_hash_table_foreach (manager->proxy_lists,
00740 unassociate_proxies, &data);
00741
00742 UNLOCK_MANAGER (manager);
00743
00744 for (tmp = data.destroyed; tmp; tmp = tmp->next)
00745 dbus_g_proxy_destroy (tmp->data);
00746 g_slist_free (data.destroyed);
00747
00748 LOCK_MANAGER (manager);
00749 }
00750 else
00751 {
00752 insert_nameinfo (manager, new_owner, info);
00753 }
00754 }
00755 }
00756
00757 static void
00758 got_name_owner_cb (DBusGProxy *bus_proxy,
00759 DBusGProxyCall *call,
00760 void *user_data)
00761 {
00762 DBusGProxy *proxy;
00763 GError *error;
00764 char *owner;
00765
00766 proxy = user_data;
00767 error = NULL;
00768 owner = NULL;
00769
00770 LOCK_MANAGER (proxy->manager);
00771
00772 if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
00773 G_TYPE_STRING, &owner,
00774 G_TYPE_INVALID))
00775 {
00776 if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
00777 {
00778 proxy->manager->unassociated_proxies = g_slist_prepend (proxy->manager->unassociated_proxies, proxy);
00779 }
00780 else
00781 g_warning ("Couldn't get name owner (%s): %s",
00782 dbus_g_error_get_name (error),
00783 error->message);
00784
00785 g_clear_error (&error);
00786 goto out;
00787 }
00788 else
00789 {
00790 dbus_g_proxy_manager_monitor_name_owner (proxy->manager, owner, proxy->name);
00791 proxy->associated = TRUE;
00792 }
00793
00794 out:
00795 proxy->name_call = NULL;
00796 UNLOCK_MANAGER (proxy->manager);
00797 g_free (owner);
00798 }
00799
00800 static char *
00801 get_name_owner (DBusConnection *connection,
00802 const char *name,
00803 GError **error)
00804 {
00805 DBusError derror;
00806 DBusMessage *request, *reply;
00807 char *base_name;
00808
00809 dbus_error_init (&derror);
00810
00811 base_name = NULL;
00812 reply = NULL;
00813
00814 request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
00815 DBUS_PATH_DBUS,
00816 DBUS_INTERFACE_DBUS,
00817 "GetNameOwner");
00818 if (request == NULL)
00819 g_error ("Out of memory");
00820
00821 if (!dbus_message_append_args (request,
00822 DBUS_TYPE_STRING, &name,
00823 DBUS_TYPE_INVALID))
00824 g_error ("Out of memory");
00825
00826 reply =
00827 dbus_connection_send_with_reply_and_block (connection,
00828 request,
00829 2000, &derror);
00830 if (reply == NULL)
00831 goto error;
00832
00833 if (dbus_set_error_from_message (&derror, reply))
00834 goto error;
00835
00836 if (!dbus_message_get_args (reply, &derror,
00837 DBUS_TYPE_STRING, &base_name,
00838 DBUS_TYPE_INVALID))
00839 goto error;
00840
00841 base_name = g_strdup (base_name);
00842 goto out;
00843
00844 error:
00845 g_assert (dbus_error_is_set (&derror));
00846 dbus_set_g_error (error, &derror);
00847 dbus_error_free (&derror);
00848
00849 out:
00850 if (request)
00851 dbus_message_unref (request);
00852 if (reply)
00853 dbus_message_unref (reply);
00854
00855 return base_name;
00856 }
00857
00858
00859 static void
00860 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
00861 DBusGProxy *proxy)
00862 {
00863 DBusGProxyList *list;
00864
00865 LOCK_MANAGER (manager);
00866
00867 if (manager->proxy_lists == NULL)
00868 {
00869 g_assert (manager->owner_names == NULL);
00870
00871 list = NULL;
00872 manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00873 tristring_equal,
00874 NULL,
00875 (GFreeFunc) g_proxy_list_free);
00876 manager->owner_names = g_hash_table_new_full (g_str_hash,
00877 g_str_equal,
00878 g_free,
00879 NULL);
00880
00881
00882
00883 dbus_bus_add_match (manager->connection,
00884 "type='signal',sender='" DBUS_SERVICE_DBUS
00885 "',path='" DBUS_PATH_DBUS
00886 "',interface='" DBUS_INTERFACE_DBUS
00887 "',member='NameOwnerChanged'",
00888 NULL);
00889 }
00890 else
00891 {
00892 char *tri;
00893
00894 tri = tristring_from_proxy (proxy);
00895
00896 list = g_hash_table_lookup (manager->proxy_lists, tri);
00897
00898 g_free (tri);
00899 }
00900
00901 if (list == NULL)
00902 {
00903 list = g_proxy_list_new (proxy);
00904
00905 g_hash_table_replace (manager->proxy_lists,
00906 list->name, list);
00907 }
00908
00909 if (list->proxies == NULL)
00910 {
00911
00912
00913
00914
00915 char *rule;
00916
00917 rule = g_proxy_get_match_rule (proxy);
00918
00919
00920
00921
00922 dbus_bus_add_match (manager->connection,
00923 rule, NULL);
00924
00925 g_free (rule);
00926 }
00927
00928 g_assert (g_slist_find (list->proxies, proxy) == NULL);
00929
00930 list->proxies = g_slist_prepend (list->proxies, proxy);
00931
00932 if (!proxy->for_owner)
00933 {
00934 const char *owner;
00935 DBusGProxyNameOwnerInfo *info;
00936
00937 if (!dbus_g_proxy_manager_lookup_name_owner (manager, proxy->name, &info, &owner))
00938 {
00939 proxy->name_call = manager_begin_bus_call (manager, "GetNameOwner",
00940 got_name_owner_cb,
00941 proxy, NULL,
00942 G_TYPE_STRING,
00943 proxy->name,
00944 G_TYPE_INVALID);
00945
00946 proxy->associated = FALSE;
00947 }
00948 else
00949 {
00950 info->refcount++;
00951 proxy->associated = TRUE;
00952 }
00953 }
00954
00955 UNLOCK_MANAGER (manager);
00956 }
00957
00958 static void
00959 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
00960 DBusGProxy *proxy)
00961 {
00962 DBusGProxyList *list;
00963 char *tri;
00964
00965 LOCK_MANAGER (manager);
00966
00967 #ifndef G_DISABLE_CHECKS
00968 if (manager->proxy_lists == NULL)
00969 {
00970 g_warning ("Trying to unregister a proxy but there aren't any registered");
00971 return;
00972 }
00973 #endif
00974
00975 tri = tristring_from_proxy (proxy);
00976
00977 list = g_hash_table_lookup (manager->proxy_lists, tri);
00978
00979 #ifndef G_DISABLE_CHECKS
00980 if (list == NULL)
00981 {
00982 g_warning ("Trying to unregister a proxy but it isn't registered");
00983 return;
00984 }
00985 #endif
00986
00987 g_assert (g_slist_find (list->proxies, proxy) != NULL);
00988
00989 list->proxies = g_slist_remove (list->proxies, proxy);
00990
00991 g_assert (g_slist_find (list->proxies, proxy) == NULL);
00992
00993 if (!proxy->for_owner)
00994 {
00995 if (!proxy->associated)
00996 {
00997 GSList *link;
00998
00999 if (proxy->name_call != 0)
01000 {
01001 dbus_g_proxy_cancel_call (manager->bus_proxy, proxy->name_call);
01002 proxy->name_call = 0;
01003 }
01004 else
01005 {
01006 link = g_slist_find (manager->unassociated_proxies, proxy);
01007 g_assert (link != NULL);
01008
01009 manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
01010 }
01011 }
01012 else
01013 {
01014 g_assert (proxy->name_call == 0);
01015
01016 dbus_g_proxy_manager_unmonitor_name_owner (manager, proxy->name);
01017 }
01018 }
01019
01020 if (list->proxies == NULL)
01021 {
01022 char *rule;
01023 g_hash_table_remove (manager->proxy_lists,
01024 tri);
01025 list = NULL;
01026
01027 rule = g_proxy_get_match_rule (proxy);
01028 dbus_bus_remove_match (manager->connection,
01029 rule, NULL);
01030 g_free (rule);
01031 }
01032
01033 if (g_hash_table_size (manager->proxy_lists) == 0)
01034 {
01035 g_hash_table_destroy (manager->proxy_lists);
01036 manager->proxy_lists = NULL;
01037 }
01038
01039 g_free (tri);
01040
01041 UNLOCK_MANAGER (manager);
01042 }
01043
01044 static void
01045 list_proxies_foreach (gpointer key,
01046 gpointer value,
01047 gpointer user_data)
01048 {
01049 DBusGProxyList *list;
01050 GSList **ret;
01051 GSList *tmp;
01052
01053 list = value;
01054 ret = user_data;
01055
01056 tmp = list->proxies;
01057 while (tmp != NULL)
01058 {
01059 DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
01060
01061 g_object_ref (proxy);
01062 *ret = g_slist_prepend (*ret, proxy);
01063
01064 tmp = tmp->next;
01065 }
01066 }
01067
01068 static GSList*
01069 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
01070 {
01071 GSList *ret;
01072
01073 ret = NULL;
01074
01075 if (manager->proxy_lists)
01076 {
01077 g_hash_table_foreach (manager->proxy_lists,
01078 list_proxies_foreach,
01079 &ret);
01080 }
01081
01082 return ret;
01083 }
01084
01085 static DBusHandlerResult
01086 dbus_g_proxy_manager_filter (DBusConnection *connection,
01087 DBusMessage *message,
01088 void *user_data)
01089 {
01090 DBusGProxyManager *manager;
01091
01092 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
01093 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01094
01095 manager = user_data;
01096
01097 dbus_g_proxy_manager_ref (manager);
01098
01099 LOCK_MANAGER (manager);
01100
01101 if (dbus_message_is_signal (message,
01102 DBUS_INTERFACE_LOCAL,
01103 "Disconnected"))
01104 {
01105
01106
01107
01108 GSList *all;
01109 GSList *tmp;
01110
01111 all = dbus_g_proxy_manager_list_all (manager);
01112
01113 tmp = all;
01114 while (tmp != NULL)
01115 {
01116 DBusGProxy *proxy;
01117
01118 proxy = DBUS_G_PROXY (tmp->data);
01119
01120 UNLOCK_MANAGER (manager);
01121 dbus_g_proxy_destroy (proxy);
01122 g_object_unref (G_OBJECT (proxy));
01123 LOCK_MANAGER (manager);
01124
01125 tmp = tmp->next;
01126 }
01127
01128 g_slist_free (all);
01129
01130 #ifndef G_DISABLE_CHECKS
01131 if (manager->proxy_lists != NULL)
01132 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.");
01133 #endif
01134 }
01135 else
01136 {
01137 char *tri;
01138 GSList *full_list;
01139 GSList *owned_names;
01140 GSList *tmp;
01141 const char *sender;
01142
01143
01144 if (dbus_message_is_signal (message,
01145 DBUS_INTERFACE_DBUS,
01146 "NameOwnerChanged"))
01147 {
01148 const char *name;
01149 const char *prev_owner;
01150 const char *new_owner;
01151 DBusError derr;
01152
01153 dbus_error_init (&derr);
01154 if (!dbus_message_get_args (message,
01155 &derr,
01156 DBUS_TYPE_STRING,
01157 &name,
01158 DBUS_TYPE_STRING,
01159 &prev_owner,
01160 DBUS_TYPE_STRING,
01161 &new_owner,
01162 DBUS_TYPE_INVALID))
01163 {
01164
01165 dbus_error_free (&derr);
01166 }
01167 else if (manager->owner_names != NULL)
01168 {
01169 dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
01170 }
01171 }
01172
01173 sender = dbus_message_get_sender (message);
01174
01175
01176 g_assert (sender != NULL);
01177 g_assert (dbus_message_get_path (message) != NULL);
01178 g_assert (dbus_message_get_interface (message) != NULL);
01179 g_assert (dbus_message_get_member (message) != NULL);
01180
01181 tri = tristring_from_message (message);
01182
01183 if (manager->proxy_lists)
01184 {
01185 DBusGProxyList *owner_list;
01186 owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01187 if (owner_list)
01188 full_list = g_slist_copy (owner_list->proxies);
01189 else
01190 full_list = NULL;
01191 }
01192 else
01193 full_list = NULL;
01194
01195 g_free (tri);
01196
01197 if (manager->owner_names)
01198 {
01199 owned_names = g_hash_table_lookup (manager->owner_names, sender);
01200 for (tmp = owned_names; tmp; tmp = tmp->next)
01201 {
01202 DBusGProxyList *owner_list;
01203 DBusGProxyNameOwnerInfo *nameinfo;
01204
01205 nameinfo = tmp->data;
01206 g_assert (nameinfo->refcount > 0);
01207 tri = tristring_alloc_from_strings (0, nameinfo->name,
01208 dbus_message_get_path (message),
01209 dbus_message_get_interface (message));
01210
01211 owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01212 if (owner_list != NULL)
01213 full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies));
01214 g_free (tri);
01215 }
01216 }
01217
01218 #if 0
01219 g_print ("proxy got %s,%s,%s = list %p\n",
01220 tri,
01221 tri + strlen (tri) + 1,
01222 tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
01223 list);
01224 #endif
01225
01226
01227
01228 g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
01229
01230 for (tmp = full_list; tmp; tmp = tmp->next)
01231 {
01232 DBusGProxy *proxy;
01233
01234 proxy = DBUS_G_PROXY (tmp->data);
01235
01236 UNLOCK_MANAGER (manager);
01237 dbus_g_proxy_emit_remote_signal (proxy, message);
01238 g_object_unref (G_OBJECT (proxy));
01239 LOCK_MANAGER (manager);
01240 }
01241 g_slist_free (full_list);
01242 }
01243
01244 UNLOCK_MANAGER (manager);
01245 dbus_g_proxy_manager_unref (manager);
01246
01247
01248
01249
01250 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01251 }
01252
01253
01254
01255
01256
01257 #define DBUS_G_PROXY_DESTROYED(proxy) (DBUS_G_PROXY (proxy)->manager == NULL)
01258
01259 static void
01260 marshal_dbus_message_to_g_marshaller (GClosure *closure,
01261 GValue *return_value,
01262 guint n_param_values,
01263 const GValue *param_values,
01264 gpointer invocation_hint,
01265 gpointer marshal_data);
01266 enum
01267 {
01268 PROP_0,
01269 PROP_NAME,
01270 PROP_PATH,
01271 PROP_INTERFACE
01272 };
01273
01274 enum
01275 {
01276 DESTROY,
01277 RECEIVED,
01278 LAST_SIGNAL
01279 };
01280
01281 static void *parent_class;
01282 static guint signals[LAST_SIGNAL] = { 0 };
01283
01284 static void
01285 dbus_g_proxy_init (DBusGProxy *proxy)
01286 {
01287 g_datalist_init (&proxy->signal_signatures);
01288 proxy->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
01289 (GDestroyNotify) dbus_pending_call_unref);
01290 }
01291
01292 static GObject *
01293 dbus_g_proxy_constructor (GType type,
01294 guint n_construct_properties,
01295 GObjectConstructParam *construct_properties)
01296 {
01297 DBusGProxy *proxy;
01298 DBusGProxyClass *klass;
01299 GObjectClass *parent_class;
01300
01301 klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
01302
01303 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
01304
01305 proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
01306 construct_properties));
01307
01308 proxy->for_owner = (proxy->name[0] == ':');
01309 proxy->name_call = 0;
01310 proxy->associated = FALSE;
01311
01312 return G_OBJECT (proxy);
01313 }
01314
01315 static void
01316 dbus_g_proxy_class_init (DBusGProxyClass *klass)
01317 {
01318 GObjectClass *object_class = G_OBJECT_CLASS (klass);
01319
01320 parent_class = g_type_class_peek_parent (klass);
01321
01322 object_class->set_property = dbus_g_proxy_set_property;
01323 object_class->get_property = dbus_g_proxy_get_property;
01324
01325 g_object_class_install_property (object_class,
01326 PROP_NAME,
01327 g_param_spec_string ("name",
01328 "name",
01329 "name",
01330 NULL,
01331 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01332
01333 g_object_class_install_property (object_class,
01334 PROP_PATH,
01335 g_param_spec_string ("path",
01336 "path",
01337 "path",
01338 NULL,
01339 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01340
01341 g_object_class_install_property (object_class,
01342 PROP_INTERFACE,
01343 g_param_spec_string ("interface",
01344 "interface",
01345 "interface",
01346 NULL,
01347 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01348
01349 object_class->finalize = dbus_g_proxy_finalize;
01350 object_class->dispose = dbus_g_proxy_dispose;
01351 object_class->constructor = dbus_g_proxy_constructor;
01352
01353 signals[DESTROY] =
01354 g_signal_new ("destroy",
01355 G_OBJECT_CLASS_TYPE (object_class),
01356 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
01357 0,
01358 NULL, NULL,
01359 g_cclosure_marshal_VOID__VOID,
01360 G_TYPE_NONE, 0);
01361
01362 signals[RECEIVED] =
01363 g_signal_new ("received",
01364 G_OBJECT_CLASS_TYPE (object_class),
01365 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
01366 0,
01367 NULL, NULL,
01368 marshal_dbus_message_to_g_marshaller,
01369 G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
01370 }
01371
01372 static void
01373 cancel_pending_call (gpointer key, gpointer val, gpointer data)
01374 {
01375 DBusGProxyCall *call = key;
01376 DBusGProxy *proxy = data;
01377
01378 dbus_g_proxy_cancel_call (proxy, call);
01379 }
01380
01381 static void
01382 dbus_g_proxy_dispose (GObject *object)
01383 {
01384 DBusGProxy *proxy;
01385
01386 proxy = DBUS_G_PROXY (object);
01387
01388
01389 g_hash_table_foreach (proxy->pending_calls, cancel_pending_call, proxy);
01390 g_hash_table_destroy (proxy->pending_calls);
01391
01392 if (proxy->manager && proxy != proxy->manager->bus_proxy)
01393 {
01394 dbus_g_proxy_manager_unregister (proxy->manager, proxy);
01395 dbus_g_proxy_manager_unref (proxy->manager);
01396 }
01397 proxy->manager = NULL;
01398
01399 g_datalist_clear (&proxy->signal_signatures);
01400
01401 g_signal_emit (object, signals[DESTROY], 0);
01402
01403 G_OBJECT_CLASS (parent_class)->dispose (object);
01404 }
01405
01406 static void
01407 dbus_g_proxy_finalize (GObject *object)
01408 {
01409 DBusGProxy *proxy;
01410
01411 proxy = DBUS_G_PROXY (object);
01412
01413 g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
01414
01415 g_free (proxy->name);
01416 g_free (proxy->path);
01417 g_free (proxy->interface);
01418
01419 G_OBJECT_CLASS (parent_class)->finalize (object);
01420 }
01421
01422 static void
01423 dbus_g_proxy_destroy (DBusGProxy *proxy)
01424 {
01425
01426
01427
01428 g_object_run_dispose (G_OBJECT (proxy));
01429 }
01430
01431 static void
01432 dbus_g_proxy_set_property (GObject *object,
01433 guint prop_id,
01434 const GValue *value,
01435 GParamSpec *pspec)
01436 {
01437 DBusGProxy *proxy = DBUS_G_PROXY (object);
01438
01439 switch (prop_id)
01440 {
01441 case PROP_NAME:
01442 proxy->name = g_strdup (g_value_get_string (value));
01443 break;
01444 case PROP_PATH:
01445 proxy->path = g_strdup (g_value_get_string (value));
01446 break;
01447 case PROP_INTERFACE:
01448 proxy->interface = g_strdup (g_value_get_string (value));
01449 break;
01450 default:
01451 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01452 break;
01453 }
01454 }
01455
01456 static void
01457 dbus_g_proxy_get_property (GObject *object,
01458 guint prop_id,
01459 GValue *value,
01460 GParamSpec *pspec)
01461 {
01462 DBusGProxy *proxy = DBUS_G_PROXY (object);
01463
01464 switch (prop_id)
01465 {
01466 case PROP_NAME:
01467 g_value_set_string (value, proxy->name);
01468 break;
01469 case PROP_PATH:
01470 g_value_set_string (value, proxy->path);
01471 break;
01472 case PROP_INTERFACE:
01473 g_value_set_string (value, proxy->interface);
01474 break;
01475 default:
01476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01477 break;
01478 }
01479 }
01480
01481
01482
01483
01484
01485
01486 static char*
01487 create_signal_name (const char *interface,
01488 const char *signal)
01489 {
01490 GString *str;
01491 char *p;
01492
01493 str = g_string_new (interface);
01494
01495 g_string_append (str, "-");
01496
01497 g_string_append (str, signal);
01498
01499
01500 p = str->str;
01501 while (*p)
01502 {
01503 if (*p == '.')
01504 *p = '-';
01505 ++p;
01506 }
01507
01508 return g_string_free (str, FALSE);
01509 }
01510
01511 static void
01512 marshal_dbus_message_to_g_marshaller (GClosure *closure,
01513 GValue *return_value,
01514 guint n_param_values,
01515 const GValue *param_values,
01516 gpointer invocation_hint,
01517 gpointer marshal_data)
01518 {
01519
01520
01521
01522
01523
01524 #define MAX_SIGNATURE_ARGS 20
01525 GValueArray *value_array;
01526 GSignalCMarshaller c_marshaller;
01527 DBusGProxy *proxy;
01528 DBusMessage *message;
01529 GArray *gsignature;
01530 const GType *types;
01531
01532 g_assert (n_param_values == 3);
01533
01534 proxy = g_value_get_object (¶m_values[0]);
01535 message = g_value_get_boxed (¶m_values[1]);
01536 gsignature = g_value_get_pointer (¶m_values[2]);
01537
01538 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
01539 g_return_if_fail (message != NULL);
01540 g_return_if_fail (gsignature != NULL);
01541
01542 c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
01543 (GType*) gsignature->data);
01544
01545 g_return_if_fail (c_marshaller != NULL);
01546
01547 {
01548 DBusGValueMarshalCtx context;
01549 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
01550 context.proxy = proxy;
01551
01552 types = (const GType*) gsignature->data;
01553 value_array = _dbus_gvalue_demarshal_message (&context, message,
01554 gsignature->len, types, NULL);
01555 }
01556
01557 if (value_array == NULL)
01558 return;
01559
01560 g_value_array_prepend (value_array, NULL);
01561 g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
01562 g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
01563
01564 (* c_marshaller) (closure, return_value, value_array->n_values,
01565 value_array->values, invocation_hint, marshal_data);
01566
01567 g_value_array_free (value_array);
01568 }
01569
01570 static void
01571 dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
01572 DBusMessage *message)
01573 {
01574 const char *interface;
01575 const char *signal;
01576 char *name;
01577 GQuark q;
01578
01579 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
01580
01581 interface = dbus_message_get_interface (message);
01582 signal = dbus_message_get_member (message);
01583
01584 g_assert (interface != NULL);
01585 g_assert (signal != NULL);
01586
01587 name = create_signal_name (interface, signal);
01588
01589
01590
01591
01592
01593 q = g_quark_try_string (name);
01594
01595 if (q != 0)
01596 {
01597 GArray *gsignature;
01598 GArray *msg_gsignature;
01599 guint i;
01600
01601 gsignature = g_datalist_id_get_data (&proxy->signal_signatures, q);
01602 if (gsignature == NULL)
01603 goto out;
01604
01605 msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
01606 TRUE);
01607 for (i = 0; i < gsignature->len; i++)
01608 {
01609 if (msg_gsignature->len == i
01610 || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
01611 goto mismatch;
01612 }
01613 if (msg_gsignature->len != i)
01614 goto mismatch;
01615
01616 g_signal_emit (proxy,
01617 signals[RECEIVED],
01618 q,
01619 message,
01620 msg_gsignature);
01621 }
01622
01623 out:
01624 g_free (name);
01625 return;
01626 mismatch:
01627 #if 0
01628
01629 g_warning ("Unexpected message signature '%s' for signal '%s'\n",
01630 dbus_message_get_signature (message),
01631 name);
01632 #endif
01633 goto out;
01634 }
01635
01636 typedef struct
01637 {
01638 DBusGProxy *proxy;
01639 guint call_id;
01640 DBusGProxyCallNotify func;
01641 void *data;
01642 GDestroyNotify free_data_func;
01643 } GPendingNotifyClosure;
01644
01645 static void
01646 d_pending_call_notify (DBusPendingCall *dcall,
01647 void *data)
01648 {
01649 GPendingNotifyClosure *closure = data;
01650
01651 (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
01652 }
01653
01654 static void
01655 d_pending_call_free (void *data)
01656 {
01657 GPendingNotifyClosure *closure = data;
01658
01659 if (closure->free_data_func)
01660 (* closure->free_data_func) (closure->data);
01661
01662 g_free (closure);
01663 }
01664
01665 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
01666 do { \
01667 GType valtype; \
01668 int i = 0; \
01669 VALARRAY = g_value_array_new (6); \
01670 valtype = FIRST_ARG_TYPE; \
01671 while (valtype != G_TYPE_INVALID) \
01672 { \
01673 const char *collect_err; \
01674 GValue *val; \
01675 g_value_array_append (VALARRAY, NULL); \
01676 val = g_value_array_get_nth (VALARRAY, i); \
01677 g_value_init (val, valtype); \
01678 collect_err = NULL; \
01679 G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
01680 valtype = va_arg (ARGS, GType); \
01681 i++; \
01682 } \
01683 } while (0)
01684
01685 DBusGProxyCall *
01686 manager_begin_bus_call (DBusGProxyManager *manager,
01687 const char *method,
01688 DBusGProxyCallNotify notify,
01689 gpointer user_data,
01690 GDestroyNotify destroy,
01691 GType first_arg_type,
01692 ...)
01693 {
01694 DBusGProxyCall *call;
01695 va_list args;
01696 GValueArray *arg_values;
01697
01698 va_start (args, first_arg_type);
01699
01700 if (!manager->bus_proxy)
01701 {
01702 manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
01703 "name", DBUS_SERVICE_DBUS,
01704 "path", DBUS_PATH_DBUS,
01705 "interface", DBUS_INTERFACE_DBUS,
01706 NULL);
01707 manager->bus_proxy->manager = manager;
01708 }
01709
01710 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
01711
01712 call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values));
01713
01714 g_value_array_free (arg_values);
01715
01716 va_end (args);
01717
01718 return call;
01719 }
01720
01732 GType
01733 dbus_g_proxy_get_type (void)
01734 {
01735 static GType object_type = 0;
01736
01737 if (!object_type)
01738 {
01739 static const GTypeInfo object_info =
01740 {
01741 sizeof (DBusGProxyClass),
01742 (GBaseInitFunc) NULL,
01743 (GBaseFinalizeFunc) NULL,
01744 (GClassInitFunc) dbus_g_proxy_class_init,
01745 NULL,
01746 NULL,
01747 sizeof (DBusGProxy),
01748 0,
01749 (GInstanceInitFunc) dbus_g_proxy_init,
01750 };
01751
01752 object_type = g_type_register_static (G_TYPE_OBJECT,
01753 "DBusGProxy",
01754 &object_info, 0);
01755 }
01756
01757 return object_type;
01758 }
01759
01760 static DBusGProxy*
01761 dbus_g_proxy_new (DBusGConnection *connection,
01762 const char *name,
01763 const char *path_name,
01764 const char *interface_name)
01765 {
01766 DBusGProxy *proxy;
01767
01768 g_assert (connection != NULL);
01769
01770 proxy = g_object_new (DBUS_TYPE_G_PROXY, "name", name, "path", path_name, "interface", interface_name, NULL);
01771
01772
01773
01774
01775
01776 proxy->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
01777
01778 dbus_g_proxy_manager_register (proxy->manager, proxy);
01779
01780 return proxy;
01781 }
01782
01809 DBusGProxy*
01810 dbus_g_proxy_new_for_name (DBusGConnection *connection,
01811 const char *name,
01812 const char *path_name,
01813 const char *interface_name)
01814 {
01815 g_return_val_if_fail (connection != NULL, NULL);
01816 g_return_val_if_fail (name != NULL, NULL);
01817 g_return_val_if_fail (path_name != NULL, NULL);
01818 g_return_val_if_fail (interface_name != NULL, NULL);
01819
01820 return dbus_g_proxy_new (connection, name,
01821 path_name, interface_name);
01822 }
01823
01847 DBusGProxy*
01848 dbus_g_proxy_new_for_name_owner (DBusGConnection *connection,
01849 const char *name,
01850 const char *path_name,
01851 const char *interface_name,
01852 GError **error)
01853 {
01854 DBusGProxy *proxy;
01855 char *unique_name;
01856
01857 g_return_val_if_fail (connection != NULL, NULL);
01858 g_return_val_if_fail (name != NULL, NULL);
01859 g_return_val_if_fail (path_name != NULL, NULL);
01860 g_return_val_if_fail (interface_name != NULL, NULL);
01861
01862 if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
01863 return NULL;
01864
01865 proxy = dbus_g_proxy_new (connection, unique_name,
01866 path_name, interface_name);
01867 g_free (unique_name);
01868 return proxy;
01869 }
01870
01881 DBusGProxy*
01882 dbus_g_proxy_new_from_proxy (DBusGProxy *proxy,
01883 const char *interface,
01884 const char *path)
01885 {
01886 g_return_val_if_fail (proxy != NULL, NULL);
01887
01888 if (interface == NULL)
01889 interface = proxy->interface;
01890 if (path == NULL)
01891 path = proxy->path;
01892
01893 return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
01894 proxy->name,
01895 path, interface);
01896 }
01897
01912 DBusGProxy*
01913 dbus_g_proxy_new_for_peer (DBusGConnection *connection,
01914 const char *path_name,
01915 const char *interface_name)
01916 {
01917 DBusGProxy *proxy;
01918
01919 g_return_val_if_fail (connection != NULL, NULL);
01920 g_return_val_if_fail (path_name != NULL, NULL);
01921 g_return_val_if_fail (interface_name != NULL, NULL);
01922
01923 proxy = dbus_g_proxy_new (connection, NULL,
01924 path_name, interface_name);
01925
01926 return proxy;
01927 }
01928
01940 const char*
01941 dbus_g_proxy_get_bus_name (DBusGProxy *proxy)
01942 {
01943 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
01944 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
01945
01946 return proxy->name;
01947 }
01948
01955 const char*
01956 dbus_g_proxy_get_interface (DBusGProxy *proxy)
01957 {
01958 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
01959 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
01960
01961 return proxy->interface;
01962 }
01963
01970 void
01971 dbus_g_proxy_set_interface (DBusGProxy *proxy,
01972 const char *interface_name)
01973 {
01974
01975
01976
01977 dbus_g_proxy_manager_unregister (proxy->manager, proxy);
01978 g_free (proxy->interface);
01979 proxy->interface = g_strdup (interface_name);
01980 dbus_g_proxy_manager_register (proxy->manager, proxy);
01981 }
01982
01989 const char*
01990 dbus_g_proxy_get_path (DBusGProxy *proxy)
01991 {
01992 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
01993 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
01994
01995 return proxy->path;
01996 }
01997
01998 static DBusMessage *
01999 dbus_g_proxy_marshal_args_to_message (DBusGProxy *proxy,
02000 const char *method,
02001 GValueArray *args)
02002 {
02003 DBusMessage *message;
02004 DBusMessageIter msgiter;
02005 guint i;
02006
02007 message = dbus_message_new_method_call (proxy->name,
02008 proxy->path,
02009 proxy->interface,
02010 method);
02011 if (message == NULL)
02012 goto oom;
02013
02014 dbus_message_iter_init_append (message, &msgiter);
02015 for (i = 0; i < args->n_values; i++)
02016 {
02017 GValue *gvalue;
02018
02019 gvalue = g_value_array_get_nth (args, i);
02020
02021 if (!_dbus_gvalue_marshal (&msgiter, gvalue))
02022 g_assert_not_reached ();
02023 }
02024 return message;
02025 oom:
02026 return NULL;
02027 }
02028
02029 static guint
02030 dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
02031 const char *method,
02032 DBusGProxyCallNotify notify,
02033 gpointer user_data,
02034 GDestroyNotify destroy,
02035 GValueArray *args)
02036 {
02037 DBusMessage *message;
02038 DBusPendingCall *pending;
02039 GPendingNotifyClosure *closure;
02040 guint call_id;
02041
02042 pending = NULL;
02043
02044 message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
02045 if (!message)
02046 goto oom;
02047
02048 if (!dbus_connection_send_with_reply (proxy->manager->connection,
02049 message,
02050 &pending,
02051 -1))
02052 goto oom;
02053 dbus_message_unref (message);
02054 g_assert (pending != NULL);
02055
02056 call_id = ++proxy->call_id_counter;
02057
02058 if (notify != NULL)
02059 {
02060 closure = g_new (GPendingNotifyClosure, 1);
02061 closure->proxy = proxy;
02062 closure->call_id = call_id;
02063 closure->func = notify;
02064 closure->data = user_data;
02065 closure->free_data_func = destroy;
02066 dbus_pending_call_set_notify (pending, d_pending_call_notify,
02067 closure,
02068 d_pending_call_free);
02069 }
02070
02071 g_hash_table_insert (proxy->pending_calls, GUINT_TO_POINTER (call_id), pending);
02072
02073 return call_id;
02074 oom:
02075 g_error ("Out of memory");
02076 return 0;
02077 }
02078
02079 static gboolean
02080 dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
02081 guint call_id,
02082 GError **error,
02083 GType first_arg_type,
02084 va_list args)
02085 {
02086 DBusMessage *reply;
02087 DBusMessageIter msgiter;
02088 DBusError derror;
02089 va_list args_unwind;
02090 guint over;
02091 int n_retvals_processed;
02092 gboolean ret;
02093 GType valtype;
02094 DBusPendingCall *pending;
02095
02096 reply = NULL;
02097 ret = FALSE;
02098 n_retvals_processed = 0;
02099 over = 0;
02100
02101 pending = g_hash_table_lookup (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02102
02103 dbus_pending_call_block (pending);
02104 reply = dbus_pending_call_steal_reply (pending);
02105
02106 g_assert (reply != NULL);
02107
02108 dbus_error_init (&derror);
02109
02110 switch (dbus_message_get_type (reply))
02111 {
02112 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
02113
02114 dbus_message_iter_init (reply, &msgiter);
02115 valtype = first_arg_type;
02116 while (valtype != G_TYPE_INVALID)
02117 {
02118 int arg_type;
02119 gpointer return_storage;
02120 GValue gvalue = { 0, };
02121 DBusGValueMarshalCtx context;
02122
02123 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
02124 context.proxy = proxy;
02125
02126 arg_type = dbus_message_iter_get_arg_type (&msgiter);
02127 if (arg_type == DBUS_TYPE_INVALID)
02128 {
02129 g_set_error (error, DBUS_GERROR,
02130 DBUS_GERROR_INVALID_ARGS,
02131 _("Too few arguments in reply"));
02132 goto out;
02133 }
02134
02135 return_storage = va_arg (args, gpointer);
02136 if (return_storage == NULL)
02137 goto next;
02138
02139
02140
02141
02142 if (arg_type == DBUS_TYPE_VARIANT
02143 && g_type_is_a (valtype, G_TYPE_VALUE))
02144 {
02145 if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
02146 {
02147 g_set_error (error,
02148 DBUS_GERROR,
02149 DBUS_GERROR_INVALID_ARGS,
02150 _("Couldn't convert argument, expected \"%s\""),
02151 g_type_name (valtype));
02152 goto out;
02153 }
02154 }
02155 else
02156 {
02157 g_value_init (&gvalue, valtype);
02158
02159 if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
02160 goto out;
02161
02162
02163 if (!_dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
02164 g_assert_not_reached ();
02165
02166 }
02167
02168 next:
02169 n_retvals_processed++;
02170 dbus_message_iter_next (&msgiter);
02171 valtype = va_arg (args, GType);
02172 }
02173
02174 while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
02175 {
02176 over++;
02177 dbus_message_iter_next (&msgiter);
02178 }
02179
02180 if (over > 0)
02181 {
02182 g_set_error (error, DBUS_GERROR,
02183 DBUS_GERROR_INVALID_ARGS,
02184 _("Too many arguments in reply; expected %d, got %d"),
02185 n_retvals_processed, over);
02186 goto out;
02187 }
02188 break;
02189 case DBUS_MESSAGE_TYPE_ERROR:
02190 dbus_set_error_from_message (&derror, reply);
02191 dbus_set_g_error (error, &derror);
02192 dbus_error_free (&derror);
02193 goto out;
02194 break;
02195 default:
02196 dbus_set_error (&derror, DBUS_ERROR_FAILED,
02197 "Reply was neither a method return nor an exception");
02198 dbus_set_g_error (error, &derror);
02199 dbus_error_free (&derror);
02200 goto out;
02201 break;
02202 }
02203
02204 ret = TRUE;
02205 out:
02206 va_end (args);
02207
02208 if (ret == FALSE)
02209 {
02210 int i;
02211 for (i = 0; i < n_retvals_processed; i++)
02212 {
02213 gpointer retval;
02214
02215 retval = va_arg (args_unwind, gpointer);
02216
02217 g_free (retval);
02218 }
02219 }
02220 va_end (args_unwind);
02221
02222 g_hash_table_remove (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02223
02224 if (reply)
02225 dbus_message_unref (reply);
02226 return ret;
02227 }
02228
02250 DBusGProxyCall *
02251 dbus_g_proxy_begin_call (DBusGProxy *proxy,
02252 const char *method,
02253 DBusGProxyCallNotify notify,
02254 gpointer user_data,
02255 GDestroyNotify destroy,
02256 GType first_arg_type,
02257 ...)
02258 {
02259 guint call_id;
02260 va_list args;
02261 GValueArray *arg_values;
02262
02263 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02264 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02265
02266 va_start (args, first_arg_type);
02267
02268 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02269
02270 call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values);
02271
02272 g_value_array_free (arg_values);
02273
02274 va_end (args);
02275
02276 return DBUS_G_PROXY_ID_TO_CALL (call_id);
02277 }
02278
02299 gboolean
02300 dbus_g_proxy_end_call (DBusGProxy *proxy,
02301 DBusGProxyCall *call,
02302 GError **error,
02303 GType first_arg_type,
02304 ...)
02305 {
02306 gboolean ret;
02307 va_list args;
02308
02309 va_start (args, first_arg_type);
02310
02311 ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
02312
02313 va_end (args);
02314
02315 return ret;
02316 }
02317
02332 gboolean
02333 dbus_g_proxy_call (DBusGProxy *proxy,
02334 const char *method,
02335 GError **error,
02336 GType first_arg_type,
02337 ...)
02338 {
02339 gboolean ret;
02340 guint call_id;
02341 va_list args;
02342 GValueArray *in_args;
02343
02344 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02345 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02346
02347 va_start (args, first_arg_type);
02348
02349 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02350
02351 call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args);
02352
02353 g_value_array_free (in_args);
02354
02355 first_arg_type = va_arg (args, GType);
02356 ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02357
02358 va_end (args);
02359
02360 return ret;
02361 }
02362
02374 void
02375 dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
02376 const char *method,
02377 GType first_arg_type,
02378 ...)
02379 {
02380 DBusMessage *message;
02381 va_list args;
02382 GValueArray *in_args;
02383
02384 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02385 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02386
02387 va_start (args, first_arg_type);
02388 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02389
02390 message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
02391
02392 g_value_array_free (in_args);
02393 va_end (args);
02394
02395 if (!message)
02396 goto oom;
02397
02398 dbus_message_set_no_reply (message, TRUE);
02399
02400 if (!dbus_connection_send (proxy->manager->connection,
02401 message,
02402 NULL))
02403 goto oom;
02404 dbus_message_unref (message);
02405 return;
02406
02407 oom:
02408 g_error ("Out of memory");
02409 }
02410
02420 void
02421 dbus_g_proxy_cancel_call (DBusGProxy *proxy,
02422 DBusGProxyCall *call)
02423 {
02424 guint call_id;
02425 DBusPendingCall *pending;
02426
02427 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02428 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02429
02430 call_id = DBUS_G_PROXY_CALL_TO_ID (call);
02431
02432 pending = g_hash_table_lookup (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02433 g_return_if_fail (pending != NULL);
02434
02435 dbus_pending_call_cancel (pending);
02436
02437 g_hash_table_remove (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02438 }
02439
02458 void
02459 dbus_g_proxy_send (DBusGProxy *proxy,
02460 DBusMessage *message,
02461 dbus_uint32_t *client_serial)
02462 {
02463 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02464 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02465
02466 if (proxy->name)
02467 {
02468 if (!dbus_message_set_destination (message, proxy->name))
02469 g_error ("Out of memory");
02470 }
02471 if (proxy->path)
02472 {
02473 if (!dbus_message_set_path (message, proxy->path))
02474 g_error ("Out of memory");
02475 }
02476 if (proxy->interface)
02477 {
02478 if (!dbus_message_set_interface (message, proxy->interface))
02479 g_error ("Out of memory");
02480 }
02481
02482 if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
02483 g_error ("Out of memory\n");
02484 }
02485
02486 static void
02487 array_free_all (gpointer array)
02488 {
02489 g_array_free (array, TRUE);
02490 }
02491
02501 void
02502 dbus_g_proxy_add_signal (DBusGProxy *proxy,
02503 const char *signal_name,
02504 GType first_type,
02505 ...)
02506 {
02507 GQuark q;
02508 char *name;
02509 GArray *gtypesig;
02510 GType gtype;
02511 va_list args;
02512
02513 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02514 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02515 g_return_if_fail (signal_name != NULL);
02516
02517 name = create_signal_name (proxy->interface, signal_name);
02518
02519 q = g_quark_from_string (name);
02520
02521 g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
02522
02523 gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
02524
02525 va_start (args, first_type);
02526 gtype = first_type;
02527 while (gtype != G_TYPE_INVALID)
02528 {
02529 g_array_append_val (gtypesig, gtype);
02530 gtype = va_arg (args, GType);
02531 }
02532 va_end (args);
02533
02534 #ifndef G_DISABLE_CHECKS
02535 if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
02536 g_warning ("No marshaller for signature of signal '%s'", signal_name);
02537 #endif
02538
02539
02540 g_datalist_id_set_data_full (&proxy->signal_signatures,
02541 q, gtypesig,
02542 array_free_all);
02543
02544 g_free (name);
02545 }
02546
02558 void
02559 dbus_g_proxy_connect_signal (DBusGProxy *proxy,
02560 const char *signal_name,
02561 GCallback handler,
02562 void *data,
02563 GClosureNotify free_data_func)
02564 {
02565 char *name;
02566 GClosure *closure;
02567 GQuark q;
02568
02569 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02570 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02571 g_return_if_fail (signal_name != NULL);
02572 g_return_if_fail (handler != NULL);
02573
02574 name = create_signal_name (proxy->interface, signal_name);
02575
02576 q = g_quark_try_string (name);
02577
02578 #ifndef G_DISABLE_CHECKS
02579 if (q == 0 || g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL)
02580 {
02581 g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
02582 g_free (name);
02583 return;
02584 }
02585 #endif
02586
02587 closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
02588
02589 g_signal_connect_closure_by_id (G_OBJECT (proxy),
02590 signals[RECEIVED],
02591 q,
02592 closure, FALSE);
02593
02594 g_free (name);
02595 }
02596
02606 void
02607 dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
02608 const char *signal_name,
02609 GCallback handler,
02610 void *data)
02611 {
02612 char *name;
02613 GQuark q;
02614
02615 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02616 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02617 g_return_if_fail (signal_name != NULL);
02618 g_return_if_fail (handler != NULL);
02619
02620 name = create_signal_name (proxy->interface, signal_name);
02621
02622 q = g_quark_try_string (name);
02623
02624 if (q != 0)
02625 {
02626 g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
02627 G_SIGNAL_MATCH_DETAIL |
02628 G_SIGNAL_MATCH_FUNC |
02629 G_SIGNAL_MATCH_DATA,
02630 signals[RECEIVED],
02631 q,
02632 NULL,
02633 G_CALLBACK (handler), data);
02634 }
02635 else
02636 {
02637 g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
02638 name);
02639 }
02640
02641 g_free (name);
02642 }
02643
02646 #ifdef DBUS_BUILD_TESTS
02647
02653 gboolean
02654 _dbus_g_proxy_test (void)
02655 {
02656
02657
02658 return TRUE;
02659 }
02660
02661 #endif