client.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * D-Bus helper library
  5. *
  6. * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
  7. *
  8. *
  9. */
  10. #ifdef HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #define _GNU_SOURCE
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <glib.h>
  17. #include <dbus/dbus.h>
  18. #include "gdbus.h"
  19. #define METHOD_CALL_TIMEOUT (300 * 1000)
  20. #ifndef DBUS_INTERFACE_OBJECT_MANAGER
  21. #define DBUS_INTERFACE_OBJECT_MANAGER DBUS_INTERFACE_DBUS ".ObjectManager"
  22. #endif
  23. struct GDBusClient {
  24. int ref_count;
  25. DBusConnection *dbus_conn;
  26. char *service_name;
  27. char *base_path;
  28. char *root_path;
  29. guint watch;
  30. guint added_watch;
  31. guint removed_watch;
  32. GPtrArray *match_rules;
  33. DBusPendingCall *pending_call;
  34. DBusPendingCall *get_objects_call;
  35. GDBusWatchFunction connect_func;
  36. void *connect_data;
  37. GDBusWatchFunction disconn_func;
  38. gboolean connected;
  39. void *disconn_data;
  40. GDBusMessageFunction signal_func;
  41. void *signal_data;
  42. GDBusProxyFunction proxy_added;
  43. GDBusProxyFunction proxy_removed;
  44. GDBusClientFunction ready;
  45. void *ready_data;
  46. GDBusPropertyFunction property_changed;
  47. void *user_data;
  48. GList *proxy_list;
  49. };
  50. struct GDBusProxy {
  51. int ref_count;
  52. GDBusClient *client;
  53. char *obj_path;
  54. char *interface;
  55. GHashTable *prop_list;
  56. guint watch;
  57. GDBusPropertyFunction prop_func;
  58. void *prop_data;
  59. GDBusProxyFunction removed_func;
  60. void *removed_data;
  61. DBusPendingCall *get_all_call;
  62. gboolean pending;
  63. };
  64. struct prop_entry {
  65. char *name;
  66. int type;
  67. DBusMessage *msg;
  68. };
  69. static void modify_match_reply(DBusPendingCall *call, void *user_data)
  70. {
  71. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  72. DBusError error;
  73. dbus_error_init(&error);
  74. if (dbus_set_error_from_message(&error, reply) == TRUE)
  75. dbus_error_free(&error);
  76. dbus_message_unref(reply);
  77. }
  78. static gboolean modify_match(DBusConnection *conn, const char *member,
  79. const char *rule)
  80. {
  81. DBusMessage *msg;
  82. DBusPendingCall *call;
  83. msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
  84. DBUS_INTERFACE_DBUS, member);
  85. if (msg == NULL)
  86. return FALSE;
  87. dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
  88. DBUS_TYPE_INVALID);
  89. if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
  90. dbus_message_unref(msg);
  91. return FALSE;
  92. }
  93. dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
  94. dbus_pending_call_unref(call);
  95. dbus_message_unref(msg);
  96. return TRUE;
  97. }
  98. static void append_variant(DBusMessageIter *iter, int type, const void *val)
  99. {
  100. DBusMessageIter value;
  101. char sig[2] = { type, '\0' };
  102. dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
  103. dbus_message_iter_append_basic(&value, type, val);
  104. dbus_message_iter_close_container(iter, &value);
  105. }
  106. static void append_array_variant(DBusMessageIter *iter, int type, void *val,
  107. int n_elements)
  108. {
  109. DBusMessageIter variant, array;
  110. char type_sig[2] = { type, '\0' };
  111. char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
  112. dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
  113. array_sig, &variant);
  114. dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
  115. type_sig, &array);
  116. if (dbus_type_is_fixed(type) == TRUE) {
  117. dbus_message_iter_append_fixed_array(&array, type, val,
  118. n_elements);
  119. } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
  120. const char ***str_array = val;
  121. int i;
  122. for (i = 0; i < n_elements; i++)
  123. dbus_message_iter_append_basic(&array, type,
  124. &((*str_array)[i]));
  125. }
  126. dbus_message_iter_close_container(&variant, &array);
  127. dbus_message_iter_close_container(iter, &variant);
  128. }
  129. static void dict_append_basic(DBusMessageIter *dict, int key_type,
  130. const void *key, int type, void *val)
  131. {
  132. DBusMessageIter entry;
  133. if (type == DBUS_TYPE_STRING) {
  134. const char *str = *((const char **) val);
  135. if (str == NULL)
  136. return;
  137. }
  138. dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
  139. NULL, &entry);
  140. dbus_message_iter_append_basic(&entry, key_type, key);
  141. append_variant(&entry, type, val);
  142. dbus_message_iter_close_container(dict, &entry);
  143. }
  144. void g_dbus_dict_append_entry(DBusMessageIter *dict,
  145. const char *key, int type, void *val)
  146. {
  147. dict_append_basic(dict, DBUS_TYPE_STRING, &key, type, val);
  148. }
  149. void g_dbus_dict_append_basic_array(DBusMessageIter *dict, int key_type,
  150. const void *key, int type, void *val,
  151. int n_elements)
  152. {
  153. DBusMessageIter entry;
  154. dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
  155. NULL, &entry);
  156. dbus_message_iter_append_basic(&entry, key_type, key);
  157. append_array_variant(&entry, type, val, n_elements);
  158. dbus_message_iter_close_container(dict, &entry);
  159. }
  160. void g_dbus_dict_append_array(DBusMessageIter *dict,
  161. const char *key, int type, void *val,
  162. int n_elements)
  163. {
  164. g_dbus_dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
  165. n_elements);
  166. }
  167. static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
  168. {
  169. int type;
  170. type = dbus_message_iter_get_arg_type(iter);
  171. if (dbus_type_is_basic(type)) {
  172. const void *value;
  173. dbus_message_iter_get_basic(iter, &value);
  174. dbus_message_iter_append_basic(base, type, &value);
  175. } else if (dbus_type_is_container(type)) {
  176. DBusMessageIter iter_sub, base_sub;
  177. char *sig;
  178. dbus_message_iter_recurse(iter, &iter_sub);
  179. switch (type) {
  180. case DBUS_TYPE_ARRAY:
  181. case DBUS_TYPE_VARIANT:
  182. sig = dbus_message_iter_get_signature(&iter_sub);
  183. break;
  184. default:
  185. sig = NULL;
  186. break;
  187. }
  188. dbus_message_iter_open_container(base, type, sig, &base_sub);
  189. if (sig != NULL)
  190. dbus_free(sig);
  191. while (dbus_message_iter_get_arg_type(&iter_sub) !=
  192. DBUS_TYPE_INVALID) {
  193. iter_append_iter(&base_sub, &iter_sub);
  194. dbus_message_iter_next(&iter_sub);
  195. }
  196. dbus_message_iter_close_container(base, &base_sub);
  197. }
  198. }
  199. static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
  200. {
  201. DBusMessage *msg;
  202. DBusMessageIter base;
  203. msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
  204. if (msg == NULL)
  205. return;
  206. dbus_message_iter_init_append(msg, &base);
  207. iter_append_iter(&base, iter);
  208. if (prop->msg != NULL)
  209. dbus_message_unref(prop->msg);
  210. prop->msg = dbus_message_copy(msg);
  211. dbus_message_unref(msg);
  212. }
  213. static struct prop_entry *prop_entry_new(const char *name,
  214. DBusMessageIter *iter)
  215. {
  216. struct prop_entry *prop;
  217. prop = g_try_new0(struct prop_entry, 1);
  218. if (prop == NULL)
  219. return NULL;
  220. prop->name = g_strdup(name);
  221. prop->type = dbus_message_iter_get_arg_type(iter);
  222. prop_entry_update(prop, iter);
  223. return prop;
  224. }
  225. static void prop_entry_free(gpointer data)
  226. {
  227. struct prop_entry *prop = data;
  228. if (prop->msg != NULL)
  229. dbus_message_unref(prop->msg);
  230. g_free(prop->name);
  231. g_free(prop);
  232. }
  233. static void add_property(GDBusProxy *proxy, const char *name,
  234. DBusMessageIter *iter, gboolean send_changed)
  235. {
  236. GDBusClient *client = proxy->client;
  237. DBusMessageIter value;
  238. struct prop_entry *prop;
  239. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
  240. return;
  241. dbus_message_iter_recurse(iter, &value);
  242. prop = g_hash_table_lookup(proxy->prop_list, name);
  243. if (prop != NULL) {
  244. prop_entry_update(prop, &value);
  245. goto done;
  246. }
  247. prop = prop_entry_new(name, &value);
  248. if (prop == NULL)
  249. return;
  250. g_hash_table_replace(proxy->prop_list, prop->name, prop);
  251. done:
  252. if (proxy->prop_func)
  253. proxy->prop_func(proxy, name, &value, proxy->prop_data);
  254. if (client == NULL || send_changed == FALSE)
  255. return;
  256. if (client->property_changed)
  257. client->property_changed(proxy, name, &value,
  258. client->user_data);
  259. }
  260. static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
  261. gboolean send_changed)
  262. {
  263. DBusMessageIter dict;
  264. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  265. return;
  266. dbus_message_iter_recurse(iter, &dict);
  267. while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
  268. DBusMessageIter entry;
  269. const char *name;
  270. dbus_message_iter_recurse(&dict, &entry);
  271. if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
  272. break;
  273. dbus_message_iter_get_basic(&entry, &name);
  274. dbus_message_iter_next(&entry);
  275. add_property(proxy, name, &entry, send_changed);
  276. dbus_message_iter_next(&dict);
  277. }
  278. }
  279. static void proxy_added(GDBusClient *client, GDBusProxy *proxy)
  280. {
  281. if (!proxy->pending)
  282. return;
  283. if (client->proxy_added)
  284. client->proxy_added(proxy, client->user_data);
  285. proxy->pending = FALSE;
  286. }
  287. static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
  288. {
  289. GDBusProxy *proxy = user_data;
  290. GDBusClient *client = proxy->client;
  291. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  292. DBusMessageIter iter;
  293. DBusError error;
  294. g_dbus_client_ref(client);
  295. dbus_error_init(&error);
  296. if (dbus_set_error_from_message(&error, reply) == TRUE) {
  297. dbus_error_free(&error);
  298. goto done;
  299. }
  300. dbus_message_iter_init(reply, &iter);
  301. update_properties(proxy, &iter, FALSE);
  302. done:
  303. proxy_added(client, proxy);
  304. dbus_message_unref(reply);
  305. dbus_pending_call_unref(proxy->get_all_call);
  306. proxy->get_all_call = NULL;
  307. g_dbus_client_unref(client);
  308. }
  309. static void get_all_properties(GDBusProxy *proxy)
  310. {
  311. GDBusClient *client = proxy->client;
  312. const char *service_name = client->service_name;
  313. DBusMessage *msg;
  314. if (proxy->get_all_call)
  315. return;
  316. msg = dbus_message_new_method_call(service_name, proxy->obj_path,
  317. DBUS_INTERFACE_PROPERTIES, "GetAll");
  318. if (msg == NULL)
  319. return;
  320. dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
  321. DBUS_TYPE_INVALID);
  322. if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
  323. &proxy->get_all_call, -1) == FALSE) {
  324. dbus_message_unref(msg);
  325. return;
  326. }
  327. dbus_pending_call_set_notify(proxy->get_all_call,
  328. get_all_properties_reply, proxy, NULL);
  329. dbus_message_unref(msg);
  330. }
  331. GDBusProxy *g_dbus_proxy_lookup(GList *list, int *index, const char *path,
  332. const char *interface)
  333. {
  334. GList *l;
  335. if (!interface)
  336. return NULL;
  337. for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) {
  338. GDBusProxy *proxy = l->data;
  339. const char *proxy_iface = g_dbus_proxy_get_interface(proxy);
  340. const char *proxy_path = g_dbus_proxy_get_path(proxy);
  341. if (index)
  342. (*index)++;
  343. if (g_str_equal(proxy_iface, interface) == TRUE &&
  344. g_str_equal(proxy_path, path) == TRUE)
  345. return proxy;
  346. }
  347. return NULL;
  348. }
  349. char *g_dbus_proxy_path_lookup(GList *list, int *index, const char *path)
  350. {
  351. int len = strlen(path);
  352. GList *l;
  353. for (l = g_list_nth(list, index ? *index : 0); l; l = g_list_next(l)) {
  354. GDBusProxy *proxy = l->data;
  355. const char *proxy_path = g_dbus_proxy_get_path(proxy);
  356. if (index)
  357. (*index)++;
  358. if (!strncasecmp(proxy_path, path, len))
  359. return strdup(proxy_path);
  360. }
  361. return NULL;
  362. }
  363. static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
  364. void *user_data)
  365. {
  366. GDBusProxy *proxy = user_data;
  367. GDBusClient *client = proxy->client;
  368. DBusMessageIter iter, entry;
  369. const char *interface;
  370. if (dbus_message_iter_init(msg, &iter) == FALSE)
  371. return TRUE;
  372. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  373. return TRUE;
  374. dbus_message_iter_get_basic(&iter, &interface);
  375. dbus_message_iter_next(&iter);
  376. update_properties(proxy, &iter, TRUE);
  377. dbus_message_iter_next(&iter);
  378. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
  379. return TRUE;
  380. dbus_message_iter_recurse(&iter, &entry);
  381. while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
  382. const char *name;
  383. dbus_message_iter_get_basic(&entry, &name);
  384. g_hash_table_remove(proxy->prop_list, name);
  385. if (proxy->prop_func)
  386. proxy->prop_func(proxy, name, NULL, proxy->prop_data);
  387. if (client->property_changed)
  388. client->property_changed(proxy, name, NULL,
  389. client->user_data);
  390. dbus_message_iter_next(&entry);
  391. }
  392. return TRUE;
  393. }
  394. static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
  395. const char *interface)
  396. {
  397. GDBusProxy *proxy;
  398. proxy = g_try_new0(GDBusProxy, 1);
  399. if (proxy == NULL)
  400. return NULL;
  401. proxy->client = client;
  402. proxy->obj_path = g_strdup(path);
  403. proxy->interface = g_strdup(interface);
  404. proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
  405. NULL, prop_entry_free);
  406. proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
  407. client->service_name,
  408. proxy->obj_path,
  409. proxy->interface,
  410. properties_changed,
  411. proxy, NULL);
  412. proxy->pending = TRUE;
  413. client->proxy_list = g_list_append(client->proxy_list, proxy);
  414. return g_dbus_proxy_ref(proxy);
  415. }
  416. static void proxy_free(gpointer data)
  417. {
  418. GDBusProxy *proxy = data;
  419. if (proxy->client) {
  420. GDBusClient *client = proxy->client;
  421. if (proxy->get_all_call != NULL) {
  422. dbus_pending_call_cancel(proxy->get_all_call);
  423. dbus_pending_call_unref(proxy->get_all_call);
  424. proxy->get_all_call = NULL;
  425. }
  426. if (client->proxy_removed)
  427. client->proxy_removed(proxy, client->user_data);
  428. g_dbus_remove_watch(client->dbus_conn, proxy->watch);
  429. g_hash_table_remove_all(proxy->prop_list);
  430. proxy->client = NULL;
  431. }
  432. if (proxy->removed_func)
  433. proxy->removed_func(proxy, proxy->removed_data);
  434. g_dbus_proxy_unref(proxy);
  435. }
  436. static void proxy_remove(GDBusClient *client, const char *path,
  437. const char *interface)
  438. {
  439. GList *list;
  440. for (list = g_list_first(client->proxy_list); list;
  441. list = g_list_next(list)) {
  442. GDBusProxy *proxy = list->data;
  443. if (g_str_equal(proxy->interface, interface) == TRUE &&
  444. g_str_equal(proxy->obj_path, path) == TRUE) {
  445. client->proxy_list =
  446. g_list_delete_link(client->proxy_list, list);
  447. proxy_free(proxy);
  448. break;
  449. }
  450. }
  451. }
  452. static void start_service(GDBusProxy *proxy)
  453. {
  454. GDBusClient *client = proxy->client;
  455. const char *service_name = client->service_name;
  456. dbus_uint32_t flags = 0;
  457. DBusMessage *msg;
  458. msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
  459. DBUS_INTERFACE_DBUS,
  460. "StartServiceByName");
  461. if (msg == NULL)
  462. return;
  463. dbus_message_append_args(msg, DBUS_TYPE_STRING, &service_name,
  464. DBUS_TYPE_UINT32, &flags,
  465. DBUS_TYPE_INVALID);
  466. g_dbus_send_message(client->dbus_conn, msg);
  467. return;
  468. }
  469. GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
  470. const char *interface)
  471. {
  472. GDBusProxy *proxy;
  473. if (client == NULL)
  474. return NULL;
  475. proxy = g_dbus_proxy_lookup(client->proxy_list, NULL,
  476. path, interface);
  477. if (proxy)
  478. return g_dbus_proxy_ref(proxy);
  479. proxy = proxy_new(client, path, interface);
  480. if (proxy == NULL)
  481. return NULL;
  482. if (!client->connected) {
  483. /* Force service to start */
  484. start_service(proxy);
  485. return g_dbus_proxy_ref(proxy);
  486. }
  487. if (!client->get_objects_call)
  488. get_all_properties(proxy);
  489. return g_dbus_proxy_ref(proxy);
  490. }
  491. GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
  492. {
  493. if (proxy == NULL)
  494. return NULL;
  495. __sync_fetch_and_add(&proxy->ref_count, 1);
  496. return proxy;
  497. }
  498. void g_dbus_proxy_unref(GDBusProxy *proxy)
  499. {
  500. if (proxy == NULL)
  501. return;
  502. if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
  503. return;
  504. if (proxy->get_all_call != NULL) {
  505. dbus_pending_call_cancel(proxy->get_all_call);
  506. dbus_pending_call_unref(proxy->get_all_call);
  507. }
  508. g_hash_table_destroy(proxy->prop_list);
  509. g_free(proxy->obj_path);
  510. g_free(proxy->interface);
  511. g_free(proxy);
  512. }
  513. const char *g_dbus_proxy_get_path(const GDBusProxy *proxy)
  514. {
  515. if (proxy == NULL)
  516. return NULL;
  517. return proxy->obj_path;
  518. }
  519. const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
  520. {
  521. if (proxy == NULL)
  522. return NULL;
  523. return proxy->interface;
  524. }
  525. gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
  526. DBusMessageIter *iter)
  527. {
  528. struct prop_entry *prop;
  529. if (proxy == NULL || name == NULL)
  530. return FALSE;
  531. prop = g_hash_table_lookup(proxy->prop_list, name);
  532. if (prop == NULL)
  533. return FALSE;
  534. if (prop->msg == NULL)
  535. return FALSE;
  536. if (dbus_message_iter_init(prop->msg, iter) == FALSE)
  537. return FALSE;
  538. return TRUE;
  539. }
  540. struct refresh_property_data {
  541. GDBusProxy *proxy;
  542. char *name;
  543. };
  544. static void refresh_property_free(gpointer user_data)
  545. {
  546. struct refresh_property_data *data = user_data;
  547. g_free(data->name);
  548. g_free(data);
  549. }
  550. static void refresh_property_reply(DBusPendingCall *call, void *user_data)
  551. {
  552. struct refresh_property_data *data = user_data;
  553. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  554. DBusError error;
  555. dbus_error_init(&error);
  556. if (dbus_set_error_from_message(&error, reply) == FALSE) {
  557. DBusMessageIter iter;
  558. dbus_message_iter_init(reply, &iter);
  559. add_property(data->proxy, data->name, &iter, TRUE);
  560. } else
  561. dbus_error_free(&error);
  562. dbus_message_unref(reply);
  563. }
  564. gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
  565. {
  566. struct refresh_property_data *data;
  567. GDBusClient *client;
  568. DBusMessage *msg;
  569. DBusMessageIter iter;
  570. DBusPendingCall *call;
  571. if (proxy == NULL || name == NULL)
  572. return FALSE;
  573. client = proxy->client;
  574. if (client == NULL)
  575. return FALSE;
  576. data = g_try_new0(struct refresh_property_data, 1);
  577. if (data == NULL)
  578. return FALSE;
  579. data->proxy = proxy;
  580. data->name = g_strdup(name);
  581. msg = dbus_message_new_method_call(client->service_name,
  582. proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
  583. if (msg == NULL) {
  584. refresh_property_free(data);
  585. return FALSE;
  586. }
  587. dbus_message_iter_init_append(msg, &iter);
  588. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
  589. &proxy->interface);
  590. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
  591. if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
  592. &call, -1) == FALSE) {
  593. dbus_message_unref(msg);
  594. refresh_property_free(data);
  595. return FALSE;
  596. }
  597. dbus_pending_call_set_notify(call, refresh_property_reply,
  598. data, refresh_property_free);
  599. dbus_pending_call_unref(call);
  600. dbus_message_unref(msg);
  601. return TRUE;
  602. }
  603. struct set_property_data {
  604. GDBusResultFunction function;
  605. void *user_data;
  606. GDBusDestroyFunction destroy;
  607. };
  608. static void set_property_reply(DBusPendingCall *call, void *user_data)
  609. {
  610. struct set_property_data *data = user_data;
  611. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  612. DBusError error;
  613. dbus_error_init(&error);
  614. dbus_set_error_from_message(&error, reply);
  615. if (data->function)
  616. data->function(&error, data->user_data);
  617. if (data->destroy)
  618. data->destroy(data->user_data);
  619. dbus_error_free(&error);
  620. dbus_message_unref(reply);
  621. }
  622. gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
  623. const char *name, int type, const void *value,
  624. GDBusResultFunction function, void *user_data,
  625. GDBusDestroyFunction destroy)
  626. {
  627. struct set_property_data *data;
  628. GDBusClient *client;
  629. DBusMessage *msg;
  630. DBusMessageIter iter;
  631. DBusPendingCall *call;
  632. if (proxy == NULL || name == NULL || value == NULL)
  633. return FALSE;
  634. if (dbus_type_is_basic(type) == FALSE)
  635. return FALSE;
  636. client = proxy->client;
  637. if (client == NULL)
  638. return FALSE;
  639. data = g_try_new0(struct set_property_data, 1);
  640. if (data == NULL)
  641. return FALSE;
  642. data->function = function;
  643. data->user_data = user_data;
  644. data->destroy = destroy;
  645. msg = dbus_message_new_method_call(client->service_name,
  646. proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
  647. if (msg == NULL) {
  648. g_free(data);
  649. return FALSE;
  650. }
  651. dbus_message_iter_init_append(msg, &iter);
  652. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
  653. &proxy->interface);
  654. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
  655. append_variant(&iter, type, value);
  656. if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
  657. &call, -1) == FALSE) {
  658. dbus_message_unref(msg);
  659. g_free(data);
  660. return FALSE;
  661. }
  662. dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
  663. dbus_pending_call_unref(call);
  664. dbus_message_unref(msg);
  665. return TRUE;
  666. }
  667. gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
  668. const char *name, int type, const void *value,
  669. size_t size, GDBusResultFunction function,
  670. void *user_data, GDBusDestroyFunction destroy)
  671. {
  672. struct set_property_data *data;
  673. GDBusClient *client;
  674. DBusMessage *msg;
  675. DBusMessageIter iter;
  676. DBusPendingCall *call;
  677. if (!proxy || !name || !value)
  678. return FALSE;
  679. if (!dbus_type_is_basic(type))
  680. return FALSE;
  681. client = proxy->client;
  682. if (!client)
  683. return FALSE;
  684. data = g_try_new0(struct set_property_data, 1);
  685. if (!data)
  686. return FALSE;
  687. data->function = function;
  688. data->user_data = user_data;
  689. data->destroy = destroy;
  690. msg = dbus_message_new_method_call(client->service_name,
  691. proxy->obj_path,
  692. DBUS_INTERFACE_PROPERTIES,
  693. "Set");
  694. if (!msg) {
  695. g_free(data);
  696. return FALSE;
  697. }
  698. dbus_message_iter_init_append(msg, &iter);
  699. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
  700. &proxy->interface);
  701. dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
  702. append_array_variant(&iter, type, &value, size);
  703. if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
  704. &call, -1) == FALSE) {
  705. dbus_message_unref(msg);
  706. g_free(data);
  707. return FALSE;
  708. }
  709. dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
  710. dbus_pending_call_unref(call);
  711. dbus_message_unref(msg);
  712. return TRUE;
  713. }
  714. struct method_call_data {
  715. GDBusReturnFunction function;
  716. void *user_data;
  717. GDBusDestroyFunction destroy;
  718. };
  719. static void method_call_reply(DBusPendingCall *call, void *user_data)
  720. {
  721. struct method_call_data *data = user_data;
  722. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  723. if (data->function)
  724. data->function(reply, data->user_data);
  725. if (data->destroy)
  726. data->destroy(data->user_data);
  727. dbus_message_unref(reply);
  728. }
  729. gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
  730. GDBusSetupFunction setup,
  731. GDBusReturnFunction function, void *user_data,
  732. GDBusDestroyFunction destroy)
  733. {
  734. struct method_call_data *data;
  735. GDBusClient *client;
  736. DBusMessage *msg;
  737. DBusPendingCall *call;
  738. if (proxy == NULL || method == NULL)
  739. return FALSE;
  740. client = proxy->client;
  741. if (client == NULL)
  742. return FALSE;
  743. msg = dbus_message_new_method_call(client->service_name,
  744. proxy->obj_path, proxy->interface, method);
  745. if (msg == NULL)
  746. return FALSE;
  747. if (setup) {
  748. DBusMessageIter iter;
  749. dbus_message_iter_init_append(msg, &iter);
  750. setup(&iter, user_data);
  751. }
  752. if (!function)
  753. return g_dbus_send_message(client->dbus_conn, msg);
  754. data = g_try_new0(struct method_call_data, 1);
  755. if (data == NULL)
  756. return FALSE;
  757. data->function = function;
  758. data->user_data = user_data;
  759. data->destroy = destroy;
  760. if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
  761. &call, METHOD_CALL_TIMEOUT) == FALSE) {
  762. dbus_message_unref(msg);
  763. g_free(data);
  764. return FALSE;
  765. }
  766. dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
  767. dbus_pending_call_unref(call);
  768. dbus_message_unref(msg);
  769. return TRUE;
  770. }
  771. gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
  772. GDBusPropertyFunction function, void *user_data)
  773. {
  774. if (proxy == NULL)
  775. return FALSE;
  776. proxy->prop_func = function;
  777. proxy->prop_data = user_data;
  778. return TRUE;
  779. }
  780. gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
  781. GDBusProxyFunction function, void *user_data)
  782. {
  783. if (proxy == NULL)
  784. return FALSE;
  785. proxy->removed_func = function;
  786. proxy->removed_data = user_data;
  787. return TRUE;
  788. }
  789. static void refresh_properties(GList *list)
  790. {
  791. GList *l;
  792. for (l = g_list_first(list); l; l = g_list_next(l)) {
  793. GDBusProxy *proxy = list->data;
  794. if (proxy->pending)
  795. get_all_properties(proxy);
  796. }
  797. }
  798. static void parse_properties(GDBusClient *client, const char *path,
  799. const char *interface, DBusMessageIter *iter)
  800. {
  801. GDBusProxy *proxy;
  802. if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
  803. return;
  804. if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
  805. return;
  806. proxy = g_dbus_proxy_lookup(client->proxy_list, NULL,
  807. path, interface);
  808. if (proxy && !proxy->pending) {
  809. update_properties(proxy, iter, FALSE);
  810. return;
  811. }
  812. if (!proxy) {
  813. proxy = proxy_new(client, path, interface);
  814. if (proxy == NULL)
  815. return;
  816. }
  817. update_properties(proxy, iter, FALSE);
  818. proxy_added(client, proxy);
  819. }
  820. static void parse_interfaces(GDBusClient *client, const char *path,
  821. DBusMessageIter *iter)
  822. {
  823. DBusMessageIter dict;
  824. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  825. return;
  826. dbus_message_iter_recurse(iter, &dict);
  827. while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
  828. DBusMessageIter entry;
  829. const char *interface;
  830. dbus_message_iter_recurse(&dict, &entry);
  831. if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
  832. break;
  833. dbus_message_iter_get_basic(&entry, &interface);
  834. dbus_message_iter_next(&entry);
  835. parse_properties(client, path, interface, &entry);
  836. dbus_message_iter_next(&dict);
  837. }
  838. }
  839. static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
  840. void *user_data)
  841. {
  842. GDBusClient *client = user_data;
  843. DBusMessageIter iter;
  844. const char *path;
  845. if (dbus_message_iter_init(msg, &iter) == FALSE)
  846. return TRUE;
  847. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
  848. return TRUE;
  849. dbus_message_iter_get_basic(&iter, &path);
  850. dbus_message_iter_next(&iter);
  851. g_dbus_client_ref(client);
  852. parse_interfaces(client, path, &iter);
  853. g_dbus_client_unref(client);
  854. return TRUE;
  855. }
  856. static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
  857. void *user_data)
  858. {
  859. GDBusClient *client = user_data;
  860. DBusMessageIter iter, entry;
  861. const char *path;
  862. if (dbus_message_iter_init(msg, &iter) == FALSE)
  863. return TRUE;
  864. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
  865. return TRUE;
  866. dbus_message_iter_get_basic(&iter, &path);
  867. dbus_message_iter_next(&iter);
  868. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
  869. return TRUE;
  870. dbus_message_iter_recurse(&iter, &entry);
  871. g_dbus_client_ref(client);
  872. while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
  873. const char *interface;
  874. dbus_message_iter_get_basic(&entry, &interface);
  875. proxy_remove(client, path, interface);
  876. dbus_message_iter_next(&entry);
  877. }
  878. g_dbus_client_unref(client);
  879. return TRUE;
  880. }
  881. static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
  882. {
  883. DBusMessageIter iter, dict;
  884. if (dbus_message_iter_init(msg, &iter) == FALSE)
  885. return;
  886. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
  887. return;
  888. dbus_message_iter_recurse(&iter, &dict);
  889. while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
  890. DBusMessageIter entry;
  891. const char *path;
  892. dbus_message_iter_recurse(&dict, &entry);
  893. if (dbus_message_iter_get_arg_type(&entry) !=
  894. DBUS_TYPE_OBJECT_PATH)
  895. break;
  896. dbus_message_iter_get_basic(&entry, &path);
  897. dbus_message_iter_next(&entry);
  898. parse_interfaces(client, path, &entry);
  899. dbus_message_iter_next(&dict);
  900. }
  901. }
  902. static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
  903. {
  904. GDBusClient *client = user_data;
  905. DBusMessage *reply = dbus_pending_call_steal_reply(call);
  906. DBusError error;
  907. g_dbus_client_ref(client);
  908. dbus_error_init(&error);
  909. if (dbus_set_error_from_message(&error, reply) == TRUE) {
  910. dbus_error_free(&error);
  911. goto done;
  912. }
  913. parse_managed_objects(client, reply);
  914. done:
  915. if (client->ready)
  916. client->ready(client, client->ready_data);
  917. dbus_message_unref(reply);
  918. dbus_pending_call_unref(client->get_objects_call);
  919. client->get_objects_call = NULL;
  920. refresh_properties(client->proxy_list);
  921. g_dbus_client_unref(client);
  922. }
  923. static void get_managed_objects(GDBusClient *client)
  924. {
  925. DBusMessage *msg;
  926. if (!client->connected)
  927. return;
  928. if ((!client->proxy_added && !client->proxy_removed) ||
  929. !client->root_path) {
  930. refresh_properties(client->proxy_list);
  931. return;
  932. }
  933. if (client->get_objects_call != NULL)
  934. return;
  935. msg = dbus_message_new_method_call(client->service_name,
  936. client->root_path,
  937. DBUS_INTERFACE_OBJECT_MANAGER,
  938. "GetManagedObjects");
  939. if (msg == NULL)
  940. return;
  941. dbus_message_append_args(msg, DBUS_TYPE_INVALID);
  942. if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
  943. &client->get_objects_call, -1) == FALSE) {
  944. dbus_message_unref(msg);
  945. return;
  946. }
  947. dbus_pending_call_set_notify(client->get_objects_call,
  948. get_managed_objects_reply,
  949. client, NULL);
  950. dbus_message_unref(msg);
  951. }
  952. static void service_connect(DBusConnection *conn, void *user_data)
  953. {
  954. GDBusClient *client = user_data;
  955. g_dbus_client_ref(client);
  956. client->connected = TRUE;
  957. get_managed_objects(client);
  958. if (client->connect_func)
  959. client->connect_func(conn, client->connect_data);
  960. g_dbus_client_unref(client);
  961. }
  962. static void service_disconnect(DBusConnection *conn, void *user_data)
  963. {
  964. GDBusClient *client = user_data;
  965. client->connected = FALSE;
  966. g_list_free_full(client->proxy_list, proxy_free);
  967. client->proxy_list = NULL;
  968. if (client->disconn_func)
  969. client->disconn_func(conn, client->disconn_data);
  970. }
  971. static DBusHandlerResult message_filter(DBusConnection *connection,
  972. DBusMessage *message, void *user_data)
  973. {
  974. GDBusClient *client = user_data;
  975. const char *sender, *path, *interface;
  976. if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
  977. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  978. sender = dbus_message_get_sender(message);
  979. if (sender == NULL)
  980. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  981. path = dbus_message_get_path(message);
  982. interface = dbus_message_get_interface(message);
  983. if (g_str_has_prefix(path, client->base_path) == FALSE)
  984. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  985. if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
  986. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  987. if (client->signal_func)
  988. client->signal_func(connection, message, client->signal_data);
  989. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  990. }
  991. GDBusClient *g_dbus_client_new(DBusConnection *connection,
  992. const char *service, const char *path)
  993. {
  994. return g_dbus_client_new_full(connection, service, path, "/");
  995. }
  996. GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
  997. const char *service,
  998. const char *path,
  999. const char *root_path)
  1000. {
  1001. GDBusClient *client;
  1002. unsigned int i;
  1003. if (!connection || !service)
  1004. return NULL;
  1005. client = g_try_new0(GDBusClient, 1);
  1006. if (client == NULL)
  1007. return NULL;
  1008. if (dbus_connection_add_filter(connection, message_filter,
  1009. client, NULL) == FALSE) {
  1010. g_free(client);
  1011. return NULL;
  1012. }
  1013. client->dbus_conn = dbus_connection_ref(connection);
  1014. client->service_name = g_strdup(service);
  1015. client->base_path = g_strdup(path);
  1016. client->root_path = g_strdup(root_path);
  1017. client->connected = FALSE;
  1018. client->match_rules = g_ptr_array_sized_new(1);
  1019. g_ptr_array_set_free_func(client->match_rules, g_free);
  1020. client->watch = g_dbus_add_service_watch(connection, service,
  1021. service_connect,
  1022. service_disconnect,
  1023. client, NULL);
  1024. if (!root_path)
  1025. return g_dbus_client_ref(client);
  1026. client->added_watch = g_dbus_add_signal_watch(connection, service,
  1027. client->root_path,
  1028. DBUS_INTERFACE_OBJECT_MANAGER,
  1029. "InterfacesAdded",
  1030. interfaces_added,
  1031. client, NULL);
  1032. client->removed_watch = g_dbus_add_signal_watch(connection, service,
  1033. client->root_path,
  1034. DBUS_INTERFACE_OBJECT_MANAGER,
  1035. "InterfacesRemoved",
  1036. interfaces_removed,
  1037. client, NULL);
  1038. g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
  1039. "sender='%s',path_namespace='%s'",
  1040. client->service_name, client->base_path));
  1041. for (i = 0; i < client->match_rules->len; i++) {
  1042. modify_match(client->dbus_conn, "AddMatch",
  1043. g_ptr_array_index(client->match_rules, i));
  1044. }
  1045. return g_dbus_client_ref(client);
  1046. }
  1047. GDBusClient *g_dbus_client_ref(GDBusClient *client)
  1048. {
  1049. if (client == NULL)
  1050. return NULL;
  1051. __sync_fetch_and_add(&client->ref_count, 1);
  1052. return client;
  1053. }
  1054. void g_dbus_client_unref(GDBusClient *client)
  1055. {
  1056. unsigned int i;
  1057. if (client == NULL)
  1058. return;
  1059. if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
  1060. return;
  1061. if (client->pending_call != NULL) {
  1062. dbus_pending_call_cancel(client->pending_call);
  1063. dbus_pending_call_unref(client->pending_call);
  1064. }
  1065. if (client->get_objects_call != NULL) {
  1066. dbus_pending_call_cancel(client->get_objects_call);
  1067. dbus_pending_call_unref(client->get_objects_call);
  1068. }
  1069. for (i = 0; i < client->match_rules->len; i++) {
  1070. modify_match(client->dbus_conn, "RemoveMatch",
  1071. g_ptr_array_index(client->match_rules, i));
  1072. }
  1073. g_ptr_array_free(client->match_rules, TRUE);
  1074. dbus_connection_remove_filter(client->dbus_conn,
  1075. message_filter, client);
  1076. g_list_free_full(client->proxy_list, proxy_free);
  1077. /*
  1078. * Don't call disconn_func twice if disconnection
  1079. * was previously reported.
  1080. */
  1081. if (client->disconn_func && client->connected)
  1082. client->disconn_func(client->dbus_conn, client->disconn_data);
  1083. g_dbus_remove_watch(client->dbus_conn, client->watch);
  1084. g_dbus_remove_watch(client->dbus_conn, client->added_watch);
  1085. g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
  1086. dbus_connection_unref(client->dbus_conn);
  1087. g_free(client->service_name);
  1088. g_free(client->base_path);
  1089. g_free(client->root_path);
  1090. g_free(client);
  1091. }
  1092. gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
  1093. GDBusWatchFunction function, void *user_data)
  1094. {
  1095. if (client == NULL)
  1096. return FALSE;
  1097. client->connect_func = function;
  1098. client->connect_data = user_data;
  1099. return TRUE;
  1100. }
  1101. gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
  1102. GDBusWatchFunction function, void *user_data)
  1103. {
  1104. if (client == NULL)
  1105. return FALSE;
  1106. client->disconn_func = function;
  1107. client->disconn_data = user_data;
  1108. return TRUE;
  1109. }
  1110. gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
  1111. GDBusMessageFunction function, void *user_data)
  1112. {
  1113. if (client == NULL)
  1114. return FALSE;
  1115. client->signal_func = function;
  1116. client->signal_data = user_data;
  1117. return TRUE;
  1118. }
  1119. gboolean g_dbus_client_set_ready_watch(GDBusClient *client,
  1120. GDBusClientFunction ready, void *user_data)
  1121. {
  1122. if (client == NULL)
  1123. return FALSE;
  1124. client->ready = ready;
  1125. client->ready_data = user_data;
  1126. return TRUE;
  1127. }
  1128. gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
  1129. GDBusProxyFunction proxy_added,
  1130. GDBusProxyFunction proxy_removed,
  1131. GDBusPropertyFunction property_changed,
  1132. void *user_data)
  1133. {
  1134. if (client == NULL)
  1135. return FALSE;
  1136. client->proxy_added = proxy_added;
  1137. client->proxy_removed = proxy_removed;
  1138. client->property_changed = property_changed;
  1139. client->user_data = user_data;
  1140. if (proxy_added || proxy_removed || property_changed)
  1141. get_managed_objects(client);
  1142. return TRUE;
  1143. }