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