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;
56 GDBusMessageFunction signal_func;
58 GDBusProxyFunction proxy_added;
59 GDBusProxyFunction proxy_removed;
60 GDBusClientFunction ready;
62 GDBusPropertyFunction property_changed;
72 GHashTable *prop_list;
74 GDBusPropertyFunction prop_func;
76 GDBusProxyFunction removed_func;
86 static void modify_match_reply(DBusPendingCall *call, void *user_data)
88 DBusMessage *reply = dbus_pending_call_steal_reply(call);
91 dbus_error_init(&error);
93 if (dbus_set_error_from_message(&error, reply) == TRUE)
94 dbus_error_free(&error);
96 dbus_message_unref(reply);
99 static gboolean modify_match(DBusConnection *conn, const char *member,
103 DBusPendingCall *call;
105 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
106 DBUS_INTERFACE_DBUS, member);
110 dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
113 if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
114 dbus_message_unref(msg);
118 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
119 dbus_pending_call_unref(call);
121 dbus_message_unref(msg);
126 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
130 type = dbus_message_iter_get_arg_type(iter);
132 if (dbus_type_is_basic(type)) {
135 dbus_message_iter_get_basic(iter, &value);
136 dbus_message_iter_append_basic(base, type, &value);
137 } else if (dbus_type_is_container(type)) {
138 DBusMessageIter iter_sub, base_sub;
141 dbus_message_iter_recurse(iter, &iter_sub);
144 case DBUS_TYPE_ARRAY:
145 case DBUS_TYPE_VARIANT:
146 sig = dbus_message_iter_get_signature(&iter_sub);
153 dbus_message_iter_open_container(base, type, sig, &base_sub);
158 while (dbus_message_iter_get_arg_type(&iter_sub) !=
160 iter_append_iter(&base_sub, &iter_sub);
161 dbus_message_iter_next(&iter_sub);
164 dbus_message_iter_close_container(base, &base_sub);
168 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
171 DBusMessageIter base;
173 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
177 dbus_message_iter_init_append(msg, &base);
178 iter_append_iter(&base, iter);
180 if (prop->msg != NULL)
181 dbus_message_unref(prop->msg);
183 prop->msg = dbus_message_copy(msg);
184 dbus_message_unref(msg);
187 static struct prop_entry *prop_entry_new(const char *name,
188 DBusMessageIter *iter)
190 struct prop_entry *prop;
192 prop = g_try_new0(struct prop_entry, 1);
196 prop->name = g_strdup(name);
197 prop->type = dbus_message_iter_get_arg_type(iter);
199 prop_entry_update(prop, iter);
204 static void prop_entry_free(gpointer data)
206 struct prop_entry *prop = data;
208 if (prop->msg != NULL)
209 dbus_message_unref(prop->msg);
216 static void add_property(GDBusProxy *proxy, const char *name,
217 DBusMessageIter *iter, gboolean send_changed)
219 GDBusClient *client = proxy->client;
220 DBusMessageIter value;
221 struct prop_entry *prop;
223 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
226 dbus_message_iter_recurse(iter, &value);
228 prop = g_hash_table_lookup(proxy->prop_list, name);
230 prop_entry_update(prop, &value);
234 prop = prop_entry_new(name, &value);
238 g_hash_table_replace(proxy->prop_list, prop->name, prop);
241 if (proxy->prop_func)
242 proxy->prop_func(proxy, name, &value, proxy->prop_data);
244 if (client == NULL || send_changed == FALSE)
247 if (client->property_changed)
248 client->property_changed(proxy, name, &value,
252 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
253 gboolean send_changed)
255 DBusMessageIter dict;
257 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
260 dbus_message_iter_recurse(iter, &dict);
262 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
263 DBusMessageIter entry;
266 dbus_message_iter_recurse(&dict, &entry);
268 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
271 dbus_message_iter_get_basic(&entry, &name);
272 dbus_message_iter_next(&entry);
274 add_property(proxy, name, &entry, send_changed);
276 dbus_message_iter_next(&dict);
280 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
282 GDBusProxy *proxy = user_data;
283 GDBusClient *client = proxy->client;
284 DBusMessage *reply = dbus_pending_call_steal_reply(call);
285 DBusMessageIter iter;
288 dbus_error_init(&error);
290 if (dbus_set_error_from_message(&error, reply) == TRUE) {
291 dbus_error_free(&error);
295 dbus_message_iter_init(reply, &iter);
297 update_properties(proxy, &iter, FALSE);
300 if (g_list_find(client->proxy_list, proxy) == NULL) {
301 if (client->proxy_added)
302 client->proxy_added(proxy, client->user_data);
304 client->proxy_list = g_list_append(client->proxy_list, proxy);
307 dbus_message_unref(reply);
309 g_dbus_client_unref(client);
312 static void get_all_properties(GDBusProxy *proxy)
314 GDBusClient *client = proxy->client;
315 const char *service_name = client->service_name;
317 DBusPendingCall *call;
319 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
320 DBUS_INTERFACE_PROPERTIES, "GetAll");
324 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
327 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
328 &call, -1) == FALSE) {
329 dbus_message_unref(msg);
333 g_dbus_client_ref(client);
335 dbus_pending_call_set_notify(call, get_all_properties_reply,
337 dbus_pending_call_unref(call);
339 dbus_message_unref(msg);
342 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
343 const char *interface)
347 for (list = g_list_first(client->proxy_list); list;
348 list = g_list_next(list)) {
349 GDBusProxy *proxy = list->data;
351 if (g_str_equal(proxy->interface, interface) == TRUE &&
352 g_str_equal(proxy->obj_path, path) == TRUE)
359 static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
362 GDBusProxy *proxy = user_data;
363 GDBusClient *client = proxy->client;
364 DBusMessageIter iter, entry;
365 const char *interface;
367 if (dbus_message_iter_init(msg, &iter) == FALSE)
370 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
373 dbus_message_iter_get_basic(&iter, &interface);
374 dbus_message_iter_next(&iter);
376 update_properties(proxy, &iter, TRUE);
378 dbus_message_iter_next(&iter);
380 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
383 dbus_message_iter_recurse(&iter, &entry);
385 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
388 dbus_message_iter_get_basic(&entry, &name);
390 g_hash_table_remove(proxy->prop_list, name);
392 if (proxy->prop_func)
393 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
395 if (client->property_changed)
396 client->property_changed(proxy, name, NULL,
399 dbus_message_iter_next(&entry);
405 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
406 const char *interface)
410 proxy = g_try_new0(GDBusProxy, 1);
414 proxy->client = client;
415 proxy->obj_path = g_strdup(path);
416 proxy->interface = g_strdup(interface);
418 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
419 NULL, prop_entry_free);
420 proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
421 client->service_name,
427 return g_dbus_proxy_ref(proxy);
430 static void proxy_free(gpointer data)
432 GDBusProxy *proxy = data;
435 GDBusClient *client = proxy->client;
437 if (client->proxy_removed)
438 client->proxy_removed(proxy, client->user_data);
440 g_dbus_remove_watch(client->dbus_conn, proxy->watch);
442 g_hash_table_remove_all(proxy->prop_list);
444 proxy->client = NULL;
447 if (proxy->removed_func)
448 proxy->removed_func(proxy, proxy->removed_data);
450 g_dbus_proxy_unref(proxy);
453 static void proxy_remove(GDBusClient *client, const char *path,
454 const char *interface)
458 for (list = g_list_first(client->proxy_list); list;
459 list = g_list_next(list)) {
460 GDBusProxy *proxy = list->data;
462 if (g_str_equal(proxy->interface, interface) == TRUE &&
463 g_str_equal(proxy->obj_path, path) == TRUE) {
465 g_list_delete_link(client->proxy_list, list);
472 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
473 const char *interface)
480 proxy = proxy_lookup(client, path, interface);
482 return g_dbus_proxy_ref(proxy);
484 proxy = proxy_new(client, path, interface);
488 get_all_properties(proxy);
490 return g_dbus_proxy_ref(proxy);
493 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
498 __sync_fetch_and_add(&proxy->ref_count, 1);
503 void g_dbus_proxy_unref(GDBusProxy *proxy)
508 if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
511 g_hash_table_destroy(proxy->prop_list);
513 g_free(proxy->obj_path);
514 g_free(proxy->interface);
519 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
524 return proxy->obj_path;
527 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
532 return proxy->interface;
535 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
536 DBusMessageIter *iter)
538 struct prop_entry *prop;
540 if (proxy == NULL || name == NULL)
543 prop = g_hash_table_lookup(proxy->prop_list, name);
547 if (prop->msg == NULL)
550 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
556 struct refresh_property_data {
561 static void refresh_property_free(gpointer user_data)
563 struct refresh_property_data *data = user_data;
569 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
571 struct refresh_property_data *data = user_data;
572 DBusMessage *reply = dbus_pending_call_steal_reply(call);
575 dbus_error_init(&error);
577 if (dbus_set_error_from_message(&error, reply) == FALSE) {
578 DBusMessageIter iter;
580 dbus_message_iter_init(reply, &iter);
582 add_property(data->proxy, data->name, &iter, TRUE);
584 dbus_error_free(&error);
586 dbus_message_unref(reply);
589 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
591 struct refresh_property_data *data;
594 DBusMessageIter iter;
595 DBusPendingCall *call;
597 if (proxy == NULL || name == NULL)
600 client = proxy->client;
604 data = g_try_new0(struct refresh_property_data, 1);
609 data->name = g_strdup(name);
611 msg = dbus_message_new_method_call(client->service_name,
612 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
614 refresh_property_free(data);
618 dbus_message_iter_init_append(msg, &iter);
619 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
621 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
623 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
624 &call, -1) == FALSE) {
625 dbus_message_unref(msg);
626 refresh_property_free(data);
630 dbus_pending_call_set_notify(call, refresh_property_reply,
631 data, refresh_property_free);
632 dbus_pending_call_unref(call);
634 dbus_message_unref(msg);
639 struct set_property_data {
640 GDBusResultFunction function;
642 GDBusDestroyFunction destroy;
645 static void set_property_reply(DBusPendingCall *call, void *user_data)
647 struct set_property_data *data = user_data;
648 DBusMessage *reply = dbus_pending_call_steal_reply(call);
651 dbus_error_init(&error);
653 dbus_set_error_from_message(&error, reply);
656 data->function(&error, data->user_data);
659 data->destroy(data->user_data);
661 dbus_error_free(&error);
663 dbus_message_unref(reply);
666 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
667 const char *name, int type, const void *value,
668 GDBusResultFunction function, void *user_data,
669 GDBusDestroyFunction destroy)
671 struct set_property_data *data;
674 DBusMessageIter iter, variant;
675 DBusPendingCall *call;
678 if (proxy == NULL || name == NULL || value == NULL)
681 if (dbus_type_is_basic(type) == FALSE)
684 client = proxy->client;
688 data = g_try_new0(struct set_property_data, 1);
692 data->function = function;
693 data->user_data = user_data;
694 data->destroy = destroy;
696 msg = dbus_message_new_method_call(client->service_name,
697 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
703 type_as_str[0] = (char) type;
704 type_as_str[1] = '\0';
706 dbus_message_iter_init_append(msg, &iter);
707 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
709 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
711 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
712 type_as_str, &variant);
713 dbus_message_iter_append_basic(&variant, type, value);
714 dbus_message_iter_close_container(&iter, &variant);
716 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
717 &call, -1) == FALSE) {
718 dbus_message_unref(msg);
723 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
724 dbus_pending_call_unref(call);
726 dbus_message_unref(msg);
731 gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
732 const char *name, int type, const void *value,
733 size_t size, GDBusResultFunction function,
734 void *user_data, GDBusDestroyFunction destroy)
736 struct set_property_data *data;
739 DBusMessageIter iter, variant, array;
740 DBusPendingCall *call;
744 if (!proxy || !name || !value)
747 if (!dbus_type_is_basic(type))
750 client = proxy->client;
754 data = g_try_new0(struct set_property_data, 1);
758 data->function = function;
759 data->user_data = user_data;
760 data->destroy = destroy;
762 msg = dbus_message_new_method_call(client->service_name,
764 DBUS_INTERFACE_PROPERTIES,
771 array_sig[0] = DBUS_TYPE_ARRAY;
772 array_sig[1] = (char) type;
775 type_sig[0] = (char) type;
778 dbus_message_iter_init_append(msg, &iter);
779 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
781 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
783 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
784 array_sig, &variant);
786 dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
789 if (dbus_type_is_fixed(type))
790 dbus_message_iter_append_fixed_array(&array, type, &value,
792 else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
793 const char **str = (const char **) value;
796 for (i = 0; i < size; i++)
797 dbus_message_iter_append_basic(&array, type, &str[i]);
800 dbus_message_iter_close_container(&variant, &array);
801 dbus_message_iter_close_container(&iter, &variant);
803 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
804 &call, -1) == FALSE) {
805 dbus_message_unref(msg);
810 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
811 dbus_pending_call_unref(call);
813 dbus_message_unref(msg);
818 struct method_call_data {
819 GDBusReturnFunction function;
821 GDBusDestroyFunction destroy;
824 static void method_call_reply(DBusPendingCall *call, void *user_data)
826 struct method_call_data *data = user_data;
827 DBusMessage *reply = dbus_pending_call_steal_reply(call);
830 data->function(reply, data->user_data);
833 data->destroy(data->user_data);
835 dbus_message_unref(reply);
838 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
839 GDBusSetupFunction setup,
840 GDBusReturnFunction function, void *user_data,
841 GDBusDestroyFunction destroy)
843 struct method_call_data *data;
846 DBusPendingCall *call;
848 if (proxy == NULL || method == NULL)
851 client = proxy->client;
855 data = g_try_new0(struct method_call_data, 1);
859 data->function = function;
860 data->user_data = user_data;
861 data->destroy = destroy;
863 msg = dbus_message_new_method_call(client->service_name,
864 proxy->obj_path, proxy->interface, method);
871 DBusMessageIter iter;
873 dbus_message_iter_init_append(msg, &iter);
874 setup(&iter, data->user_data);
877 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
878 &call, METHOD_CALL_TIMEOUT) == FALSE) {
879 dbus_message_unref(msg);
884 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
885 dbus_pending_call_unref(call);
887 dbus_message_unref(msg);
892 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
893 GDBusPropertyFunction function, void *user_data)
898 proxy->prop_func = function;
899 proxy->prop_data = user_data;
904 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
905 GDBusProxyFunction function, void *user_data)
910 proxy->removed_func = function;
911 proxy->removed_data = user_data;
916 static void refresh_properties(GDBusClient *client)
920 for (list = g_list_first(client->proxy_list); list;
921 list = g_list_next(list)) {
922 GDBusProxy *proxy = list->data;
924 get_all_properties(proxy);
928 static void parse_properties(GDBusClient *client, const char *path,
929 const char *interface, DBusMessageIter *iter)
933 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
936 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
939 proxy = proxy_lookup(client, path, interface);
941 update_properties(proxy, iter, FALSE);
945 proxy = proxy_new(client, path, interface);
949 update_properties(proxy, iter, FALSE);
951 if (client->proxy_added)
952 client->proxy_added(proxy, client->user_data);
954 client->proxy_list = g_list_append(client->proxy_list, proxy);
957 static void parse_interfaces(GDBusClient *client, const char *path,
958 DBusMessageIter *iter)
960 DBusMessageIter dict;
962 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
965 dbus_message_iter_recurse(iter, &dict);
967 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
968 DBusMessageIter entry;
969 const char *interface;
971 dbus_message_iter_recurse(&dict, &entry);
973 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
976 dbus_message_iter_get_basic(&entry, &interface);
977 dbus_message_iter_next(&entry);
979 parse_properties(client, path, interface, &entry);
981 dbus_message_iter_next(&dict);
985 static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
988 GDBusClient *client = user_data;
989 DBusMessageIter iter;
992 if (dbus_message_iter_init(msg, &iter) == FALSE)
995 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
998 dbus_message_iter_get_basic(&iter, &path);
999 dbus_message_iter_next(&iter);
1001 g_dbus_client_ref(client);
1003 parse_interfaces(client, path, &iter);
1005 g_dbus_client_unref(client);
1010 static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
1013 GDBusClient *client = user_data;
1014 DBusMessageIter iter, entry;
1017 if (dbus_message_iter_init(msg, &iter) == FALSE)
1020 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1023 dbus_message_iter_get_basic(&iter, &path);
1024 dbus_message_iter_next(&iter);
1026 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1029 dbus_message_iter_recurse(&iter, &entry);
1031 g_dbus_client_ref(client);
1033 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1034 const char *interface;
1036 dbus_message_iter_get_basic(&entry, &interface);
1037 proxy_remove(client, path, interface);
1038 dbus_message_iter_next(&entry);
1041 g_dbus_client_unref(client);
1046 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
1048 DBusMessageIter iter, dict;
1050 if (dbus_message_iter_init(msg, &iter) == FALSE)
1053 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1056 dbus_message_iter_recurse(&iter, &dict);
1058 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1059 DBusMessageIter entry;
1062 dbus_message_iter_recurse(&dict, &entry);
1064 if (dbus_message_iter_get_arg_type(&entry) !=
1065 DBUS_TYPE_OBJECT_PATH)
1068 dbus_message_iter_get_basic(&entry, &path);
1069 dbus_message_iter_next(&entry);
1071 parse_interfaces(client, path, &entry);
1073 dbus_message_iter_next(&dict);
1077 client->ready(client, client->ready_data);
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);
1098 dbus_message_unref(reply);
1100 dbus_pending_call_unref(client->get_objects_call);
1101 client->get_objects_call = NULL;
1103 g_dbus_client_unref(client);
1106 static void get_managed_objects(GDBusClient *client)
1110 if (!client->proxy_added && !client->proxy_removed) {
1111 refresh_properties(client);
1115 if (client->get_objects_call != NULL)
1118 msg = dbus_message_new_method_call(client->service_name, "/",
1119 DBUS_INTERFACE_DBUS ".ObjectManager",
1120 "GetManagedObjects");
1124 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1126 if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
1127 &client->get_objects_call, -1) == FALSE) {
1128 dbus_message_unref(msg);
1132 dbus_pending_call_set_notify(client->get_objects_call,
1133 get_managed_objects_reply,
1136 dbus_message_unref(msg);
1139 static void service_connect(DBusConnection *conn, void *user_data)
1141 GDBusClient *client = user_data;
1143 g_dbus_client_ref(client);
1145 if (client->connect_func)
1146 client->connect_func(conn, client->connect_data);
1148 get_managed_objects(client);
1150 client->connected = TRUE;
1152 g_dbus_client_unref(client);
1155 static void service_disconnect(DBusConnection *conn, void *user_data)
1157 GDBusClient *client = user_data;
1159 g_list_free_full(client->proxy_list, proxy_free);
1160 client->proxy_list = NULL;
1162 if (client->disconn_func) {
1163 client->disconn_func(conn, client->disconn_data);
1164 client->connected = FALSE;
1168 static DBusHandlerResult message_filter(DBusConnection *connection,
1169 DBusMessage *message, void *user_data)
1171 GDBusClient *client = user_data;
1172 const char *sender, *path, *interface;
1174 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1175 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1177 sender = dbus_message_get_sender(message);
1179 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1181 path = dbus_message_get_path(message);
1182 interface = dbus_message_get_interface(message);
1184 if (g_str_has_prefix(path, client->base_path) == FALSE)
1185 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1187 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
1188 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1190 if (client->signal_func)
1191 client->signal_func(connection, message, client->signal_data);
1193 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1196 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1197 const char *service, const char *path)
1199 GDBusClient *client;
1202 if (connection == NULL)
1205 client = g_try_new0(GDBusClient, 1);
1209 if (dbus_connection_add_filter(connection, message_filter,
1210 client, NULL) == FALSE) {
1215 client->dbus_conn = dbus_connection_ref(connection);
1216 client->service_name = g_strdup(service);
1217 client->base_path = g_strdup(path);
1218 client->connected = FALSE;
1220 client->match_rules = g_ptr_array_sized_new(1);
1221 g_ptr_array_set_free_func(client->match_rules, g_free);
1223 client->watch = g_dbus_add_service_watch(connection, service,
1227 client->added_watch = g_dbus_add_signal_watch(connection, service,
1229 DBUS_INTERFACE_OBJECT_MANAGER,
1233 client->removed_watch = g_dbus_add_signal_watch(connection, service,
1235 DBUS_INTERFACE_OBJECT_MANAGER,
1236 "InterfacesRemoved",
1239 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1240 "sender='%s',path_namespace='%s'",
1241 client->service_name, client->base_path));
1243 for (i = 0; i < client->match_rules->len; i++) {
1244 modify_match(client->dbus_conn, "AddMatch",
1245 g_ptr_array_index(client->match_rules, i));
1248 return g_dbus_client_ref(client);
1251 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1256 __sync_fetch_and_add(&client->ref_count, 1);
1261 void g_dbus_client_unref(GDBusClient *client)
1268 if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
1271 if (client->pending_call != NULL) {
1272 dbus_pending_call_cancel(client->pending_call);
1273 dbus_pending_call_unref(client->pending_call);
1276 if (client->get_objects_call != NULL) {
1277 dbus_pending_call_cancel(client->get_objects_call);
1278 dbus_pending_call_unref(client->get_objects_call);
1281 for (i = 0; i < client->match_rules->len; i++) {
1282 modify_match(client->dbus_conn, "RemoveMatch",
1283 g_ptr_array_index(client->match_rules, i));
1286 g_ptr_array_free(client->match_rules, TRUE);
1288 dbus_connection_remove_filter(client->dbus_conn,
1289 message_filter, client);
1291 g_list_free_full(client->proxy_list, proxy_free);
1294 * Don't call disconn_func twice if disconnection
1295 * was previously reported.
1297 if (client->disconn_func && client->connected)
1298 client->disconn_func(client->dbus_conn, client->disconn_data);
1300 g_dbus_remove_watch(client->dbus_conn, client->watch);
1301 g_dbus_remove_watch(client->dbus_conn, client->added_watch);
1302 g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
1304 dbus_connection_unref(client->dbus_conn);
1306 g_free(client->service_name);
1307 g_free(client->base_path);
1312 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1313 GDBusWatchFunction function, void *user_data)
1318 client->connect_func = function;
1319 client->connect_data = user_data;
1324 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1325 GDBusWatchFunction function, void *user_data)
1330 client->disconn_func = function;
1331 client->disconn_data = user_data;
1336 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1337 GDBusMessageFunction function, void *user_data)
1342 client->signal_func = function;
1343 client->signal_data = user_data;
1348 gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
1349 GDBusClientFunction ready, void *user_data)
1354 client->ready = ready;
1355 client->ready_data = user_data;
1360 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1361 GDBusProxyFunction proxy_added,
1362 GDBusProxyFunction proxy_removed,
1363 GDBusPropertyFunction property_changed,
1369 client->proxy_added = proxy_added;
1370 client->proxy_removed = proxy_removed;
1371 client->property_changed = property_changed;
1372 client->user_data = user_data;
1374 get_managed_objects(client);