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
29 #include <dbus/dbus.h>
33 #define METHOD_CALL_TIMEOUT (300 * 1000)
37 DBusConnection *dbus_conn;
41 GPtrArray *match_rules;
42 DBusPendingCall *pending_call;
43 DBusPendingCall *get_objects_call;
44 GDBusWatchFunction connect_func;
46 GDBusWatchFunction disconn_func;
48 GDBusMessageFunction signal_func;
50 GDBusProxyFunction proxy_added;
51 GDBusProxyFunction proxy_removed;
52 GDBusPropertyFunction property_changed;
62 GHashTable *prop_list;
64 GDBusPropertyFunction prop_func;
66 GDBusProxyFunction removed_func;
76 static void modify_match_reply(DBusPendingCall *call, void *user_data)
78 DBusMessage *reply = dbus_pending_call_steal_reply(call);
81 dbus_error_init(&error);
83 if (dbus_set_error_from_message(&error, reply) == TRUE)
84 dbus_error_free(&error);
86 dbus_message_unref(reply);
89 static gboolean modify_match(DBusConnection *conn, const char *member,
93 DBusPendingCall *call;
95 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
96 DBUS_INTERFACE_DBUS, member);
100 dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
103 if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
104 dbus_message_unref(msg);
109 dbus_message_unref(msg);
113 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
114 dbus_pending_call_unref(call);
116 dbus_message_unref(msg);
121 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
125 type = dbus_message_iter_get_arg_type(iter);
127 if (dbus_type_is_basic(type)) {
130 dbus_message_iter_get_basic(iter, &value);
131 dbus_message_iter_append_basic(base, type, &value);
132 } else if (dbus_type_is_container(type)) {
133 DBusMessageIter iter_sub, base_sub;
136 dbus_message_iter_recurse(iter, &iter_sub);
139 case DBUS_TYPE_ARRAY:
140 case DBUS_TYPE_VARIANT:
141 sig = dbus_message_iter_get_signature(&iter_sub);
148 dbus_message_iter_open_container(base, type, sig, &base_sub);
153 while (dbus_message_iter_get_arg_type(&iter_sub) !=
155 iter_append_iter(&base_sub, &iter_sub);
156 dbus_message_iter_next(&iter_sub);
159 dbus_message_iter_close_container(base, &base_sub);
163 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
166 DBusMessageIter base;
168 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
172 dbus_message_iter_init_append(msg, &base);
173 iter_append_iter(&base, iter);
175 if (prop->msg != NULL)
176 dbus_message_unref(prop->msg);
178 prop->msg = dbus_message_copy(msg);
179 dbus_message_unref(msg);
182 static struct prop_entry *prop_entry_new(const char *name,
183 DBusMessageIter *iter)
185 struct prop_entry *prop;
187 prop = g_try_new0(struct prop_entry, 1);
191 prop->name = g_strdup(name);
192 prop->type = dbus_message_iter_get_arg_type(iter);
194 prop_entry_update(prop, iter);
199 static void prop_entry_free(gpointer data)
201 struct prop_entry *prop = data;
203 if (prop->msg != NULL)
204 dbus_message_unref(prop->msg);
211 static void add_property(GDBusProxy *proxy, const char *name,
212 DBusMessageIter *iter, gboolean send_changed)
214 GDBusClient *client = proxy->client;
215 DBusMessageIter value;
216 struct prop_entry *prop;
218 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
221 dbus_message_iter_recurse(iter, &value);
223 prop = g_hash_table_lookup(proxy->prop_list, name);
225 prop_entry_update(prop, &value);
229 prop = prop_entry_new(name, &value);
233 g_hash_table_replace(proxy->prop_list, prop->name, prop);
236 if (proxy->prop_func)
237 proxy->prop_func(proxy, name, &value, proxy->prop_data);
239 if (client == NULL || send_changed == FALSE)
242 if (client->property_changed)
243 client->property_changed(proxy, name, &value,
247 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
248 gboolean send_changed)
250 DBusMessageIter dict;
252 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
255 dbus_message_iter_recurse(iter, &dict);
257 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
258 DBusMessageIter entry;
261 dbus_message_iter_recurse(&dict, &entry);
263 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
266 dbus_message_iter_get_basic(&entry, &name);
267 dbus_message_iter_next(&entry);
269 add_property(proxy, name, &entry, send_changed);
271 dbus_message_iter_next(&dict);
275 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
277 GDBusProxy *proxy = user_data;
278 GDBusClient *client = proxy->client;
279 DBusMessage *reply = dbus_pending_call_steal_reply(call);
280 DBusMessageIter iter;
283 dbus_error_init(&error);
285 if (dbus_set_error_from_message(&error, reply) == TRUE) {
286 dbus_error_free(&error);
290 dbus_message_iter_init(reply, &iter);
292 update_properties(proxy, &iter, FALSE);
295 if (g_list_find(client->proxy_list, proxy) == NULL) {
296 if (client->proxy_added)
297 client->proxy_added(proxy, client->user_data);
299 client->proxy_list = g_list_append(client->proxy_list, proxy);
302 dbus_message_unref(reply);
304 g_dbus_client_unref(client);
307 static void get_all_properties(GDBusProxy *proxy)
309 GDBusClient *client = proxy->client;
310 const char *service_name = client->service_name;
312 DBusPendingCall *call;
314 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
315 DBUS_INTERFACE_PROPERTIES, "GetAll");
319 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
322 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
323 &call, -1) == FALSE) {
324 dbus_message_unref(msg);
328 g_dbus_client_ref(client);
330 dbus_pending_call_set_notify(call, get_all_properties_reply,
332 dbus_pending_call_unref(call);
334 dbus_message_unref(msg);
337 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
338 const char *interface)
342 for (list = g_list_first(client->proxy_list); list;
343 list = g_list_next(list)) {
344 GDBusProxy *proxy = list->data;
346 if (g_str_equal(proxy->interface, interface) == TRUE &&
347 g_str_equal(proxy->obj_path, path) == TRUE)
354 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
355 const char *interface)
359 proxy = g_try_new0(GDBusProxy, 1);
363 proxy->client = client;
364 proxy->obj_path = g_strdup(path);
365 proxy->interface = g_strdup(interface);
367 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
368 NULL, prop_entry_free);
370 proxy->match_rule = g_strdup_printf("type='signal',"
371 "sender='%s',path='%s',interface='%s',"
372 "member='PropertiesChanged',arg0='%s'",
373 client->service_name, proxy->obj_path,
374 DBUS_INTERFACE_PROPERTIES, proxy->interface);
376 modify_match(client->dbus_conn, "AddMatch", proxy->match_rule);
378 return g_dbus_proxy_ref(proxy);
381 static void proxy_free(gpointer data)
383 GDBusProxy *proxy = data;
386 GDBusClient *client = proxy->client;
388 if (client->proxy_removed)
389 client->proxy_removed(proxy, client->user_data);
391 modify_match(client->dbus_conn, "RemoveMatch",
394 g_free(proxy->match_rule);
395 proxy->match_rule = NULL;
397 g_hash_table_remove_all(proxy->prop_list);
399 proxy->client = NULL;
402 if (proxy->removed_func)
403 proxy->removed_func(proxy, proxy->removed_data);
405 g_dbus_proxy_unref(proxy);
408 static void proxy_remove(GDBusClient *client, const char *path,
409 const char *interface)
413 for (list = g_list_first(client->proxy_list); list;
414 list = g_list_next(list)) {
415 GDBusProxy *proxy = list->data;
417 if (g_str_equal(proxy->interface, interface) == TRUE &&
418 g_str_equal(proxy->obj_path, path) == TRUE) {
420 g_list_delete_link(client->proxy_list, list);
427 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
428 const char *interface)
435 proxy = proxy_lookup(client, path, interface);
437 return g_dbus_proxy_ref(proxy);
439 proxy = proxy_new(client, path, interface);
443 get_all_properties(proxy);
445 return g_dbus_proxy_ref(proxy);
448 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
453 __sync_fetch_and_add(&proxy->ref_count, 1);
458 void g_dbus_proxy_unref(GDBusProxy *proxy)
463 if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
466 g_hash_table_destroy(proxy->prop_list);
468 g_free(proxy->obj_path);
469 g_free(proxy->interface);
474 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
479 return proxy->obj_path;
482 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
487 return proxy->interface;
490 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
491 DBusMessageIter *iter)
493 struct prop_entry *prop;
495 if (proxy == NULL || name == NULL)
498 prop = g_hash_table_lookup(proxy->prop_list, name);
502 if (prop->msg == NULL)
505 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
511 struct refresh_property_data {
516 static void refresh_property_free(gpointer user_data)
518 struct refresh_property_data *data = user_data;
524 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
526 struct refresh_property_data *data = user_data;
527 DBusMessage *reply = dbus_pending_call_steal_reply(call);
530 dbus_error_init(&error);
532 if (dbus_set_error_from_message(&error, reply) == FALSE) {
533 DBusMessageIter iter;
535 dbus_message_iter_init(reply, &iter);
537 add_property(data->proxy, data->name, &iter, TRUE);
539 dbus_error_free(&error);
541 dbus_message_unref(reply);
544 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
546 struct refresh_property_data *data;
549 DBusMessageIter iter;
550 DBusPendingCall *call;
552 if (proxy == NULL || name == NULL)
555 client = proxy->client;
559 data = g_try_new0(struct refresh_property_data, 1);
564 data->name = g_strdup(name);
566 msg = dbus_message_new_method_call(client->service_name,
567 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
569 refresh_property_free(data);
573 dbus_message_iter_init_append(msg, &iter);
574 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
576 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
578 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
579 &call, -1) == FALSE) {
580 dbus_message_unref(msg);
581 refresh_property_free(data);
585 dbus_pending_call_set_notify(call, refresh_property_reply,
586 data, refresh_property_free);
587 dbus_pending_call_unref(call);
589 dbus_message_unref(msg);
594 struct set_property_data {
595 GDBusResultFunction function;
597 GDBusDestroyFunction destroy;
600 static void set_property_reply(DBusPendingCall *call, void *user_data)
602 struct set_property_data *data = user_data;
603 DBusMessage *reply = dbus_pending_call_steal_reply(call);
606 dbus_error_init(&error);
608 dbus_set_error_from_message(&error, reply);
611 data->function(&error, data->user_data);
614 data->destroy(data->user_data);
616 dbus_error_free(&error);
618 dbus_message_unref(reply);
621 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
622 const char *name, int type, const void *value,
623 GDBusResultFunction function, void *user_data,
624 GDBusDestroyFunction destroy)
626 struct set_property_data *data;
629 DBusMessageIter iter, variant;
630 DBusPendingCall *call;
633 if (proxy == NULL || name == NULL || value == NULL)
636 if (dbus_type_is_basic(type) == FALSE)
639 client = proxy->client;
643 data = g_try_new0(struct set_property_data, 1);
647 data->function = function;
648 data->user_data = user_data;
649 data->destroy = destroy;
651 msg = dbus_message_new_method_call(client->service_name,
652 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
658 type_as_str[0] = (char) type;
659 type_as_str[1] = '\0';
661 dbus_message_iter_init_append(msg, &iter);
662 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
664 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
666 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
667 type_as_str, &variant);
668 dbus_message_iter_append_basic(&variant, type, value);
669 dbus_message_iter_close_container(&iter, &variant);
671 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
672 &call, -1) == FALSE) {
673 dbus_message_unref(msg);
678 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
679 dbus_pending_call_unref(call);
681 dbus_message_unref(msg);
686 struct method_call_data {
687 GDBusReturnFunction function;
689 GDBusDestroyFunction destroy;
692 static void method_call_reply(DBusPendingCall *call, void *user_data)
694 struct method_call_data *data = user_data;
695 DBusMessage *reply = dbus_pending_call_steal_reply(call);
698 data->function(reply, data->user_data);
701 data->destroy(data->user_data);
703 dbus_message_unref(reply);
706 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
707 GDBusSetupFunction setup,
708 GDBusReturnFunction function, void *user_data,
709 GDBusDestroyFunction destroy)
711 struct method_call_data *data;
714 DBusPendingCall *call;
716 if (proxy == NULL || method == NULL)
719 client = proxy->client;
723 data = g_try_new0(struct method_call_data, 1);
727 data->function = function;
728 data->user_data = user_data;
729 data->destroy = destroy;
731 msg = dbus_message_new_method_call(client->service_name,
732 proxy->obj_path, proxy->interface, method);
739 DBusMessageIter iter;
741 dbus_message_iter_init_append(msg, &iter);
742 setup(&iter, data->user_data);
745 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
746 &call, METHOD_CALL_TIMEOUT) == FALSE) {
747 dbus_message_unref(msg);
752 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
753 dbus_pending_call_unref(call);
755 dbus_message_unref(msg);
760 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
761 GDBusPropertyFunction function, void *user_data)
766 proxy->prop_func = function;
767 proxy->prop_data = user_data;
772 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
773 GDBusProxyFunction function, void *user_data)
778 proxy->removed_func = function;
779 proxy->removed_data = user_data;
784 static void refresh_properties(GDBusClient *client)
788 for (list = g_list_first(client->proxy_list); list;
789 list = g_list_next(list)) {
790 GDBusProxy *proxy = list->data;
792 get_all_properties(proxy);
796 static void properties_changed(GDBusClient *client, const char *path,
799 GDBusProxy *proxy = NULL;
800 DBusMessageIter iter, entry;
801 const char *interface;
804 if (dbus_message_iter_init(msg, &iter) == FALSE)
807 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
810 dbus_message_iter_get_basic(&iter, &interface);
811 dbus_message_iter_next(&iter);
813 for (list = g_list_first(client->proxy_list); list;
814 list = g_list_next(list)) {
815 GDBusProxy *data = list->data;
817 if (g_str_equal(data->interface, interface) == TRUE &&
818 g_str_equal(data->obj_path, path) == TRUE) {
827 update_properties(proxy, &iter, TRUE);
829 dbus_message_iter_next(&iter);
831 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
834 dbus_message_iter_recurse(&iter, &entry);
836 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
839 dbus_message_iter_get_basic(&entry, &name);
841 g_hash_table_remove(proxy->prop_list, name);
843 if (proxy->prop_func)
844 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
846 if (client->property_changed)
847 client->property_changed(proxy, name, NULL,
850 dbus_message_iter_next(&entry);
854 static void parse_properties(GDBusClient *client, const char *path,
855 const char *interface, DBusMessageIter *iter)
859 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
862 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
865 proxy = proxy_lookup(client, path, interface);
867 update_properties(proxy, iter, FALSE);
871 proxy = proxy_new(client, path, interface);
875 update_properties(proxy, iter, FALSE);
877 if (client->proxy_added)
878 client->proxy_added(proxy, client->user_data);
880 client->proxy_list = g_list_append(client->proxy_list, proxy);
883 static void parse_interfaces(GDBusClient *client, const char *path,
884 DBusMessageIter *iter)
886 DBusMessageIter dict;
888 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
891 dbus_message_iter_recurse(iter, &dict);
893 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
894 DBusMessageIter entry;
895 const char *interface;
897 dbus_message_iter_recurse(&dict, &entry);
899 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
902 dbus_message_iter_get_basic(&entry, &interface);
903 dbus_message_iter_next(&entry);
905 parse_properties(client, path, interface, &entry);
907 dbus_message_iter_next(&dict);
911 static void interfaces_added(GDBusClient *client, DBusMessage *msg)
913 DBusMessageIter iter;
916 if (dbus_message_iter_init(msg, &iter) == FALSE)
919 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
922 dbus_message_iter_get_basic(&iter, &path);
923 dbus_message_iter_next(&iter);
925 g_dbus_client_ref(client);
927 parse_interfaces(client, path, &iter);
929 g_dbus_client_unref(client);
932 static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
934 DBusMessageIter iter, entry;
937 if (dbus_message_iter_init(msg, &iter) == FALSE)
940 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
943 dbus_message_iter_get_basic(&iter, &path);
944 dbus_message_iter_next(&iter);
946 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
949 dbus_message_iter_recurse(&iter, &entry);
951 g_dbus_client_ref(client);
953 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
954 const char *interface;
956 dbus_message_iter_get_basic(&entry, &interface);
957 proxy_remove(client, path, interface);
958 dbus_message_iter_next(&entry);
961 g_dbus_client_unref(client);
964 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
966 DBusMessageIter iter, dict;
968 if (dbus_message_iter_init(msg, &iter) == FALSE)
971 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
974 dbus_message_iter_recurse(&iter, &dict);
976 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
977 DBusMessageIter entry;
980 dbus_message_iter_recurse(&dict, &entry);
982 if (dbus_message_iter_get_arg_type(&entry) !=
983 DBUS_TYPE_OBJECT_PATH)
986 dbus_message_iter_get_basic(&entry, &path);
987 dbus_message_iter_next(&entry);
989 parse_interfaces(client, path, &entry);
991 dbus_message_iter_next(&dict);
995 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
997 GDBusClient *client = user_data;
998 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1001 g_dbus_client_ref(client);
1003 dbus_error_init(&error);
1005 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1006 dbus_error_free(&error);
1010 parse_managed_objects(client, reply);
1013 dbus_message_unref(reply);
1015 dbus_pending_call_unref(client->get_objects_call);
1016 client->get_objects_call = NULL;
1018 g_dbus_client_unref(client);
1021 static void get_managed_objects(GDBusClient *client)
1025 if (!client->proxy_added && !client->proxy_removed) {
1026 refresh_properties(client);
1030 if (client->get_objects_call != NULL)
1033 msg = dbus_message_new_method_call(client->service_name, "/",
1034 DBUS_INTERFACE_DBUS ".ObjectManager",
1035 "GetManagedObjects");
1039 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1041 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1042 &client->get_objects_call, -1) == FALSE) {
1043 dbus_message_unref(msg);
1047 dbus_pending_call_set_notify(client->get_objects_call,
1048 get_managed_objects_reply,
1051 dbus_message_unref(msg);
1054 static void get_name_owner_reply(DBusPendingCall *call, void *user_data)
1056 GDBusClient *client = user_data;
1057 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1061 g_dbus_client_ref(client);
1063 dbus_error_init(&error);
1065 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1066 dbus_error_free(&error);
1070 if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name,
1071 DBUS_TYPE_INVALID) == FALSE)
1074 if (client->unique_name == NULL) {
1075 client->unique_name = g_strdup(name);
1077 if (client->connect_func)
1078 client->connect_func(client->dbus_conn,
1079 client->connect_data);
1081 get_managed_objects(client);
1085 dbus_message_unref(reply);
1087 dbus_pending_call_unref(client->pending_call);
1088 client->pending_call = NULL;
1090 g_dbus_client_unref(client);
1093 static void get_name_owner(GDBusClient *client, const char *name)
1097 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1098 DBUS_INTERFACE_DBUS, "GetNameOwner");
1102 dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
1105 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1106 &client->pending_call, -1) == FALSE) {
1107 dbus_message_unref(msg);
1111 dbus_pending_call_set_notify(client->pending_call,
1112 get_name_owner_reply, client, NULL);
1114 dbus_message_unref(msg);
1117 static DBusHandlerResult message_filter(DBusConnection *connection,
1118 DBusMessage *message, void *user_data)
1120 GDBusClient *client = user_data;
1123 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1124 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1126 sender = dbus_message_get_sender(message);
1128 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1130 if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) {
1131 const char *interface, *member;
1132 const char *name, *old, *new;
1134 interface = dbus_message_get_interface(message);
1136 if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE)
1137 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1139 member = dbus_message_get_member(message);
1141 if (g_str_equal(member, "NameOwnerChanged") == FALSE)
1142 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1144 if (dbus_message_get_args(message, NULL,
1145 DBUS_TYPE_STRING, &name,
1146 DBUS_TYPE_STRING, &old,
1147 DBUS_TYPE_STRING, &new,
1148 DBUS_TYPE_INVALID) == FALSE)
1149 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1151 if (g_str_equal(name, client->service_name) == FALSE)
1152 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1154 if (*new == '\0' && client->unique_name != NULL &&
1155 g_str_equal(old, client->unique_name) == TRUE) {
1156 if (client->disconn_func)
1157 client->disconn_func(client->dbus_conn,
1158 client->disconn_data);
1160 g_free(client->unique_name);
1161 client->unique_name = NULL;
1162 } else if (*old == '\0' && client->unique_name == NULL) {
1163 client->unique_name = g_strdup(new);
1165 if (client->connect_func)
1166 client->connect_func(client->dbus_conn,
1167 client->connect_data);
1169 get_managed_objects(client);
1172 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1175 if (client->unique_name == NULL)
1176 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1178 if (g_str_equal(sender, client->unique_name) == TRUE) {
1179 const char *path, *interface, *member;
1181 path = dbus_message_get_path(message);
1182 interface = dbus_message_get_interface(message);
1183 member = dbus_message_get_member(message);
1185 if (g_str_equal(path, "/") == TRUE) {
1186 if (g_str_equal(interface, DBUS_INTERFACE_DBUS
1187 ".ObjectManager") == FALSE)
1188 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1190 if (g_str_equal(member, "InterfacesAdded") == TRUE) {
1191 interfaces_added(client, message);
1192 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1195 if (g_str_equal(member, "InterfacesRemoved") == TRUE) {
1196 interfaces_removed(client, message);
1197 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1200 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1203 if (g_str_has_prefix(path, client->base_path) == FALSE)
1204 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1206 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) {
1207 if (g_str_equal(member, "PropertiesChanged") == TRUE)
1208 properties_changed(client, path, message);
1210 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1213 if (client->signal_func)
1214 client->signal_func(client->dbus_conn,
1215 message, client->signal_data);
1218 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1221 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1222 const char *service, const char *path)
1224 GDBusClient *client;
1227 if (connection == NULL)
1230 client = g_try_new0(GDBusClient, 1);
1234 if (dbus_connection_add_filter(connection, message_filter,
1235 client, NULL) == FALSE) {
1240 client->dbus_conn = dbus_connection_ref(connection);
1241 client->service_name = g_strdup(service);
1242 client->base_path = g_strdup(path);
1244 get_name_owner(client, client->service_name);
1246 client->match_rules = g_ptr_array_sized_new(4);
1247 g_ptr_array_set_free_func(client->match_rules, g_free);
1249 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1250 "sender='%s',path='%s',interface='%s',"
1251 "member='NameOwnerChanged',arg0='%s'",
1252 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1253 DBUS_INTERFACE_DBUS, client->service_name));
1254 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1256 "path='/',interface='%s.ObjectManager',"
1257 "member='InterfacesAdded'",
1258 client->service_name, DBUS_INTERFACE_DBUS));
1259 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1261 "path='/',interface='%s.ObjectManager',"
1262 "member='InterfacesRemoved'",
1263 client->service_name, DBUS_INTERFACE_DBUS));
1264 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1265 "sender='%s',path_namespace='%s'",
1266 client->service_name, client->base_path));
1268 for (i = 0; i < client->match_rules->len; i++) {
1269 modify_match(client->dbus_conn, "AddMatch",
1270 g_ptr_array_index(client->match_rules, i));
1273 return g_dbus_client_ref(client);
1276 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1281 __sync_fetch_and_add(&client->ref_count, 1);
1286 void g_dbus_client_unref(GDBusClient *client)
1293 if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
1296 if (client->pending_call != NULL) {
1297 dbus_pending_call_cancel(client->pending_call);
1298 dbus_pending_call_unref(client->pending_call);
1301 if (client->get_objects_call != NULL) {
1302 dbus_pending_call_cancel(client->get_objects_call);
1303 dbus_pending_call_unref(client->get_objects_call);
1306 for (i = 0; i < client->match_rules->len; i++) {
1307 modify_match(client->dbus_conn, "RemoveMatch",
1308 g_ptr_array_index(client->match_rules, i));
1311 g_ptr_array_free(client->match_rules, TRUE);
1313 dbus_connection_remove_filter(client->dbus_conn,
1314 message_filter, client);
1316 g_list_free_full(client->proxy_list, proxy_free);
1318 if (client->disconn_func)
1319 client->disconn_func(client->dbus_conn, client->disconn_data);
1321 dbus_connection_unref(client->dbus_conn);
1323 g_free(client->service_name);
1324 g_free(client->unique_name);
1325 g_free(client->base_path);
1330 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1331 GDBusWatchFunction function, void *user_data)
1336 client->connect_func = function;
1337 client->connect_data = user_data;
1342 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1343 GDBusWatchFunction function, void *user_data)
1348 client->disconn_func = function;
1349 client->disconn_data = user_data;
1354 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1355 GDBusMessageFunction function, void *user_data)
1360 client->signal_func = function;
1361 client->signal_data = user_data;
1366 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1367 GDBusProxyFunction proxy_added,
1368 GDBusProxyFunction proxy_removed,
1369 GDBusPropertyFunction property_changed,
1375 client->proxy_added = proxy_added;
1376 client->proxy_removed = proxy_removed;
1377 client->property_changed = property_changed;
1378 client->user_data = user_data;
1380 get_managed_objects(client);