5 * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <dbus/dbus.h>
34 #define METHOD_CALL_TIMEOUT (300 * 1000)
36 #ifndef DBUS_INTERFACE_OBJECT_MANAGER
37 #define DBUS_INTERFACE_OBJECT_MANAGER DBUS_INTERFACE_DBUS ".ObjectManager"
42 DBusConnection *dbus_conn;
49 GPtrArray *match_rules;
50 DBusPendingCall *pending_call;
51 DBusPendingCall *get_objects_call;
52 GDBusWatchFunction connect_func;
54 GDBusWatchFunction disconn_func;
57 GDBusMessageFunction signal_func;
59 GDBusProxyFunction proxy_added;
60 GDBusProxyFunction proxy_removed;
61 GDBusClientFunction ready;
63 GDBusPropertyFunction property_changed;
73 GHashTable *prop_list;
75 GDBusPropertyFunction prop_func;
77 GDBusProxyFunction removed_func;
87 static void modify_match_reply(DBusPendingCall *call, void *user_data)
89 DBusMessage *reply = dbus_pending_call_steal_reply(call);
92 dbus_error_init(&error);
94 if (dbus_set_error_from_message(&error, reply) == TRUE)
95 dbus_error_free(&error);
97 dbus_message_unref(reply);
100 static gboolean modify_match(DBusConnection *conn, const char *member,
104 DBusPendingCall *call;
106 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
107 DBUS_INTERFACE_DBUS, member);
111 dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
114 if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
115 dbus_message_unref(msg);
119 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
120 dbus_pending_call_unref(call);
122 dbus_message_unref(msg);
127 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
131 type = dbus_message_iter_get_arg_type(iter);
133 if (dbus_type_is_basic(type)) {
136 dbus_message_iter_get_basic(iter, &value);
137 dbus_message_iter_append_basic(base, type, &value);
138 } else if (dbus_type_is_container(type)) {
139 DBusMessageIter iter_sub, base_sub;
142 dbus_message_iter_recurse(iter, &iter_sub);
145 case DBUS_TYPE_ARRAY:
146 case DBUS_TYPE_VARIANT:
147 sig = dbus_message_iter_get_signature(&iter_sub);
154 dbus_message_iter_open_container(base, type, sig, &base_sub);
159 while (dbus_message_iter_get_arg_type(&iter_sub) !=
161 iter_append_iter(&base_sub, &iter_sub);
162 dbus_message_iter_next(&iter_sub);
165 dbus_message_iter_close_container(base, &base_sub);
169 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
172 DBusMessageIter base;
174 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
178 dbus_message_iter_init_append(msg, &base);
179 iter_append_iter(&base, iter);
181 if (prop->msg != NULL)
182 dbus_message_unref(prop->msg);
184 prop->msg = dbus_message_copy(msg);
185 dbus_message_unref(msg);
188 static struct prop_entry *prop_entry_new(const char *name,
189 DBusMessageIter *iter)
191 struct prop_entry *prop;
193 prop = g_try_new0(struct prop_entry, 1);
197 prop->name = g_strdup(name);
198 prop->type = dbus_message_iter_get_arg_type(iter);
200 prop_entry_update(prop, iter);
205 static void prop_entry_free(gpointer data)
207 struct prop_entry *prop = data;
209 if (prop->msg != NULL)
210 dbus_message_unref(prop->msg);
217 static void add_property(GDBusProxy *proxy, const char *name,
218 DBusMessageIter *iter, gboolean send_changed)
220 GDBusClient *client = proxy->client;
221 DBusMessageIter value;
222 struct prop_entry *prop;
224 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
227 dbus_message_iter_recurse(iter, &value);
229 prop = g_hash_table_lookup(proxy->prop_list, name);
231 prop_entry_update(prop, &value);
235 prop = prop_entry_new(name, &value);
239 g_hash_table_replace(proxy->prop_list, prop->name, prop);
242 if (proxy->prop_func)
243 proxy->prop_func(proxy, name, &value, proxy->prop_data);
245 if (client == NULL || send_changed == FALSE)
248 if (client->property_changed)
249 client->property_changed(proxy, name, &value,
253 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
254 gboolean send_changed)
256 DBusMessageIter dict;
258 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
261 dbus_message_iter_recurse(iter, &dict);
263 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
264 DBusMessageIter entry;
267 dbus_message_iter_recurse(&dict, &entry);
269 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
272 dbus_message_iter_get_basic(&entry, &name);
273 dbus_message_iter_next(&entry);
275 add_property(proxy, name, &entry, send_changed);
277 dbus_message_iter_next(&dict);
281 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
283 GDBusProxy *proxy = user_data;
284 GDBusClient *client = proxy->client;
285 DBusMessage *reply = dbus_pending_call_steal_reply(call);
286 DBusMessageIter iter;
289 dbus_error_init(&error);
291 if (dbus_set_error_from_message(&error, reply) == TRUE) {
292 dbus_error_free(&error);
296 dbus_message_iter_init(reply, &iter);
298 update_properties(proxy, &iter, FALSE);
301 if (g_list_find(client->proxy_list, proxy) == NULL) {
302 if (client->proxy_added)
303 client->proxy_added(proxy, client->user_data);
305 client->proxy_list = g_list_append(client->proxy_list, proxy);
308 dbus_message_unref(reply);
310 g_dbus_client_unref(client);
313 static void get_all_properties(GDBusProxy *proxy)
315 GDBusClient *client = proxy->client;
316 const char *service_name = client->service_name;
318 DBusPendingCall *call;
320 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
321 DBUS_INTERFACE_PROPERTIES, "GetAll");
325 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
328 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
329 &call, -1) == FALSE) {
330 dbus_message_unref(msg);
334 g_dbus_client_ref(client);
336 dbus_pending_call_set_notify(call, get_all_properties_reply,
338 dbus_pending_call_unref(call);
340 dbus_message_unref(msg);
343 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
344 const char *interface)
348 for (list = g_list_first(client->proxy_list); list;
349 list = g_list_next(list)) {
350 GDBusProxy *proxy = list->data;
352 if (g_str_equal(proxy->interface, interface) == TRUE &&
353 g_str_equal(proxy->obj_path, path) == TRUE)
360 static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
363 GDBusProxy *proxy = user_data;
364 GDBusClient *client = proxy->client;
365 DBusMessageIter iter, entry;
366 const char *interface;
368 if (dbus_message_iter_init(msg, &iter) == FALSE)
371 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
374 dbus_message_iter_get_basic(&iter, &interface);
375 dbus_message_iter_next(&iter);
377 update_properties(proxy, &iter, TRUE);
379 dbus_message_iter_next(&iter);
381 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
384 dbus_message_iter_recurse(&iter, &entry);
386 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
389 dbus_message_iter_get_basic(&entry, &name);
391 g_hash_table_remove(proxy->prop_list, name);
393 if (proxy->prop_func)
394 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
396 if (client->property_changed)
397 client->property_changed(proxy, name, NULL,
400 dbus_message_iter_next(&entry);
406 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
407 const char *interface)
411 proxy = g_try_new0(GDBusProxy, 1);
415 proxy->client = client;
416 proxy->obj_path = g_strdup(path);
417 proxy->interface = g_strdup(interface);
419 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
420 NULL, prop_entry_free);
421 proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
422 client->service_name,
428 return g_dbus_proxy_ref(proxy);
431 static void proxy_free(gpointer data)
433 GDBusProxy *proxy = data;
436 GDBusClient *client = proxy->client;
438 if (client->proxy_removed)
439 client->proxy_removed(proxy, client->user_data);
441 g_dbus_remove_watch(client->dbus_conn, proxy->watch);
443 g_hash_table_remove_all(proxy->prop_list);
445 proxy->client = NULL;
448 if (proxy->removed_func)
449 proxy->removed_func(proxy, proxy->removed_data);
451 g_dbus_proxy_unref(proxy);
454 static void proxy_remove(GDBusClient *client, const char *path,
455 const char *interface)
459 for (list = g_list_first(client->proxy_list); list;
460 list = g_list_next(list)) {
461 GDBusProxy *proxy = list->data;
463 if (g_str_equal(proxy->interface, interface) == TRUE &&
464 g_str_equal(proxy->obj_path, path) == TRUE) {
466 g_list_delete_link(client->proxy_list, list);
473 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
474 const char *interface)
481 proxy = proxy_lookup(client, path, interface);
483 return g_dbus_proxy_ref(proxy);
485 proxy = proxy_new(client, path, interface);
489 get_all_properties(proxy);
491 return g_dbus_proxy_ref(proxy);
494 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
499 __sync_fetch_and_add(&proxy->ref_count, 1);
504 void g_dbus_proxy_unref(GDBusProxy *proxy)
509 if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
512 g_hash_table_destroy(proxy->prop_list);
514 g_free(proxy->obj_path);
515 g_free(proxy->interface);
520 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
525 return proxy->obj_path;
528 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
533 return proxy->interface;
536 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
537 DBusMessageIter *iter)
539 struct prop_entry *prop;
541 if (proxy == NULL || name == NULL)
544 prop = g_hash_table_lookup(proxy->prop_list, name);
548 if (prop->msg == NULL)
551 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
557 struct refresh_property_data {
562 static void refresh_property_free(gpointer user_data)
564 struct refresh_property_data *data = user_data;
570 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
572 struct refresh_property_data *data = user_data;
573 DBusMessage *reply = dbus_pending_call_steal_reply(call);
576 dbus_error_init(&error);
578 if (dbus_set_error_from_message(&error, reply) == FALSE) {
579 DBusMessageIter iter;
581 dbus_message_iter_init(reply, &iter);
583 add_property(data->proxy, data->name, &iter, TRUE);
585 dbus_error_free(&error);
587 dbus_message_unref(reply);
590 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
592 struct refresh_property_data *data;
595 DBusMessageIter iter;
596 DBusPendingCall *call;
598 if (proxy == NULL || name == NULL)
601 client = proxy->client;
605 data = g_try_new0(struct refresh_property_data, 1);
610 data->name = g_strdup(name);
612 msg = dbus_message_new_method_call(client->service_name,
613 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
615 refresh_property_free(data);
619 dbus_message_iter_init_append(msg, &iter);
620 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
622 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
624 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
625 &call, -1) == FALSE) {
626 dbus_message_unref(msg);
627 refresh_property_free(data);
631 dbus_pending_call_set_notify(call, refresh_property_reply,
632 data, refresh_property_free);
633 dbus_pending_call_unref(call);
635 dbus_message_unref(msg);
640 struct set_property_data {
641 GDBusResultFunction function;
643 GDBusDestroyFunction destroy;
646 static void set_property_reply(DBusPendingCall *call, void *user_data)
648 struct set_property_data *data = user_data;
649 DBusMessage *reply = dbus_pending_call_steal_reply(call);
652 dbus_error_init(&error);
654 dbus_set_error_from_message(&error, reply);
657 data->function(&error, data->user_data);
660 data->destroy(data->user_data);
662 dbus_error_free(&error);
664 dbus_message_unref(reply);
667 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
668 const char *name, int type, const void *value,
669 GDBusResultFunction function, void *user_data,
670 GDBusDestroyFunction destroy)
672 struct set_property_data *data;
675 DBusMessageIter iter, variant;
676 DBusPendingCall *call;
679 if (proxy == NULL || name == NULL || value == NULL)
682 if (dbus_type_is_basic(type) == FALSE)
685 client = proxy->client;
689 data = g_try_new0(struct set_property_data, 1);
693 data->function = function;
694 data->user_data = user_data;
695 data->destroy = destroy;
697 msg = dbus_message_new_method_call(client->service_name,
698 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
704 type_as_str[0] = (char) type;
705 type_as_str[1] = '\0';
707 dbus_message_iter_init_append(msg, &iter);
708 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
710 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
712 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
713 type_as_str, &variant);
714 dbus_message_iter_append_basic(&variant, type, value);
715 dbus_message_iter_close_container(&iter, &variant);
717 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
718 &call, -1) == FALSE) {
719 dbus_message_unref(msg);
724 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
725 dbus_pending_call_unref(call);
727 dbus_message_unref(msg);
732 gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
733 const char *name, int type, const void *value,
734 size_t size, GDBusResultFunction function,
735 void *user_data, GDBusDestroyFunction destroy)
737 struct set_property_data *data;
740 DBusMessageIter iter, variant, array;
741 DBusPendingCall *call;
745 if (!proxy || !name || !value)
748 if (!dbus_type_is_basic(type))
751 client = proxy->client;
755 data = g_try_new0(struct set_property_data, 1);
759 data->function = function;
760 data->user_data = user_data;
761 data->destroy = destroy;
763 msg = dbus_message_new_method_call(client->service_name,
765 DBUS_INTERFACE_PROPERTIES,
772 array_sig[0] = DBUS_TYPE_ARRAY;
773 array_sig[1] = (char) type;
776 type_sig[0] = (char) type;
779 dbus_message_iter_init_append(msg, &iter);
780 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
782 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
784 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
785 array_sig, &variant);
787 dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
790 if (dbus_type_is_fixed(type))
791 dbus_message_iter_append_fixed_array(&array, type, &value,
793 else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
794 const char **str = (const char **) value;
797 for (i = 0; i < size; i++)
798 dbus_message_iter_append_basic(&array, type, &str[i]);
801 dbus_message_iter_close_container(&variant, &array);
802 dbus_message_iter_close_container(&iter, &variant);
804 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
805 &call, -1) == FALSE) {
806 dbus_message_unref(msg);
811 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
812 dbus_pending_call_unref(call);
814 dbus_message_unref(msg);
819 struct method_call_data {
820 GDBusReturnFunction function;
822 GDBusDestroyFunction destroy;
825 static void method_call_reply(DBusPendingCall *call, void *user_data)
827 struct method_call_data *data = user_data;
828 DBusMessage *reply = dbus_pending_call_steal_reply(call);
831 data->function(reply, data->user_data);
834 data->destroy(data->user_data);
836 dbus_message_unref(reply);
839 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
840 GDBusSetupFunction setup,
841 GDBusReturnFunction function, void *user_data,
842 GDBusDestroyFunction destroy)
844 struct method_call_data *data;
847 DBusPendingCall *call;
849 if (proxy == NULL || method == NULL)
852 client = proxy->client;
856 msg = dbus_message_new_method_call(client->service_name,
857 proxy->obj_path, proxy->interface, method);
862 DBusMessageIter iter;
864 dbus_message_iter_init_append(msg, &iter);
865 setup(&iter, user_data);
869 return g_dbus_send_message(client->dbus_conn, msg);
871 data = g_try_new0(struct method_call_data, 1);
875 data->function = function;
876 data->user_data = user_data;
877 data->destroy = destroy;
880 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
881 &call, METHOD_CALL_TIMEOUT) == FALSE) {
882 dbus_message_unref(msg);
887 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
888 dbus_pending_call_unref(call);
890 dbus_message_unref(msg);
895 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
896 GDBusPropertyFunction function, void *user_data)
901 proxy->prop_func = function;
902 proxy->prop_data = user_data;
907 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
908 GDBusProxyFunction function, void *user_data)
913 proxy->removed_func = function;
914 proxy->removed_data = user_data;
919 static void refresh_properties(GDBusClient *client)
923 for (list = g_list_first(client->proxy_list); list;
924 list = g_list_next(list)) {
925 GDBusProxy *proxy = list->data;
927 get_all_properties(proxy);
931 static void parse_properties(GDBusClient *client, const char *path,
932 const char *interface, DBusMessageIter *iter)
936 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
939 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
942 proxy = proxy_lookup(client, path, interface);
944 update_properties(proxy, iter, FALSE);
948 proxy = proxy_new(client, path, interface);
952 update_properties(proxy, iter, FALSE);
954 if (client->proxy_added)
955 client->proxy_added(proxy, client->user_data);
957 client->proxy_list = g_list_append(client->proxy_list, proxy);
960 static void parse_interfaces(GDBusClient *client, const char *path,
961 DBusMessageIter *iter)
963 DBusMessageIter dict;
965 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
968 dbus_message_iter_recurse(iter, &dict);
970 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
971 DBusMessageIter entry;
972 const char *interface;
974 dbus_message_iter_recurse(&dict, &entry);
976 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
979 dbus_message_iter_get_basic(&entry, &interface);
980 dbus_message_iter_next(&entry);
982 parse_properties(client, path, interface, &entry);
984 dbus_message_iter_next(&dict);
988 static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
991 GDBusClient *client = user_data;
992 DBusMessageIter iter;
995 if (dbus_message_iter_init(msg, &iter) == FALSE)
998 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1001 dbus_message_iter_get_basic(&iter, &path);
1002 dbus_message_iter_next(&iter);
1004 g_dbus_client_ref(client);
1006 parse_interfaces(client, path, &iter);
1008 g_dbus_client_unref(client);
1013 static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
1016 GDBusClient *client = user_data;
1017 DBusMessageIter iter, entry;
1020 if (dbus_message_iter_init(msg, &iter) == FALSE)
1023 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1026 dbus_message_iter_get_basic(&iter, &path);
1027 dbus_message_iter_next(&iter);
1029 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1032 dbus_message_iter_recurse(&iter, &entry);
1034 g_dbus_client_ref(client);
1036 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1037 const char *interface;
1039 dbus_message_iter_get_basic(&entry, &interface);
1040 proxy_remove(client, path, interface);
1041 dbus_message_iter_next(&entry);
1044 g_dbus_client_unref(client);
1049 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
1051 DBusMessageIter iter, dict;
1053 if (dbus_message_iter_init(msg, &iter) == FALSE)
1056 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1059 dbus_message_iter_recurse(&iter, &dict);
1061 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1062 DBusMessageIter entry;
1065 dbus_message_iter_recurse(&dict, &entry);
1067 if (dbus_message_iter_get_arg_type(&entry) !=
1068 DBUS_TYPE_OBJECT_PATH)
1071 dbus_message_iter_get_basic(&entry, &path);
1072 dbus_message_iter_next(&entry);
1074 parse_interfaces(client, path, &entry);
1076 dbus_message_iter_next(&dict);
1080 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
1082 GDBusClient *client = user_data;
1083 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1086 g_dbus_client_ref(client);
1088 dbus_error_init(&error);
1090 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1091 dbus_error_free(&error);
1095 parse_managed_objects(client, reply);
1099 client->ready(client, client->ready_data);
1101 dbus_message_unref(reply);
1103 dbus_pending_call_unref(client->get_objects_call);
1104 client->get_objects_call = NULL;
1106 g_dbus_client_unref(client);
1109 static void get_managed_objects(GDBusClient *client)
1113 if (!client->connected)
1116 if ((!client->proxy_added && !client->proxy_removed) ||
1117 !client->root_path) {
1118 refresh_properties(client);
1122 if (client->get_objects_call != NULL)
1125 msg = dbus_message_new_method_call(client->service_name,
1127 DBUS_INTERFACE_OBJECT_MANAGER,
1128 "GetManagedObjects");
1132 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1134 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
1135 &client->get_objects_call, -1) == FALSE) {
1136 dbus_message_unref(msg);
1140 dbus_pending_call_set_notify(client->get_objects_call,
1141 get_managed_objects_reply,
1144 dbus_message_unref(msg);
1147 static void service_connect(DBusConnection *conn, void *user_data)
1149 GDBusClient *client = user_data;
1151 g_dbus_client_ref(client);
1153 client->connected = TRUE;
1155 if (client->connect_func)
1156 client->connect_func(conn, client->connect_data);
1158 get_managed_objects(client);
1160 g_dbus_client_unref(client);
1163 static void service_disconnect(DBusConnection *conn, void *user_data)
1165 GDBusClient *client = user_data;
1167 client->connected = FALSE;
1169 g_list_free_full(client->proxy_list, proxy_free);
1170 client->proxy_list = NULL;
1172 if (client->disconn_func)
1173 client->disconn_func(conn, client->disconn_data);
1176 static DBusHandlerResult message_filter(DBusConnection *connection,
1177 DBusMessage *message, void *user_data)
1179 GDBusClient *client = user_data;
1180 const char *sender, *path, *interface;
1182 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1183 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1185 sender = dbus_message_get_sender(message);
1187 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1189 path = dbus_message_get_path(message);
1190 interface = dbus_message_get_interface(message);
1192 if (g_str_has_prefix(path, client->base_path) == FALSE)
1193 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1195 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
1196 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1198 if (client->signal_func)
1199 client->signal_func(connection, message, client->signal_data);
1201 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1204 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1205 const char *service, const char *path)
1207 return g_dbus_client_new_full(connection, service, path, "/");
1210 GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
1211 const char *service,
1213 const char *root_path)
1215 GDBusClient *client;
1218 if (!connection || !service)
1221 client = g_try_new0(GDBusClient, 1);
1225 if (dbus_connection_add_filter(connection, message_filter,
1226 client, NULL) == FALSE) {
1231 client->dbus_conn = dbus_connection_ref(connection);
1232 client->service_name = g_strdup(service);
1233 client->base_path = g_strdup(path);
1234 client->root_path = g_strdup(root_path);
1235 client->connected = FALSE;
1237 client->match_rules = g_ptr_array_sized_new(1);
1238 g_ptr_array_set_free_func(client->match_rules, g_free);
1240 client->watch = g_dbus_add_service_watch(connection, service,
1246 return g_dbus_client_ref(client);
1248 client->added_watch = g_dbus_add_signal_watch(connection, service,
1250 DBUS_INTERFACE_OBJECT_MANAGER,
1254 client->removed_watch = g_dbus_add_signal_watch(connection, service,
1256 DBUS_INTERFACE_OBJECT_MANAGER,
1257 "InterfacesRemoved",
1260 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1261 "sender='%s',path_namespace='%s'",
1262 client->service_name, client->base_path));
1264 for (i = 0; i < client->match_rules->len; i++) {
1265 modify_match(client->dbus_conn, "AddMatch",
1266 g_ptr_array_index(client->match_rules, i));
1269 return g_dbus_client_ref(client);
1272 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1277 __sync_fetch_and_add(&client->ref_count, 1);
1282 void g_dbus_client_unref(GDBusClient *client)
1289 if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
1292 if (client->pending_call != NULL) {
1293 dbus_pending_call_cancel(client->pending_call);
1294 dbus_pending_call_unref(client->pending_call);
1297 if (client->get_objects_call != NULL) {
1298 dbus_pending_call_cancel(client->get_objects_call);
1299 dbus_pending_call_unref(client->get_objects_call);
1302 for (i = 0; i < client->match_rules->len; i++) {
1303 modify_match(client->dbus_conn, "RemoveMatch",
1304 g_ptr_array_index(client->match_rules, i));
1307 g_ptr_array_free(client->match_rules, TRUE);
1309 dbus_connection_remove_filter(client->dbus_conn,
1310 message_filter, client);
1312 g_list_free_full(client->proxy_list, proxy_free);
1315 * Don't call disconn_func twice if disconnection
1316 * was previously reported.
1318 if (client->disconn_func && client->connected)
1319 client->disconn_func(client->dbus_conn, client->disconn_data);
1321 g_dbus_remove_watch(client->dbus_conn, client->watch);
1322 g_dbus_remove_watch(client->dbus_conn, client->added_watch);
1323 g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
1325 dbus_connection_unref(client->dbus_conn);
1327 g_free(client->service_name);
1328 g_free(client->base_path);
1329 g_free(client->root_path);
1334 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1335 GDBusWatchFunction function, void *user_data)
1340 client->connect_func = function;
1341 client->connect_data = user_data;
1346 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1347 GDBusWatchFunction function, void *user_data)
1352 client->disconn_func = function;
1353 client->disconn_data = user_data;
1358 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1359 GDBusMessageFunction function, void *user_data)
1364 client->signal_func = function;
1365 client->signal_data = user_data;
1370 gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
1371 GDBusClientFunction ready, void *user_data)
1376 client->ready = ready;
1377 client->ready_data = user_data;
1382 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1383 GDBusProxyFunction proxy_added,
1384 GDBusProxyFunction proxy_removed,
1385 GDBusPropertyFunction property_changed,
1391 client->proxy_added = proxy_added;
1392 client->proxy_removed = proxy_removed;
1393 client->property_changed = property_changed;
1394 client->user_data = user_data;
1396 if (proxy_added || proxy_removed || property_changed)
1397 get_managed_objects(client);