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);
108 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
109 dbus_pending_call_unref(call);
111 dbus_message_unref(msg);
116 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
120 type = dbus_message_iter_get_arg_type(iter);
122 if (dbus_type_is_basic(type)) {
125 dbus_message_iter_get_basic(iter, &value);
126 dbus_message_iter_append_basic(base, type, &value);
127 } else if (dbus_type_is_container(type)) {
128 DBusMessageIter iter_sub, base_sub;
131 dbus_message_iter_recurse(iter, &iter_sub);
134 case DBUS_TYPE_ARRAY:
135 case DBUS_TYPE_VARIANT:
136 sig = dbus_message_iter_get_signature(&iter_sub);
143 dbus_message_iter_open_container(base, type, sig, &base_sub);
148 while (dbus_message_iter_get_arg_type(&iter_sub) !=
150 iter_append_iter(&base_sub, &iter_sub);
151 dbus_message_iter_next(&iter_sub);
154 dbus_message_iter_close_container(base, &base_sub);
158 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
161 DBusMessageIter base;
163 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
167 dbus_message_iter_init_append(msg, &base);
168 iter_append_iter(&base, iter);
170 if (prop->msg != NULL)
171 dbus_message_unref(prop->msg);
173 prop->msg = dbus_message_copy(msg);
174 dbus_message_unref(msg);
177 static struct prop_entry *prop_entry_new(const char *name,
178 DBusMessageIter *iter)
180 struct prop_entry *prop;
182 prop = g_try_new0(struct prop_entry, 1);
186 prop->name = g_strdup(name);
187 prop->type = dbus_message_iter_get_arg_type(iter);
189 prop_entry_update(prop, iter);
194 static void prop_entry_free(gpointer data)
196 struct prop_entry *prop = data;
198 if (prop->msg != NULL)
199 dbus_message_unref(prop->msg);
206 static void add_property(GDBusProxy *proxy, const char *name,
207 DBusMessageIter *iter, gboolean send_changed)
209 GDBusClient *client = proxy->client;
210 DBusMessageIter value;
211 struct prop_entry *prop;
213 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
216 dbus_message_iter_recurse(iter, &value);
218 prop = g_hash_table_lookup(proxy->prop_list, name);
220 prop_entry_update(prop, &value);
224 prop = prop_entry_new(name, &value);
228 g_hash_table_replace(proxy->prop_list, prop->name, prop);
231 if (proxy->prop_func)
232 proxy->prop_func(proxy, name, &value, proxy->prop_data);
234 if (client == NULL || send_changed == FALSE)
237 if (client->property_changed)
238 client->property_changed(proxy, name, &value,
242 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
243 gboolean send_changed)
245 DBusMessageIter dict;
247 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
250 dbus_message_iter_recurse(iter, &dict);
252 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
253 DBusMessageIter entry;
256 dbus_message_iter_recurse(&dict, &entry);
258 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
261 dbus_message_iter_get_basic(&entry, &name);
262 dbus_message_iter_next(&entry);
264 add_property(proxy, name, &entry, send_changed);
266 dbus_message_iter_next(&dict);
270 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
272 GDBusProxy *proxy = user_data;
273 GDBusClient *client = proxy->client;
274 DBusMessage *reply = dbus_pending_call_steal_reply(call);
275 DBusMessageIter iter;
278 dbus_error_init(&error);
280 if (dbus_set_error_from_message(&error, reply) == TRUE) {
281 dbus_error_free(&error);
285 dbus_message_iter_init(reply, &iter);
287 update_properties(proxy, &iter, FALSE);
290 if (g_list_find(client->proxy_list, proxy) == NULL) {
291 if (client->proxy_added)
292 client->proxy_added(proxy, client->user_data);
294 client->proxy_list = g_list_append(client->proxy_list, proxy);
297 dbus_message_unref(reply);
299 g_dbus_client_unref(client);
302 static void get_all_properties(GDBusProxy *proxy)
304 GDBusClient *client = proxy->client;
305 const char *service_name = client->service_name;
307 DBusPendingCall *call;
309 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
310 DBUS_INTERFACE_PROPERTIES, "GetAll");
314 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
317 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
318 &call, -1) == FALSE) {
319 dbus_message_unref(msg);
323 g_dbus_client_ref(client);
325 dbus_pending_call_set_notify(call, get_all_properties_reply,
327 dbus_pending_call_unref(call);
329 dbus_message_unref(msg);
332 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
333 const char *interface)
337 for (list = g_list_first(client->proxy_list); list;
338 list = g_list_next(list)) {
339 GDBusProxy *proxy = list->data;
341 if (g_str_equal(proxy->interface, interface) == TRUE &&
342 g_str_equal(proxy->obj_path, path) == TRUE)
349 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
350 const char *interface)
354 proxy = g_try_new0(GDBusProxy, 1);
358 proxy->client = client;
359 proxy->obj_path = g_strdup(path);
360 proxy->interface = g_strdup(interface);
362 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
363 NULL, prop_entry_free);
365 proxy->match_rule = g_strdup_printf("type='signal',"
366 "sender='%s',path='%s',interface='%s',"
367 "member='PropertiesChanged',arg0='%s'",
368 client->service_name, proxy->obj_path,
369 DBUS_INTERFACE_PROPERTIES, proxy->interface);
371 modify_match(client->dbus_conn, "AddMatch", proxy->match_rule);
373 return g_dbus_proxy_ref(proxy);
376 static void proxy_free(gpointer data)
378 GDBusProxy *proxy = data;
381 GDBusClient *client = proxy->client;
383 if (client->proxy_removed)
384 client->proxy_removed(proxy, client->user_data);
386 modify_match(client->dbus_conn, "RemoveMatch",
389 g_free(proxy->match_rule);
390 proxy->match_rule = NULL;
392 g_hash_table_remove_all(proxy->prop_list);
394 proxy->client = NULL;
397 if (proxy->removed_func)
398 proxy->removed_func(proxy, proxy->removed_data);
400 g_dbus_proxy_unref(proxy);
403 static void proxy_remove(GDBusClient *client, const char *path,
404 const char *interface)
408 for (list = g_list_first(client->proxy_list); list;
409 list = g_list_next(list)) {
410 GDBusProxy *proxy = list->data;
412 if (g_str_equal(proxy->interface, interface) == TRUE &&
413 g_str_equal(proxy->obj_path, path) == TRUE) {
415 g_list_delete_link(client->proxy_list, list);
422 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
423 const char *interface)
430 proxy = proxy_lookup(client, path, interface);
432 return g_dbus_proxy_ref(proxy);
434 proxy = proxy_new(client, path, interface);
438 get_all_properties(proxy);
440 return g_dbus_proxy_ref(proxy);
443 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
448 __sync_fetch_and_add(&proxy->ref_count, 1);
453 void g_dbus_proxy_unref(GDBusProxy *proxy)
458 if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
461 g_hash_table_destroy(proxy->prop_list);
463 g_free(proxy->obj_path);
464 g_free(proxy->interface);
469 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
474 return proxy->obj_path;
477 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
482 return proxy->interface;
485 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
486 DBusMessageIter *iter)
488 struct prop_entry *prop;
490 if (proxy == NULL || name == NULL)
493 prop = g_hash_table_lookup(proxy->prop_list, name);
497 if (prop->msg == NULL)
500 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
506 struct refresh_property_data {
511 static void refresh_property_free(gpointer user_data)
513 struct refresh_property_data *data = user_data;
519 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
521 struct refresh_property_data *data = user_data;
522 DBusMessage *reply = dbus_pending_call_steal_reply(call);
525 dbus_error_init(&error);
527 if (dbus_set_error_from_message(&error, reply) == FALSE) {
528 DBusMessageIter iter;
530 dbus_message_iter_init(reply, &iter);
532 add_property(data->proxy, data->name, &iter, TRUE);
534 dbus_error_free(&error);
536 dbus_message_unref(reply);
539 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
541 struct refresh_property_data *data;
544 DBusMessageIter iter;
545 DBusPendingCall *call;
547 if (proxy == NULL || name == NULL)
550 client = proxy->client;
554 data = g_try_new0(struct refresh_property_data, 1);
559 data->name = g_strdup(name);
561 msg = dbus_message_new_method_call(client->service_name,
562 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
564 refresh_property_free(data);
568 dbus_message_iter_init_append(msg, &iter);
569 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
571 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
573 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
574 &call, -1) == FALSE) {
575 dbus_message_unref(msg);
576 refresh_property_free(data);
580 dbus_pending_call_set_notify(call, refresh_property_reply,
581 data, refresh_property_free);
582 dbus_pending_call_unref(call);
584 dbus_message_unref(msg);
589 struct set_property_data {
590 GDBusResultFunction function;
592 GDBusDestroyFunction destroy;
595 static void set_property_reply(DBusPendingCall *call, void *user_data)
597 struct set_property_data *data = user_data;
598 DBusMessage *reply = dbus_pending_call_steal_reply(call);
601 dbus_error_init(&error);
603 dbus_set_error_from_message(&error, reply);
606 data->function(&error, data->user_data);
609 data->destroy(data->user_data);
611 dbus_error_free(&error);
613 dbus_message_unref(reply);
616 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
617 const char *name, int type, const void *value,
618 GDBusResultFunction function, void *user_data,
619 GDBusDestroyFunction destroy)
621 struct set_property_data *data;
624 DBusMessageIter iter, variant;
625 DBusPendingCall *call;
628 if (proxy == NULL || name == NULL || value == NULL)
631 if (dbus_type_is_basic(type) == FALSE)
634 client = proxy->client;
638 data = g_try_new0(struct set_property_data, 1);
642 data->function = function;
643 data->user_data = user_data;
644 data->destroy = destroy;
646 msg = dbus_message_new_method_call(client->service_name,
647 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
653 type_as_str[0] = (char) type;
654 type_as_str[1] = '\0';
656 dbus_message_iter_init_append(msg, &iter);
657 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
659 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
661 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
662 type_as_str, &variant);
663 dbus_message_iter_append_basic(&variant, type, value);
664 dbus_message_iter_close_container(&iter, &variant);
666 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
667 &call, -1) == FALSE) {
668 dbus_message_unref(msg);
673 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
674 dbus_pending_call_unref(call);
676 dbus_message_unref(msg);
681 struct method_call_data {
682 GDBusReturnFunction function;
684 GDBusDestroyFunction destroy;
687 static void method_call_reply(DBusPendingCall *call, void *user_data)
689 struct method_call_data *data = user_data;
690 DBusMessage *reply = dbus_pending_call_steal_reply(call);
693 data->function(reply, data->user_data);
696 data->destroy(data->user_data);
698 dbus_message_unref(reply);
701 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
702 GDBusSetupFunction setup,
703 GDBusReturnFunction function, void *user_data,
704 GDBusDestroyFunction destroy)
706 struct method_call_data *data;
709 DBusPendingCall *call;
711 if (proxy == NULL || method == NULL)
714 client = proxy->client;
718 data = g_try_new0(struct method_call_data, 1);
722 data->function = function;
723 data->user_data = user_data;
724 data->destroy = destroy;
726 msg = dbus_message_new_method_call(client->service_name,
727 proxy->obj_path, proxy->interface, method);
734 DBusMessageIter iter;
736 dbus_message_iter_init_append(msg, &iter);
737 setup(&iter, data->user_data);
740 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
741 &call, METHOD_CALL_TIMEOUT) == FALSE) {
742 dbus_message_unref(msg);
747 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
748 dbus_pending_call_unref(call);
750 dbus_message_unref(msg);
755 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
756 GDBusPropertyFunction function, void *user_data)
761 proxy->prop_func = function;
762 proxy->prop_data = user_data;
767 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
768 GDBusProxyFunction function, void *user_data)
773 proxy->removed_func = function;
774 proxy->removed_data = user_data;
779 static void refresh_properties(GDBusClient *client)
783 for (list = g_list_first(client->proxy_list); list;
784 list = g_list_next(list)) {
785 GDBusProxy *proxy = list->data;
787 get_all_properties(proxy);
791 static void properties_changed(GDBusClient *client, const char *path,
794 GDBusProxy *proxy = NULL;
795 DBusMessageIter iter, entry;
796 const char *interface;
799 if (dbus_message_iter_init(msg, &iter) == FALSE)
802 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
805 dbus_message_iter_get_basic(&iter, &interface);
806 dbus_message_iter_next(&iter);
808 for (list = g_list_first(client->proxy_list); list;
809 list = g_list_next(list)) {
810 GDBusProxy *data = list->data;
812 if (g_str_equal(data->interface, interface) == TRUE &&
813 g_str_equal(data->obj_path, path) == TRUE) {
822 update_properties(proxy, &iter, TRUE);
824 dbus_message_iter_next(&iter);
826 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
829 dbus_message_iter_recurse(&iter, &entry);
831 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
834 dbus_message_iter_get_basic(&entry, &name);
836 g_hash_table_remove(proxy->prop_list, name);
838 if (proxy->prop_func)
839 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
841 if (client->property_changed)
842 client->property_changed(proxy, name, NULL,
845 dbus_message_iter_next(&entry);
849 static void parse_properties(GDBusClient *client, const char *path,
850 const char *interface, DBusMessageIter *iter)
854 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
857 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
860 proxy = proxy_lookup(client, path, interface);
862 update_properties(proxy, iter, FALSE);
866 proxy = proxy_new(client, path, interface);
870 update_properties(proxy, iter, FALSE);
872 if (client->proxy_added)
873 client->proxy_added(proxy, client->user_data);
875 client->proxy_list = g_list_append(client->proxy_list, proxy);
878 static void parse_interfaces(GDBusClient *client, const char *path,
879 DBusMessageIter *iter)
881 DBusMessageIter dict;
883 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
886 dbus_message_iter_recurse(iter, &dict);
888 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
889 DBusMessageIter entry;
890 const char *interface;
892 dbus_message_iter_recurse(&dict, &entry);
894 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
897 dbus_message_iter_get_basic(&entry, &interface);
898 dbus_message_iter_next(&entry);
900 parse_properties(client, path, interface, &entry);
902 dbus_message_iter_next(&dict);
906 static void interfaces_added(GDBusClient *client, DBusMessage *msg)
908 DBusMessageIter iter;
911 if (dbus_message_iter_init(msg, &iter) == FALSE)
914 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
917 dbus_message_iter_get_basic(&iter, &path);
918 dbus_message_iter_next(&iter);
920 g_dbus_client_ref(client);
922 parse_interfaces(client, path, &iter);
924 g_dbus_client_unref(client);
927 static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
929 DBusMessageIter iter, entry;
932 if (dbus_message_iter_init(msg, &iter) == FALSE)
935 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
938 dbus_message_iter_get_basic(&iter, &path);
939 dbus_message_iter_next(&iter);
941 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
944 dbus_message_iter_recurse(&iter, &entry);
946 g_dbus_client_ref(client);
948 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
949 const char *interface;
951 dbus_message_iter_get_basic(&entry, &interface);
952 proxy_remove(client, path, interface);
953 dbus_message_iter_next(&entry);
956 g_dbus_client_unref(client);
959 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
961 DBusMessageIter iter, dict;
963 if (dbus_message_iter_init(msg, &iter) == FALSE)
966 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
969 dbus_message_iter_recurse(&iter, &dict);
971 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
972 DBusMessageIter entry;
975 dbus_message_iter_recurse(&dict, &entry);
977 if (dbus_message_iter_get_arg_type(&entry) !=
978 DBUS_TYPE_OBJECT_PATH)
981 dbus_message_iter_get_basic(&entry, &path);
982 dbus_message_iter_next(&entry);
984 parse_interfaces(client, path, &entry);
986 dbus_message_iter_next(&dict);
990 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
992 GDBusClient *client = user_data;
993 DBusMessage *reply = dbus_pending_call_steal_reply(call);
996 g_dbus_client_ref(client);
998 dbus_error_init(&error);
1000 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1001 dbus_error_free(&error);
1005 parse_managed_objects(client, reply);
1008 dbus_message_unref(reply);
1010 dbus_pending_call_unref(client->get_objects_call);
1011 client->get_objects_call = NULL;
1013 g_dbus_client_unref(client);
1016 static void get_managed_objects(GDBusClient *client)
1020 if (!client->proxy_added && !client->proxy_removed) {
1021 refresh_properties(client);
1025 if (client->get_objects_call != NULL)
1028 msg = dbus_message_new_method_call(client->service_name, "/",
1029 DBUS_INTERFACE_DBUS ".ObjectManager",
1030 "GetManagedObjects");
1034 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1036 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1037 &client->get_objects_call, -1) == FALSE) {
1038 dbus_message_unref(msg);
1042 dbus_pending_call_set_notify(client->get_objects_call,
1043 get_managed_objects_reply,
1046 dbus_message_unref(msg);
1049 static void get_name_owner_reply(DBusPendingCall *call, void *user_data)
1051 GDBusClient *client = user_data;
1052 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1056 g_dbus_client_ref(client);
1058 dbus_error_init(&error);
1060 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1061 dbus_error_free(&error);
1065 if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name,
1066 DBUS_TYPE_INVALID) == FALSE)
1069 if (client->unique_name == NULL) {
1070 client->unique_name = g_strdup(name);
1072 if (client->connect_func)
1073 client->connect_func(client->dbus_conn,
1074 client->connect_data);
1076 get_managed_objects(client);
1080 dbus_message_unref(reply);
1082 dbus_pending_call_unref(client->pending_call);
1083 client->pending_call = NULL;
1085 g_dbus_client_unref(client);
1088 static void get_name_owner(GDBusClient *client, const char *name)
1092 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1093 DBUS_INTERFACE_DBUS, "GetNameOwner");
1097 dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
1100 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1101 &client->pending_call, -1) == FALSE) {
1102 dbus_message_unref(msg);
1106 dbus_pending_call_set_notify(client->pending_call,
1107 get_name_owner_reply, client, NULL);
1109 dbus_message_unref(msg);
1112 static DBusHandlerResult message_filter(DBusConnection *connection,
1113 DBusMessage *message, void *user_data)
1115 GDBusClient *client = user_data;
1118 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1119 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1121 sender = dbus_message_get_sender(message);
1123 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1125 if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) {
1126 const char *interface, *member;
1127 const char *name, *old, *new;
1129 interface = dbus_message_get_interface(message);
1131 if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE)
1132 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1134 member = dbus_message_get_member(message);
1136 if (g_str_equal(member, "NameOwnerChanged") == FALSE)
1137 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1139 if (dbus_message_get_args(message, NULL,
1140 DBUS_TYPE_STRING, &name,
1141 DBUS_TYPE_STRING, &old,
1142 DBUS_TYPE_STRING, &new,
1143 DBUS_TYPE_INVALID) == FALSE)
1144 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1146 if (g_str_equal(name, client->service_name) == FALSE)
1147 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1149 if (*new == '\0' && client->unique_name != NULL &&
1150 g_str_equal(old, client->unique_name) == TRUE) {
1151 if (client->disconn_func)
1152 client->disconn_func(client->dbus_conn,
1153 client->disconn_data);
1155 g_free(client->unique_name);
1156 client->unique_name = NULL;
1157 } else if (*old == '\0' && client->unique_name == NULL) {
1158 client->unique_name = g_strdup(new);
1160 if (client->connect_func)
1161 client->connect_func(client->dbus_conn,
1162 client->connect_data);
1164 get_managed_objects(client);
1167 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1170 if (client->unique_name == NULL)
1171 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1173 if (g_str_equal(sender, client->unique_name) == TRUE) {
1174 const char *path, *interface, *member;
1176 path = dbus_message_get_path(message);
1177 interface = dbus_message_get_interface(message);
1178 member = dbus_message_get_member(message);
1180 if (g_str_equal(path, "/") == TRUE) {
1181 if (g_str_equal(interface, DBUS_INTERFACE_DBUS
1182 ".ObjectManager") == FALSE)
1183 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1185 if (g_str_equal(member, "InterfacesAdded") == TRUE) {
1186 interfaces_added(client, message);
1187 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1190 if (g_str_equal(member, "InterfacesRemoved") == TRUE) {
1191 interfaces_removed(client, message);
1192 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1195 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1198 if (g_str_has_prefix(path, client->base_path) == FALSE)
1199 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1201 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) {
1202 if (g_str_equal(member, "PropertiesChanged") == TRUE)
1203 properties_changed(client, path, message);
1205 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1208 if (client->signal_func)
1209 client->signal_func(client->dbus_conn,
1210 message, client->signal_data);
1213 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1216 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1217 const char *service, const char *path)
1219 GDBusClient *client;
1222 if (connection == NULL)
1225 client = g_try_new0(GDBusClient, 1);
1229 if (dbus_connection_add_filter(connection, message_filter,
1230 client, NULL) == FALSE) {
1235 client->dbus_conn = dbus_connection_ref(connection);
1236 client->service_name = g_strdup(service);
1237 client->base_path = g_strdup(path);
1239 get_name_owner(client, client->service_name);
1241 client->match_rules = g_ptr_array_sized_new(4);
1242 g_ptr_array_set_free_func(client->match_rules, g_free);
1244 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1245 "sender='%s',path='%s',interface='%s',"
1246 "member='NameOwnerChanged',arg0='%s'",
1247 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1248 DBUS_INTERFACE_DBUS, client->service_name));
1249 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1251 "path='/',interface='%s.ObjectManager',"
1252 "member='InterfacesAdded'",
1253 client->service_name, DBUS_INTERFACE_DBUS));
1254 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1256 "path='/',interface='%s.ObjectManager',"
1257 "member='InterfacesRemoved'",
1258 client->service_name, DBUS_INTERFACE_DBUS));
1259 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1260 "sender='%s',path_namespace='%s'",
1261 client->service_name, client->base_path));
1263 for (i = 0; i < client->match_rules->len; i++) {
1264 modify_match(client->dbus_conn, "AddMatch",
1265 g_ptr_array_index(client->match_rules, i));
1268 return g_dbus_client_ref(client);
1271 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1276 __sync_fetch_and_add(&client->ref_count, 1);
1281 void g_dbus_client_unref(GDBusClient *client)
1288 if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
1291 if (client->pending_call != NULL) {
1292 dbus_pending_call_cancel(client->pending_call);
1293 dbus_pending_call_unref(client->pending_call);
1296 if (client->get_objects_call != NULL) {
1297 dbus_pending_call_cancel(client->get_objects_call);
1298 dbus_pending_call_unref(client->get_objects_call);
1301 for (i = 0; i < client->match_rules->len; i++) {
1302 modify_match(client->dbus_conn, "RemoveMatch",
1303 g_ptr_array_index(client->match_rules, i));
1306 g_ptr_array_free(client->match_rules, TRUE);
1308 dbus_connection_remove_filter(client->dbus_conn,
1309 message_filter, client);
1311 g_list_free_full(client->proxy_list, proxy_free);
1313 if (client->disconn_func)
1314 client->disconn_func(client->dbus_conn, client->disconn_data);
1316 dbus_connection_unref(client->dbus_conn);
1318 g_free(client->service_name);
1319 g_free(client->unique_name);
1320 g_free(client->base_path);
1325 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1326 GDBusWatchFunction function, void *user_data)
1331 client->connect_func = function;
1332 client->connect_data = user_data;
1337 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1338 GDBusWatchFunction function, void *user_data)
1343 client->disconn_func = function;
1344 client->disconn_data = user_data;
1349 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1350 GDBusMessageFunction function, void *user_data)
1355 client->signal_func = function;
1356 client->signal_data = user_data;
1361 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1362 GDBusProxyFunction proxy_added,
1363 GDBusProxyFunction proxy_removed,
1364 GDBusPropertyFunction property_changed,
1370 client->proxy_added = proxy_added;
1371 client->proxy_removed = proxy_removed;
1372 client->property_changed = property_changed;
1373 client->user_data = user_data;
1375 get_managed_objects(client);