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;
73 static void modify_match_reply(DBusPendingCall *call, void *user_data)
75 DBusMessage *reply = dbus_pending_call_steal_reply(call);
78 dbus_error_init(&error);
80 if (dbus_set_error_from_message(&error, reply) == TRUE)
81 dbus_error_free(&error);
83 dbus_message_unref(reply);
86 static gboolean modify_match(DBusConnection *conn, const char *member,
90 DBusPendingCall *call;
92 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
93 DBUS_INTERFACE_DBUS, member);
97 dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
100 if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
101 dbus_message_unref(msg);
105 dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
106 dbus_pending_call_unref(call);
108 dbus_message_unref(msg);
113 static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
117 type = dbus_message_iter_get_arg_type(iter);
119 if (dbus_type_is_basic(type)) {
122 dbus_message_iter_get_basic(iter, &value);
123 dbus_message_iter_append_basic(base, type, &value);
124 } else if (dbus_type_is_container(type)) {
125 DBusMessageIter iter_sub, base_sub;
128 dbus_message_iter_recurse(iter, &iter_sub);
131 case DBUS_TYPE_ARRAY:
132 case DBUS_TYPE_VARIANT:
133 sig = dbus_message_iter_get_signature(&iter_sub);
140 dbus_message_iter_open_container(base, type, sig, &base_sub);
145 while (dbus_message_iter_get_arg_type(&iter_sub) !=
147 iter_append_iter(&base_sub, &iter_sub);
148 dbus_message_iter_next(&iter_sub);
151 dbus_message_iter_close_container(base, &base_sub);
155 static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
158 DBusMessageIter base;
160 msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
164 dbus_message_iter_init_append(msg, &base);
165 iter_append_iter(&base, iter);
167 if (prop->msg != NULL)
168 dbus_message_unref(prop->msg);
170 prop->msg = dbus_message_copy(msg);
171 dbus_message_unref(msg);
174 static struct prop_entry *prop_entry_new(const char *name,
175 DBusMessageIter *iter)
177 struct prop_entry *prop;
179 prop = g_try_new0(struct prop_entry, 1);
183 prop->name = g_strdup(name);
184 prop->type = dbus_message_iter_get_arg_type(iter);
186 prop_entry_update(prop, iter);
191 static void prop_entry_free(gpointer data)
193 struct prop_entry *prop = data;
195 if (prop->msg != NULL)
196 dbus_message_unref(prop->msg);
203 static void add_property(GDBusProxy *proxy, const char *name,
204 DBusMessageIter *iter)
206 DBusMessageIter value;
207 struct prop_entry *prop;
209 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
212 dbus_message_iter_recurse(iter, &value);
214 prop = g_hash_table_lookup(proxy->prop_list, name);
216 GDBusClient *client = proxy->client;
218 prop_entry_update(prop, &value);
220 if (proxy->prop_func)
221 proxy->prop_func(proxy, name, &value, proxy->prop_data);
226 if (client->property_changed)
227 client->property_changed(proxy, name, &value,
232 prop = prop_entry_new(name, &value);
236 g_hash_table_replace(proxy->prop_list, prop->name, prop);
238 if (proxy->prop_func)
239 proxy->prop_func(proxy, name, &value, proxy->prop_data);
242 static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter)
244 DBusMessageIter dict;
246 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
249 dbus_message_iter_recurse(iter, &dict);
251 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
252 DBusMessageIter entry;
255 dbus_message_iter_recurse(&dict, &entry);
257 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
260 dbus_message_iter_get_basic(&entry, &name);
261 dbus_message_iter_next(&entry);
263 add_property(proxy, name, &entry);
265 dbus_message_iter_next(&dict);
269 static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
271 GDBusProxy *proxy = user_data;
272 GDBusClient *client = proxy->client;
273 DBusMessage *reply = dbus_pending_call_steal_reply(call);
274 DBusMessageIter iter;
277 dbus_error_init(&error);
279 if (dbus_set_error_from_message(&error, reply) == TRUE) {
280 dbus_error_free(&error);
284 dbus_message_iter_init(reply, &iter);
286 update_properties(proxy, &iter);
289 if (g_list_find(client->proxy_list, proxy) == NULL) {
290 if (client->proxy_added)
291 client->proxy_added(proxy, client->user_data);
293 client->proxy_list = g_list_append(client->proxy_list, proxy);
296 dbus_message_unref(reply);
298 g_dbus_client_unref(client);
301 static void get_all_properties(GDBusProxy *proxy)
303 GDBusClient *client = proxy->client;
304 const char *service_name = client->service_name;
306 DBusPendingCall *call;
308 msg = dbus_message_new_method_call(service_name, proxy->obj_path,
309 DBUS_INTERFACE_PROPERTIES, "GetAll");
313 dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
316 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
317 &call, -1) == FALSE) {
318 dbus_message_unref(msg);
322 g_dbus_client_ref(client);
324 dbus_pending_call_set_notify(call, get_all_properties_reply,
326 dbus_pending_call_unref(call);
328 dbus_message_unref(msg);
331 static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
332 const char *interface)
336 for (list = g_list_first(client->proxy_list); list;
337 list = g_list_next(list)) {
338 GDBusProxy *proxy = list->data;
340 if (g_str_equal(proxy->interface, interface) == TRUE &&
341 g_str_equal(proxy->obj_path, path) == TRUE)
348 static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
349 const char *interface)
353 proxy = g_try_new0(GDBusProxy, 1);
357 proxy->client = client;
358 proxy->obj_path = g_strdup(path);
359 proxy->interface = g_strdup(interface);
361 proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
362 NULL, prop_entry_free);
364 proxy->match_rule = g_strdup_printf("type='signal',"
365 "sender='%s',path='%s',interface='%s',"
366 "member='PropertiesChanged',arg0='%s'",
367 client->service_name, proxy->obj_path,
368 DBUS_INTERFACE_PROPERTIES, proxy->interface);
370 modify_match(client->dbus_conn, "AddMatch", proxy->match_rule);
372 return g_dbus_proxy_ref(proxy);
375 static void proxy_free(gpointer data)
377 GDBusProxy *proxy = data;
380 GDBusClient *client = proxy->client;
382 if (client->proxy_removed)
383 client->proxy_removed(proxy, client->user_data);
385 modify_match(client->dbus_conn, "RemoveMatch",
388 g_free(proxy->match_rule);
389 proxy->match_rule = NULL;
391 g_hash_table_remove_all(proxy->prop_list);
393 proxy->client = NULL;
396 g_dbus_proxy_unref(proxy);
399 static void proxy_remove(GDBusClient *client, const char *path,
400 const char *interface)
404 for (list = g_list_first(client->proxy_list); list;
405 list = g_list_next(list)) {
406 GDBusProxy *proxy = list->data;
408 if (g_str_equal(proxy->interface, interface) == TRUE &&
409 g_str_equal(proxy->obj_path, path) == TRUE) {
411 g_list_delete_link(client->proxy_list, list);
418 GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
419 const char *interface)
426 proxy = proxy_lookup(client, path, interface);
428 return g_dbus_proxy_ref(proxy);
430 proxy = proxy_new(client, path, interface);
434 get_all_properties(proxy);
436 return g_dbus_proxy_ref(proxy);
439 GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
444 g_atomic_int_inc(&proxy->ref_count);
449 void g_dbus_proxy_unref(GDBusProxy *proxy)
454 if (g_atomic_int_dec_and_test(&proxy->ref_count) == FALSE)
457 g_hash_table_destroy(proxy->prop_list);
459 g_free(proxy->obj_path);
460 g_free(proxy->interface);
465 const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
470 return proxy->obj_path;
473 const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
478 return proxy->interface;
481 gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
482 DBusMessageIter *iter)
484 struct prop_entry *prop;
486 if (proxy == NULL || name == NULL)
489 prop = g_hash_table_lookup(proxy->prop_list, name);
493 if (prop->msg == NULL)
496 if (dbus_message_iter_init(prop->msg, iter) == FALSE)
502 struct refresh_property_data {
507 static void refresh_property_free(gpointer user_data)
509 struct refresh_property_data *data = user_data;
515 static void refresh_property_reply(DBusPendingCall *call, void *user_data)
517 struct refresh_property_data *data = user_data;
518 DBusMessage *reply = dbus_pending_call_steal_reply(call);
521 dbus_error_init(&error);
523 if (dbus_set_error_from_message(&error, reply) == FALSE) {
524 DBusMessageIter iter;
526 dbus_message_iter_init(reply, &iter);
528 add_property(data->proxy, data->name, &iter);
530 dbus_error_free(&error);
532 dbus_message_unref(reply);
535 gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
537 struct refresh_property_data *data;
540 DBusMessageIter iter;
541 DBusPendingCall *call;
543 if (proxy == NULL || name == NULL)
546 client = proxy->client;
550 data = g_try_new0(struct refresh_property_data, 1);
555 data->name = g_strdup(name);
557 msg = dbus_message_new_method_call(client->service_name,
558 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
560 refresh_property_free(data);
564 dbus_message_iter_init_append(msg, &iter);
565 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
567 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
569 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
570 &call, -1) == FALSE) {
571 dbus_message_unref(msg);
572 refresh_property_free(data);
576 dbus_pending_call_set_notify(call, refresh_property_reply,
577 data, refresh_property_free);
578 dbus_pending_call_unref(call);
580 dbus_message_unref(msg);
585 struct set_property_data {
586 GDBusResultFunction function;
588 GDBusDestroyFunction destroy;
591 static void set_property_reply(DBusPendingCall *call, void *user_data)
593 struct set_property_data *data = user_data;
594 DBusMessage *reply = dbus_pending_call_steal_reply(call);
597 dbus_error_init(&error);
599 dbus_set_error_from_message(&error, reply);
602 data->function(&error, data->user_data);
605 data->destroy(data->user_data);
607 dbus_error_free(&error);
609 dbus_message_unref(reply);
612 gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
613 const char *name, int type, const void *value,
614 GDBusResultFunction function, void *user_data,
615 GDBusDestroyFunction destroy)
617 struct set_property_data *data;
620 DBusMessageIter iter, variant;
621 DBusPendingCall *call;
624 if (proxy == NULL || name == NULL || value == NULL)
627 if (dbus_type_is_basic(type) == FALSE)
630 client = proxy->client;
634 data = g_try_new0(struct set_property_data, 1);
638 data->function = function;
639 data->user_data = user_data;
640 data->destroy = destroy;
642 msg = dbus_message_new_method_call(client->service_name,
643 proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
649 type_as_str[0] = (char) type;
650 type_as_str[1] = '\0';
652 dbus_message_iter_init_append(msg, &iter);
653 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
655 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
657 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
658 type_as_str, &variant);
659 dbus_message_iter_append_basic(&variant, type, value);
660 dbus_message_iter_close_container(&iter, &variant);
662 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
663 &call, -1) == FALSE) {
664 dbus_message_unref(msg);
669 dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
670 dbus_pending_call_unref(call);
672 dbus_message_unref(msg);
677 struct method_call_data {
678 GDBusReturnFunction function;
680 GDBusDestroyFunction destroy;
683 static void method_call_reply(DBusPendingCall *call, void *user_data)
685 struct method_call_data *data = user_data;
686 DBusMessage *reply = dbus_pending_call_steal_reply(call);
689 data->function(reply, data->user_data);
692 data->destroy(data->user_data);
694 dbus_message_unref(reply);
697 gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
698 GDBusSetupFunction setup,
699 GDBusReturnFunction function, void *user_data,
700 GDBusDestroyFunction destroy)
702 struct method_call_data *data;
705 DBusPendingCall *call;
707 if (proxy == NULL || method == NULL)
710 client = proxy->client;
714 data = g_try_new0(struct method_call_data, 1);
718 data->function = function;
719 data->user_data = user_data;
720 data->destroy = destroy;
722 msg = dbus_message_new_method_call(client->service_name,
723 proxy->obj_path, proxy->interface, method);
730 DBusMessageIter iter;
732 dbus_message_iter_init_append(msg, &iter);
733 setup(&iter, data->user_data);
736 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
737 &call, METHOD_CALL_TIMEOUT) == FALSE) {
738 dbus_message_unref(msg);
743 dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
744 dbus_pending_call_unref(call);
746 dbus_message_unref(msg);
751 gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
752 GDBusPropertyFunction function, void *user_data)
757 proxy->prop_func = function;
758 proxy->prop_data = user_data;
763 static void refresh_properties(GDBusClient *client)
767 for (list = g_list_first(client->proxy_list); list;
768 list = g_list_next(list)) {
769 GDBusProxy *proxy = list->data;
771 get_all_properties(proxy);
775 static void properties_changed(GDBusClient *client, const char *path,
778 GDBusProxy *proxy = NULL;
779 DBusMessageIter iter, entry;
780 const char *interface;
783 if (dbus_message_iter_init(msg, &iter) == FALSE)
786 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
789 dbus_message_iter_get_basic(&iter, &interface);
790 dbus_message_iter_next(&iter);
792 for (list = g_list_first(client->proxy_list); list;
793 list = g_list_next(list)) {
794 GDBusProxy *data = list->data;
796 if (g_str_equal(data->interface, interface) == TRUE &&
797 g_str_equal(data->obj_path, path) == TRUE) {
806 update_properties(proxy, &iter);
808 dbus_message_iter_next(&iter);
810 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
813 dbus_message_iter_recurse(&iter, &entry);
815 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
818 dbus_message_iter_get_basic(&entry, &name);
820 g_hash_table_remove(proxy->prop_list, name);
822 if (proxy->prop_func)
823 proxy->prop_func(proxy, name, NULL, proxy->prop_data);
825 if (client->property_changed)
826 client->property_changed(proxy, name, NULL,
829 dbus_message_iter_next(&entry);
833 static void parse_properties(GDBusClient *client, const char *path,
834 const char *interface, DBusMessageIter *iter)
838 if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
841 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
844 proxy = proxy_lookup(client, path, interface);
846 update_properties(proxy, iter);
850 proxy = proxy_new(client, path, interface);
854 update_properties(proxy, iter);
856 if (client->proxy_added)
857 client->proxy_added(proxy, client->user_data);
859 client->proxy_list = g_list_append(client->proxy_list, proxy);
862 static void parse_interfaces(GDBusClient *client, const char *path,
863 DBusMessageIter *iter)
865 DBusMessageIter dict;
867 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
870 dbus_message_iter_recurse(iter, &dict);
872 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
873 DBusMessageIter entry;
874 const char *interface;
876 dbus_message_iter_recurse(&dict, &entry);
878 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
881 dbus_message_iter_get_basic(&entry, &interface);
882 dbus_message_iter_next(&entry);
884 parse_properties(client, path, interface, &entry);
886 dbus_message_iter_next(&dict);
890 static void interfaces_added(GDBusClient *client, DBusMessage *msg)
892 DBusMessageIter iter;
895 if (dbus_message_iter_init(msg, &iter) == FALSE)
898 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
901 dbus_message_iter_get_basic(&iter, &path);
902 dbus_message_iter_next(&iter);
904 g_dbus_client_ref(client);
906 parse_interfaces(client, path, &iter);
908 g_dbus_client_unref(client);
911 static void interfaces_removed(GDBusClient *client, DBusMessage *msg)
913 DBusMessageIter iter, entry;
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 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
928 dbus_message_iter_recurse(&iter, &entry);
930 g_dbus_client_ref(client);
932 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
933 const char *interface;
935 dbus_message_iter_get_basic(&entry, &interface);
936 proxy_remove(client, path, interface);
937 dbus_message_iter_next(&entry);
940 g_dbus_client_unref(client);
943 static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
945 DBusMessageIter iter, dict;
947 if (dbus_message_iter_init(msg, &iter) == FALSE)
950 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
953 dbus_message_iter_recurse(&iter, &dict);
955 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
956 DBusMessageIter entry;
959 dbus_message_iter_recurse(&dict, &entry);
961 if (dbus_message_iter_get_arg_type(&entry) !=
962 DBUS_TYPE_OBJECT_PATH)
965 dbus_message_iter_get_basic(&entry, &path);
966 dbus_message_iter_next(&entry);
968 parse_interfaces(client, path, &entry);
970 dbus_message_iter_next(&dict);
974 static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
976 GDBusClient *client = user_data;
977 DBusMessage *reply = dbus_pending_call_steal_reply(call);
980 dbus_error_init(&error);
982 if (dbus_set_error_from_message(&error, reply) == TRUE) {
983 dbus_error_free(&error);
987 parse_managed_objects(client, reply);
990 dbus_message_unref(reply);
992 g_dbus_client_unref(client);
995 static void get_managed_objects(GDBusClient *client)
998 DBusPendingCall *call;
1000 if (!client->proxy_added && !client->proxy_removed) {
1001 refresh_properties(client);
1005 msg = dbus_message_new_method_call(client->service_name, "/",
1006 DBUS_INTERFACE_DBUS ".ObjectManager",
1007 "GetManagedObjects");
1011 dbus_message_append_args(msg, DBUS_TYPE_INVALID);
1013 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1014 &call, -1) == FALSE) {
1015 dbus_message_unref(msg);
1019 g_dbus_client_ref(client);
1021 dbus_pending_call_set_notify(call, get_managed_objects_reply,
1023 dbus_pending_call_unref(call);
1025 dbus_message_unref(msg);
1028 static void get_name_owner_reply(DBusPendingCall *call, void *user_data)
1030 GDBusClient *client = user_data;
1031 DBusMessage *reply = dbus_pending_call_steal_reply(call);
1035 dbus_error_init(&error);
1037 if (dbus_set_error_from_message(&error, reply) == TRUE) {
1038 dbus_error_free(&error);
1042 if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name,
1043 DBUS_TYPE_INVALID) == FALSE)
1046 if (client->unique_name == NULL) {
1047 client->unique_name = g_strdup(name);
1049 if (client->connect_func)
1050 client->connect_func(client->dbus_conn,
1051 client->connect_data);
1053 get_managed_objects(client);
1057 dbus_message_unref(reply);
1059 dbus_pending_call_unref(client->pending_call);
1060 client->pending_call = NULL;
1063 static void get_name_owner(GDBusClient *client, const char *name)
1067 msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1068 DBUS_INTERFACE_DBUS, "GetNameOwner");
1072 dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
1075 if (dbus_connection_send_with_reply(client->dbus_conn, msg,
1076 &client->pending_call, -1) == FALSE) {
1077 dbus_message_unref(msg);
1081 dbus_pending_call_set_notify(client->pending_call,
1082 get_name_owner_reply, client, NULL);
1084 dbus_message_unref(msg);
1087 static DBusHandlerResult message_filter(DBusConnection *connection,
1088 DBusMessage *message, void *user_data)
1090 GDBusClient *client = user_data;
1093 if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
1094 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1096 sender = dbus_message_get_sender(message);
1098 if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) {
1099 const char *interface, *member;
1100 const char *name, *old, *new;
1102 interface = dbus_message_get_interface(message);
1104 if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE)
1105 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1107 member = dbus_message_get_member(message);
1109 if (g_str_equal(member, "NameOwnerChanged") == FALSE)
1110 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1112 if (dbus_message_get_args(message, NULL,
1113 DBUS_TYPE_STRING, &name,
1114 DBUS_TYPE_STRING, &old,
1115 DBUS_TYPE_STRING, &new,
1116 DBUS_TYPE_INVALID) == FALSE)
1117 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1119 if (g_str_equal(name, client->service_name) == FALSE)
1120 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1122 if (*new == '\0' && client->unique_name != NULL &&
1123 g_str_equal(old, client->unique_name) == TRUE) {
1124 if (client->disconn_func)
1125 client->disconn_func(client->dbus_conn,
1126 client->disconn_data);
1128 g_free(client->unique_name);
1129 client->unique_name = NULL;
1130 } else if (*old == '\0' && client->unique_name == NULL) {
1131 client->unique_name = g_strdup(new);
1133 if (client->connect_func)
1134 client->connect_func(client->dbus_conn,
1135 client->connect_data);
1137 get_managed_objects(client);
1140 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1143 if (client->unique_name == NULL)
1144 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1146 if (g_str_equal(sender, client->unique_name) == TRUE) {
1147 const char *path, *interface, *member;
1149 path = dbus_message_get_path(message);
1150 interface = dbus_message_get_interface(message);
1151 member = dbus_message_get_member(message);
1153 if (g_str_equal(path, "/") == TRUE) {
1154 if (g_str_equal(interface, DBUS_INTERFACE_DBUS
1155 ".ObjectManager") == FALSE)
1156 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1158 if (g_str_equal(member, "InterfacesAdded") == TRUE) {
1159 interfaces_added(client, message);
1160 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1163 if (g_str_equal(member, "InterfacesRemoved") == TRUE) {
1164 interfaces_removed(client, message);
1165 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1168 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1171 if (g_str_has_prefix(path, client->base_path) == FALSE)
1172 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1174 if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) {
1175 if (g_str_equal(member, "PropertiesChanged") == TRUE)
1176 properties_changed(client, path, message);
1178 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1181 if (client->signal_func)
1182 client->signal_func(client->dbus_conn,
1183 message, client->signal_data);
1186 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1189 GDBusClient *g_dbus_client_new(DBusConnection *connection,
1190 const char *service, const char *path)
1192 GDBusClient *client;
1195 if (connection == NULL)
1198 client = g_try_new0(GDBusClient, 1);
1202 if (dbus_connection_add_filter(connection, message_filter,
1203 client, NULL) == FALSE) {
1208 client->dbus_conn = dbus_connection_ref(connection);
1209 client->service_name = g_strdup(service);
1210 client->base_path = g_strdup(path);
1212 get_name_owner(client, client->service_name);
1214 client->match_rules = g_ptr_array_sized_new(4);
1215 g_ptr_array_set_free_func(client->match_rules, g_free);
1217 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1218 "sender='%s',path='%s',interface='%s',"
1219 "member='NameOwnerChanged',arg0='%s'",
1220 DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
1221 DBUS_INTERFACE_DBUS, client->service_name));
1222 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1224 "path='/',interface='%s.ObjectManager',"
1225 "member='InterfacesAdded'",
1226 client->service_name, DBUS_INTERFACE_DBUS));
1227 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1229 "path='/',interface='%s.ObjectManager',"
1230 "member='InterfacesRemoved'",
1231 client->service_name, DBUS_INTERFACE_DBUS));
1232 g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
1233 "sender='%s',path_namespace='%s'",
1234 client->service_name, client->base_path));
1236 for (i = 0; i < client->match_rules->len; i++) {
1237 modify_match(client->dbus_conn, "AddMatch",
1238 g_ptr_array_index(client->match_rules, i));
1241 return g_dbus_client_ref(client);
1244 GDBusClient *g_dbus_client_ref(GDBusClient *client)
1249 g_atomic_int_inc(&client->ref_count);
1254 void g_dbus_client_unref(GDBusClient *client)
1261 if (g_atomic_int_dec_and_test(&client->ref_count) == FALSE)
1264 if (client->pending_call != NULL) {
1265 dbus_pending_call_cancel(client->pending_call);
1266 dbus_pending_call_unref(client->pending_call);
1269 for (i = 0; i < client->match_rules->len; i++) {
1270 modify_match(client->dbus_conn, "RemoveMatch",
1271 g_ptr_array_index(client->match_rules, i));
1274 g_ptr_array_free(client->match_rules, TRUE);
1276 dbus_connection_remove_filter(client->dbus_conn,
1277 message_filter, client);
1279 g_list_free_full(client->proxy_list, proxy_free);
1281 if (client->disconn_func)
1282 client->disconn_func(client->dbus_conn, client->disconn_data);
1284 dbus_connection_unref(client->dbus_conn);
1286 g_free(client->service_name);
1287 g_free(client->unique_name);
1288 g_free(client->base_path);
1293 gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
1294 GDBusWatchFunction function, void *user_data)
1299 client->connect_func = function;
1300 client->connect_data = user_data;
1305 gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
1306 GDBusWatchFunction function, void *user_data)
1311 client->disconn_func = function;
1312 client->disconn_data = user_data;
1317 gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
1318 GDBusMessageFunction function, void *user_data)
1323 client->signal_func = function;
1324 client->signal_data = user_data;
1329 gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
1330 GDBusProxyFunction proxy_added,
1331 GDBusProxyFunction proxy_removed,
1332 GDBusPropertyFunction property_changed,
1338 client->proxy_added = proxy_added;
1339 client->proxy_removed = proxy_removed;
1340 client->property_changed = property_changed;
1341 client->user_data = user_data;
1343 get_managed_objects(client);