summaryrefslogtreecommitdiff
path: root/src/lib/eldbus/eldbus_service.c
diff options
context:
space:
mode:
authorLucas De Marchi <lucas.demarchi@profusion.mobi>2013-04-23 11:40:05 -0300
committerLucas De Marchi <lucas.demarchi@profusion.mobi>2013-04-23 12:36:29 -0300
commit4e3804041f8e865e007b2a6a0d45a05f39500c3b (patch)
treea493b9c8f8a610d2667651f3ba81819ed16fbe8c /src/lib/eldbus/eldbus_service.c
parent4cf68bf728b5a858ce1c0efac25ded1a49ba8d9d (diff)
Rename edbus->eldbus
git grep -l edbus2 | while read f; do sed -i 's/edbus2/eldbus/g' "$f"; done find . -name '*edbus2*' -exec rename edbus2 eldbus {} \; git grep -l "EDBUS" | while read f; do sed -i 's/EDBUS/ELDBUS/g' "$f"; done git grep -l "EDBus" | while read f; do sed -i 's/EDBus/Eldbus/g' "$f"; done git grep -l "edbus (v2)" | while read f; do sed -i 's/edbus (v2)/eldbus/g' "$f"; done git grep -l "Edbus" | while read f; do sed -i 's/Edbus/Eldbus/g' "$f"; done git grep -l "edbus" | while read f; do sed -i 's/edbus/eldbus/g' "$f"; done find . -name '*edbus*' -exec rename edbus eldbus {} \; find . -name '*EDBus*' -exec rename EDBus Eldbus {} \;
Diffstat (limited to 'src/lib/eldbus/eldbus_service.c')
-rw-r--r--src/lib/eldbus/eldbus_service.c1475
1 files changed, 1475 insertions, 0 deletions
diff --git a/src/lib/eldbus/eldbus_service.c b/src/lib/eldbus/eldbus_service.c
new file mode 100644
index 0000000000..e6946c21b1
--- /dev/null
+++ b/src/lib/eldbus/eldbus_service.c
@@ -0,0 +1,1475 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "eldbus_private.h"
6#include "eldbus_private_types.h"
7
8#define DBUS_ANNOTATION(name, value) \
9 "<annotation" \
10 " name=\"org.freedesktop.DBus." name "\"" \
11 " value=\"" value "\"" \
12 "/>"
13
14#define DBUS_ANNOTATION_DEPRECATED DBUS_ANNOTATION("Deprecated", "true")
15#define DBUS_ANNOTATION_NOREPLY DBUS_ANNOTATION("Method.NoReply", "true")
16
17#ifndef DBUS_ERROR_UNKNOWN_INTERFACE
18# define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface"
19#endif
20
21#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
22# define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
23#endif
24
25#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
26# define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
27#endif
28
29#define ELDBUS_SERVICE_INTERFACE_CHECK(obj) \
30 do \
31 { \
32 EINA_SAFETY_ON_NULL_RETURN(obj); \
33 if (!EINA_MAGIC_CHECK(obj, ELDBUS_SERVICE_INTERFACE_MAGIC)) \
34 { \
35 EINA_MAGIC_FAIL(obj, ELDBUS_SERVICE_INTERFACE_MAGIC); \
36 return; \
37 } \
38 } \
39 while (0)
40
41#define ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(obj, retval) \
42 do \
43 { \
44 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, retval); \
45 if (!EINA_MAGIC_CHECK(obj, ELDBUS_SERVICE_INTERFACE_MAGIC)) \
46 { \
47 EINA_MAGIC_FAIL(obj, ELDBUS_SERVICE_INTERFACE_MAGIC); \
48 return retval; \
49 } \
50 } \
51 while (0)
52
53
54static void _object_unregister(DBusConnection *conn, void *user_data);
55static DBusHandlerResult _object_handler(DBusConnection *conn, DBusMessage *message, void *user_data);
56static void _object_free(Eldbus_Service_Object *obj);
57static void _interface_free(Eldbus_Service_Interface *interface);
58static void _on_connection_free(void *data, const void *dead_pointer);
59
60static DBusObjectPathVTable vtable = {
61 _object_unregister,
62 _object_handler,
63 NULL,
64 NULL,
65 NULL,
66 NULL
67};
68
69Eldbus_Service_Interface *introspectable;
70Eldbus_Service_Interface *properties_iface;
71Eldbus_Service_Interface *objmanager;
72
73static inline void
74_introspect_arguments_append(Eina_Strbuf *buf, const Eldbus_Arg_Info *args,
75 const char *direction)
76{
77 for (; args && args->signature; args++)
78 {
79 if (args->name && args->name[0])
80 eina_strbuf_append_printf(buf, "<arg type=\"%s\" name=\"%s\"",
81 args->signature, args->name);
82 else
83 eina_strbuf_append_printf(buf, "<arg type=\"%s\"", args->signature);
84
85 if (direction)
86 eina_strbuf_append_printf(buf, " direction=\"%s\" />", direction);
87 else
88 eina_strbuf_append(buf, " />");
89 }
90}
91
92static inline void
93_introspect_append_signal(Eina_Strbuf *buf, const Eldbus_Signal *sig)
94{
95 eina_strbuf_append_printf(buf, "<signal name=\"%s\"", sig->name);
96
97 if (!sig->flags && !(sig->args && sig->args->signature))
98 {
99 eina_strbuf_append(buf, " />");
100 return;
101 }
102
103 eina_strbuf_append(buf, ">");
104
105 if (sig->flags & ELDBUS_SIGNAL_FLAG_DEPRECATED)
106 eina_strbuf_append(buf, DBUS_ANNOTATION_DEPRECATED);
107
108 _introspect_arguments_append(buf, sig->args, NULL);
109
110 eina_strbuf_append(buf, "</signal>");
111}
112
113static inline void
114_instrospect_append_property(Eina_Strbuf *buf, const Eldbus_Property *prop, const Eldbus_Service_Interface *iface)
115{
116 eina_strbuf_append_printf(buf, "<property name=\"%s\" type=\"%s\" access=\"",
117 prop->name, prop->type);
118
119 if (iface->get_func || prop->get_func)
120 eina_strbuf_append(buf, "read");
121
122 if (iface->set_func || prop->set_func)
123 eina_strbuf_append(buf, "write");
124
125 if (!prop->flags)
126 {
127 eina_strbuf_append(buf, "\" />");
128 return;
129 }
130
131 eina_strbuf_append(buf, "\">");
132
133 if (prop->flags & ELDBUS_PROPERTY_FLAG_DEPRECATED)
134 eina_strbuf_append(buf, DBUS_ANNOTATION_DEPRECATED);
135
136 eina_strbuf_append(buf, "</property>");
137}
138
139static inline void
140_introspect_append_method(Eina_Strbuf *buf, const Eldbus_Method *method)
141{
142 eina_strbuf_append_printf(buf, "<method name=\"%s\">", method->member);
143
144 if (method->flags & ELDBUS_METHOD_FLAG_DEPRECATED)
145 eina_strbuf_append(buf, DBUS_ANNOTATION_DEPRECATED);
146
147 if (method->flags & ELDBUS_METHOD_FLAG_NOREPLY)
148 eina_strbuf_append(buf, DBUS_ANNOTATION_NOREPLY);
149
150 _introspect_arguments_append(buf, method->in, "in");
151 _introspect_arguments_append(buf, method->out, "out");
152 eina_strbuf_append(buf, "</method>");
153}
154
155typedef struct _Property
156{
157 const Eldbus_Property *property;
158 Eina_Bool is_invalidate:1;
159} Property;
160
161static void
162_introspect_append_interface(Eina_Strbuf *buf, Eldbus_Service_Interface *iface)
163{
164 const Eldbus_Method *method;
165 Property *prop;
166 Eina_Iterator *iterator;
167 unsigned short i;
168
169 eina_strbuf_append_printf(buf, "<interface name=\"%s\">", iface->name);
170
171 iterator = eina_hash_iterator_data_new(iface->methods);
172 EINA_ITERATOR_FOREACH(iterator, method)
173 _introspect_append_method(buf, method);
174 eina_iterator_free(iterator);
175
176 for (i = 0; i < eina_array_count(iface->sign_of_signals); i++)
177 _introspect_append_signal(buf, &iface->signals[i]);
178
179 iterator = eina_hash_iterator_data_new(iface->properties);
180 EINA_ITERATOR_FOREACH(iterator, prop)
181 _instrospect_append_property(buf, prop->property, iface);
182 eina_iterator_free(iterator);
183
184 eina_strbuf_append(buf, "</interface>");
185}
186
187static Eldbus_Message *
188_cb_property_get(const Eldbus_Service_Interface *piface, const Eldbus_Message *msg)
189{
190 const char *propname, *iface_name;
191 Eldbus_Service_Object *obj = piface->obj;
192 Eldbus_Service_Interface *iface;
193 Property *prop;
194 Eldbus_Message *reply, *error_reply = NULL;
195 Eldbus_Message_Iter *main_iter, *variant;
196 Eina_Bool ret;
197 Eldbus_Property_Get_Cb getter = NULL;
198
199 if (!eldbus_message_arguments_get(msg, "ss", &iface_name, &propname))
200 return NULL;
201
202 iface = eina_hash_find(obj->interfaces, iface_name);
203 if (!iface)
204 return eldbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_INTERFACE,
205 "Interface not found.");
206
207 prop = eina_hash_find(iface->properties, propname);
208 if (!prop || prop->is_invalidate) goto not_found;
209
210 if (prop->property->get_func)
211 getter = prop->property->get_func;
212 else if (iface->get_func)
213 getter = iface->get_func;
214
215 if (!getter) goto not_found;
216
217 reply = eldbus_message_method_return_new(msg);
218 EINA_SAFETY_ON_NULL_RETURN_VAL(reply, NULL);
219
220 main_iter = eldbus_message_iter_get(reply);
221 variant = eldbus_message_iter_container_new(main_iter, 'v',
222 prop->property->type);
223
224 ret = getter(iface, propname, variant, msg, &error_reply);
225
226 if (ret)
227 {
228 eldbus_message_iter_container_close(main_iter, variant);
229 return reply;
230 }
231
232 eldbus_message_unref(reply);
233 return error_reply;
234
235not_found:
236 return eldbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_PROPERTY,
237 "Property not found.");
238}
239
240static Eina_Bool
241_props_getall(Eldbus_Service_Interface *iface, Eina_Iterator *iterator, Eldbus_Message_Iter *dict, const Eldbus_Message *input_msg, Eldbus_Message **error_reply)
242{
243 Property *prop;
244 EINA_ITERATOR_FOREACH(iterator, prop)
245 {
246 Eldbus_Message_Iter *entry, *var;
247 Eina_Bool ret;
248 Eldbus_Property_Get_Cb getter = NULL;
249
250 if (prop->property->get_func)
251 getter = prop->property->get_func;
252 else if (iface->get_func)
253 getter = iface->get_func;
254
255 if (!getter || prop->is_invalidate)
256 continue;
257
258 if (!eldbus_message_iter_arguments_append(dict, "{sv}", &entry))
259 continue;
260
261 eldbus_message_iter_basic_append(entry, 's', prop->property->name);
262 var = eldbus_message_iter_container_new(entry, 'v',
263 prop->property->type);
264
265 ret = getter(iface, prop->property->name, var, input_msg, error_reply);
266 if (!ret)
267 return EINA_FALSE;
268
269 eldbus_message_iter_container_close(entry, var);
270 eldbus_message_iter_container_close(dict, entry);
271 }
272 return EINA_TRUE;
273}
274
275static Eldbus_Message *
276_cb_property_getall(const Eldbus_Service_Interface *piface, const Eldbus_Message *msg)
277{
278 const char *iface_name;
279 Eldbus_Service_Object *obj = piface->obj;
280 Eldbus_Service_Interface *iface;
281 Eina_Iterator *iterator;
282 Eldbus_Message *reply, *error_reply;
283 Eldbus_Message_Iter *main_iter, *dict;
284
285 if (!eldbus_message_arguments_get(msg, "s", &iface_name))
286 return NULL;
287
288 iface = eina_hash_find(obj->interfaces, iface_name);
289 if (!iface)
290 return eldbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_INTERFACE,
291 "Interface not found.");
292
293 reply = eldbus_message_method_return_new(msg);
294 EINA_SAFETY_ON_NULL_RETURN_VAL(reply, NULL);
295 main_iter = eldbus_message_iter_get(reply);
296 if (!eldbus_message_iter_arguments_append(main_iter, "a{sv}", &dict))
297 {
298 eldbus_message_unref(reply);
299 return NULL;
300 }
301
302 iterator = eina_hash_iterator_data_new(iface->properties);
303 if (!_props_getall(iface, iterator, dict, msg, &error_reply))
304 {
305 eldbus_message_unref(reply);
306 eina_iterator_free(iterator);
307 return error_reply;
308 }
309 eldbus_message_iter_container_close(main_iter, dict);
310
311 eina_iterator_free(iterator);
312 return reply;
313}
314
315static Eldbus_Message *
316_cb_property_set(const Eldbus_Service_Interface *piface, const Eldbus_Message *msg)
317{
318 const char *propname, *iface_name;
319 Eldbus_Service_Object *obj = piface->obj;
320 Eldbus_Service_Interface *iface;
321 Property *prop;
322 Eldbus_Message *reply;
323 Eldbus_Message_Iter *variant;
324 Eldbus_Property_Set_Cb setter = NULL;
325
326 if (!eldbus_message_arguments_get(msg, "ssv", &iface_name, &propname, &variant))
327 return NULL;
328
329 iface = eina_hash_find(obj->interfaces, iface_name);
330 if (!iface)
331 return eldbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_INTERFACE,
332 "Interface not found.");
333
334 prop = eina_hash_find(iface->properties, propname);
335 if (!prop || prop->is_invalidate)
336 return eldbus_message_error_new(msg, DBUS_ERROR_UNKNOWN_PROPERTY,
337 "Property not found.");
338
339 if (prop->property->set_func)
340 setter = prop->property->set_func;
341 else if (iface->set_func)
342 setter = iface->set_func;
343
344 if (!setter)
345 return eldbus_message_error_new(msg, DBUS_ERROR_PROPERTY_READ_ONLY,
346 "This property is read only");
347
348 reply = setter(iface, propname, variant, msg);
349 return reply;
350}
351
352static Eldbus_Message *
353cb_introspect(const Eldbus_Service_Interface *_iface, const Eldbus_Message *message)
354{
355 Eldbus_Service_Object *obj = _iface->obj;
356 Eldbus_Message *reply = eldbus_message_method_return_new(message);
357 if (obj->introspection_dirty || !obj->introspection_data)
358 {
359 Eina_Iterator *iterator;
360 Eldbus_Service_Interface *iface;
361 Eldbus_Service_Object *child;
362 size_t baselen;
363
364 if (obj->introspection_data)
365 eina_strbuf_reset(obj->introspection_data);
366 else
367 obj->introspection_data = eina_strbuf_new();
368 EINA_SAFETY_ON_NULL_RETURN_VAL(obj->introspection_data, NULL);
369
370 eina_strbuf_append(obj->introspection_data, "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">");
371 eina_strbuf_append_printf(obj->introspection_data,
372 "<node name=\"%s\">", obj->path);
373
374 iterator = eina_hash_iterator_data_new(obj->interfaces);
375 EINA_ITERATOR_FOREACH(iterator, iface)
376 _introspect_append_interface(obj->introspection_data, iface);
377 eina_iterator_free(iterator);
378
379 baselen = strlen(obj->path);
380 /* account for the last '/' */
381 if (baselen != 1)
382 baselen++;
383
384 EINA_INLIST_FOREACH(obj->children, child)
385 eina_strbuf_append_printf(obj->introspection_data,
386 "<node name=\"%s\" />",
387 child->path + baselen);
388
389 eina_strbuf_append(obj->introspection_data, "</node>");
390 obj->introspection_dirty = EINA_FALSE;
391 }
392
393 eldbus_message_arguments_append(reply, "s", eina_strbuf_string_get(obj->introspection_data));
394 return reply;
395}
396
397static const Eldbus_Method introspect = {
398 "Introspect", NULL, ELDBUS_ARGS({ "s", "xml" }), cb_introspect
399};
400
401static void
402_introspectable_create(void)
403{
404 introspectable = calloc(1, sizeof(Eldbus_Service_Interface));
405 EINA_SAFETY_ON_NULL_RETURN(introspectable);
406
407 EINA_MAGIC_SET(introspectable, ELDBUS_SERVICE_INTERFACE_MAGIC);
408 introspectable->sign_of_signals = eina_array_new(1);
409 introspectable->properties = eina_hash_string_small_new(NULL);
410 introspectable->name = ELDBUS_FDO_INTERFACE_INTROSPECTABLE;
411 introspectable->methods = eina_hash_string_small_new(NULL);
412
413 eina_hash_add(introspectable->methods, introspect.member, &introspect);
414}
415
416static void
417_default_interfaces_free(void)
418{
419 eina_hash_free(introspectable->methods);
420 eina_hash_free(introspectable->properties);
421 eina_array_free(introspectable->sign_of_signals);
422 free(introspectable);
423
424 eina_hash_free(properties_iface->methods);
425 eina_hash_free(properties_iface->properties);
426 eina_array_free(properties_iface->sign_of_signals);
427 free(properties_iface);
428
429 eina_hash_free(objmanager->methods);
430 eina_hash_free(objmanager->properties);
431 eina_array_free(objmanager->sign_of_signals);
432 free(objmanager);
433}
434
435static const Eldbus_Method _property_methods[] = {
436 {
437 "Get", ELDBUS_ARGS({"s", "interface"}, {"s", "property"}),
438 ELDBUS_ARGS({"v", "value"}), _cb_property_get
439 },
440 {
441 "Set", ELDBUS_ARGS({"s", "interface"}, {"s", "property"}, {"v", "value"}),
442 NULL, _cb_property_set
443 },
444 {
445 "GetAll", ELDBUS_ARGS({"s", "interface"}), ELDBUS_ARGS({"a{sv}", "props"}),
446 _cb_property_getall
447 }
448};
449
450static const Eldbus_Signal _properties_signals[] = {
451 {
452 "PropertiesChanged",
453 ELDBUS_ARGS({"s", "interface"}, {"a{sv}", "changed_properties"}, {"as", "invalidated_properties"})
454 }
455};
456
457static void
458_properties_create(void)
459{
460 properties_iface = calloc(1, sizeof(Eldbus_Service_Interface));
461 if (!properties_iface) return;
462
463 properties_iface->sign_of_signals = eina_array_new(1);
464 properties_iface->properties = eina_hash_string_small_new(NULL);
465 properties_iface->name = ELDBUS_FDO_INTERFACE_PROPERTIES;
466 properties_iface->methods = eina_hash_string_small_new(NULL);
467 EINA_MAGIC_SET(properties_iface, ELDBUS_SERVICE_INTERFACE_MAGIC);
468
469 eina_hash_add(properties_iface->methods, _property_methods[0].member,
470 &_property_methods[0]);
471 eina_hash_add(properties_iface->methods, _property_methods[1].member,
472 &_property_methods[1]);
473 eina_hash_add(properties_iface->methods, _property_methods[2].member,
474 &_property_methods[2]);
475
476 properties_iface->signals = _properties_signals;
477 eina_array_push(properties_iface->sign_of_signals, "sa{sv}as");
478}
479
480static Eina_Bool
481_propmgr_iface_props_append(Eldbus_Service_Interface *iface, Eldbus_Message_Iter *array)
482{
483 Eldbus_Message_Iter *iface_entry, *props_array;
484 Eina_Iterator *iterator;
485 Eldbus_Message *error_msg;
486
487 eldbus_message_iter_arguments_append(array, "{sa{sv}}", &iface_entry);
488
489 eldbus_message_iter_arguments_append(iface_entry, "sa{sv}", iface->name, &props_array);
490 iterator = eina_hash_iterator_data_new(iface->properties);
491 if (!_props_getall(iface, iterator, props_array, NULL, &error_msg))
492 {
493 ERR("Error reply was set without pass any input message.");
494 eldbus_message_unref(error_msg);
495 eina_iterator_free(iterator);
496 return EINA_FALSE;
497 }
498 eina_iterator_free(iterator);
499 eldbus_message_iter_container_close(iface_entry, props_array);
500 eldbus_message_iter_container_close(array, iface_entry);
501 return EINA_TRUE;
502}
503
504static Eina_Bool
505_managed_obj_append(Eldbus_Service_Object *obj, Eldbus_Message_Iter *array, Eina_Bool first)
506{
507 Eldbus_Message_Iter *obj_entry, *array_interface;
508 Eina_Iterator *iface_iter;
509 Eldbus_Service_Interface *iface;
510 Eldbus_Service_Object *children;
511
512 if (first) goto foreach;
513 if (obj->objmanager) return EINA_TRUE;
514
515 eldbus_message_iter_arguments_append(array, "{oa{sa{sv}}}", &obj_entry);
516 eldbus_message_iter_arguments_append(obj_entry, "oa{sa{sv}}", obj->path,
517 &array_interface);
518 iface_iter = eina_hash_iterator_data_new(obj->interfaces);
519
520 EINA_ITERATOR_FOREACH(iface_iter, iface)
521 {
522 Eina_Bool ret;
523
524 if (eina_list_data_find(obj->iface_added, iface))
525 continue;
526
527 ret = _propmgr_iface_props_append(iface, array_interface);
528 if (ret)
529 continue;
530
531 eina_iterator_free(iface_iter);
532 return EINA_FALSE;
533 }
534 eina_iterator_free(iface_iter);
535 eldbus_message_iter_container_close(obj_entry, array_interface);
536 eldbus_message_iter_container_close(array, obj_entry);
537
538foreach:
539 EINA_INLIST_FOREACH(obj->children, children)
540 {
541 Eina_Bool ret;
542 ret = _managed_obj_append(children, array, EINA_FALSE);
543 if (!ret) return EINA_FALSE;
544 }
545 return EINA_TRUE;
546}
547
548static Eldbus_Message *
549_cb_managed_objects(const Eldbus_Service_Interface *iface, const Eldbus_Message *msg)
550{
551 Eldbus_Message *reply = eldbus_message_method_return_new(msg);
552 Eldbus_Message_Iter *array_path, *main_iter;
553 Eina_Bool ret;
554
555 EINA_SAFETY_ON_NULL_RETURN_VAL(reply, NULL);
556 main_iter = eldbus_message_iter_get(reply);
557 eldbus_message_iter_arguments_append(main_iter, "a{oa{sa{sv}}}", &array_path);
558
559 ret = _managed_obj_append(iface->obj, array_path, EINA_TRUE);
560 if (!ret)
561 {
562 eldbus_message_unref(reply);
563 return eldbus_message_error_new(msg, "org.freedesktop.DBus.Error",
564 "Irrecoverable error happen");
565 }
566
567 eldbus_message_iter_container_close(main_iter, array_path);
568 return reply;
569}
570
571static Eldbus_Method get_managed_objects = {
572 "GetManagedObjects", NULL, ELDBUS_ARGS({"a{oa{sa{sv}}}", "objects"}),
573 _cb_managed_objects
574};
575
576static const Eldbus_Signal _object_manager_signals[] = {
577 {
578 "InterfacesAdded", ELDBUS_ARGS({"o", "object"}, {"a{sa{sv}}", "interfaces"})
579 },
580 {
581 "InterfacesRemoved", ELDBUS_ARGS({"o", "object"}, {"as", "interfaces"})
582 }
583};
584
585static void
586_object_manager_create(void)
587{
588 objmanager = calloc(1, sizeof(Eldbus_Service_Interface));
589 if (!objmanager) return;
590
591 EINA_MAGIC_SET(objmanager, ELDBUS_SERVICE_INTERFACE_MAGIC);
592 objmanager->sign_of_signals = eina_array_new(1);
593 objmanager->properties = eina_hash_string_small_new(NULL);
594 objmanager->name = ELDBUS_FDO_INTERFACE_OBJECT_MANAGER;
595 objmanager->methods = eina_hash_string_small_new(NULL);
596
597 eina_hash_add(objmanager->methods, get_managed_objects.member,
598 &get_managed_objects);
599
600 objmanager->signals = _object_manager_signals;
601 eina_array_push(objmanager->sign_of_signals, "oa{sa{sv}}");
602 eina_array_push(objmanager->sign_of_signals, "oas");
603}
604
605Eina_Bool
606eldbus_service_init(void)
607{
608 _introspectable_create();
609 EINA_SAFETY_ON_NULL_RETURN_VAL(introspectable, EINA_FALSE);
610 _properties_create();
611 EINA_SAFETY_ON_NULL_RETURN_VAL(properties_iface, EINA_FALSE);
612 _object_manager_create();
613 EINA_SAFETY_ON_NULL_RETURN_VAL(objmanager, EINA_FALSE);
614
615 return EINA_TRUE;
616}
617
618void
619eldbus_service_shutdown(void)
620{
621 _default_interfaces_free();
622}
623
624static Eldbus_Service_Object *
625_eldbus_service_object_parent_find(Eldbus_Service_Object *obj)
626{
627 Eldbus_Service_Object *parent = NULL;
628 size_t len = strlen(obj->path);
629 char *path = strdup(obj->path);
630 char *slash;
631
632 for (slash = path[len] != '/' ? &path[len - 1] : &path[len - 2];
633 slash > path; slash--)
634 {
635 if (*slash != '/')
636 continue;
637
638 *slash = '\0';
639
640 if (dbus_connection_get_object_path_data(obj->conn->dbus_conn,
641 path, (void **) &parent) && parent != NULL)
642 break;
643 }
644
645 free(path);
646 return parent;
647}
648
649static Eldbus_Service_Object *
650_eldbus_service_object_add(Eldbus_Connection *conn, const char *path)
651{
652 Eldbus_Service_Object *obj, *rootobj;
653 Eina_Inlist *safe;
654 size_t pathlen;
655
656 obj = calloc(1, sizeof(Eldbus_Service_Object));
657 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
658
659 if (!dbus_connection_register_object_path(conn->dbus_conn, path, &vtable,
660 obj))
661 {
662 free(obj);
663 return NULL;
664 }
665
666 obj->conn = conn;
667 obj->path = eina_stringshare_add(path);
668 obj->interfaces = eina_hash_string_superfast_new(NULL);
669 eldbus_connection_free_cb_add(conn, _on_connection_free, obj);
670
671 eina_hash_add(obj->interfaces, introspectable->name, introspectable);
672 eina_hash_add(obj->interfaces, properties_iface->name, properties_iface);
673
674 obj->parent = _eldbus_service_object_parent_find(obj);
675 if (obj->parent)
676 {
677 obj->parent->children = eina_inlist_append(obj->parent->children,
678 EINA_INLIST_GET(obj));
679 return obj;
680 }
681
682 /*
683 * If there wasn't any object above us, check if anyone in conn->root_obj
684 * should become our child and append ourselves there.
685 */
686 pathlen = strlen(obj->path);
687 EINA_INLIST_FOREACH_SAFE(conn->root_objs, safe, rootobj)
688 {
689 if (strncmp(obj->path, rootobj->path, pathlen) != 0)
690 continue;
691
692 if (rootobj->path[pathlen] != '/' && pathlen > 1)
693 continue;
694
695 conn->root_objs = eina_inlist_remove(conn->root_objs,
696 EINA_INLIST_GET(rootobj));
697 obj->children = eina_inlist_append(obj->children,
698 EINA_INLIST_GET(rootobj));
699 rootobj->parent = obj;
700 }
701 conn->root_objs = eina_inlist_append(conn->root_objs, EINA_INLIST_GET(obj));
702
703 return obj;
704}
705
706static void
707_props_free(void *data)
708{
709 Property *p = data;
710 free(p);
711}
712
713static void
714_object_manager_iface_added_emit(Eldbus_Service_Object *obj,
715 Eldbus_Service_Object *parent)
716{
717 Eina_List *l;
718 Eldbus_Service_Interface *iface;
719 Eldbus_Message_Iter *iter, *array;
720 Eldbus_Message *sig = eldbus_message_signal_new(parent->path,
721 ELDBUS_FDO_INTERFACE_OBJECT_MANAGER,
722 "InterfacesAdded");
723 EINA_SAFETY_ON_NULL_RETURN(sig);
724 iter = eldbus_message_iter_get(sig);
725 eldbus_message_iter_arguments_append(iter, "oa{sa{sv}}", obj->path,
726 &array);
727
728 EINA_LIST_FOREACH(obj->iface_added, l, iface)
729 {
730 if (!_propmgr_iface_props_append(iface, array))
731 {
732 ERR("Could not append properties to InterfacesAdded signal");
733 eldbus_message_unref(sig);
734 goto done;
735 }
736 }
737 eldbus_message_iter_container_close(iter, array);
738 eldbus_connection_send(parent->conn, sig, NULL, NULL, -1);
739
740done:
741 obj->iface_added = eina_list_free(obj->iface_added);
742}
743
744static void
745_object_manager_iface_removed_emit(Eldbus_Service_Object *obj,
746 Eldbus_Service_Object *parent)
747{
748 Eina_List *l;
749 const char *name;
750 Eldbus_Message_Iter *iter, *array;
751 Eldbus_Message *sig = eldbus_message_signal_new(parent->path,
752 ELDBUS_FDO_INTERFACE_OBJECT_MANAGER,
753 "InterfacesRemoved");
754 EINA_SAFETY_ON_NULL_RETURN(sig);
755
756 iter = eldbus_message_iter_get(sig);
757 eldbus_message_iter_arguments_append(iter, "oas", obj->path, &array);
758
759 EINA_LIST_FOREACH(obj->iface_removed, l, name)
760 {
761 eldbus_message_iter_arguments_append(array, name);
762 eina_stringshare_del(name);
763 }
764 eldbus_message_iter_container_close(iter, array);
765 eldbus_connection_send(parent->conn, sig, NULL, NULL, -1);
766 obj->iface_removed = eina_list_free(obj->iface_removed);
767}
768
769static Eldbus_Service_Object *
770_object_manager_parent_find(Eldbus_Service_Object *obj)
771{
772 if (!obj->parent)
773 return NULL;
774 if (obj->parent->objmanager)
775 return obj->parent;
776 return _object_manager_parent_find(obj->parent);
777}
778
779static Eina_Bool
780_object_manager_changes_process(void *data)
781{
782 Eldbus_Service_Object *obj = data;
783 Eldbus_Service_Object *parent = _object_manager_parent_find(obj);
784
785 obj->idler_iface_changed = NULL;
786
787 if (!parent)
788 return EINA_FALSE;
789
790 if (obj->iface_added)
791 _object_manager_iface_added_emit(obj, parent);
792 if (obj->iface_removed)
793 _object_manager_iface_removed_emit(obj, parent);
794
795 return EINA_FALSE;
796}
797
798static Eldbus_Service_Interface *
799_eldbus_service_interface_add(Eldbus_Service_Object *obj, const char *interface)
800{
801 Eldbus_Service_Interface *iface;
802
803 iface = eina_hash_find(obj->interfaces, interface);
804 if (iface) return iface;
805
806 iface = calloc(1, sizeof(Eldbus_Service_Interface));
807 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL);
808
809 EINA_MAGIC_SET(iface, ELDBUS_SERVICE_INTERFACE_MAGIC);
810 iface->name = eina_stringshare_add(interface);
811 iface->methods = eina_hash_string_superfast_new(NULL);
812 iface->properties = eina_hash_string_superfast_new(_props_free);
813 iface->obj = obj;
814 eina_hash_add(obj->interfaces, iface->name, iface);
815
816 if (!obj->idler_iface_changed)
817 obj->idler_iface_changed = ecore_idler_add(_object_manager_changes_process,
818 obj);
819 obj->iface_added = eina_list_append(obj->iface_added, iface);
820
821 return iface;
822}
823
824static Eina_Bool
825_have_signature(const Eldbus_Arg_Info *args, Eldbus_Message *msg)
826{
827 const char *sig = dbus_message_get_signature(msg->dbus_msg);
828 const char *p = NULL;
829
830 for (; args && args->signature && *sig; args++)
831 {
832 p = args->signature;
833 for (; *sig && *p; sig++, p++)
834 {
835 if (*p != *sig)
836 return EINA_FALSE;
837 }
838 }
839
840 if (*sig || (p && *p) || (args && args->signature))
841 return EINA_FALSE;
842
843 return EINA_TRUE;
844}
845
846static Eina_Bool
847_eldbus_service_method_add(Eldbus_Service_Interface *interface,
848 const Eldbus_Method *method)
849{
850 EINA_SAFETY_ON_TRUE_RETURN_VAL(!!eina_hash_find(interface->methods,
851 method->member), EINA_FALSE);
852 EINA_SAFETY_ON_NULL_RETURN_VAL(method->member, EINA_FALSE);
853 EINA_SAFETY_ON_NULL_RETURN_VAL(method->cb, EINA_FALSE);
854
855 eina_hash_add(interface->methods, method->member, method);
856 return EINA_TRUE;
857}
858
859static Eina_Bool
860_eldbus_service_property_add(Eldbus_Service_Interface *interface,
861 const Eldbus_Property *property)
862{
863 Property *p;
864 EINA_SAFETY_ON_TRUE_RETURN_VAL(!!eina_hash_find(interface->properties,
865 property->name), EINA_FALSE);
866 EINA_SAFETY_ON_NULL_RETURN_VAL(property->type, EINA_FALSE);
867 EINA_SAFETY_ON_FALSE_RETURN_VAL(
868 dbus_signature_validate_single(property->type, NULL), EINA_FALSE);
869
870 p = calloc(1, sizeof(Property));
871 EINA_SAFETY_ON_NULL_RETURN_VAL(p, EINA_FALSE);
872 p->property = property;
873
874 return eina_hash_add(interface->properties, property->name, p);
875}
876
877/* Check if all signals in desc have valid signatures and return an Eina_Array
878 * with each of them. Return NULL if any of the signatures is invalid */
879static inline Eina_Array *
880_eldbus_service_interface_desc_signals_signatures_get(
881 const Eldbus_Service_Interface_Desc *desc)
882{
883 const Eldbus_Signal *sig;
884 Eina_Strbuf *buf = eina_strbuf_new();
885 Eina_Array *signatures = eina_array_new(1);
886
887 EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL);
888 EINA_SAFETY_ON_NULL_RETURN_VAL(signatures, NULL);
889
890 for (sig = desc->signals; sig && sig->name; sig++)
891 {
892 const Eldbus_Arg_Info *arg;
893
894 eina_strbuf_reset(buf);
895 for (arg = sig->args; arg && arg->signature; arg++)
896 eina_strbuf_append(buf, arg->signature);
897
898 if (!dbus_signature_validate(eina_strbuf_string_get(buf), NULL))
899 {
900 ERR("Signal with invalid signature: interface=%s signal=%s",
901 desc->interface, sig->name);
902 goto fail_signature;
903 }
904
905 eina_array_push(signatures,
906 eina_stringshare_add(eina_strbuf_string_get(buf)));
907 }
908 eina_strbuf_free(buf);
909
910 return signatures;
911
912fail_signature:
913 eina_strbuf_free(buf);
914 eina_array_free(signatures);
915 return NULL;
916}
917
918EAPI Eldbus_Service_Interface *
919eldbus_service_interface_register(Eldbus_Connection *conn, const char *path, const Eldbus_Service_Interface_Desc *desc)
920{
921 Eldbus_Service_Object *obj;
922 Eldbus_Service_Interface *iface;
923 const Eldbus_Method *method;
924 const Eldbus_Property *property;
925 Eina_Array *signatures;
926
927 EINA_SAFETY_ON_NULL_RETURN_VAL(conn, EINA_FALSE);
928 EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
929 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
930 EINA_SAFETY_ON_NULL_RETURN_VAL(desc->interface, EINA_FALSE);
931
932 if (!dbus_connection_get_object_path_data(conn->dbus_conn, path,
933 (void*)&obj))
934 {
935 ERR("Invalid object path");
936 return NULL;
937 }
938
939 signatures = _eldbus_service_interface_desc_signals_signatures_get(desc);
940 if (!signatures)
941 return NULL;
942
943 if (!obj)
944 obj = _eldbus_service_object_add(conn, path);
945 else
946 obj->introspection_dirty = EINA_TRUE;
947 EINA_SAFETY_ON_NULL_GOTO(obj, fail);
948
949 iface = _eldbus_service_interface_add(obj, desc->interface);
950 if (!iface)
951 goto fail;
952
953 for (method = desc->methods; method && method->member; method++)
954 _eldbus_service_method_add(iface, method);
955
956 iface->signals = desc->signals;
957 iface->sign_of_signals = signatures;
958
959 for (property = desc->properties; property && property->name; property++)
960 _eldbus_service_property_add(iface, property);
961
962 iface->get_func = desc->default_get;
963 iface->set_func = desc->default_set;
964
965 return iface;
966
967fail:
968 eina_array_free(signatures);
969
970 if (obj && (eina_hash_population(obj->interfaces) < 2))
971 _object_free(obj);
972
973 return NULL;
974}
975
976static void
977_interface_free(Eldbus_Service_Interface *interface)
978{
979 const char *sig;
980 Eldbus_Service_Object *obj;
981 Eina_List *l;
982
983 if (interface == introspectable || interface == properties_iface ||
984 interface == objmanager)
985 return;
986
987 eina_hash_free(interface->methods);
988 while ((sig = eina_array_pop(interface->sign_of_signals)))
989 eina_stringshare_del(sig);
990 eina_array_free(interface->sign_of_signals);
991 eina_hash_free(interface->properties);
992 if (interface->props_changed)
993 eina_array_free(interface->props_changed);
994 if (interface->idler_propschanged)
995 ecore_idler_del(interface->idler_propschanged);
996 if (interface->prop_invalidated)
997 eina_array_free(interface->prop_invalidated);
998
999 obj = interface->obj;
1000 l = eina_list_data_find_list(obj->iface_added, interface);
1001 if (l)
1002 {
1003 /* Adding and removing the interface in the same main loop iteration.
1004 * Let's not send any signal */
1005 obj->iface_added = eina_list_remove_list(obj->iface_added, l);
1006 if (!obj->iface_added && !obj->iface_removed && obj->idler_iface_changed)
1007 obj->idler_iface_changed = ecore_idler_del(obj->idler_iface_changed);
1008 }
1009 else
1010 {
1011 if (!obj->idler_iface_changed)
1012 {
1013 obj->idler_iface_changed = ecore_idler_add(
1014 _object_manager_changes_process, obj);
1015 }
1016
1017 obj->iface_removed = eina_list_append(
1018 obj->iface_removed, eina_stringshare_ref(interface->name));
1019 }
1020
1021 eina_stringshare_del(interface->name);
1022 free(interface);
1023}
1024
1025static void
1026_object_free(Eldbus_Service_Object *obj)
1027{
1028 Eina_Iterator *iterator;
1029 Eldbus_Service_Interface *iface;
1030
1031 /* Flush ObjectManager interface before the entire object goes away */
1032 if (obj->idler_iface_changed)
1033 ecore_idler_del(obj->idler_iface_changed);
1034 _object_manager_changes_process(obj);
1035
1036 iterator = eina_hash_iterator_data_new(obj->interfaces);
1037 EINA_ITERATOR_FOREACH(iterator, iface)
1038 _interface_free(iface);
1039
1040 while (obj->children)
1041 {
1042 Eldbus_Service_Object *child;
1043 child = EINA_INLIST_CONTAINER_GET(obj->children, Eldbus_Service_Object);
1044 obj->children = eina_inlist_remove(obj->children, obj->children);
1045 if (obj->parent)
1046 {
1047 obj->parent->children = eina_inlist_append(obj->parent->children,
1048 EINA_INLIST_GET(child));
1049 child->parent = obj->parent;
1050 }
1051 else
1052 {
1053 obj->conn->root_objs = eina_inlist_append(obj->conn->root_objs,
1054 EINA_INLIST_GET(child));
1055 child->parent = NULL;
1056 }
1057 }
1058 if (obj->parent)
1059 obj->parent->children = eina_inlist_remove(obj->parent->children,
1060 EINA_INLIST_GET(obj));
1061 else
1062 obj->conn->root_objs = eina_inlist_remove(obj->conn->root_objs,
1063 EINA_INLIST_GET(obj));
1064
1065 eldbus_data_del_all(&obj->data);
1066
1067 eina_hash_free(obj->interfaces);
1068 eina_iterator_free(iterator);
1069 if (obj->introspection_data)
1070 eina_strbuf_free(obj->introspection_data);
1071 eina_stringshare_del(obj->path);
1072 free(obj);
1073}
1074
1075static void
1076_on_connection_free(void *data, const void *dead_pointer EINA_UNUSED)
1077{
1078 Eldbus_Service_Object *obj = data;
1079 dbus_connection_unregister_object_path(obj->conn->dbus_conn, obj->path);
1080}
1081
1082EAPI void
1083eldbus_service_interface_unregister(Eldbus_Service_Interface *iface)
1084{
1085 ELDBUS_SERVICE_INTERFACE_CHECK(iface);
1086 if (!eina_hash_find(iface->obj->interfaces, objmanager->name))
1087 {
1088 //properties + introspectable + iface that user wants unregister
1089 if (eina_hash_population(iface->obj->interfaces) < 4)
1090 eldbus_service_object_unregister(iface);
1091 return;
1092 }
1093 eina_hash_del(iface->obj->interfaces, NULL, iface);
1094 iface->obj->introspection_dirty = EINA_TRUE;
1095 _interface_free(iface);
1096}
1097
1098EAPI void
1099eldbus_service_object_unregister(Eldbus_Service_Interface *iface)
1100{
1101 ELDBUS_SERVICE_INTERFACE_CHECK(iface);
1102 /*
1103 * It will be freed when _object_unregister() is called
1104 * by libdbus.
1105 */
1106 eldbus_connection_free_cb_del(iface->obj->conn, _on_connection_free, iface->obj);
1107 dbus_connection_unregister_object_path(iface->obj->conn->dbus_conn, iface->obj->path);
1108}
1109
1110static void
1111_object_unregister(DBusConnection *conn EINA_UNUSED, void *user_data)
1112{
1113 Eldbus_Service_Object *obj = user_data;
1114 _object_free(obj);
1115}
1116
1117static DBusHandlerResult
1118_object_handler(DBusConnection *conn EINA_UNUSED, DBusMessage *msg, void *user_data)
1119{
1120 Eldbus_Service_Object *obj;
1121 Eldbus_Service_Interface *iface;
1122 const Eldbus_Method *method;
1123 Eldbus_Message *eldbus_msg;
1124 Eldbus_Message *reply;
1125
1126 obj = user_data;
1127 if (!obj) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1128
1129 DBG("Connection@%p Got message:\n"
1130 " Type: %s\n"
1131 " Path: %s\n"
1132 " Interface: %s\n"
1133 " Member: %s\n"
1134 " Sender: %s", obj->conn,
1135 dbus_message_type_to_string(dbus_message_get_type(msg)),
1136 dbus_message_get_path(msg),
1137 dbus_message_get_interface(msg),
1138 dbus_message_get_member(msg),
1139 dbus_message_get_sender(msg));
1140
1141 iface = eina_hash_find(obj->interfaces, dbus_message_get_interface(msg));
1142 if (!iface) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1143
1144 method = eina_hash_find(iface->methods, dbus_message_get_member(msg));
1145 if (!method) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1146
1147 eldbus_msg = eldbus_message_new(EINA_FALSE);
1148 EINA_SAFETY_ON_NULL_RETURN_VAL(eldbus_msg, DBUS_HANDLER_RESULT_NEED_MEMORY);
1149 eldbus_msg->dbus_msg = msg;
1150 dbus_message_iter_init(eldbus_msg->dbus_msg, &eldbus_msg->iterator->dbus_iterator);
1151
1152 if (!_have_signature(method->in, eldbus_msg))
1153 {
1154 reply = eldbus_message_error_new(eldbus_msg,
1155 DBUS_ERROR_INVALID_SIGNATURE,
1156 "See introspectable to know the expected signature");
1157 }
1158 else
1159 {
1160 if (iface->obj)
1161 reply = method->cb(iface, eldbus_msg);
1162 else
1163 {
1164 //if iface does have obj it is some of FreeDesktop interfaces:
1165 //Introspectable, Properties...
1166 Eldbus_Service_Interface *cpy;
1167 cpy = calloc(1, sizeof(Eldbus_Service_Interface));
1168 if (!cpy)
1169 {
1170 dbus_message_ref(eldbus_msg->dbus_msg);
1171 eldbus_message_unref(eldbus_msg);
1172 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1173 }
1174 cpy->obj = obj;
1175 reply = method->cb(cpy, eldbus_msg);
1176 free(cpy);
1177 }
1178 }
1179
1180 dbus_message_ref(eldbus_msg->dbus_msg);
1181 eldbus_message_unref(eldbus_msg);
1182 if (!reply) return DBUS_HANDLER_RESULT_HANDLED;
1183
1184 _eldbus_connection_send(obj->conn, reply, NULL, NULL, -1);
1185
1186 return DBUS_HANDLER_RESULT_HANDLED;
1187}
1188
1189EAPI Eldbus_Connection *
1190eldbus_service_connection_get(const Eldbus_Service_Interface *iface)
1191{
1192 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
1193 return iface->obj->conn;
1194}
1195
1196EAPI const char *
1197eldbus_service_object_path_get(const Eldbus_Service_Interface *iface)
1198{
1199 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
1200 return iface->obj->path;
1201}
1202
1203EAPI Eldbus_Message *
1204eldbus_service_signal_new(const Eldbus_Service_Interface *iface, unsigned int signal_id)
1205{
1206 unsigned size;
1207 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1208 size = eina_array_count(iface->sign_of_signals);
1209 EINA_SAFETY_ON_FALSE_RETURN_VAL(signal_id < size, EINA_FALSE);
1210
1211 return eldbus_message_signal_new(iface->obj->path, iface->name,
1212 iface->signals[signal_id].name);
1213}
1214
1215EAPI Eina_Bool
1216eldbus_service_signal_emit(const Eldbus_Service_Interface *iface, unsigned int signal_id, ...)
1217{
1218 Eldbus_Message *sig;
1219 va_list ap;
1220 Eina_Bool r;
1221 const char *signature;
1222 unsigned size;
1223
1224 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1225 size = eina_array_count(iface->sign_of_signals);
1226 EINA_SAFETY_ON_FALSE_RETURN_VAL(signal_id < size, EINA_FALSE);
1227
1228 sig = eldbus_service_signal_new(iface, signal_id);
1229 EINA_SAFETY_ON_NULL_RETURN_VAL(sig, EINA_FALSE);
1230
1231 signature = eina_array_data_get(iface->sign_of_signals, signal_id);
1232 va_start(ap, signal_id);
1233 r = eldbus_message_arguments_vappend(sig, signature, ap);
1234 va_end(ap);
1235 EINA_SAFETY_ON_FALSE_RETURN_VAL(r, EINA_FALSE);
1236
1237 eldbus_service_signal_send(iface, sig);
1238 return EINA_TRUE;
1239}
1240
1241EAPI Eina_Bool
1242eldbus_service_signal_send(const Eldbus_Service_Interface *iface, Eldbus_Message *signal_msg)
1243{
1244 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1245 EINA_SAFETY_ON_NULL_RETURN_VAL(signal_msg, EINA_FALSE);
1246 _eldbus_connection_send(iface->obj->conn, signal_msg, NULL, NULL, -1);
1247 return EINA_TRUE;
1248}
1249
1250EAPI void
1251eldbus_service_object_data_set(Eldbus_Service_Interface *iface, const char *key, const void *data)
1252{
1253 ELDBUS_SERVICE_INTERFACE_CHECK(iface);
1254 EINA_SAFETY_ON_NULL_RETURN(key);
1255 EINA_SAFETY_ON_NULL_RETURN(data);
1256 eldbus_data_set(&(iface->obj->data), key, data);
1257}
1258
1259EAPI void *
1260eldbus_service_object_data_get(const Eldbus_Service_Interface *iface, const char *key)
1261{
1262 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
1263 EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
1264 return eldbus_data_get(&(((Eldbus_Service_Object *)iface->obj)->data), key);
1265}
1266
1267EAPI void *
1268eldbus_service_object_data_del(Eldbus_Service_Interface *iface, const char *key)
1269{
1270 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
1271 EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
1272 return eldbus_data_del(&(((Eldbus_Service_Object *)iface->obj)->data), key);
1273}
1274
1275static Eina_Bool
1276_idler_propschanged(void *data)
1277{
1278 Eldbus_Service_Interface *iface = data;
1279 Eldbus_Message *msg;
1280 Eldbus_Message_Iter *main_iter, *dict, *array_invalidate;
1281 Eina_Hash *added = NULL;
1282 Property *prop;
1283
1284 iface->idler_propschanged = NULL;
1285
1286 added = eina_hash_string_small_new(NULL);
1287 msg = eldbus_message_signal_new(iface->obj->path, properties_iface->name,
1288 properties_iface->signals[0].name);
1289 EINA_SAFETY_ON_NULL_GOTO(msg, error);
1290
1291 main_iter = eldbus_message_iter_get(msg);
1292 if (!eldbus_message_iter_arguments_append(main_iter, "sa{sv}", iface->name, &dict))
1293 {
1294 eldbus_message_unref(msg);
1295 goto error;
1296 }
1297
1298 if (!iface->props_changed)
1299 goto invalidate;
1300 while ((prop = eina_array_pop(iface->props_changed)))
1301 {
1302 Eldbus_Message_Iter *entry, *var;
1303 Eldbus_Message *error_reply = NULL;
1304 Eina_Bool ret;
1305 Eldbus_Property_Get_Cb getter = NULL;
1306
1307 if (eina_hash_find(added, prop->property->name))
1308 continue;
1309 eina_hash_add(added, prop->property->name, prop);
1310
1311 if (prop->property->get_func)
1312 getter = prop->property->get_func;
1313 else if (iface->get_func)
1314 getter = iface->get_func;
1315
1316 if (!getter || prop->is_invalidate)
1317 continue;
1318
1319 EINA_SAFETY_ON_FALSE_GOTO(
1320 eldbus_message_iter_arguments_append(dict, "{sv}", &entry), error);
1321
1322 eldbus_message_iter_basic_append(entry, 's', prop->property->name);
1323 var = eldbus_message_iter_container_new(entry, 'v',
1324 prop->property->type);
1325
1326 ret = getter(iface, prop->property->name, var, NULL, &error_reply);
1327 if (!ret)
1328 {
1329 eldbus_message_unref(msg);
1330 if (error_reply)
1331 {
1332 ERR("Error reply was set without pass any input message.");
1333 eldbus_message_unref(error_reply);
1334 }
1335 ERR("Getter of property %s returned error.", prop->property->name);
1336 goto error;
1337 }
1338
1339 eldbus_message_iter_container_close(entry, var);
1340 eldbus_message_iter_container_close(dict, entry);
1341 }
1342invalidate:
1343 eldbus_message_iter_container_close(main_iter, dict);
1344
1345 eldbus_message_iter_arguments_append(main_iter, "as", &array_invalidate);
1346
1347 if (!iface->prop_invalidated)
1348 goto end;
1349 while ((prop = eina_array_pop(iface->prop_invalidated)))
1350 {
1351 if (!prop->is_invalidate)
1352 continue;
1353 eldbus_message_iter_basic_append(array_invalidate, 's',
1354 prop->property->name);
1355 }
1356end:
1357 eldbus_message_iter_container_close(main_iter, array_invalidate);
1358
1359 eldbus_service_signal_send(iface, msg);
1360error:
1361 if (added)
1362 eina_hash_free(added);
1363 if (iface->props_changed)
1364 eina_array_flush(iface->props_changed);
1365 if (iface->prop_invalidated)
1366 eina_array_flush(iface->prop_invalidated);
1367 return ECORE_CALLBACK_CANCEL;
1368}
1369
1370EAPI Eina_Bool
1371eldbus_service_property_changed(const Eldbus_Service_Interface *interface, const char *name)
1372{
1373 Property *prop;
1374 Eldbus_Service_Interface *iface = (Eldbus_Service_Interface *)interface;
1375 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1376 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
1377
1378 prop = eina_hash_find(iface->properties, name);
1379 EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1380
1381 if (!iface->idler_propschanged)
1382 iface->idler_propschanged = ecore_idler_add(_idler_propschanged, iface);
1383 if (!iface->props_changed)
1384 iface->props_changed = eina_array_new(1);
1385
1386 return eina_array_push(iface->props_changed, prop);
1387}
1388
1389EAPI Eina_Bool
1390eldbus_service_property_invalidate_set(const Eldbus_Service_Interface *interface, const char *name, Eina_Bool is_invalidate)
1391{
1392 Property *prop;
1393 Eldbus_Service_Interface *iface = (Eldbus_Service_Interface *) interface;
1394
1395 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1396 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
1397
1398 prop = eina_hash_find(iface->properties, name);
1399 EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1400
1401 if (prop->is_invalidate == is_invalidate)
1402 return EINA_TRUE;
1403
1404 prop->is_invalidate = is_invalidate;
1405
1406 if (!iface->idler_propschanged)
1407 iface->idler_propschanged = ecore_idler_add(_idler_propschanged, iface);
1408
1409 if (is_invalidate)
1410 {
1411 if (!iface->props_changed)
1412 iface->props_changed = eina_array_new(1);
1413 return eina_array_push(iface->props_changed, prop);
1414 }
1415
1416 if (!iface->prop_invalidated)
1417 iface->prop_invalidated = eina_array_new(1);
1418 return eina_array_push(iface->prop_invalidated, prop);
1419}
1420
1421EAPI Eina_Bool
1422eldbus_service_object_manager_attach(Eldbus_Service_Interface *iface)
1423{
1424 Eldbus_Service_Object *obj;
1425 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1426
1427 obj = iface->obj;
1428
1429 /* We already have it and we registered it ourselves */
1430 if (obj->objmanager)
1431 return EINA_TRUE;
1432
1433 /* Ugh. User already registered the ObjectManager interface himself? */
1434 if (eina_hash_find(obj->interfaces, obj->objmanager->name))
1435 return EINA_FALSE;
1436
1437 if (!eina_hash_add(obj->interfaces, objmanager->name, objmanager))
1438 return EINA_FALSE;
1439
1440 /*
1441 * Flush the iface_added and iface_removed, otherwise it could be sent
1442 * with path equal to our path rather than from the previous
1443 * ObjectManager
1444 */
1445 if (obj->idler_iface_changed)
1446 ecore_idler_del(obj->idler_iface_changed);
1447 _object_manager_changes_process(obj);
1448
1449 obj->objmanager = objmanager;
1450 obj->introspection_dirty = EINA_TRUE;
1451 return EINA_TRUE;
1452}
1453
1454EAPI Eina_Bool
1455eldbus_service_object_manager_detach(Eldbus_Service_Interface *iface)
1456{
1457 Eldbus_Service_Object *obj;
1458 Eina_Bool ret;
1459
1460 ELDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
1461 obj = iface->obj;
1462
1463 /* Flush our iface_added/iface_removed before our ObjectManager goes away */
1464 if (obj->idler_iface_changed)
1465 ecore_idler_del(obj->idler_iface_changed);
1466 _object_manager_changes_process(obj);
1467
1468 ret = eina_hash_del(obj->interfaces, objmanager->name, NULL);
1469 obj->objmanager = NULL;
1470 obj->introspection_dirty = EINA_TRUE;
1471 //properties + introspectable
1472 if (eina_hash_population(iface->obj->interfaces) < 3)
1473 eldbus_service_object_unregister(iface);
1474 return ret;
1475}