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 GDBusWatchFunction connect_func;
45 GDBusWatchFunction disconn_func;
47 GDBusMessageFunction signal_func;
49 GDBusProxyFunction proxy_added;
50 GDBusProxyFunction proxy_removed;
51 GDBusPropertyFunction property_changed;
61 GHashTable *prop_list;
63 GDBusPropertyFunction prop_func;
65 GDBusProxyFunction removed_func;
75 static void modify_match_reply(DBusPendingCall *call, void *user_data)
77 DBusMessage *reply = dbus_pending_call_steal_reply(call);
80 dbus_error_init(&error);
82 if (dbus_set_error_from_message(&error, reply) == TRUE)
83 dbus_error_free(&error);
85 dbus_message_unref(reply);
88 static gboolean modify_match(DBusConnection *conn, const char *member,
92 DBusPendingCall *call;
94 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
95 DBUS_INTERFACE_DBUS, member);
99 dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
102 if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
103 dbus_message_unref(msg);
107 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
108 dbus_pending_call_unref(call);
110 dbus_message_unref(msg);
115 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
119 type = dbus_message_iter_get_arg_type(iter);
121 if (dbus_type_is_basic(type)) {
124 dbus_message_iter_get_basic(iter, &value);
125 dbus_message_iter_append_basic(base, type, &value);
126 } else if (dbus_type_is_container(type)) {
127 DBusMessageIter iter_sub, base_sub;
130 dbus_message_iter_recurse(iter, &iter_sub);
133 case DBUS_TYPE_ARRAY:
134 case DBUS_TYPE_VARIANT:
135 sig = dbus_message_iter_get_signature(&iter_sub);
142 dbus_message_iter_open_container(base, type, sig, &base_sub);
147 while (dbus_message_iter_get_arg_type(&iter_sub) !=
149 iter_append_iter(&base_sub, &iter_sub);
150 dbus_message_iter_next(&iter_sub);
153 dbus_message_iter_close_container(base, &base_sub);
157 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
160 DBusMessageIter base;
162 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
166 dbus_message_iter_init_append(msg, &base);
167 iter_append_iter(&base, iter);
169 if (prop->msg != NULL)
170 dbus_message_unref(prop->msg);
172 prop->msg = dbus_message_copy(msg);
173 dbus_message_unref(msg);
176 static struct prop_entry *prop_entry_new(const char *name,
177 DBusMessageIter *iter)
179 struct prop_entry *prop;
181 prop = g_try_new0(struct prop_entry, 1);
185 prop->name = g_strdup(name);
186 prop->type = dbus_message_iter_get_arg_type(iter);
188 prop_entry_update(prop, iter);
193 static void prop_entry_free(gpointer data)
195 struct prop_entry *prop = data;
197 if (prop->msg != NULL)
198 dbus_message_unref(prop->msg);
205 static void add_property(GDBusProxy *proxy, const char *name,
206 DBusMessageIter *iter, gboolean send_changed)
208 DBusMessageIter value;
209 struct prop_entry *prop;
211 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
214 dbus_message_iter_recurse(iter, &value);
216 prop = g_hash_table_lookup(proxy->prop_list, name);
218 GDBusClient *client = proxy->client;
220 prop_entry_update(prop, &value);
222 if (proxy->prop_func)
223 proxy->prop_func(proxy, name, &value, proxy->prop_data);
225 if (client == NULL || send_changed == FALSE)
228 if (client->property_changed)
229 client->property_changed(proxy, name, &value,
234 prop = prop_entry_new(name, &value);
238 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);
244 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
245 gboolean send_changed)
247 DBusMessageIter dict;
249 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
252 dbus_message_iter_recurse(iter, &dict);
254 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
255 DBusMessageIter entry;
258 dbus_message_iter_recurse(&dict, &entry);
260 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
263 dbus_message_iter_get_basic(&entry, &name);
264 dbus_message_iter_next(&entry);
266 add_property(proxy, name, &entry, send_changed);
268 dbus_message_iter_next(&dict);
272 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
274 GDBusProxy *proxy = user_data;
275 GDBusClient *client = proxy->client;
276 DBusMessage *reply = dbus_pending_call_steal_reply(call);
277 DBusMessageIter iter;
280 dbus_error_init(&error);
282 if (dbus_set_error_from_message(&error, reply) == TRUE) {
283 dbus_error_free(&error);
287 dbus_message_iter_init(reply, &iter);
289 update_properties(proxy, &iter, FALSE);
292 if (g_list_find(client->proxy_list, proxy) == NULL) {
293 if (client->proxy_added)
294 client->proxy_added(proxy, client->user_data);
296 client->proxy_list = g_list_append(client->proxy_list, proxy);
299 dbus_message_unref(reply);
301 g_dbus_client_unref(client);
304 static void get_all_properties(GDBusProxy *proxy)
306 GDBusClient *client = proxy->client;
307 const char *service_name = client->service_name;
309 DBusPendingCall *call;
311 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
312 DBUS_INTERFACE_PROPERTIES, "GetAll");
316 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
319 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
320 &call, -1) == FALSE) {
321 dbus_message_unref(msg);
325 g_dbus_client_ref(client);
327 dbus_pending_call_set_notify(call, get_all_properties_reply,
329 dbus_pending_call_unref(call);
331 dbus_message_unref(msg);
334 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
335 const char *interface)
339 for (list = g_list_first(client->proxy_list); list;
340 list = g_list_next(list)) {
341 GDBusProxy *proxy = list->data;
343 if (g_str_equal(proxy->interface, interface) == TRUE &&
344 g_str_equal(proxy->obj_path, path) == TRUE)
351 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
352 const char *interface)
356 proxy = g_try_new0(GDBusProxy, 1);
360 proxy->client = client;
361 proxy->obj_path = g_strdup(path);
362 proxy->interface = g_strdup(interface);
364 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
365 NULL, prop_entry_free);
367 proxy->match_rule = g_strdup_printf("type='signal',"
368 "sender='%s',path='%s',interface='%s',"
369 "member='PropertiesChanged',arg0='%s'",
370 client->service_name, proxy->obj_path,
371 DBUS_INTERFACE_PROPERTIES, proxy->interface);
373 modify_match(client->dbus_conn, "AddMatch", proxy->match_rule);
375 return g_dbus_proxy_ref(proxy);
378 static void proxy_free(gpointer data)
380 GDBusProxy *proxy = data;
383 GDBusClient *client = proxy->client;
385 if (client->proxy_removed)
386 client->proxy_removed(proxy, client->user_data);
388 modify_match(client->dbus_conn, "RemoveMatch",
391 g_free(proxy->match_rule);
392 proxy->match_rule = NULL;
394 g_hash_table_remove_all(proxy->prop_list);
396 proxy->client = NULL;
399 if (proxy->removed_func)
400 proxy->removed_func(proxy, proxy->removed_data);
402 g_dbus_proxy_unref(proxy);
405 static void proxy_remove(GDBusClient *client, const char *path,
406 const char *interface)
410 for (list = g_list_first(client->proxy_list); list;
411 list = g_list_next(list)) {
412 GDBusProxy *proxy = list->data;
414 if (g_str_equal(proxy->interface, interface) == TRUE &&
415 g_str_equal(proxy->obj_path, path) == TRUE) {
417 g_list_delete_link(client->proxy_list, list);
424 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
425 const char *interface)
432 proxy = proxy_lookup(client, path, interface);
434 return g_dbus_proxy_ref(proxy);
436 proxy = proxy_new(client, path, interface);
440 get_all_properties(proxy);
442 return g_dbus_proxy_ref(proxy);
445 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
450 g_atomic_int_inc(&proxy->ref_count);
455 void g_dbus_proxy_unref(GDBusProxy *proxy)
460 if (g_atomic_int_dec_and_test(&proxy->ref_count) == FALSE)
463 g_hash_table_destroy(proxy->prop_list);
465 g_free(proxy->obj_path);
466 g_free(proxy->interface);
471 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
476 return proxy->obj_path;
479 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
484 return proxy->interface;
487 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
488 DBusMessageIter *iter)
490 struct prop_entry *prop;
492 if (proxy == NULL || name == NULL)
495 prop = g_hash_table_lookup(proxy->prop_list, name);
499 if (prop->msg == NULL)
502 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
508 struct refresh_property_data {
513 static void refresh_property_free(gpointer user_data)
515 struct refresh_property_data *data = user_data;
521 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
523 struct refresh_property_data *data = user_data;
524 DBusMessage *reply = dbus_pending_call_steal_reply(call);
527 dbus_error_init(&error);
529 if (dbus_set_error_from_message(&error, reply) == FALSE) {
530 DBusMessageIter iter;
532 dbus_message_iter_init(reply, &iter);
534 add_property(data->proxy, data->name, &iter, TRUE);
536 dbus_error_free(&error);
538 dbus_message_unref(reply);
541 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
543 struct refresh_property_data *data;
546 DBusMessageIter iter;
547 DBusPendingCall *call;
549 if (proxy == NULL || name == NULL)
552 client = proxy->client;
556 data = g_try_new0(struct refresh_property_data, 1);
561 data->name = g_strdup(name);
563 msg = dbus_message_new_method_call(client->service_name,
564 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
566 refresh_property_free(data);
570 dbus_message_iter_init_append(msg, &iter);
571 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
573 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
575 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
576 &call, -1) == FALSE) {
577 dbus_message_unref(msg);
578 refresh_property_free(data);
582 dbus_pending_call_set_notify(call, refresh_property_reply,
583 data, refresh_property_free);
584 dbus_pending_call_unref(call);
586 dbus_message_unref(msg);
591 struct set_property_data {
592 GDBusResultFunction function;
594 GDBusDestroyFunction destroy;
597 static void set_property_reply(DBusPendingCall *call, void *user_data)
599 struct set_property_data *data = user_data;
600 DBusMessage *reply = dbus_pending_call_steal_reply(call);
603 dbus_error_init(&error);
605 dbus_set_error_from_message(&error, reply);
608 data->function(&error, data->user_data);
611 data->destroy(data->user_data);
613 dbus_error_free(&error);
615 dbus_message_unref(reply);
618 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
619 const char *name, int type, const void *value,
620 GDBusResultFunction function, void *user_data,
621 GDBusDestroyFunction destroy)
623 struct set_property_data *data;
626 DBusMessageIter iter, variant;
627 DBusPendingCall *call;
630 if (proxy == NULL || name == NULL || value == NULL)
633 if (dbus_type_is_basic(type) == FALSE)
636 client = proxy->client;
640 data = g_try_new0(struct set_property_data, 1);
644 data->function = function;
645 data->user_data = user_data;
646 data->destroy = destroy;
648 msg = dbus_message_new_method_call(client->service_name,
649 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
655 type_as_str[0] = (char) type;
656 type_as_str[1] = '\0';
658 dbus_message_iter_init_append(msg, &iter);
659 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
661 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
663 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
664 type_as_str, &variant);
665 dbus_message_iter_append_basic(&variant, type, value);
666 dbus_message_iter_close_container(&iter, &variant);
668 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
669 &call, -1) == FALSE) {
670 dbus_message_unref(msg);
675 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
676 dbus_pending_call_unref(call);
678 dbus_message_unref(msg);
683 struct method_call_data {
684 GDBusReturnFunction function;
686 GDBusDestroyFunction destroy;
689 static void method_call_reply(DBusPendingCall *call, void *user_data)
691 struct method_call_data *data = user_data;
692 DBusMessage *reply = dbus_pending_call_steal_reply(call);
695 data->function(reply, data->user_data);
698 data->destroy(data->user_data);
700 dbus_message_unref(reply);
703 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
704 GDBusSetupFunction setup,
705 GDBusReturnFunction function, void *user_data,
706 GDBusDestroyFunction destroy)
708 struct method_call_data *data;
711 DBusPendingCall *call;
713 if (proxy == NULL || method == NULL)
716 client = proxy->client;
720 data = g_try_new0(struct method_call_data, 1);
724 data->function = function;
725 data->user_data = user_data;
726 data->destroy = destroy;
728 msg = dbus_message_new_method_call(client->service_name,
729 proxy->obj_path, proxy->interface, method);
736 DBusMessageIter iter;
738 dbus_message_iter_init_append(msg, &iter);
739 setup(&iter, data->user_data);
742 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
743 &call, METHOD_CALL_TIMEOUT) == FALSE) {
744 dbus_message_unref(msg);
749 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
750 dbus_pending_call_unref(call);
752 dbus_message_unref(msg);
757 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
758 GDBusPropertyFunction function, void *user_data)
763 proxy->prop_func = function;
764 proxy->prop_data = user_data;
769 gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
770 GDBusProxyFunction function, void *user_data)
775 proxy->removed_func = function;
776 proxy->removed_data = user_data;
781 static void refresh_properties(GDBusClient *client)
785 for (list = g_list_first(client->proxy_list); list;
786 list = g_list_next(list)) {
787 GDBusProxy *proxy = list->data;
789 get_all_properties(proxy);
793 static void properties_changed(GDBusClient *client, const char *path,
796 GDBusProxy *proxy = NULL;
797 DBusMessageIter iter, entry;
798 const char *interface;
801 if (dbus_message_iter_init(msg, &iter) == FALSE)
804 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
807 dbus_message_iter_get_basic(&iter, &interface);
808 dbus_message_iter_next(&iter);
810 for (list = g_list_first(client->proxy_list); list;
811 list = g_list_next(list)) {
812 GDBusProxy *data = list->data;
814 if (g_str_equal(data->interface, interface) == TRUE &&
815 g_str_equal(data->obj_path, path) == TRUE) {
824 update_properties(proxy, &iter, TRUE);
826 dbus_message_iter_next(&iter);
828 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
831 dbus_message_iter_recurse(&iter, &entry);
833 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
836 dbus_message_iter_get_basic(&entry, &name);
838 g_hash_table_remove(proxy->prop_list, name);
840 if (proxy->prop_func)
841 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
843 if (client->property_changed)
844 client->property_changed(proxy, name, NULL,
847 dbus_message_iter_next(&entry);
851 static void parse_properties(GDBusClient *client, const char *path,
852 const char *interface, DBusMessageIter *iter)
856 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
859 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
862 proxy = proxy_lookup(client, path, interface);
864 update_properties(proxy, iter, FALSE);
868 proxy = proxy_new(client, path, interface);
872 update_properties(proxy, iter, FALSE);
874 if (client->proxy_added)
875 client->proxy_added(proxy, client->user_data);
877 client->proxy_list = g_list_append(client->proxy_list, proxy);
880 static void parse_interfaces(GDBusClient *client, const char *path,
881 DBusMessageIter *iter)
883 DBusMessageIter dict;
885 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
888 dbus_message_iter_recurse(iter, &dict);
890 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
891 DBusMessageIter entry;
892 const char *interface;
894 dbus_message_iter_recurse(&dict, &entry);
896 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
899 dbus_message_iter_get_basic(&entry, &interface);
900 dbus_message_iter_next(&entry);
902 parse_properties(client, path, interface, &entry);
904 dbus_message_iter_next(&dict);
908 static void interfaces_added(GDBusClient *client, DBusMessage *msg)
910 DBusMessageIter iter;
913 if (dbus_message_iter_init(msg, &iter) == FALSE)
916 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
919 dbus_message_iter_get_basic(&iter, &path);
920 dbus_message_iter_next(&iter);
922 g_dbus_client_ref(client);
924 parse_interfaces(client, path, &iter);
926 g_dbus_client_unref(client);
929 static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
931 DBusMessageIter iter, entry;
934 if (dbus_message_iter_init(msg, &iter) == FALSE)
937 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
940 dbus_message_iter_get_basic(&iter, &path);
941 dbus_message_iter_next(&iter);
943 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
946 dbus_message_iter_recurse(&iter, &entry);
948 g_dbus_client_ref(client);
950 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
951 const char *interface;
953 dbus_message_iter_get_basic(&entry, &interface);
954 proxy_remove(client, path, interface);
955 dbus_message_iter_next(&entry);
958 g_dbus_client_unref(client);
961 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
963 DBusMessageIter iter, dict;
965 if (dbus_message_iter_init(msg, &iter) == FALSE)
968 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
971 dbus_message_iter_recurse(&iter, &dict);
973 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
974 DBusMessageIter entry;
977 dbus_message_iter_recurse(&dict, &entry);
979 if (dbus_message_iter_get_arg_type(&entry) !=
980 DBUS_TYPE_OBJECT_PATH)
983 dbus_message_iter_get_basic(&entry, &path);
984 dbus_message_iter_next(&entry);
986 parse_interfaces(client, path, &entry);
988 dbus_message_iter_next(&dict);
992 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
994 GDBusClient *client = user_data;
995 DBusMessage *reply = dbus_pending_call_steal_reply(call);
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 g_dbus_client_unref(client);
1013 static void get_managed_objects(GDBusClient *client)
1016 DBusPendingCall *call;
1018 if (!client->proxy_added && !client->proxy_removed) {
1019 refresh_properties(client);
1023 msg = dbus_message_new_method_call(client->service_name, "/",
1024 DBUS_INTERFACE_DBUS ".ObjectManager",
1025 "GetManagedObjects");
1029 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1031 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1032 &call, -1) == FALSE) {
1033 dbus_message_unref(msg);
1037 g_dbus_client_ref(client);
1039 dbus_pending_call_set_notify(call, get_managed_objects_reply,
1041 dbus_pending_call_unref(call);
1043 dbus_message_unref(msg);
1046 static void get_name_owner_reply(DBusPendingCall *call, void *user_data)
1048 GDBusClient *client = user_data;
1049 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1053 g_dbus_client_ref(client);
1055 dbus_error_init(&error);
1057 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1058 dbus_error_free(&error);
1062 if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name,
1063 DBUS_TYPE_INVALID) == FALSE)
1066 if (client->unique_name == NULL) {
1067 client->unique_name = g_strdup(name);
1069 if (client->connect_func)
1070 client->connect_func(client->dbus_conn,
1071 client->connect_data);
1073 get_managed_objects(client);
1077 dbus_message_unref(reply);
1079 dbus_pending_call_unref(client->pending_call);
1080 client->pending_call = NULL;
1082 g_dbus_client_unref(client);
1085 static void get_name_owner(GDBusClient *client, const char *name)
1089 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1090 DBUS_INTERFACE_DBUS, "GetNameOwner");
1094 dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
1097 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1098 &client->pending_call, -1) == FALSE) {
1099 dbus_message_unref(msg);
1103 dbus_pending_call_set_notify(client->pending_call,
1104 get_name_owner_reply, client, NULL);
1106 dbus_message_unref(msg);
1109 static DBusHandlerResult message_filter(DBusConnection *connection,
1110 DBusMessage *message, void *user_data)
1112 GDBusClient *client = user_data;
1115 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1116 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1118 sender = dbus_message_get_sender(message);
1120 if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) {
1121 const char *interface, *member;
1122 const char *name, *old, *new;
1124 interface = dbus_message_get_interface(message);
1126 if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE)
1127 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1129 member = dbus_message_get_member(message);
1131 if (g_str_equal(member, "NameOwnerChanged") == FALSE)
1132 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1134 if (dbus_message_get_args(message, NULL,
1135 DBUS_TYPE_STRING, &name,
1136 DBUS_TYPE_STRING, &old,
1137 DBUS_TYPE_STRING, &new,
1138 DBUS_TYPE_INVALID) == FALSE)
1139 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1141 if (g_str_equal(name, client->service_name) == FALSE)
1142 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1144 if (*new == '\0' && client->unique_name != NULL &&
1145 g_str_equal(old, client->unique_name) == TRUE) {
1146 if (client->disconn_func)
1147 client->disconn_func(client->dbus_conn,
1148 client->disconn_data);
1150 g_free(client->unique_name);
1151 client->unique_name = NULL;
1152 } else if (*old == '\0' && client->unique_name == NULL) {
1153 client->unique_name = g_strdup(new);
1155 if (client->connect_func)
1156 client->connect_func(client->dbus_conn,
1157 client->connect_data);
1159 get_managed_objects(client);
1162 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1165 if (client->unique_name == NULL)
1166 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1168 if (g_str_equal(sender, client->unique_name) == TRUE) {
1169 const char *path, *interface, *member;
1171 path = dbus_message_get_path(message);
1172 interface = dbus_message_get_interface(message);
1173 member = dbus_message_get_member(message);
1175 if (g_str_equal(path, "/") == TRUE) {
1176 if (g_str_equal(interface, DBUS_INTERFACE_DBUS
1177 ".ObjectManager") == FALSE)
1178 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1180 if (g_str_equal(member, "InterfacesAdded") == TRUE) {
1181 interfaces_added(client, message);
1182 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1185 if (g_str_equal(member, "InterfacesRemoved") == TRUE) {
1186 interfaces_removed(client, message);
1187 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1190 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1193 if (g_str_has_prefix(path, client->base_path) == FALSE)
1194 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1196 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) {
1197 if (g_str_equal(member, "PropertiesChanged") == TRUE)
1198 properties_changed(client, path, message);
1200 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1203 if (client->signal_func)
1204 client->signal_func(client->dbus_conn,
1205 message, client->signal_data);
1208 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1211 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1212 const char *service, const char *path)
1214 GDBusClient *client;
1217 if (connection == NULL)
1220 client = g_try_new0(GDBusClient, 1);
1224 if (dbus_connection_add_filter(connection, message_filter,
1225 client, NULL) == FALSE) {
1230 client->dbus_conn = dbus_connection_ref(connection);
1231 client->service_name = g_strdup(service);
1232 client->base_path = g_strdup(path);
1234 get_name_owner(client, client->service_name);
1236 client->match_rules = g_ptr_array_sized_new(4);
1237 g_ptr_array_set_free_func(client->match_rules, g_free);
1239 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1240 "sender='%s',path='%s',interface='%s',"
1241 "member='NameOwnerChanged',arg0='%s'",
1242 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1243 DBUS_INTERFACE_DBUS, client->service_name));
1244 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1246 "path='/',interface='%s.ObjectManager',"
1247 "member='InterfacesAdded'",
1248 client->service_name, DBUS_INTERFACE_DBUS));
1249 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1251 "path='/',interface='%s.ObjectManager',"
1252 "member='InterfacesRemoved'",
1253 client->service_name, DBUS_INTERFACE_DBUS));
1254 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1255 "sender='%s',path_namespace='%s'",
1256 client->service_name, client->base_path));
1258 for (i = 0; i < client->match_rules->len; i++) {
1259 modify_match(client->dbus_conn, "AddMatch",
1260 g_ptr_array_index(client->match_rules, i));
1263 return g_dbus_client_ref(client);
1266 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1271 g_atomic_int_inc(&client->ref_count);
1276 void g_dbus_client_unref(GDBusClient *client)
1283 if (g_atomic_int_dec_and_test(&client->ref_count) == FALSE)
1286 if (client->pending_call != NULL) {
1287 dbus_pending_call_cancel(client->pending_call);
1288 dbus_pending_call_unref(client->pending_call);
1291 for (i = 0; i < client->match_rules->len; i++) {
1292 modify_match(client->dbus_conn, "RemoveMatch",
1293 g_ptr_array_index(client->match_rules, i));
1296 g_ptr_array_free(client->match_rules, TRUE);
1298 dbus_connection_remove_filter(client->dbus_conn,
1299 message_filter, client);
1301 g_list_free_full(client->proxy_list, proxy_free);
1303 if (client->disconn_func)
1304 client->disconn_func(client->dbus_conn, client->disconn_data);
1306 dbus_connection_unref(client->dbus_conn);
1308 g_free(client->service_name);
1309 g_free(client->unique_name);
1310 g_free(client->base_path);
1315 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1316 GDBusWatchFunction function, void *user_data)
1321 client->connect_func = function;
1322 client->connect_data = user_data;
1327 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1328 GDBusWatchFunction function, void *user_data)
1333 client->disconn_func = function;
1334 client->disconn_data = user_data;
1339 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1340 GDBusMessageFunction function, void *user_data)
1345 client->signal_func = function;
1346 client->signal_data = user_data;
1351 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1352 GDBusProxyFunction proxy_added,
1353 GDBusProxyFunction proxy_removed,
1354 GDBusPropertyFunction property_changed,
1360 client->proxy_added = proxy_added;
1361 client->proxy_removed = proxy_removed;
1362 client->property_changed = property_changed;
1363 client->user_data = user_data;
1365 get_managed_objects(client);