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