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;
48 GPtrArray *match_rules;
49 DBusPendingCall *pending_call;
50 DBusPendingCall *get_objects_call;
51 GDBusWatchFunction connect_func;
53 GDBusWatchFunction disconn_func;
55 GDBusMessageFunction signal_func;
57 GDBusProxyFunction proxy_added;
58 GDBusProxyFunction proxy_removed;
59 GDBusClientFunction ready;
61 GDBusPropertyFunction property_changed;
71 GHashTable *prop_list;
73 GDBusPropertyFunction prop_func;
75 GDBusProxyFunction removed_func;
85 static void modify_match_reply(DBusPendingCall *call, void *user_data)
87 DBusMessage *reply = dbus_pending_call_steal_reply(call);
90 dbus_error_init(&error);
92 if (dbus_set_error_from_message(&error, reply) == TRUE)
93 dbus_error_free(&error);
95 dbus_message_unref(reply);
98 static gboolean modify_match(DBusConnection *conn, const char *member,
102 DBusPendingCall *call;
104 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
105 DBUS_INTERFACE_DBUS, member);
109 dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
112 if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
113 dbus_message_unref(msg);
117 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
118 dbus_pending_call_unref(call);
120 dbus_message_unref(msg);
125 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
129 type = dbus_message_iter_get_arg_type(iter);
131 if (dbus_type_is_basic(type)) {
134 dbus_message_iter_get_basic(iter, &value);
135 dbus_message_iter_append_basic(base, type, &value);
136 } else if (dbus_type_is_container(type)) {
137 DBusMessageIter iter_sub, base_sub;
140 dbus_message_iter_recurse(iter, &iter_sub);
143 case DBUS_TYPE_ARRAY:
144 case DBUS_TYPE_VARIANT:
145 sig = dbus_message_iter_get_signature(&iter_sub);
152 dbus_message_iter_open_container(base, type, sig, &base_sub);
157 while (dbus_message_iter_get_arg_type(&iter_sub) !=
159 iter_append_iter(&base_sub, &iter_sub);
160 dbus_message_iter_next(&iter_sub);
163 dbus_message_iter_close_container(base, &base_sub);
167 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
170 DBusMessageIter base;
172 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
176 dbus_message_iter_init_append(msg, &base);
177 iter_append_iter(&base, iter);
179 if (prop->msg != NULL)
180 dbus_message_unref(prop->msg);
182 prop->msg = dbus_message_copy(msg);
183 dbus_message_unref(msg);
186 static struct prop_entry *prop_entry_new(const char *name,
187 DBusMessageIter *iter)
189 struct prop_entry *prop;
191 prop = g_try_new0(struct prop_entry, 1);
195 prop->name = g_strdup(name);
196 prop->type = dbus_message_iter_get_arg_type(iter);
198 prop_entry_update(prop, iter);
203 static void prop_entry_free(gpointer data)
205 struct prop_entry *prop = data;
207 if (prop->msg != NULL)
208 dbus_message_unref(prop->msg);
215 static void add_property(GDBusProxy *proxy, const char *name,
216 DBusMessageIter *iter, gboolean send_changed)
218 GDBusClient *client = proxy->client;
219 DBusMessageIter value;
220 struct prop_entry *prop;
222 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
225 dbus_message_iter_recurse(iter, &value);
227 prop = g_hash_table_lookup(proxy->prop_list, name);
229 prop_entry_update(prop, &value);
233 prop = prop_entry_new(name, &value);
237 g_hash_table_replace(proxy->prop_list, prop->name, prop);
240 if (proxy->prop_func)
241 proxy->prop_func(proxy, name, &value, proxy->prop_data);
243 if (client == NULL || send_changed == FALSE)
246 if (client->property_changed)
247 client->property_changed(proxy, name, &value,
251 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
252 gboolean send_changed)
254 DBusMessageIter dict;
256 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
259 dbus_message_iter_recurse(iter, &dict);
261 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
262 DBusMessageIter entry;
265 dbus_message_iter_recurse(&dict, &entry);
267 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
270 dbus_message_iter_get_basic(&entry, &name);
271 dbus_message_iter_next(&entry);
273 add_property(proxy, name, &entry, send_changed);
275 dbus_message_iter_next(&dict);
279 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
281 GDBusProxy *proxy = user_data;
282 GDBusClient *client = proxy->client;
283 DBusMessage *reply = dbus_pending_call_steal_reply(call);
284 DBusMessageIter iter;
287 dbus_error_init(&error);
289 if (dbus_set_error_from_message(&error, reply) == TRUE) {
290 dbus_error_free(&error);
294 dbus_message_iter_init(reply, &iter);
296 update_properties(proxy, &iter, FALSE);
299 if (g_list_find(client->proxy_list, proxy) == NULL) {
300 if (client->proxy_added)
301 client->proxy_added(proxy, client->user_data);
303 client->proxy_list = g_list_append(client->proxy_list, proxy);
306 dbus_message_unref(reply);
308 g_dbus_client_unref(client);
311 static void get_all_properties(GDBusProxy *proxy)
313 GDBusClient *client = proxy->client;
314 const char *service_name = client->service_name;
316 DBusPendingCall *call;
318 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
319 DBUS_INTERFACE_PROPERTIES, "GetAll");
323 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
326 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
327 &call, -1) == FALSE) {
328 dbus_message_unref(msg);
332 g_dbus_client_ref(client);
334 dbus_pending_call_set_notify(call, get_all_properties_reply,
336 dbus_pending_call_unref(call);
338 dbus_message_unref(msg);
341 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
342 const char *interface)
346 for (list = g_list_first(client->proxy_list); list;
347 list = g_list_next(list)) {
348 GDBusProxy *proxy = list->data;
350 if (g_str_equal(proxy->interface, interface) == TRUE &&
351 g_str_equal(proxy->obj_path, path) == TRUE)
358 static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
361 GDBusProxy *proxy = user_data;
362 GDBusClient *client = proxy->client;
363 DBusMessageIter iter, entry;
364 const char *interface;
366 if (dbus_message_iter_init(msg, &iter) == FALSE)
369 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
372 dbus_message_iter_get_basic(&iter, &interface);
373 dbus_message_iter_next(&iter);
375 update_properties(proxy, &iter, TRUE);
377 dbus_message_iter_next(&iter);
379 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
382 dbus_message_iter_recurse(&iter, &entry);
384 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
387 dbus_message_iter_get_basic(&entry, &name);
389 g_hash_table_remove(proxy->prop_list, name);
391 if (proxy->prop_func)
392 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
394 if (client->property_changed)
395 client->property_changed(proxy, name, NULL,
398 dbus_message_iter_next(&entry);
404 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
405 const char *interface)
409 proxy = g_try_new0(GDBusProxy, 1);
413 proxy->client = client;
414 proxy->obj_path = g_strdup(path);
415 proxy->interface = g_strdup(interface);
417 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
418 NULL, prop_entry_free);
419 proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
420 client->service_name,
426 return g_dbus_proxy_ref(proxy);
429 static void proxy_free(gpointer data)
431 GDBusProxy *proxy = data;
434 GDBusClient *client = proxy->client;
436 if (client->proxy_removed)
437 client->proxy_removed(proxy, client->user_data);
439 g_dbus_remove_watch(client->dbus_conn, proxy->watch);
441 g_hash_table_remove_all(proxy->prop_list);
443 proxy->client = NULL;
446 if (proxy->removed_func)
447 proxy->removed_func(proxy, proxy->removed_data);
449 g_dbus_proxy_unref(proxy);
452 static void proxy_remove(GDBusClient *client, const char *path,
453 const char *interface)
457 for (list = g_list_first(client->proxy_list); list;
458 list = g_list_next(list)) {
459 GDBusProxy *proxy = list->data;
461 if (g_str_equal(proxy->interface, interface) == TRUE &&
462 g_str_equal(proxy->obj_path, path) == TRUE) {
464 g_list_delete_link(client->proxy_list, list);
471 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
472 const char *interface)
479 proxy = proxy_lookup(client, path, interface);
481 return g_dbus_proxy_ref(proxy);
483 proxy = proxy_new(client, path, interface);
487 get_all_properties(proxy);
489 return g_dbus_proxy_ref(proxy);
492 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
497 __sync_fetch_and_add(&proxy->ref_count, 1);
502 void g_dbus_proxy_unref(GDBusProxy *proxy)
507 if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
510 g_hash_table_destroy(proxy->prop_list);
512 g_free(proxy->obj_path);
513 g_free(proxy->interface);
518 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
523 return proxy->obj_path;
526 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
531 return proxy->interface;
534 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
535 DBusMessageIter *iter)
537 struct prop_entry *prop;
539 if (proxy == NULL || name == NULL)
542 prop = g_hash_table_lookup(proxy->prop_list, name);
546 if (prop->msg == NULL)
549 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
555 struct refresh_property_data {
560 static void refresh_property_free(gpointer user_data)
562 struct refresh_property_data *data = user_data;
568 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
570 struct refresh_property_data *data = user_data;
571 DBusMessage *reply = dbus_pending_call_steal_reply(call);
574 dbus_error_init(&error);
576 if (dbus_set_error_from_message(&error, reply) == FALSE) {
577 DBusMessageIter iter;
579 dbus_message_iter_init(reply, &iter);
581 add_property(data->proxy, data->name, &iter, TRUE);
583 dbus_error_free(&error);
585 dbus_message_unref(reply);
588 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
590 struct refresh_property_data *data;
593 DBusMessageIter iter;
594 DBusPendingCall *call;
596 if (proxy == NULL || name == NULL)
599 client = proxy->client;
603 data = g_try_new0(struct refresh_property_data, 1);
608 data->name = g_strdup(name);
610 msg = dbus_message_new_method_call(client->service_name,
611 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
613 refresh_property_free(data);
617 dbus_message_iter_init_append(msg, &iter);
618 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
620 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
622 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
623 &call, -1) == FALSE) {
624 dbus_message_unref(msg);
625 refresh_property_free(data);
629 dbus_pending_call_set_notify(call, refresh_property_reply,
630 data, refresh_property_free);
631 dbus_pending_call_unref(call);
633 dbus_message_unref(msg);
638 struct set_property_data {
639 GDBusResultFunction function;
641 GDBusDestroyFunction destroy;
644 static void set_property_reply(DBusPendingCall *call, void *user_data)
646 struct set_property_data *data = user_data;
647 DBusMessage *reply = dbus_pending_call_steal_reply(call);
650 dbus_error_init(&error);
652 dbus_set_error_from_message(&error, reply);
655 data->function(&error, data->user_data);
658 data->destroy(data->user_data);
660 dbus_error_free(&error);
662 dbus_message_unref(reply);
665 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
666 const char *name, int type, const void *value,
667 GDBusResultFunction function, void *user_data,
668 GDBusDestroyFunction destroy)
670 struct set_property_data *data;
673 DBusMessageIter iter, variant;
674 DBusPendingCall *call;
677 if (proxy == NULL || name == NULL || value == NULL)
680 if (dbus_type_is_basic(type) == FALSE)
683 client = proxy->client;
687 data = g_try_new0(struct set_property_data, 1);
691 data->function = function;
692 data->user_data = user_data;
693 data->destroy = destroy;
695 msg = dbus_message_new_method_call(client->service_name,
696 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
702 type_as_str[0] = (char) type;
703 type_as_str[1] = '\0';
705 dbus_message_iter_init_append(msg, &iter);
706 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
708 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
710 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
711 type_as_str, &variant);
712 dbus_message_iter_append_basic(&variant, type, value);
713 dbus_message_iter_close_container(&iter, &variant);
715 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
716 &call, -1) == FALSE) {
717 dbus_message_unref(msg);
722 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
723 dbus_pending_call_unref(call);
725 dbus_message_unref(msg);
730 gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
731 const char *name, int type, const void *value,
732 size_t size, GDBusResultFunction function,
733 void *user_data, GDBusDestroyFunction destroy)
735 struct set_property_data *data;
738 DBusMessageIter iter, variant, array;
739 DBusPendingCall *call;
743 if (!proxy || !name || !value)
746 if (!dbus_type_is_basic(type))
749 client = proxy->client;
753 data = g_try_new0(struct set_property_data, 1);
757 data->function = function;
758 data->user_data = user_data;
759 data->destroy = destroy;
761 msg = dbus_message_new_method_call(client->service_name,
763 DBUS_INTERFACE_PROPERTIES,
770 array_sig[0] = DBUS_TYPE_ARRAY;
771 array_sig[1] = (char) type;
774 type_sig[0] = (char) type;
777 dbus_message_iter_init_append(msg, &iter);
778 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
780 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
782 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
783 array_sig, &variant);
785 dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
788 if (dbus_type_is_fixed(type))
789 dbus_message_iter_append_fixed_array(&array, type, &value,
791 else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
792 const char **str = (const char **) value;
795 for (i = 0; i < size; i++)
796 dbus_message_iter_append_basic(&array, type, &str[i]);
799 dbus_message_iter_close_container(&variant, &array);
800 dbus_message_iter_close_container(&iter, &variant);
802 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
803 &call, -1) == FALSE) {
804 dbus_message_unref(msg);
809 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
810 dbus_pending_call_unref(call);
812 dbus_message_unref(msg);
817 struct method_call_data {
818 GDBusReturnFunction function;
820 GDBusDestroyFunction destroy;
823 static void method_call_reply(DBusPendingCall *call, void *user_data)
825 struct method_call_data *data = user_data;
826 DBusMessage *reply = dbus_pending_call_steal_reply(call);
829 data->function(reply, data->user_data);
832 data->destroy(data->user_data);
834 dbus_message_unref(reply);
837 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
838 GDBusSetupFunction setup,
839 GDBusReturnFunction function, void *user_data,
840 GDBusDestroyFunction destroy)
842 struct method_call_data *data;
845 DBusPendingCall *call;
847 if (proxy == NULL || method == NULL)
850 client = proxy->client;
854 data = g_try_new0(struct method_call_data, 1);
858 data->function = function;
859 data->user_data = user_data;
860 data->destroy = destroy;
862 msg = dbus_message_new_method_call(client->service_name,
863 proxy->obj_path, proxy->interface, method);
870 DBusMessageIter iter;
872 dbus_message_iter_init_append(msg, &iter);
873 setup(&iter, data->user_data);
876 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
877 &call, METHOD_CALL_TIMEOUT) == FALSE) {
878 dbus_message_unref(msg);
883 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
884 dbus_pending_call_unref(call);
886 dbus_message_unref(msg);
891 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
892 GDBusPropertyFunction function, void *user_data)
897 proxy->prop_func = function;
898 proxy->prop_data = user_data;
903 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
904 GDBusProxyFunction function, void *user_data)
909 proxy->removed_func = function;
910 proxy->removed_data = user_data;
915 static void refresh_properties(GDBusClient *client)
919 for (list = g_list_first(client->proxy_list); list;
920 list = g_list_next(list)) {
921 GDBusProxy *proxy = list->data;
923 get_all_properties(proxy);
927 static void parse_properties(GDBusClient *client, const char *path,
928 const char *interface, DBusMessageIter *iter)
932 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
935 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
938 proxy = proxy_lookup(client, path, interface);
940 update_properties(proxy, iter, FALSE);
944 proxy = proxy_new(client, path, interface);
948 update_properties(proxy, iter, FALSE);
950 if (client->proxy_added)
951 client->proxy_added(proxy, client->user_data);
953 client->proxy_list = g_list_append(client->proxy_list, proxy);
956 static void parse_interfaces(GDBusClient *client, const char *path,
957 DBusMessageIter *iter)
959 DBusMessageIter dict;
961 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
964 dbus_message_iter_recurse(iter, &dict);
966 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
967 DBusMessageIter entry;
968 const char *interface;
970 dbus_message_iter_recurse(&dict, &entry);
972 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
975 dbus_message_iter_get_basic(&entry, &interface);
976 dbus_message_iter_next(&entry);
978 parse_properties(client, path, interface, &entry);
980 dbus_message_iter_next(&dict);
984 static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
987 GDBusClient *client = user_data;
988 DBusMessageIter iter;
991 if (dbus_message_iter_init(msg, &iter) == FALSE)
994 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
997 dbus_message_iter_get_basic(&iter, &path);
998 dbus_message_iter_next(&iter);
1000 g_dbus_client_ref(client);
1002 parse_interfaces(client, path, &iter);
1004 g_dbus_client_unref(client);
1009 static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
1012 GDBusClient *client = user_data;
1013 DBusMessageIter iter, entry;
1016 if (dbus_message_iter_init(msg, &iter) == FALSE)
1019 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1022 dbus_message_iter_get_basic(&iter, &path);
1023 dbus_message_iter_next(&iter);
1025 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1028 dbus_message_iter_recurse(&iter, &entry);
1030 g_dbus_client_ref(client);
1032 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1033 const char *interface;
1035 dbus_message_iter_get_basic(&entry, &interface);
1036 proxy_remove(client, path, interface);
1037 dbus_message_iter_next(&entry);
1040 g_dbus_client_unref(client);
1045 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
1047 DBusMessageIter iter, dict;
1049 if (dbus_message_iter_init(msg, &iter) == FALSE)
1052 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1055 dbus_message_iter_recurse(&iter, &dict);
1057 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1058 DBusMessageIter entry;
1061 dbus_message_iter_recurse(&dict, &entry);
1063 if (dbus_message_iter_get_arg_type(&entry) !=
1064 DBUS_TYPE_OBJECT_PATH)
1067 dbus_message_iter_get_basic(&entry, &path);
1068 dbus_message_iter_next(&entry);
1070 parse_interfaces(client, path, &entry);
1072 dbus_message_iter_next(&dict);
1076 client->ready(client, client->ready_data);
1079 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
1081 GDBusClient *client = user_data;
1082 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1085 g_dbus_client_ref(client);
1087 dbus_error_init(&error);
1089 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1090 dbus_error_free(&error);
1094 parse_managed_objects(client, reply);
1097 dbus_message_unref(reply);
1099 dbus_pending_call_unref(client->get_objects_call);
1100 client->get_objects_call = NULL;
1102 g_dbus_client_unref(client);
1105 static void get_managed_objects(GDBusClient *client)
1109 if (!client->proxy_added && !client->proxy_removed) {
1110 refresh_properties(client);
1114 if (client->get_objects_call != NULL)
1117 msg = dbus_message_new_method_call(client->service_name, "/",
1118 DBUS_INTERFACE_DBUS ".ObjectManager",
1119 "GetManagedObjects");
1123 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1125 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
1126 &client->get_objects_call, -1) == FALSE) {
1127 dbus_message_unref(msg);
1131 dbus_pending_call_set_notify(client->get_objects_call,
1132 get_managed_objects_reply,
1135 dbus_message_unref(msg);
1138 static void service_connect(DBusConnection *conn, void *user_data)
1140 GDBusClient *client = user_data;
1142 g_dbus_client_ref(client);
1144 if (client->connect_func)
1145 client->connect_func(conn, client->connect_data);
1147 get_managed_objects(client);
1149 g_dbus_client_unref(client);
1152 static void service_disconnect(DBusConnection *conn, void *user_data)
1154 GDBusClient *client = user_data;
1156 g_list_free_full(client->proxy_list, proxy_free);
1157 client->proxy_list = NULL;
1159 if (client->disconn_func)
1160 client->disconn_func(conn, client->disconn_data);
1163 static DBusHandlerResult message_filter(DBusConnection *connection,
1164 DBusMessage *message, void *user_data)
1166 GDBusClient *client = user_data;
1167 const char *sender, *path, *interface;
1169 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1170 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1172 sender = dbus_message_get_sender(message);
1174 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1176 path = dbus_message_get_path(message);
1177 interface = dbus_message_get_interface(message);
1179 if (g_str_has_prefix(path, client->base_path) == FALSE)
1180 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1182 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
1183 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1185 if (client->signal_func)
1186 client->signal_func(connection, message, client->signal_data);
1188 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1191 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1192 const char *service, const char *path)
1194 GDBusClient *client;
1197 if (connection == NULL)
1200 client = g_try_new0(GDBusClient, 1);
1204 if (dbus_connection_add_filter(connection, message_filter,
1205 client, NULL) == FALSE) {
1210 client->dbus_conn = dbus_connection_ref(connection);
1211 client->service_name = g_strdup(service);
1212 client->base_path = g_strdup(path);
1214 client->match_rules = g_ptr_array_sized_new(1);
1215 g_ptr_array_set_free_func(client->match_rules, g_free);
1217 client->watch = g_dbus_add_service_watch(connection, service,
1221 client->added_watch = g_dbus_add_signal_watch(connection, service,
1223 DBUS_INTERFACE_OBJECT_MANAGER,
1227 client->removed_watch = g_dbus_add_signal_watch(connection, service,
1229 DBUS_INTERFACE_OBJECT_MANAGER,
1230 "InterfacesRemoved",
1233 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1234 "sender='%s',path_namespace='%s'",
1235 client->service_name, client->base_path));
1237 for (i = 0; i < client->match_rules->len; i++) {
1238 modify_match(client->dbus_conn, "AddMatch",
1239 g_ptr_array_index(client->match_rules, i));
1242 return g_dbus_client_ref(client);
1245 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1250 __sync_fetch_and_add(&client->ref_count, 1);
1255 void g_dbus_client_unref(GDBusClient *client)
1262 if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
1265 if (client->pending_call != NULL) {
1266 dbus_pending_call_cancel(client->pending_call);
1267 dbus_pending_call_unref(client->pending_call);
1270 if (client->get_objects_call != NULL) {
1271 dbus_pending_call_cancel(client->get_objects_call);
1272 dbus_pending_call_unref(client->get_objects_call);
1275 for (i = 0; i < client->match_rules->len; i++) {
1276 modify_match(client->dbus_conn, "RemoveMatch",
1277 g_ptr_array_index(client->match_rules, i));
1280 g_ptr_array_free(client->match_rules, TRUE);
1282 dbus_connection_remove_filter(client->dbus_conn,
1283 message_filter, client);
1285 g_list_free_full(client->proxy_list, proxy_free);
1287 if (client->disconn_func)
1288 client->disconn_func(client->dbus_conn, client->disconn_data);
1290 g_dbus_remove_watch(client->dbus_conn, client->watch);
1291 g_dbus_remove_watch(client->dbus_conn, client->added_watch);
1292 g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
1294 dbus_connection_unref(client->dbus_conn);
1296 g_free(client->service_name);
1297 g_free(client->base_path);
1302 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1303 GDBusWatchFunction function, void *user_data)
1308 client->connect_func = function;
1309 client->connect_data = user_data;
1314 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1315 GDBusWatchFunction function, void *user_data)
1320 client->disconn_func = function;
1321 client->disconn_data = user_data;
1326 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1327 GDBusMessageFunction function, void *user_data)
1332 client->signal_func = function;
1333 client->signal_data = user_data;
1338 gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
1339 GDBusClientFunction ready, void *user_data)
1344 client->ready = ready;
1345 client->ready_data = user_data;
1350 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1351 GDBusProxyFunction proxy_added,
1352 GDBusProxyFunction proxy_removed,
1353 GDBusPropertyFunction property_changed,
1359 client->proxy_added = proxy_added;
1360 client->proxy_removed = proxy_removed;
1361 client->property_changed = property_changed;
1362 client->user_data = user_data;
1364 get_managed_objects(client);