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 const char *tri;
00639 DBusGProxyList *list;
00640 const char *name;
00641 GSList *tmp;
00642 DBusGProxyUnassociateData *data;
00643
00644 tri = key;
00645 list = val;
00646 data = user_data;
00647 name = data->name;
00648
00649 for (tmp = list->proxies; tmp; tmp = tmp->next)
00650 {
00651 DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
00652 DBusGProxyManager *manager;
00653
00654 manager = proxy->manager;
00655
00656 if (!strcmp (proxy->name, name))
00657 {
00658 if (!proxy->for_owner)
00659 {
00660 g_assert (proxy->associated);
00661 g_assert (proxy->name_call == NULL);
00662
00663 proxy->associated = FALSE;
00664 manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
00665 }
00666 else
00667 {
00668 data->destroyed = g_slist_prepend (data->destroyed, proxy);
00669 }
00670 }
00671 }
00672 }
00673
00674 static void
00675 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager *manager,
00676 const char *name,
00677 const char *prev_owner,
00678 const char *new_owner)
00679 {
00680 GSList *names;
00681
00682 if (prev_owner[0] == '\0')
00683 {
00684 GSList *tmp;
00685 GSList *removed;
00686
00687
00688
00689 removed = NULL;
00690
00691 for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
00692 {
00693 DBusGProxy *proxy;
00694
00695 proxy = tmp->data;
00696
00697 if (!strcmp (proxy->name, name))
00698 {
00699 removed = g_slist_prepend (removed, tmp);
00700
00701 dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
00702 proxy->associated = TRUE;
00703 }
00704 }
00705
00706 for (tmp = removed; tmp; tmp = tmp->next)
00707 manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
00708 g_slist_free (removed);
00709 }
00710 else
00711 {
00712 DBusGProxyNameOwnerInfo *info;
00713 GSList *link;
00714
00715
00716
00717 names = g_hash_table_lookup (manager->owner_names, prev_owner);
00718
00719 link = g_slist_find_custom (names, name, find_name_in_info);
00720
00721 info = NULL;
00722 if (link != NULL)
00723 {
00724 info = link->data;
00725
00726 names = g_slist_delete_link (names, link);
00727
00728 if (names == NULL)
00729 g_hash_table_remove (manager->owner_names, prev_owner);
00730 }
00731
00732 if (new_owner[0] == '\0')
00733 {
00734 DBusGProxyUnassociateData data;
00735 GSList *tmp;
00736
00737 data.name = name;
00738 data.destroyed = NULL;
00739
00740
00741 g_hash_table_foreach (manager->proxy_lists,
00742 unassociate_proxies, &data);
00743
00744 UNLOCK_MANAGER (manager);
00745
00746 for (tmp = data.destroyed; tmp; tmp = tmp->next)
00747 dbus_g_proxy_destroy (tmp->data);
00748 g_slist_free (data.destroyed);
00749
00750 LOCK_MANAGER (manager);
00751 }
00752 else
00753 {
00754 insert_nameinfo (manager, new_owner, info);
00755 }
00756 }
00757 }
00758
00759 static void
00760 got_name_owner_cb (DBusGProxy *bus_proxy,
00761 DBusGProxyCall *call,
00762 void *user_data)
00763 {
00764 DBusGProxy *proxy;
00765 GError *error;
00766 char *owner;
00767
00768 proxy = user_data;
00769 error = NULL;
00770 owner = NULL;
00771
00772 LOCK_MANAGER (proxy->manager);
00773
00774 if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
00775 G_TYPE_STRING, &owner,
00776 G_TYPE_INVALID))
00777 {
00778 if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
00779 {
00780 proxy->manager->unassociated_proxies = g_slist_prepend (proxy->manager->unassociated_proxies, proxy);
00781 }
00782 else
00783 g_warning ("Couldn't get name owner (%s): %s",
00784 dbus_g_error_get_name (error),
00785 error->message);
00786
00787 g_clear_error (&error);
00788 goto out;
00789 }
00790 else
00791 {
00792 dbus_g_proxy_manager_monitor_name_owner (proxy->manager, owner, proxy->name);
00793 proxy->associated = TRUE;
00794 }
00795
00796 out:
00797 proxy->name_call = NULL;
00798 UNLOCK_MANAGER (proxy->manager);
00799 g_free (owner);
00800 }
00801
00802 static char *
00803 get_name_owner (DBusConnection *connection,
00804 const char *name,
00805 GError **error)
00806 {
00807 DBusError derror;
00808 DBusMessage *request, *reply;
00809 char *base_name;
00810
00811 dbus_error_init (&derror);
00812
00813 base_name = NULL;
00814 reply = NULL;
00815
00816 request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
00817 DBUS_PATH_DBUS,
00818 DBUS_INTERFACE_DBUS,
00819 "GetNameOwner");
00820 if (request == NULL)
00821 g_error ("Out of memory");
00822
00823 if (!dbus_message_append_args (request,
00824 DBUS_TYPE_STRING, &name,
00825 DBUS_TYPE_INVALID))
00826 g_error ("Out of memory");
00827
00828 reply =
00829 dbus_connection_send_with_reply_and_block (connection,
00830 request,
00831 2000, &derror);
00832 if (reply == NULL)
00833 goto error;
00834
00835 if (dbus_set_error_from_message (&derror, reply))
00836 goto error;
00837
00838 if (!dbus_message_get_args (reply, &derror,
00839 DBUS_TYPE_STRING, &base_name,
00840 DBUS_TYPE_INVALID))
00841 goto error;
00842
00843 base_name = g_strdup (base_name);
00844 goto out;
00845
00846 error:
00847 g_assert (dbus_error_is_set (&derror));
00848 dbus_set_g_error (error, &derror);
00849 dbus_error_free (&derror);
00850
00851 out:
00852 if (request)
00853 dbus_message_unref (request);
00854 if (reply)
00855 dbus_message_unref (reply);
00856
00857 return base_name;
00858 }
00859
00860
00861 static void
00862 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
00863 DBusGProxy *proxy)
00864 {
00865 DBusGProxyList *list;
00866
00867 LOCK_MANAGER (manager);
00868
00869 if (manager->proxy_lists == NULL)
00870 {
00871 g_assert (manager->owner_names == NULL);
00872
00873 list = NULL;
00874 manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00875 tristring_equal,
00876 NULL,
00877 (GFreeFunc) g_proxy_list_free);
00878 manager->owner_names = g_hash_table_new_full (g_str_hash,
00879 g_str_equal,
00880 g_free,
00881 NULL);
00882
00883
00884
00885 dbus_bus_add_match (manager->connection,
00886 "type='signal',sender='" DBUS_SERVICE_DBUS
00887 "',path='" DBUS_PATH_DBUS
00888 "',interface='" DBUS_INTERFACE_DBUS
00889 "',member='NameOwnerChanged'",
00890 NULL);
00891 }
00892 else
00893 {
00894 char *tri;
00895
00896 tri = tristring_from_proxy (proxy);
00897
00898 list = g_hash_table_lookup (manager->proxy_lists, tri);
00899
00900 g_free (tri);
00901 }
00902
00903 if (list == NULL)
00904 {
00905 list = g_proxy_list_new (proxy);
00906
00907 g_hash_table_replace (manager->proxy_lists,
00908 list->name, list);
00909 }
00910
00911 if (list->proxies == NULL)
00912 {
00913
00914
00915
00916
00917 char *rule;
00918
00919 rule = g_proxy_get_match_rule (proxy);
00920
00921
00922
00923
00924 dbus_bus_add_match (manager->connection,
00925 rule, NULL);
00926
00927 g_free (rule);
00928 }
00929
00930 g_assert (g_slist_find (list->proxies, proxy) == NULL);
00931
00932 list->proxies = g_slist_prepend (list->proxies, proxy);
00933
00934 if (!proxy->for_owner)
00935 {
00936 const char *owner;
00937 DBusGProxyNameOwnerInfo *info;
00938
00939 if (!dbus_g_proxy_manager_lookup_name_owner (manager, proxy->name, &info, &owner))
00940 {
00941 proxy->name_call = manager_begin_bus_call (manager, "GetNameOwner",
00942 got_name_owner_cb,
00943 proxy, NULL,
00944 G_TYPE_STRING,
00945 proxy->name,
00946 G_TYPE_INVALID);
00947
00948 proxy->associated = FALSE;
00949 }
00950 else
00951 {
00952 info->refcount++;
00953 proxy->associated = TRUE;
00954 }
00955 }
00956
00957 UNLOCK_MANAGER (manager);
00958 }
00959
00960 static void
00961 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
00962 DBusGProxy *proxy)
00963 {
00964 DBusGProxyList *list;
00965 char *tri;
00966
00967 LOCK_MANAGER (manager);
00968
00969 #ifndef G_DISABLE_CHECKS
00970 if (manager->proxy_lists == NULL)
00971 {
00972 g_warning ("Trying to unregister a proxy but there aren't any registered");
00973 return;
00974 }
00975 #endif
00976
00977 tri = tristring_from_proxy (proxy);
00978
00979 list = g_hash_table_lookup (manager->proxy_lists, tri);
00980
00981 #ifndef G_DISABLE_CHECKS
00982 if (list == NULL)
00983 {
00984 g_warning ("Trying to unregister a proxy but it isn't registered");
00985 return;
00986 }
00987 #endif
00988
00989 g_assert (g_slist_find (list->proxies, proxy) != NULL);
00990
00991 list->proxies = g_slist_remove (list->proxies, proxy);
00992
00993 g_assert (g_slist_find (list->proxies, proxy) == NULL);
00994
00995 if (!proxy->for_owner)
00996 {
00997 if (!proxy->associated)
00998 {
00999 GSList *link;
01000
01001 if (proxy->name_call != 0)
01002 {
01003 dbus_g_proxy_cancel_call (manager->bus_proxy, proxy->name_call);
01004 proxy->name_call = 0;
01005 }
01006 else
01007 {
01008 link = g_slist_find (manager->unassociated_proxies, proxy);
01009 g_assert (link != NULL);
01010
01011 manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link);
01012 }
01013 }
01014 else
01015 {
01016 g_assert (proxy->name_call == 0);
01017
01018 dbus_g_proxy_manager_unmonitor_name_owner (manager, proxy->name);
01019 }
01020 }
01021
01022 if (list->proxies == NULL)
01023 {
01024 char *rule;
01025 g_hash_table_remove (manager->proxy_lists,
01026 tri);
01027 list = NULL;
01028
01029 rule = g_proxy_get_match_rule (proxy);
01030 dbus_bus_remove_match (manager->connection,
01031 rule, NULL);
01032 g_free (rule);
01033 }
01034
01035 if (g_hash_table_size (manager->proxy_lists) == 0)
01036 {
01037 g_hash_table_destroy (manager->proxy_lists);
01038 manager->proxy_lists = NULL;
01039 }
01040
01041 g_free (tri);
01042
01043 UNLOCK_MANAGER (manager);
01044 }
01045
01046 static void
01047 list_proxies_foreach (gpointer key,
01048 gpointer value,
01049 gpointer user_data)
01050 {
01051 DBusGProxyList *list;
01052 GSList **ret;
01053 GSList *tmp;
01054
01055 list = value;
01056 ret = user_data;
01057
01058 tmp = list->proxies;
01059 while (tmp != NULL)
01060 {
01061 DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
01062
01063 g_object_ref (proxy);
01064 *ret = g_slist_prepend (*ret, proxy);
01065
01066 tmp = tmp->next;
01067 }
01068 }
01069
01070 static GSList*
01071 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
01072 {
01073 GSList *ret;
01074
01075 ret = NULL;
01076
01077 if (manager->proxy_lists)
01078 {
01079 g_hash_table_foreach (manager->proxy_lists,
01080 list_proxies_foreach,
01081 &ret);
01082 }
01083
01084 return ret;
01085 }
01086
01087 static DBusHandlerResult
01088 dbus_g_proxy_manager_filter (DBusConnection *connection,
01089 DBusMessage *message,
01090 void *user_data)
01091 {
01092 DBusGProxyManager *manager;
01093
01094 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
01095 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01096
01097 manager = user_data;
01098
01099 dbus_g_proxy_manager_ref (manager);
01100
01101 LOCK_MANAGER (manager);
01102
01103 if (dbus_message_is_signal (message,
01104 DBUS_INTERFACE_LOCAL,
01105 "Disconnected"))
01106 {
01107
01108
01109
01110 GSList *all;
01111 GSList *tmp;
01112
01113 all = dbus_g_proxy_manager_list_all (manager);
01114
01115 tmp = all;
01116 while (tmp != NULL)
01117 {
01118 DBusGProxy *proxy;
01119
01120 proxy = DBUS_G_PROXY (tmp->data);
01121
01122 UNLOCK_MANAGER (manager);
01123 dbus_g_proxy_destroy (proxy);
01124 g_object_unref (G_OBJECT (proxy));
01125 LOCK_MANAGER (manager);
01126
01127 tmp = tmp->next;
01128 }
01129
01130 g_slist_free (all);
01131
01132 #ifndef G_DISABLE_CHECKS
01133 if (manager->proxy_lists != NULL)
01134 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.");
01135 #endif
01136 }
01137 else
01138 {
01139 char *tri;
01140 GSList *full_list;
01141 GSList *owned_names;
01142 GSList *tmp;
01143 const char *sender;
01144
01145
01146 if (dbus_message_is_signal (message,
01147 DBUS_INTERFACE_DBUS,
01148 "NameOwnerChanged"))
01149 {
01150 const char *name;
01151 const char *prev_owner;
01152 const char *new_owner;
01153 DBusError derr;
01154
01155 dbus_error_init (&derr);
01156 if (!dbus_message_get_args (message,
01157 &derr,
01158 DBUS_TYPE_STRING,
01159 &name,
01160 DBUS_TYPE_STRING,
01161 &prev_owner,
01162 DBUS_TYPE_STRING,
01163 &new_owner,
01164 DBUS_TYPE_INVALID))
01165 {
01166
01167 dbus_error_free (&derr);
01168 }
01169 else if (manager->owner_names != NULL)
01170 {
01171 dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
01172 }
01173 }
01174
01175 sender = dbus_message_get_sender (message);
01176
01177
01178 g_assert (sender != NULL);
01179 g_assert (dbus_message_get_path (message) != NULL);
01180 g_assert (dbus_message_get_interface (message) != NULL);
01181 g_assert (dbus_message_get_member (message) != NULL);
01182
01183 tri = tristring_from_message (message);
01184
01185 if (manager->proxy_lists)
01186 {
01187 DBusGProxyList *owner_list;
01188 owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01189 if (owner_list)
01190 full_list = g_slist_copy (owner_list->proxies);
01191 else
01192 full_list = NULL;
01193 }
01194 else
01195 full_list = NULL;
01196
01197 g_free (tri);
01198
01199 if (manager->owner_names)
01200 {
01201 owned_names = g_hash_table_lookup (manager->owner_names, sender);
01202 for (tmp = owned_names; tmp; tmp = tmp->next)
01203 {
01204 DBusGProxyList *owner_list;
01205 DBusGProxyNameOwnerInfo *nameinfo;
01206
01207 nameinfo = tmp->data;
01208 g_assert (nameinfo->refcount > 0);
01209 tri = tristring_alloc_from_strings (0, nameinfo->name,
01210 dbus_message_get_path (message),
01211 dbus_message_get_interface (message));
01212
01213 owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
01214 if (owner_list != NULL)
01215 full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies));
01216 g_free (tri);
01217 }
01218 }
01219
01220 #if 0
01221 g_print ("proxy got %s,%s,%s = list %p\n",
01222 tri,
01223 tri + strlen (tri) + 1,
01224 tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
01225 list);
01226 #endif
01227
01228
01229
01230 g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
01231
01232 for (tmp = full_list; tmp; tmp = tmp->next)
01233 {
01234 DBusGProxy *proxy;
01235
01236 proxy = DBUS_G_PROXY (tmp->data);
01237
01238 UNLOCK_MANAGER (manager);
01239 dbus_g_proxy_emit_remote_signal (proxy, message);
01240 g_object_unref (G_OBJECT (proxy));
01241 LOCK_MANAGER (manager);
01242 }
01243 g_slist_free (full_list);
01244 }
01245
01246 UNLOCK_MANAGER (manager);
01247 dbus_g_proxy_manager_unref (manager);
01248
01249
01250
01251
01252 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01253 }
01254
01255
01256
01257
01258
01259 #define DBUS_G_PROXY_DESTROYED(proxy) (DBUS_G_PROXY (proxy)->manager == NULL)
01260
01261 static void
01262 marshal_dbus_message_to_g_marshaller (GClosure *closure,
01263 GValue *return_value,
01264 guint n_param_values,
01265 const GValue *param_values,
01266 gpointer invocation_hint,
01267 gpointer marshal_data);
01268 enum
01269 {
01270 PROP_0,
01271 PROP_NAME,
01272 PROP_PATH,
01273 PROP_INTERFACE
01274 };
01275
01276 enum
01277 {
01278 DESTROY,
01279 RECEIVED,
01280 LAST_SIGNAL
01281 };
01282
01283 static void *parent_class;
01284 static guint signals[LAST_SIGNAL] = { 0 };
01285
01286 static void
01287 dbus_g_proxy_init (DBusGProxy *proxy)
01288 {
01289 g_datalist_init (&proxy->signal_signatures);
01290 proxy->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
01291 (GDestroyNotify) dbus_pending_call_unref);
01292 }
01293
01294 static GObject *
01295 dbus_g_proxy_constructor (GType type,
01296 guint n_construct_properties,
01297 GObjectConstructParam *construct_properties)
01298 {
01299 DBusGProxy *proxy;
01300 DBusGProxyClass *klass;
01301 GObjectClass *parent_class;
01302
01303 klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
01304
01305 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
01306
01307 proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
01308 construct_properties));
01309
01310 proxy->for_owner = (proxy->name[0] == ':');
01311 proxy->name_call = 0;
01312 proxy->associated = FALSE;
01313
01314 return G_OBJECT (proxy);
01315 }
01316
01317 static void
01318 dbus_g_proxy_class_init (DBusGProxyClass *klass)
01319 {
01320 GObjectClass *object_class = G_OBJECT_CLASS (klass);
01321
01322 parent_class = g_type_class_peek_parent (klass);
01323
01324 object_class->set_property = dbus_g_proxy_set_property;
01325 object_class->get_property = dbus_g_proxy_get_property;
01326
01327 g_object_class_install_property (object_class,
01328 PROP_NAME,
01329 g_param_spec_string ("name",
01330 "name",
01331 "name",
01332 NULL,
01333 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01334
01335 g_object_class_install_property (object_class,
01336 PROP_PATH,
01337 g_param_spec_string ("path",
01338 "path",
01339 "path",
01340 NULL,
01341 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01342
01343 g_object_class_install_property (object_class,
01344 PROP_INTERFACE,
01345 g_param_spec_string ("interface",
01346 "interface",
01347 "interface",
01348 NULL,
01349 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
01350
01351 object_class->finalize = dbus_g_proxy_finalize;
01352 object_class->dispose = dbus_g_proxy_dispose;
01353 object_class->constructor = dbus_g_proxy_constructor;
01354
01355 signals[DESTROY] =
01356 g_signal_new ("destroy",
01357 G_OBJECT_CLASS_TYPE (object_class),
01358 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
01359 0,
01360 NULL, NULL,
01361 g_cclosure_marshal_VOID__VOID,
01362 G_TYPE_NONE, 0);
01363
01364 signals[RECEIVED] =
01365 g_signal_new ("received",
01366 G_OBJECT_CLASS_TYPE (object_class),
01367 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
01368 0,
01369 NULL, NULL,
01370 marshal_dbus_message_to_g_marshaller,
01371 G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
01372 }
01373
01374 static void
01375 cancel_pending_call (gpointer key, gpointer val, gpointer data)
01376 {
01377 DBusGProxyCall *call = key;
01378 DBusGProxy *proxy = data;
01379
01380 dbus_g_proxy_cancel_call (proxy, call);
01381 }
01382
01383 static void
01384 dbus_g_proxy_dispose (GObject *object)
01385 {
01386 DBusGProxy *proxy;
01387
01388 proxy = DBUS_G_PROXY (object);
01389
01390
01391 g_hash_table_foreach (proxy->pending_calls, cancel_pending_call, proxy);
01392 g_hash_table_destroy (proxy->pending_calls);
01393
01394 if (proxy->manager && proxy != proxy->manager->bus_proxy)
01395 {
01396 dbus_g_proxy_manager_unregister (proxy->manager, proxy);
01397 dbus_g_proxy_manager_unref (proxy->manager);
01398 }
01399 proxy->manager = NULL;
01400
01401 g_datalist_clear (&proxy->signal_signatures);
01402
01403 g_signal_emit (object, signals[DESTROY], 0);
01404
01405 G_OBJECT_CLASS (parent_class)->dispose (object);
01406 }
01407
01408 static void
01409 dbus_g_proxy_finalize (GObject *object)
01410 {
01411 DBusGProxy *proxy;
01412
01413 proxy = DBUS_G_PROXY (object);
01414
01415 g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
01416
01417 g_free (proxy->name);
01418 g_free (proxy->path);
01419 g_free (proxy->interface);
01420
01421 G_OBJECT_CLASS (parent_class)->finalize (object);
01422 }
01423
01424 static void
01425 dbus_g_proxy_destroy (DBusGProxy *proxy)
01426 {
01427
01428
01429
01430 g_object_run_dispose (G_OBJECT (proxy));
01431 }
01432
01433 static void
01434 dbus_g_proxy_set_property (GObject *object,
01435 guint prop_id,
01436 const GValue *value,
01437 GParamSpec *pspec)
01438 {
01439 DBusGProxy *proxy = DBUS_G_PROXY (object);
01440
01441 switch (prop_id)
01442 {
01443 case PROP_NAME:
01444 proxy->name = g_strdup (g_value_get_string (value));
01445 break;
01446 case PROP_PATH:
01447 proxy->path = g_strdup (g_value_get_string (value));
01448 break;
01449 case PROP_INTERFACE:
01450 proxy->interface = g_strdup (g_value_get_string (value));
01451 break;
01452 default:
01453 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01454 break;
01455 }
01456 }
01457
01458 static void
01459 dbus_g_proxy_get_property (GObject *object,
01460 guint prop_id,
01461 GValue *value,
01462 GParamSpec *pspec)
01463 {
01464 DBusGProxy *proxy = DBUS_G_PROXY (object);
01465
01466 switch (prop_id)
01467 {
01468 case PROP_NAME:
01469 g_value_set_string (value, proxy->name);
01470 break;
01471 case PROP_PATH:
01472 g_value_set_string (value, proxy->path);
01473 break;
01474 case PROP_INTERFACE:
01475 g_value_set_string (value, proxy->interface);
01476 break;
01477 default:
01478 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01479 break;
01480 }
01481 }
01482
01483
01484
01485
01486
01487
01488 static char*
01489 create_signal_name (const char *interface,
01490 const char *signal)
01491 {
01492 GString *str;
01493 char *p;
01494
01495 str = g_string_new (interface);
01496
01497 g_string_append (str, "-");
01498
01499 g_string_append (str, signal);
01500
01501
01502 p = str->str;
01503 while (*p)
01504 {
01505 if (*p == '.')
01506 *p = '-';
01507 ++p;
01508 }
01509
01510 return g_string_free (str, FALSE);
01511 }
01512
01513 static void
01514 marshal_dbus_message_to_g_marshaller (GClosure *closure,
01515 GValue *return_value,
01516 guint n_param_values,
01517 const GValue *param_values,
01518 gpointer invocation_hint,
01519 gpointer marshal_data)
01520 {
01521
01522
01523
01524
01525
01526 #define MAX_SIGNATURE_ARGS 20
01527 GValueArray *value_array;
01528 GSignalCMarshaller c_marshaller;
01529 DBusGProxy *proxy;
01530 DBusMessage *message;
01531 GArray *gsignature;
01532 const GType *types;
01533
01534 g_assert (n_param_values == 3);
01535
01536 proxy = g_value_get_object (¶m_values[0]);
01537 message = g_value_get_boxed (¶m_values[1]);
01538 gsignature = g_value_get_pointer (¶m_values[2]);
01539
01540 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
01541 g_return_if_fail (message != NULL);
01542 g_return_if_fail (gsignature != NULL);
01543
01544 c_marshaller = _dbus_gobject_lookup_marshaller (G_TYPE_NONE, gsignature->len,
01545 (GType*) gsignature->data);
01546
01547 g_return_if_fail (c_marshaller != NULL);
01548
01549 {
01550 DBusGValueMarshalCtx context;
01551 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
01552 context.proxy = proxy;
01553
01554 types = (const GType*) gsignature->data;
01555 value_array = _dbus_gvalue_demarshal_message (&context, message,
01556 gsignature->len, types, NULL);
01557 }
01558
01559 if (value_array == NULL)
01560 return;
01561
01562 g_value_array_prepend (value_array, NULL);
01563 g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
01564 g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
01565
01566 (* c_marshaller) (closure, return_value, value_array->n_values,
01567 value_array->values, invocation_hint, marshal_data);
01568
01569 g_value_array_free (value_array);
01570 }
01571
01572 static void
01573 dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
01574 DBusMessage *message)
01575 {
01576 const char *interface;
01577 const char *signal;
01578 char *name;
01579 GQuark q;
01580
01581 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
01582
01583 interface = dbus_message_get_interface (message);
01584 signal = dbus_message_get_member (message);
01585
01586 g_assert (interface != NULL);
01587 g_assert (signal != NULL);
01588
01589 name = create_signal_name (interface, signal);
01590
01591
01592
01593
01594
01595 q = g_quark_try_string (name);
01596
01597 if (q != 0)
01598 {
01599 GArray *gsignature;
01600 GArray *msg_gsignature;
01601 guint i;
01602
01603 gsignature = g_datalist_id_get_data (&proxy->signal_signatures, q);
01604 if (gsignature == NULL)
01605 goto out;
01606
01607 msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
01608 TRUE);
01609 for (i = 0; i < gsignature->len; i++)
01610 {
01611 if (msg_gsignature->len == i
01612 || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
01613 goto mismatch;
01614 }
01615 if (msg_gsignature->len != i)
01616 goto mismatch;
01617
01618 g_signal_emit (proxy,
01619 signals[RECEIVED],
01620 q,
01621 message,
01622 msg_gsignature);
01623 }
01624
01625 out:
01626 g_free (name);
01627 return;
01628 mismatch:
01629 #if 0
01630
01631 g_warning ("Unexpected message signature '%s' for signal '%s'\n",
01632 dbus_message_get_signature (message),
01633 name);
01634 #endif
01635 goto out;
01636 }
01637
01638 typedef struct
01639 {
01640 DBusGProxy *proxy;
01641 guint call_id;
01642 DBusGProxyCallNotify func;
01643 void *data;
01644 GDestroyNotify free_data_func;
01645 } GPendingNotifyClosure;
01646
01647 static void
01648 d_pending_call_notify (DBusPendingCall *dcall,
01649 void *data)
01650 {
01651 GPendingNotifyClosure *closure = data;
01652
01653 (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
01654 }
01655
01656 static void
01657 d_pending_call_free (void *data)
01658 {
01659 GPendingNotifyClosure *closure = data;
01660
01661 if (closure->free_data_func)
01662 (* closure->free_data_func) (closure->data);
01663
01664 g_free (closure);
01665 }
01666
01667 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
01668 do { \
01669 GType valtype; \
01670 int i = 0; \
01671 VALARRAY = g_value_array_new (6); \
01672 valtype = FIRST_ARG_TYPE; \
01673 while (valtype != G_TYPE_INVALID) \
01674 { \
01675 const char *collect_err; \
01676 GValue *val; \
01677 g_value_array_append (VALARRAY, NULL); \
01678 val = g_value_array_get_nth (VALARRAY, i); \
01679 g_value_init (val, valtype); \
01680 collect_err = NULL; \
01681 G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
01682 valtype = va_arg (ARGS, GType); \
01683 i++; \
01684 } \
01685 } while (0)
01686
01687 DBusGProxyCall *
01688 manager_begin_bus_call (DBusGProxyManager *manager,
01689 const char *method,
01690 DBusGProxyCallNotify notify,
01691 gpointer user_data,
01692 GDestroyNotify destroy,
01693 GType first_arg_type,
01694 ...)
01695 {
01696 DBusGProxyCall *call;
01697 va_list args;
01698 GValueArray *arg_values;
01699
01700 va_start (args, first_arg_type);
01701
01702 if (!manager->bus_proxy)
01703 {
01704 manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
01705 "name", DBUS_SERVICE_DBUS,
01706 "path", DBUS_PATH_DBUS,
01707 "interface", DBUS_INTERFACE_DBUS,
01708 NULL);
01709 manager->bus_proxy->manager = manager;
01710 }
01711
01712 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
01713
01714 call = DBUS_G_PROXY_ID_TO_CALL (dbus_g_proxy_begin_call_internal (manager->bus_proxy, method, notify, user_data, destroy, arg_values));
01715
01716 g_value_array_free (arg_values);
01717
01718 va_end (args);
01719
01720 return call;
01721 }
01722
01734 GType
01735 dbus_g_proxy_get_type (void)
01736 {
01737 static GType object_type = 0;
01738
01739 if (!object_type)
01740 {
01741 static const GTypeInfo object_info =
01742 {
01743 sizeof (DBusGProxyClass),
01744 (GBaseInitFunc) NULL,
01745 (GBaseFinalizeFunc) NULL,
01746 (GClassInitFunc) dbus_g_proxy_class_init,
01747 NULL,
01748 NULL,
01749 sizeof (DBusGProxy),
01750 0,
01751 (GInstanceInitFunc) dbus_g_proxy_init,
01752 };
01753
01754 object_type = g_type_register_static (G_TYPE_OBJECT,
01755 "DBusGProxy",
01756 &object_info, 0);
01757 }
01758
01759 return object_type;
01760 }
01761
01762 static DBusGProxy*
01763 dbus_g_proxy_new (DBusGConnection *connection,
01764 const char *name,
01765 const char *path_name,
01766 const char *interface_name)
01767 {
01768 DBusGProxy *proxy;
01769
01770 g_assert (connection != NULL);
01771
01772 proxy = g_object_new (DBUS_TYPE_G_PROXY, "name", name, "path", path_name, "interface", interface_name, NULL);
01773
01774
01775
01776
01777
01778 proxy->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
01779
01780 dbus_g_proxy_manager_register (proxy->manager, proxy);
01781
01782 return proxy;
01783 }
01784
01811 DBusGProxy*
01812 dbus_g_proxy_new_for_name (DBusGConnection *connection,
01813 const char *name,
01814 const char *path_name,
01815 const char *interface_name)
01816 {
01817 g_return_val_if_fail (connection != NULL, NULL);
01818 g_return_val_if_fail (name != NULL, NULL);
01819 g_return_val_if_fail (path_name != NULL, NULL);
01820 g_return_val_if_fail (interface_name != NULL, NULL);
01821
01822 return dbus_g_proxy_new (connection, name,
01823 path_name, interface_name);
01824 }
01825
01849 DBusGProxy*
01850 dbus_g_proxy_new_for_name_owner (DBusGConnection *connection,
01851 const char *name,
01852 const char *path_name,
01853 const char *interface_name,
01854 GError **error)
01855 {
01856 DBusGProxy *proxy;
01857 char *unique_name;
01858
01859 g_return_val_if_fail (connection != NULL, NULL);
01860 g_return_val_if_fail (name != NULL, NULL);
01861 g_return_val_if_fail (path_name != NULL, NULL);
01862 g_return_val_if_fail (interface_name != NULL, NULL);
01863
01864 if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
01865 return NULL;
01866
01867 proxy = dbus_g_proxy_new (connection, unique_name,
01868 path_name, interface_name);
01869 g_free (unique_name);
01870 return proxy;
01871 }
01872
01883 DBusGProxy*
01884 dbus_g_proxy_new_from_proxy (DBusGProxy *proxy,
01885 const char *interface,
01886 const char *path)
01887 {
01888 g_return_val_if_fail (proxy != NULL, NULL);
01889
01890 if (interface == NULL)
01891 interface = proxy->interface;
01892 if (path == NULL)
01893 path = proxy->path;
01894
01895 return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection),
01896 proxy->name,
01897 path, interface);
01898 }
01899
01914 DBusGProxy*
01915 dbus_g_proxy_new_for_peer (DBusGConnection *connection,
01916 const char *path_name,
01917 const char *interface_name)
01918 {
01919 DBusGProxy *proxy;
01920
01921 g_return_val_if_fail (connection != NULL, NULL);
01922 g_return_val_if_fail (path_name != NULL, NULL);
01923 g_return_val_if_fail (interface_name != NULL, NULL);
01924
01925 proxy = dbus_g_proxy_new (connection, NULL,
01926 path_name, interface_name);
01927
01928 return proxy;
01929 }
01930
01942 const char*
01943 dbus_g_proxy_get_bus_name (DBusGProxy *proxy)
01944 {
01945 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
01946 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
01947
01948 return proxy->name;
01949 }
01950
01957 const char*
01958 dbus_g_proxy_get_interface (DBusGProxy *proxy)
01959 {
01960 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
01961 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
01962
01963 return proxy->interface;
01964 }
01965
01972 void
01973 dbus_g_proxy_set_interface (DBusGProxy *proxy,
01974 const char *interface_name)
01975 {
01976
01977
01978
01979 dbus_g_proxy_manager_unregister (proxy->manager, proxy);
01980 g_free (proxy->interface);
01981 proxy->interface = g_strdup (interface_name);
01982 dbus_g_proxy_manager_register (proxy->manager, proxy);
01983 }
01984
01991 const char*
01992 dbus_g_proxy_get_path (DBusGProxy *proxy)
01993 {
01994 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
01995 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
01996
01997 return proxy->path;
01998 }
01999
02000 static DBusMessage *
02001 dbus_g_proxy_marshal_args_to_message (DBusGProxy *proxy,
02002 const char *method,
02003 GValueArray *args)
02004 {
02005 DBusMessage *message;
02006 DBusMessageIter msgiter;
02007 guint i;
02008
02009 message = dbus_message_new_method_call (proxy->name,
02010 proxy->path,
02011 proxy->interface,
02012 method);
02013 if (message == NULL)
02014 goto oom;
02015
02016 dbus_message_iter_init_append (message, &msgiter);
02017 for (i = 0; i < args->n_values; i++)
02018 {
02019 GValue *gvalue;
02020
02021 gvalue = g_value_array_get_nth (args, i);
02022
02023 if (!_dbus_gvalue_marshal (&msgiter, gvalue))
02024 g_assert_not_reached ();
02025 }
02026 return message;
02027 oom:
02028 return NULL;
02029 }
02030
02031 static guint
02032 dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
02033 const char *method,
02034 DBusGProxyCallNotify notify,
02035 gpointer user_data,
02036 GDestroyNotify destroy,
02037 GValueArray *args)
02038 {
02039 DBusMessage *message;
02040 DBusPendingCall *pending;
02041 GPendingNotifyClosure *closure;
02042 guint call_id;
02043
02044 pending = NULL;
02045
02046 message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
02047 if (!message)
02048 goto oom;
02049
02050 if (!dbus_connection_send_with_reply (proxy->manager->connection,
02051 message,
02052 &pending,
02053 -1))
02054 goto oom;
02055 dbus_message_unref (message);
02056 g_assert (pending != NULL);
02057
02058 call_id = ++proxy->call_id_counter;
02059
02060 if (notify != NULL)
02061 {
02062 closure = g_new (GPendingNotifyClosure, 1);
02063 closure->proxy = proxy;
02064 closure->call_id = call_id;
02065 closure->func = notify;
02066 closure->data = user_data;
02067 closure->free_data_func = destroy;
02068 dbus_pending_call_set_notify (pending, d_pending_call_notify,
02069 closure,
02070 d_pending_call_free);
02071 }
02072
02073 g_hash_table_insert (proxy->pending_calls, GUINT_TO_POINTER (call_id), pending);
02074
02075 return call_id;
02076 oom:
02077 g_error ("Out of memory");
02078 return 0;
02079 }
02080
02081 static gboolean
02082 dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
02083 guint call_id,
02084 GError **error,
02085 GType first_arg_type,
02086 va_list args)
02087 {
02088 DBusMessage *reply;
02089 DBusMessageIter msgiter;
02090 DBusError derror;
02091 va_list args_unwind;
02092 guint over;
02093 int n_retvals_processed;
02094 gboolean ret;
02095 GType valtype;
02096 DBusPendingCall *pending;
02097
02098 reply = NULL;
02099 ret = FALSE;
02100 n_retvals_processed = 0;
02101 over = 0;
02102
02103 pending = g_hash_table_lookup (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02104
02105 dbus_pending_call_block (pending);
02106 reply = dbus_pending_call_steal_reply (pending);
02107
02108 g_assert (reply != NULL);
02109
02110 dbus_error_init (&derror);
02111
02112 switch (dbus_message_get_type (reply))
02113 {
02114 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
02115
02116 dbus_message_iter_init (reply, &msgiter);
02117 valtype = first_arg_type;
02118 while (valtype != G_TYPE_INVALID)
02119 {
02120 int arg_type;
02121 gpointer return_storage;
02122 GValue gvalue = { 0, };
02123 DBusGValueMarshalCtx context;
02124
02125 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection);
02126 context.proxy = proxy;
02127
02128 arg_type = dbus_message_iter_get_arg_type (&msgiter);
02129 if (arg_type == DBUS_TYPE_INVALID)
02130 {
02131 g_set_error (error, DBUS_GERROR,
02132 DBUS_GERROR_INVALID_ARGS,
02133 _("Too few arguments in reply"));
02134 goto out;
02135 }
02136
02137 return_storage = va_arg (args, gpointer);
02138 if (return_storage == NULL)
02139 goto next;
02140
02141
02142
02143
02144 if (arg_type == DBUS_TYPE_VARIANT
02145 && g_type_is_a (valtype, G_TYPE_VALUE))
02146 {
02147 if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
02148 {
02149 g_set_error (error,
02150 DBUS_GERROR,
02151 DBUS_GERROR_INVALID_ARGS,
02152 _("Couldn't convert argument, expected \"%s\""),
02153 g_type_name (valtype));
02154 goto out;
02155 }
02156 }
02157 else
02158 {
02159 g_value_init (&gvalue, valtype);
02160
02161 if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
02162 goto out;
02163
02164
02165 if (!_dbus_gvalue_store (&gvalue, (gpointer*) return_storage))
02166 g_assert_not_reached ();
02167
02168 }
02169
02170 next:
02171 n_retvals_processed++;
02172 dbus_message_iter_next (&msgiter);
02173 valtype = va_arg (args, GType);
02174 }
02175
02176 while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
02177 {
02178 over++;
02179 dbus_message_iter_next (&msgiter);
02180 }
02181
02182 if (over > 0)
02183 {
02184 g_set_error (error, DBUS_GERROR,
02185 DBUS_GERROR_INVALID_ARGS,
02186 _("Too many arguments in reply; expected %d, got %d"),
02187 n_retvals_processed, over);
02188 goto out;
02189 }
02190 break;
02191 case DBUS_MESSAGE_TYPE_ERROR:
02192 dbus_set_error_from_message (&derror, reply);
02193 dbus_set_g_error (error, &derror);
02194 dbus_error_free (&derror);
02195 goto out;
02196 break;
02197 default:
02198 dbus_set_error (&derror, DBUS_ERROR_FAILED,
02199 "Reply was neither a method return nor an exception");
02200 dbus_set_g_error (error, &derror);
02201 dbus_error_free (&derror);
02202 goto out;
02203 break;
02204 }
02205
02206 ret = TRUE;
02207 out:
02208 va_end (args);
02209
02210 if (ret == FALSE)
02211 {
02212 int i;
02213 for (i = 0; i < n_retvals_processed; i++)
02214 {
02215 gpointer retval;
02216
02217 retval = va_arg (args_unwind, gpointer);
02218
02219 g_free (retval);
02220 }
02221 }
02222 va_end (args_unwind);
02223
02224 g_hash_table_remove (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02225
02226 if (reply)
02227 dbus_message_unref (reply);
02228 return ret;
02229 }
02230
02252 DBusGProxyCall *
02253 dbus_g_proxy_begin_call (DBusGProxy *proxy,
02254 const char *method,
02255 DBusGProxyCallNotify notify,
02256 gpointer user_data,
02257 GDestroyNotify destroy,
02258 GType first_arg_type,
02259 ...)
02260 {
02261 guint call_id;
02262 va_list args;
02263 GValueArray *arg_values;
02264
02265 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02266 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02267
02268 va_start (args, first_arg_type);
02269
02270 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
02271
02272 call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify, user_data, destroy, arg_values);
02273
02274 g_value_array_free (arg_values);
02275
02276 va_end (args);
02277
02278 return DBUS_G_PROXY_ID_TO_CALL (call_id);
02279 }
02280
02301 gboolean
02302 dbus_g_proxy_end_call (DBusGProxy *proxy,
02303 DBusGProxyCall *call,
02304 GError **error,
02305 GType first_arg_type,
02306 ...)
02307 {
02308 gboolean ret;
02309 va_list args;
02310
02311 va_start (args, first_arg_type);
02312
02313 ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
02314
02315 va_end (args);
02316
02317 return ret;
02318 }
02319
02333 gboolean
02334 dbus_g_proxy_call (DBusGProxy *proxy,
02335 const char *method,
02336 GError **error,
02337 GType first_arg_type,
02338 ...)
02339 {
02340 gboolean ret;
02341 guint call_id;
02342 va_list args;
02343 GValueArray *in_args;
02344
02345 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
02346 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
02347
02348 va_start (args, first_arg_type);
02349
02350 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02351
02352 call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL, NULL, in_args);
02353
02354 g_value_array_free (in_args);
02355
02356 first_arg_type = va_arg (args, GType);
02357 ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type, args);
02358
02359 va_end (args);
02360
02361 return ret;
02362 }
02363
02375 void
02376 dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
02377 const char *method,
02378 GType first_arg_type,
02379 ...)
02380 {
02381 DBusMessage *message;
02382 va_list args;
02383 GValueArray *in_args;
02384
02385 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02386 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02387
02388 va_start (args, first_arg_type);
02389 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
02390
02391 message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
02392
02393 g_value_array_free (in_args);
02394 va_end (args);
02395
02396 if (!message)
02397 goto oom;
02398
02399 dbus_message_set_no_reply (message, TRUE);
02400
02401 if (!dbus_connection_send (proxy->manager->connection,
02402 message,
02403 NULL))
02404 goto oom;
02405 dbus_message_unref (message);
02406 return;
02407
02408 oom:
02409 g_error ("Out of memory");
02410 }
02411
02421 void
02422 dbus_g_proxy_cancel_call (DBusGProxy *proxy,
02423 DBusGProxyCall *call)
02424 {
02425 guint call_id;
02426 DBusPendingCall *pending;
02427
02428 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02429 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02430
02431 call_id = DBUS_G_PROXY_CALL_TO_ID (call);
02432
02433 pending = g_hash_table_lookup (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02434 g_return_if_fail (pending != NULL);
02435
02436 dbus_pending_call_cancel (pending);
02437
02438 g_hash_table_remove (proxy->pending_calls, GUINT_TO_POINTER (call_id));
02439 }
02440
02459 void
02460 dbus_g_proxy_send (DBusGProxy *proxy,
02461 DBusMessage *message,
02462 dbus_uint32_t *client_serial)
02463 {
02464 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02465 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02466
02467 if (proxy->name)
02468 {
02469 if (!dbus_message_set_destination (message, proxy->name))
02470 g_error ("Out of memory");
02471 }
02472 if (proxy->path)
02473 {
02474 if (!dbus_message_set_path (message, proxy->path))
02475 g_error ("Out of memory");
02476 }
02477 if (proxy->interface)
02478 {
02479 if (!dbus_message_set_interface (message, proxy->interface))
02480 g_error ("Out of memory");
02481 }
02482
02483 if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
02484 g_error ("Out of memory\n");
02485 }
02486
02487 static void
02488 array_free_all (gpointer array)
02489 {
02490 g_array_free (array, TRUE);
02491 }
02492
02502 void
02503 dbus_g_proxy_add_signal (DBusGProxy *proxy,
02504 const char *signal_name,
02505 GType first_type,
02506 ...)
02507 {
02508 GQuark q;
02509 char *name;
02510 GArray *gtypesig;
02511 GType gtype;
02512 va_list args;
02513
02514 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02515 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02516 g_return_if_fail (signal_name != NULL);
02517
02518 name = create_signal_name (proxy->interface, signal_name);
02519
02520 q = g_quark_from_string (name);
02521
02522 g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
02523
02524 gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
02525
02526 va_start (args, first_type);
02527 gtype = first_type;
02528 while (gtype != G_TYPE_INVALID)
02529 {
02530 g_array_append_val (gtypesig, gtype);
02531 gtype = va_arg (args, GType);
02532 }
02533 va_end (args);
02534
02535 #ifndef G_DISABLE_CHECKS
02536 if (_dbus_gobject_lookup_marshaller (G_TYPE_NONE, gtypesig->len, (const GType*) gtypesig->data) == NULL)
02537 g_warning ("No marshaller for signature of signal '%s'", signal_name);
02538 #endif
02539
02540
02541 g_datalist_id_set_data_full (&proxy->signal_signatures,
02542 q, gtypesig,
02543 array_free_all);
02544
02545 g_free (name);
02546 }
02547
02559 void
02560 dbus_g_proxy_connect_signal (DBusGProxy *proxy,
02561 const char *signal_name,
02562 GCallback handler,
02563 void *data,
02564 GClosureNotify free_data_func)
02565 {
02566 char *name;
02567 GClosure *closure;
02568 GQuark q;
02569
02570 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02571 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02572 g_return_if_fail (signal_name != NULL);
02573 g_return_if_fail (handler != NULL);
02574
02575 name = create_signal_name (proxy->interface, signal_name);
02576
02577 q = g_quark_try_string (name);
02578
02579 #ifndef G_DISABLE_CHECKS
02580 if (q == 0 || g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL)
02581 {
02582 g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
02583 g_free (name);
02584 return;
02585 }
02586 #endif
02587
02588 closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
02589
02590 g_signal_connect_closure_by_id (G_OBJECT (proxy),
02591 signals[RECEIVED],
02592 q,
02593 closure, FALSE);
02594
02595 g_free (name);
02596 }
02597
02607 void
02608 dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
02609 const char *signal_name,
02610 GCallback handler,
02611 void *data)
02612 {
02613 char *name;
02614 GQuark q;
02615
02616 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
02617 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
02618 g_return_if_fail (signal_name != NULL);
02619 g_return_if_fail (handler != NULL);
02620
02621 name = create_signal_name (proxy->interface, signal_name);
02622
02623 q = g_quark_try_string (name);
02624
02625 if (q != 0)
02626 {
02627 g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
02628 G_SIGNAL_MATCH_DETAIL |
02629 G_SIGNAL_MATCH_FUNC |
02630 G_SIGNAL_MATCH_DATA,
02631 signals[RECEIVED],
02632 q,
02633 NULL,
02634 G_CALLBACK (handler), data);
02635 }
02636 else
02637 {
02638 g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
02639 name);
02640 }
02641
02642 g_free (name);
02643 }
02644
02647 #ifdef DBUS_BUILD_TESTS
02648
02654 gboolean
02655 _dbus_g_proxy_test (void)
02656 {
02657
02658
02659 return TRUE;
02660 }
02661
02662 #endif