004560ea51489267903c9c2975df6975ac44ede0
[platform/upstream/eldbus.git] / src / lib / edbus_object.c
1 #include "edbus_private.h"
2 #include "edbus_private_types.h"
3 #include <dbus/dbus.h>
4
5 /* TODO: mempool of EDBus_Object, Edbus_Object_Context_Event_Cb and
6  * EDBus_Object_Context_Event
7  */
8
9 #define EDBUS_OBJECT_CHECK(obj)                        \
10   do                                                   \
11     {                                                  \
12        EINA_SAFETY_ON_NULL_RETURN(obj);                \
13        if (!EINA_MAGIC_CHECK(obj, EDBUS_OBJECT_MAGIC)) \
14          {                                             \
15             EINA_MAGIC_FAIL(obj, EDBUS_OBJECT_MAGIC);  \
16             return;                                    \
17          }                                             \
18        EINA_SAFETY_ON_TRUE_RETURN(obj->refcount <= 0); \
19     }                                                  \
20   while (0)
21
22 #define EDBUS_OBJECT_CHECK_RETVAL(obj, retval)                     \
23   do                                                               \
24     {                                                              \
25        EINA_SAFETY_ON_NULL_RETURN_VAL(obj, retval);                \
26        if (!EINA_MAGIC_CHECK(obj, EDBUS_OBJECT_MAGIC))             \
27          {                                                         \
28             EINA_MAGIC_FAIL(obj, EDBUS_OBJECT_MAGIC);              \
29             return retval;                                         \
30          }                                                         \
31        EINA_SAFETY_ON_TRUE_RETURN_VAL(obj->refcount <= 0, retval); \
32     }                                                              \
33   while (0)
34
35 #define EDBUS_OBJECT_CHECK_GOTO(obj, label)                 \
36   do                                                        \
37     {                                                       \
38        EINA_SAFETY_ON_NULL_GOTO(obj, label);                \
39        if (!EINA_MAGIC_CHECK(obj, EDBUS_OBJECT_MAGIC))      \
40          {                                                  \
41             EINA_MAGIC_FAIL(obj, EDBUS_OBJECT_MAGIC);       \
42             goto label;                                     \
43          }                                                  \
44        EINA_SAFETY_ON_TRUE_GOTO(obj->refcount <= 0, label); \
45     }                                                       \
46   while (0)
47
48 Eina_Bool
49 edbus_object_init(void)
50 {
51    return EINA_TRUE;
52 }
53
54 void
55 edbus_object_shutdown(void)
56 {
57 }
58
59 static void _edbus_object_event_callback_call(EDBus_Object *obj, EDBus_Object_Event_Type type, const void *event_info);
60 static void _edbus_object_context_event_cb_del(EDBus_Object_Context_Event *ce, EDBus_Object_Context_Event_Cb *ctx);
61 static void _on_connection_free(void *data, const void *dead_pointer);
62 static void _on_signal_handler_free(void *data, const void *dead_pointer);
63
64 static void
65 _edbus_object_call_del(EDBus_Object *obj)
66 {
67    EDBus_Object_Context_Event *ce;
68
69    _edbus_object_event_callback_call(obj, EDBUS_OBJECT_EVENT_DEL, NULL);
70
71    /* clear all del callbacks so we don't call them twice at
72     * _edbus_object_clear()
73     */
74    ce = obj->event_handlers + EDBUS_OBJECT_EVENT_DEL;
75    while (ce->list)
76      {
77         EDBus_Object_Context_Event_Cb *ctx;
78
79         ctx = EINA_INLIST_CONTAINER_GET(ce->list,
80                                         EDBus_Object_Context_Event_Cb);
81         _edbus_object_context_event_cb_del(ce, ctx);
82      }
83 }
84
85 static void
86 _edbus_object_clear(EDBus_Object *obj)
87 {
88    EDBus_Signal_Handler *h;
89    EDBus_Pending *p;
90    Eina_List *iter, *iter_next;
91    Eina_Inlist *in_l;
92    DBG("obj=%p, refcount=%d, name=%s, path=%s",
93        obj, obj->refcount, obj->name, obj->path);
94
95    obj->refcount = 1;
96    _edbus_object_call_del(obj);
97    edbus_connection_name_object_del(obj->conn, obj);
98
99    /* NOTE: obj->proxies is deleted from obj->cbs_free. */
100
101    EINA_LIST_FOREACH_SAFE(obj->signal_handlers, iter, iter_next, h)
102      {
103         DBG("obj=%p delete owned signal handler %p %s",
104             obj, h, edbus_signal_handler_match_get(h));
105         edbus_signal_handler_del(h);
106      }
107    EINA_INLIST_FOREACH_SAFE(obj->pendings, in_l, p)
108      {
109         DBG("obj=%p delete owned pending call=%p dest=%s path=%s %s.%s()",
110             obj, p,
111             edbus_pending_destination_get(p),
112             edbus_pending_path_get(p),
113             edbus_pending_interface_get(p),
114             edbus_pending_method_get(p));
115         edbus_pending_cancel(p);
116      }
117
118    edbus_cbs_free_dispatch(&(obj->cbs_free), obj);
119    obj->refcount = 0;
120 }
121
122 static void
123 _edbus_object_free(EDBus_Object *obj)
124 {
125    unsigned int i;
126    EDBus_Signal_Handler *h;
127
128    if (obj->proxies)
129      {
130         Eina_Iterator *iterator = eina_hash_iterator_data_new(obj->proxies);
131         EDBus_Proxy *proxy;
132         EINA_ITERATOR_FOREACH(iterator, proxy)
133           ERR("obj=%p alive proxy=%p %s", obj, proxy,
134               edbus_proxy_interface_get(proxy));
135         eina_iterator_free(iterator);
136         eina_hash_free(obj->proxies);
137      }
138
139    EINA_LIST_FREE(obj->signal_handlers, h)
140      {
141         if (h->dangling)
142           edbus_signal_handler_cb_free_del(h, _on_signal_handler_free, obj);
143         else
144           ERR("obj=%p alive handler=%p %s", obj, h,
145               edbus_signal_handler_match_get(h));
146      }
147
148    if (obj->pendings)
149      CRITICAL("Object %p released with live pending calls!", obj);
150
151    for (i = 0; i < EDBUS_OBJECT_EVENT_LAST; i++)
152      {
153         EDBus_Object_Context_Event *ce = obj->event_handlers + i;
154         while (ce->list)
155           {
156              EDBus_Object_Context_Event_Cb *ctx;
157
158              ctx = EINA_INLIST_CONTAINER_GET(ce->list,
159                                              EDBus_Object_Context_Event_Cb);
160              _edbus_object_context_event_cb_del(ce, ctx);
161           }
162         eina_list_free(ce->to_delete);
163      }
164
165    if (obj->interfaces_added)
166      edbus_signal_handler_del(obj->interfaces_added);
167    if (obj->interfaces_removed)
168      edbus_signal_handler_del(obj->interfaces_removed);
169    if (obj->properties_changed)
170      edbus_signal_handler_del(obj->properties_changed);
171    eina_stringshare_del(obj->name);
172    eina_stringshare_del(obj->path);
173    EINA_MAGIC_SET(obj, EINA_MAGIC_NONE);
174
175    free(obj);
176 }
177
178 static void
179 _on_connection_free(void *data, const void *dead_pointer)
180 {
181    EDBus_Object *obj = data;
182    EDBUS_OBJECT_CHECK(obj);
183    _edbus_object_clear(obj);
184    _edbus_object_free(obj);
185 }
186
187 EAPI EDBus_Object *
188 edbus_object_get(EDBus_Connection *conn, const char *bus, const char *path)
189 {
190    EDBus_Object *obj;
191
192    EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
193    EINA_SAFETY_ON_NULL_RETURN_VAL(bus, NULL);
194    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
195
196    obj = edbus_connection_name_object_get(conn, bus, path);
197    if (obj)
198      return edbus_object_ref(obj);
199
200    obj = calloc(1, sizeof(EDBus_Object));
201    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
202
203    obj->conn = conn;
204    obj->refcount = 1;
205    obj->path = eina_stringshare_add(path);
206    obj->name = eina_stringshare_add(bus);
207    obj->proxies = eina_hash_string_small_new(NULL);
208    EINA_SAFETY_ON_NULL_GOTO(obj->proxies, cleanup);
209    EINA_MAGIC_SET(obj, EDBUS_OBJECT_MAGIC);
210
211    edbus_connection_name_object_set(conn, obj);
212    edbus_connection_cb_free_add(obj->conn, _on_connection_free, obj);
213
214    obj->properties = edbus_proxy_get(obj, EDBUS_FDO_INTERFACE_PROPERTIES);
215
216    return obj;
217
218 cleanup:
219    eina_stringshare_del(obj->path);
220    eina_stringshare_del(obj->name);
221    free(obj);
222
223    return NULL;
224 }
225
226 static void _on_signal_handler_free(void *data, const void *dead_pointer);
227
228 static void
229 _edbus_object_unref(EDBus_Object *obj)
230 {
231    obj->refcount--;
232    if (obj->refcount > 0) return;
233
234    edbus_connection_cb_free_del(obj->conn, _on_connection_free, obj);
235    _edbus_object_clear(obj);
236    _edbus_object_free(obj);
237 }
238
239 EAPI EDBus_Object *
240 edbus_object_ref(EDBus_Object *obj)
241 {
242    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
243    DBG("obj=%p, pre-refcount=%d, name=%s, path=%s",
244        obj, obj->refcount, obj->name, obj->path);
245    obj->refcount++;
246    return obj;
247 }
248
249 EAPI void
250 edbus_object_unref(EDBus_Object *obj)
251 {
252    EDBUS_OBJECT_CHECK(obj);
253    DBG("obj=%p, pre-refcount=%d, name=%s, path=%s",
254        obj, obj->refcount, obj->name, obj->path);
255    _edbus_object_unref(obj);
256 }
257
258 EAPI void
259 edbus_object_cb_free_add(EDBus_Object *obj, EDBus_Free_Cb cb, const void *data)
260 {
261    EDBUS_OBJECT_CHECK(obj);
262    EINA_SAFETY_ON_NULL_RETURN(cb);
263    obj->cbs_free = edbus_cbs_free_add(obj->cbs_free, cb, data);
264 }
265
266 EAPI void
267 edbus_object_cb_free_del(EDBus_Object *obj, EDBus_Free_Cb cb, const void *data)
268 {
269    EDBUS_OBJECT_CHECK(obj);
270    EINA_SAFETY_ON_NULL_RETURN(cb);
271    obj->cbs_free = edbus_cbs_free_del(obj->cbs_free, cb, data);
272 }
273
274 static void
275 _cb_interfaces_added(void *data, const EDBus_Message *msg)
276 {
277    EDBus_Object *obj = data;
278    const char *obj_path;
279    EDBus_Message_Iter *array_ifaces, *entry_iface;
280
281    if (!edbus_message_arguments_get(msg, "oa{sa{sv}}", &obj_path, &array_ifaces))
282      return;
283
284    while (edbus_message_iter_get_and_next(array_ifaces, 'e', &entry_iface))
285      {
286         const char *iface_name;
287         EDBus_Object_Event_Interface_Added event;
288         EDBus_Proxy *proxy;
289
290         edbus_message_iter_basic_get(entry_iface, &iface_name);
291         proxy = edbus_proxy_get(obj, iface_name);
292         EINA_SAFETY_ON_NULL_RETURN(proxy);
293         event.interface = iface_name;
294         event.proxy = proxy;
295         _edbus_object_event_callback_call(obj, EDBUS_OBJECT_EVENT_IFACE_ADDED,
296                                           &event);
297      }
298 }
299
300 static void
301 _cb_interfaces_removed(void *data, const EDBus_Message *msg)
302 {
303    EDBus_Object *obj = data;
304    const char *obj_path, *iface;
305    EDBus_Message_Iter *array_ifaces;
306
307    if (!edbus_message_arguments_get(msg, "oas", &obj_path, &array_ifaces))
308      return;
309
310    while (edbus_message_iter_get_and_next(array_ifaces, 's', &iface))
311      {
312         EDBus_Object_Event_Interface_Removed event;
313         event.interface = iface;
314         _edbus_object_event_callback_call(obj, EDBUS_OBJECT_EVENT_IFACE_REMOVED,
315                                           &event);
316      }
317 }
318
319 static void
320 _property_changed_iter(void *data, const void *key, EDBus_Message_Iter *var)
321 {
322    EDBus_Proxy *proxy = data;
323    const char *skey = key;
324    Eina_Value *st_value, stack_value;
325    EDBus_Object_Event_Property_Changed event;
326
327    st_value = _message_iter_struct_to_eina_value(var);
328    eina_value_struct_value_get(st_value, "arg0", &stack_value);
329
330    event.interface = edbus_proxy_interface_get(proxy);
331    event.proxy = proxy;
332    event.name = skey;
333    event.value = &stack_value;
334    _edbus_object_event_callback_call(edbus_proxy_object_get(proxy),
335                                      EDBUS_OBJECT_EVENT_PROPERTY_CHANGED,
336                                      &event);
337    eina_value_free(st_value);
338    eina_value_flush(&stack_value);
339 }
340
341 static void
342 _cb_properties_changed(void *data, const EDBus_Message *msg)
343 {
344    EDBus_Object *obj = data;
345    EDBus_Proxy *proxy;
346    EDBus_Message_Iter *array, *invalidate;
347    const char *iface;
348    const char *invalidate_prop;
349
350    if (!edbus_message_arguments_get(msg, "sa{sv}as", &iface, &array, &invalidate))
351      {
352         ERR("Error getting data from properties changed signal.");
353         return;
354      }
355
356    proxy = edbus_proxy_get(obj, iface);
357    EINA_SAFETY_ON_NULL_RETURN(proxy);
358
359    if (obj->event_handlers[EDBUS_OBJECT_EVENT_PROPERTY_CHANGED].list)
360      edbus_message_iter_dict_iterate(array, "sv", _property_changed_iter,
361                                      proxy);
362
363    if (!obj->event_handlers[EDBUS_OBJECT_EVENT_PROPERTY_REMOVED].list)
364      return;
365
366    while (edbus_message_iter_get_and_next(invalidate, 's', &invalidate_prop))
367      {
368         EDBus_Object_Event_Property_Removed event;
369         event.interface = iface;
370         event.name = invalidate_prop;
371         event.proxy = proxy;
372         _edbus_object_event_callback_call(obj,
373                                           EDBUS_OBJECT_EVENT_PROPERTY_REMOVED,
374                                           &event);
375      }
376 }
377
378 EAPI void
379 edbus_object_event_callback_add(EDBus_Object *obj, EDBus_Object_Event_Type type, EDBus_Object_Event_Cb cb, const void *cb_data)
380 {
381    EDBus_Object_Context_Event *ce;
382    EDBus_Object_Context_Event_Cb *ctx;
383
384    EDBUS_OBJECT_CHECK(obj);
385    EINA_SAFETY_ON_NULL_RETURN(cb);
386    EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_OBJECT_EVENT_LAST);
387
388    ce = obj->event_handlers + type;
389
390    ctx = calloc(1, sizeof(EDBus_Object_Context_Event_Cb));
391    EINA_SAFETY_ON_NULL_RETURN(ctx);
392
393    ctx->cb = cb;
394    ctx->cb_data = cb_data;
395
396    ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
397
398    switch (type)
399      {
400       case EDBUS_OBJECT_EVENT_IFACE_ADDED:
401          {
402             if (obj->interfaces_added)
403               break;
404             obj->interfaces_added =
405                      _edbus_signal_handler_add(obj->conn, obj->name, NULL,
406                                                EDBUS_FDO_INTERFACE_OBJECT_MANAGER,
407                                                "InterfacesAdded",
408                                                _cb_interfaces_added, obj);
409             EINA_SAFETY_ON_NULL_RETURN(obj->interfaces_added);
410             edbus_signal_handler_match_extra_set(obj->interfaces_added, "arg0",
411                                                  obj->path, NULL);
412             break;
413          }
414       case EDBUS_OBJECT_EVENT_IFACE_REMOVED:
415         {
416            if (obj->interfaces_removed)
417              break;
418            obj->interfaces_removed =
419                     _edbus_signal_handler_add(obj->conn, obj->name, NULL,
420                                               EDBUS_FDO_INTERFACE_OBJECT_MANAGER,
421                                               "InterfacesRemoved",
422                                               _cb_interfaces_removed, obj);
423            EINA_SAFETY_ON_NULL_RETURN(obj->interfaces_added);
424            edbus_signal_handler_match_extra_set(obj->interfaces_removed,
425                                                 "arg0", obj->path, NULL);
426            break;
427         }
428       case EDBUS_OBJECT_EVENT_PROPERTY_CHANGED:
429       case EDBUS_OBJECT_EVENT_PROPERTY_REMOVED:
430         {
431            if (obj->properties_changed)
432              break;
433            obj->properties_changed =
434                     edbus_object_signal_handler_add(obj,
435                                                     EDBUS_FDO_INTERFACE_PROPERTIES,
436                                                     "PropertiesChanged",
437                                                     _cb_properties_changed, obj);
438            EINA_SAFETY_ON_NULL_RETURN(obj->properties_changed);
439            break;
440         }
441       default:
442         break;
443      }
444 }
445
446 static void
447 _edbus_object_context_event_cb_del(EDBus_Object_Context_Event *ce, EDBus_Object_Context_Event_Cb *ctx)
448 {
449    ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx));
450    free(ctx);
451 }
452
453 EAPI void
454 edbus_object_event_callback_del(EDBus_Object *obj, EDBus_Object_Event_Type type, EDBus_Object_Event_Cb cb, const void *cb_data)
455 {
456    EDBus_Object_Context_Event *ce;
457    EDBus_Object_Context_Event_Cb *iter, *found = NULL;
458
459    EDBUS_OBJECT_CHECK(obj);
460    EINA_SAFETY_ON_NULL_RETURN(cb);
461    EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_OBJECT_EVENT_LAST);
462
463    ce = obj->event_handlers + type;
464
465    EINA_INLIST_FOREACH(ce->list, iter)
466      {
467         if (cb != iter->cb) continue;
468         if ((cb_data) && (cb_data != iter->cb_data)) continue;
469
470         found = iter;
471         break;
472      }
473
474    EINA_SAFETY_ON_NULL_RETURN(found);
475    EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
476
477    if (ce->walking)
478      {
479         found->deleted = EINA_TRUE;
480         ce->to_delete = eina_list_append(ce->to_delete, found);
481         return;
482      }
483
484    _edbus_object_context_event_cb_del(ce, found);
485
486    switch (type)
487      {
488       case EDBUS_OBJECT_EVENT_IFACE_ADDED:
489          {
490             if (obj->event_handlers[EDBUS_OBJECT_EVENT_IFACE_ADDED].list)
491               break;
492             edbus_signal_handler_del(obj->interfaces_added);
493             obj->interfaces_added = NULL;
494             break;
495          }
496       case EDBUS_OBJECT_EVENT_IFACE_REMOVED:
497         {
498            if (obj->event_handlers[EDBUS_OBJECT_EVENT_IFACE_REMOVED].list)
499              break;
500            edbus_signal_handler_del(obj->interfaces_removed);
501            obj->interfaces_removed = NULL;
502            break;
503         }
504       case EDBUS_OBJECT_EVENT_PROPERTY_CHANGED:
505       case EDBUS_OBJECT_EVENT_PROPERTY_REMOVED:
506         {
507            if (obj->event_handlers[EDBUS_OBJECT_EVENT_PROPERTY_CHANGED].list ||
508                obj->event_handlers[EDBUS_OBJECT_EVENT_PROPERTY_REMOVED].list)
509              break;
510            edbus_signal_handler_del(obj->properties_changed);
511            obj->properties_changed = NULL;
512            break;
513         }
514       default:
515         break;
516      }
517 }
518
519 static void
520 _edbus_object_event_callback_call(EDBus_Object *obj, EDBus_Object_Event_Type type, const void *event_info)
521 {
522    EDBus_Object_Context_Event *ce;
523    EDBus_Object_Context_Event_Cb *iter;
524
525    ce = obj->event_handlers + type;
526
527    ce->walking++;
528    EINA_INLIST_FOREACH(ce->list, iter)
529      {
530         if (iter->deleted) continue;
531         iter->cb((void *)iter->cb_data, obj, (void *)event_info);
532      }
533    ce->walking--;
534    if (ce->walking > 0) return;
535
536    EINA_LIST_FREE(ce->to_delete, iter)
537      _edbus_object_context_event_cb_del(ce, iter);
538 }
539
540 EAPI EDBus_Connection *
541 edbus_object_connection_get(const EDBus_Object *obj)
542 {
543    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
544    return obj->conn;
545 }
546
547 EAPI const char *
548 edbus_object_bus_name_get(const EDBus_Object *obj)
549 {
550    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
551    return obj->name;
552 }
553
554 EAPI const char *
555 edbus_object_path_get(const EDBus_Object *obj)
556 {
557    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
558    return obj->path;
559 }
560
561 static void
562 _on_pending_free(void *data, const void *dead_pointer)
563 {
564    EDBus_Object *obj = data;
565    EDBus_Pending *pending = (EDBus_Pending*) dead_pointer;
566    EDBUS_OBJECT_CHECK(obj);
567    obj->pendings = eina_inlist_remove(obj->pendings, EINA_INLIST_GET(pending));
568 }
569
570 EAPI EDBus_Pending *
571 edbus_object_send(EDBus_Object *obj, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout)
572 {
573    EDBus_Pending *pending;
574
575    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
576    EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
577
578    pending = _edbus_connection_send(obj->conn, msg, cb, cb_data, timeout);
579    if (!cb) return NULL;
580    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
581
582    edbus_pending_cb_free_add(pending, _on_pending_free, obj);
583    obj->pendings = eina_inlist_append(obj->pendings, EINA_INLIST_GET(pending));
584
585    return pending;
586 }
587
588 static void
589 _on_signal_handler_free(void *data, const void *dead_pointer)
590 {
591    EDBus_Object *obj = data;
592    EDBUS_OBJECT_CHECK(obj);
593    obj->signal_handlers = eina_list_remove(obj->signal_handlers, dead_pointer);
594 }
595
596 EAPI EDBus_Signal_Handler *
597 edbus_object_signal_handler_add(EDBus_Object *obj, const char *interface, const char *member, EDBus_Signal_Cb cb, const void *cb_data)
598 {
599    EDBus_Signal_Handler *handler;
600
601    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
602    EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
603
604    handler = _edbus_signal_handler_add(obj->conn, obj->name, obj->path,
605                                        interface, member, cb, cb_data);
606    EINA_SAFETY_ON_NULL_RETURN_VAL(handler, NULL);
607
608    edbus_signal_handler_cb_free_add(handler, _on_signal_handler_free, obj);
609    obj->signal_handlers = eina_list_append(obj->signal_handlers, handler);
610
611    return handler;
612 }
613
614 EAPI EDBus_Message *
615 edbus_object_method_call_new(EDBus_Object *obj, const char *interface, const char *member)
616 {
617    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
618    EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
619    EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL);
620
621    return edbus_message_method_call_new(obj->name, obj->path, interface, member);
622 }
623
624 Eina_Bool
625 edbus_object_proxy_add(EDBus_Object *obj, EDBus_Proxy *proxy)
626 {
627    return eina_hash_add(obj->proxies, edbus_proxy_interface_get(proxy), proxy);
628 }
629
630 EDBus_Proxy *
631 edbus_object_proxy_get(EDBus_Object *obj, const char *interface)
632 {
633    return eina_hash_find(obj->proxies, interface);
634 }
635
636 Eina_Bool
637 edbus_object_proxy_del(EDBus_Object *obj, EDBus_Proxy *proxy, const char *interface)
638 {
639    return eina_hash_del(obj->proxies, interface, proxy);
640 }
641
642 static EDBus_Proxy *
643 get_peer_proxy(EDBus_Object *obj)
644 {
645    return edbus_proxy_get(obj, "org.freedesktop.DBus.Peer");
646 }
647
648 EAPI EDBus_Pending *
649 edbus_object_peer_ping(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data)
650 {
651    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
652    return edbus_proxy_call(get_peer_proxy(obj), "Ping", cb,
653                            data, -1, "");
654 }
655
656 EAPI EDBus_Pending *
657 edbus_object_peer_machine_id_get(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data)
658 {
659    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
660    return edbus_proxy_call(get_peer_proxy(obj), "GetMachineId", cb,
661                            data, -1, "");
662 }
663
664 EAPI EDBus_Pending *
665 edbus_object_introspect(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data)
666 {
667    EDBus_Proxy *introspectable;
668    EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
669
670    introspectable = edbus_proxy_get(obj, EDBUS_FDO_INTERFACE_INTROSPECTABLE);
671    return edbus_proxy_call(introspectable, "Introspect", cb, data, -1, "");
672 }