edbus: Add edbus_service_object_manager_attach/detach
authorJosé Roberto de Souza <zehortigoza@profusion.mobi>
Fri, 16 Nov 2012 13:07:14 +0000 (13:07 +0000)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Fri, 16 Nov 2012 13:07:14 +0000 (13:07 +0000)
Patch by: José Roberto de Souza  <zehortigoza@profusion.mobi>

SVN revision: 79382

legacy/edbus/src/lib/EDBus.h
legacy/edbus/src/lib/edbus_private_types.h
legacy/edbus/src/lib/edbus_service.c
legacy/edbus/src/lib/edbus_service.h

index 784139c..820bc31 100644 (file)
@@ -46,6 +46,7 @@ extern "C" {
 #define EDBUS_FDO_PATH "/org/freedesktop/DBus"
 #define EDBUS_FDO_INTERFACE EDBUS_FDO_BUS
 #define EDBUS_FDO_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+#define EDBUS_FDO_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
 
 typedef struct _EDBus_Version
 {
index e899743..be2725e 100644 (file)
@@ -145,6 +145,11 @@ struct _EDBus_Service_Object
    Eina_Inlist *data;
    EDBus_Service_Object *parent;
    Eina_Inlist *children;
+   //ObjectManager data
+   Eina_Bool has_objectmanager:1;
+   Eina_List *iface_added;
+   Eina_List *iface_removed;
+   Ecore_Idler *idler_iface_changed;
 };
 
 struct _EDBus_Service_Interface
index 54f21b2..3cfff24 100644 (file)
@@ -64,6 +64,7 @@ static DBusObjectPathVTable vtable = {
 
 EDBus_Service_Interface *introspectable;
 EDBus_Service_Interface *properties_iface;
+EDBus_Service_Interface *objmanager;
 
 static inline void
 _introspect_arguments_append(Eina_Strbuf *buf, const EDBus_Arg_Info *args,
@@ -232,6 +233,41 @@ not_found:
                                   "Property not found.");
 }
 
+static Eina_Bool
+_props_getall(EDBus_Service_Interface *iface, Eina_Iterator *iterator, EDBus_Message_Iter *dict, const EDBus_Message *input_msg, EDBus_Message **error_reply)
+{
+   Property *prop;
+   EINA_ITERATOR_FOREACH(iterator, prop)
+     {
+        EDBus_Message_Iter *entry, *var;
+        Eina_Bool ret;
+        EDBus_Property_Get_Cb getter = NULL;
+
+        if (prop->property->get_func)
+          getter = prop->property->get_func;
+        else if (iface->get_func)
+          getter = iface->get_func;
+
+        if (!getter || prop->is_invalidate)
+          continue;
+
+        if (!edbus_message_iter_arguments_set(dict, "{sv}", &entry))
+          continue;
+
+        edbus_message_iter_basic_append(entry, 's', prop->property->name);
+        var = edbus_message_iter_container_new(entry, 'v',
+                                               prop->property->type);
+
+        ret = getter(iface, prop->property->name, var, input_msg, error_reply);
+        if (!ret)
+          return EINA_FALSE;
+
+        edbus_message_iter_container_close(entry, var);
+        edbus_message_iter_container_close(dict, entry);
+     }
+   return EINA_TRUE;
+}
+
 static EDBus_Message *
 _cb_property_getall(const EDBus_Service_Interface *piface, const EDBus_Message *msg)
 {
@@ -239,7 +275,6 @@ _cb_property_getall(const EDBus_Service_Interface *piface, const EDBus_Message *
    EDBus_Service_Object *obj = piface->obj;
    EDBus_Service_Interface *iface;
    Eina_Iterator *iterator;
-   Property *prop;
    EDBus_Message *reply, *error_reply;
    EDBus_Message_Iter *main_iter, *dict;
 
@@ -261,42 +296,14 @@ _cb_property_getall(const EDBus_Service_Interface *piface, const EDBus_Message *
      }
 
    iterator = eina_hash_iterator_data_new(iface->properties);
-   EINA_ITERATOR_FOREACH(iterator, prop)
+   if (!_props_getall(iface, iterator, dict, msg, &error_reply))
      {
-        EDBus_Message_Iter *entry, *var;
-        Eina_Bool ret;
-        EDBus_Property_Get_Cb getter = NULL;
-
-        if (prop->property->get_func)
-          getter = prop->property->get_func;
-        else if (iface->get_func)
-          getter = iface->get_func;
-
-        if (!getter || prop->is_invalidate)
-          continue;
-
-        if (!edbus_message_iter_arguments_set(dict, "{sv}", &entry))
-          continue;
-
-        edbus_message_iter_basic_append(entry, 's', prop->property->name);
-        var = edbus_message_iter_container_new(entry, 'v',
-                                               prop->property->type);
-
-        ret = getter(iface, prop->property->name, var, msg, &error_reply);
-
-        if (!ret)
-          {
-             edbus_message_unref(reply);
-             reply = error_reply;
-             goto end;
-          }
-
-        edbus_message_iter_container_close(entry, var);
-        edbus_message_iter_container_close(dict, entry);
+        edbus_message_unref(reply);
+        eina_iterator_free(iterator);
+        return error_reply;
      }
    edbus_message_iter_container_close(main_iter, dict);
 
-end:
    eina_iterator_free(iterator);
    return reply;
 }
@@ -420,6 +427,11 @@ _default_interfaces_free(void)
    eina_hash_free(properties_iface->properties);
    eina_array_free(properties_iface->sign_of_signals);
    free(properties_iface);
+
+   eina_hash_free(objmanager->methods);
+   eina_hash_free(objmanager->properties);
+   eina_array_free(objmanager->sign_of_signals);
+   free(objmanager);
 }
 
 static const EDBus_Method _property_methods[] = {
@@ -467,6 +479,125 @@ _properties_create(void)
    eina_array_push(properties_iface->sign_of_signals, "sa{sv}as");
 }
 
+static Eina_Bool
+_propmgr_iface_props_append(EDBus_Service_Interface *iface, EDBus_Message_Iter *array)
+{
+   EDBus_Message_Iter *iface_entry, *props_array;
+   Eina_Iterator *iterator;
+   EDBus_Message *error_msg;
+
+   edbus_message_iter_arguments_set(array, "{sa{sv}}", &iface_entry);
+
+   edbus_message_iter_arguments_set(iface_entry, "sa{sv}", iface->name, &props_array);
+   iterator = eina_hash_iterator_data_new(iface->properties);
+   if (!_props_getall(iface, iterator, props_array, NULL, &error_msg))
+     {
+        ERR("Error reply was set without pass any input message.");
+        edbus_message_unref(error_msg);
+        eina_iterator_free(iterator);
+        return EINA_FALSE;
+     }
+   eina_iterator_free(iterator);
+   edbus_message_iter_container_close(iface_entry, props_array);
+   edbus_message_iter_container_close(array, iface_entry);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_managed_obj_append(EDBus_Service_Object *obj, EDBus_Message_Iter *array, Eina_Bool first)
+{
+   EDBus_Message_Iter *obj_entry, *array_interface;
+   Eina_Iterator *iface_iter;
+   EDBus_Service_Interface *children_iface;
+   EDBus_Service_Object *children;
+
+   if (first) goto foreach;
+   if (obj->has_objectmanager) return EINA_TRUE;
+
+   edbus_message_iter_arguments_set(array, "{oa{sa{sv}}}", &obj_entry);
+   edbus_message_iter_arguments_set(obj_entry, "oa{sa{sv}}", obj->path,
+                                    &array_interface);
+   iface_iter = eina_hash_iterator_data_new(obj->interfaces);
+   EINA_ITERATOR_FOREACH(iface_iter, children_iface)
+     {
+        Eina_Bool ret;
+        ret = _propmgr_iface_props_append(children_iface, array_interface);
+        if (ret) continue;
+
+        eina_iterator_free(iface_iter);
+        return EINA_FALSE;
+     }
+   eina_iterator_free(iface_iter);
+   edbus_message_iter_container_close(obj_entry, array_interface);
+   edbus_message_iter_container_close(array, obj_entry);
+
+foreach:
+   EINA_INLIST_FOREACH(obj->children, children)
+     {
+        Eina_Bool ret;
+        ret = _managed_obj_append(children, array, EINA_FALSE);
+        if (!ret) return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+static EDBus_Message *
+_cb_managed_objects(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   EDBus_Message_Iter *array_path, *main_iter;
+   Eina_Bool ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(reply, NULL);
+   main_iter =  edbus_message_iter_get(reply);
+   edbus_message_iter_arguments_set(main_iter, "a{oa{sa{sv}}}", &array_path);
+
+   ret = _managed_obj_append(iface->obj, array_path, EINA_TRUE);
+   if (!ret)
+     {
+        edbus_message_unref(reply);
+        return edbus_message_error_new(msg, "org.freedesktop.DBus.Error",
+                                       "Irrecoverable error happen");
+     }
+
+   edbus_message_iter_container_close(main_iter, array_path);
+   return reply;
+}
+
+static EDBus_Method get_managed_objects = {
+   "GetManagedObjects", NULL, EDBUS_ARGS({"a{oa{sa{sv}}}", "objects"}),
+   _cb_managed_objects
+};
+
+static const EDBus_Signal _object_manager_signals[] = {
+   {
+    "InterfacesAdded", EDBUS_ARGS({"o", "object"}, {"a{sa{sv}}", "interfaces"})
+   },
+   {
+    "InterfacesRemoved", EDBUS_ARGS({"o", "object"}, {"as", "interfaces"})
+   }
+};
+
+static void
+_object_manager_create(void)
+{
+   objmanager = calloc(1, sizeof(EDBus_Service_Interface));
+   if (!objmanager) return;
+
+   EINA_MAGIC_SET(objmanager, EDBUS_SERVICE_INTERFACE_MAGIC);
+   objmanager->sign_of_signals = eina_array_new(1);
+   objmanager->properties = eina_hash_string_small_new(NULL);
+   objmanager->name = EDBUS_FDO_INTERFACE_OBJECT_MANAGER;
+   objmanager->methods = eina_hash_string_small_new(NULL);
+
+   eina_hash_add(objmanager->methods, get_managed_objects.member,
+                 &get_managed_objects);
+
+   objmanager->signals = _object_manager_signals;
+   eina_array_push(objmanager->sign_of_signals, "oa{sa{sv}}");
+   eina_array_push(objmanager->sign_of_signals, "oas");
+}
+
 Eina_Bool
 edbus_service_init(void)
 {
@@ -474,6 +605,8 @@ edbus_service_init(void)
    EINA_SAFETY_ON_NULL_RETURN_VAL(introspectable, EINA_FALSE);
    _properties_create();
    EINA_SAFETY_ON_NULL_RETURN_VAL(properties_iface, EINA_FALSE);
+   _object_manager_create();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(objmanager, EINA_FALSE);
 
    return EINA_TRUE;
 }
@@ -538,7 +671,7 @@ _edbus_service_object_add(EDBus_Connection *conn, const char *path)
    if (obj->parent)
      {
         obj->parent->children = eina_inlist_append(obj->parent->children,
-                                                    EINA_INLIST_GET(obj));
+                                                   EINA_INLIST_GET(obj));
         return obj;
      }
 
@@ -573,10 +706,118 @@ _props_free(void *data)
    free(p);
 }
 
+struct iface_remove_data {
+   const char *obj_path;
+   const char *iface;
+};
+
+static Eina_Bool
+_iface_changed_send(void *data)
+{
+   EDBus_Service_Object *parent = data;
+
+   while (parent->iface_added)
+     {
+        EDBus_Service_Interface *iface, *next_iface;
+        EDBus_Message *msg;
+        EDBus_Message_Iter *array_iface, *main_iter;
+        Eina_List *l, *l2;
+
+        iface = eina_list_data_get(parent->iface_added);
+        parent->iface_added = eina_list_remove_list(parent->iface_added,
+                                                    parent->iface_added);
+
+        msg = edbus_message_signal_new(parent->path,
+                                       EDBUS_FDO_INTERFACE_OBJECT_MANAGER,
+                                       "InterfacesAdded");
+        if (!msg)
+          {
+             ERR("msg == NULL");
+             continue;
+          }
+        main_iter = edbus_message_iter_get(msg);
+        edbus_message_iter_arguments_set(main_iter, "oa{sa{sv}}",
+                                         iface->obj->path, &array_iface);
+        if (!_propmgr_iface_props_append(iface, array_iface))
+          goto error;
+        EINA_LIST_FOREACH_SAFE(parent->iface_added, l, l2, next_iface)
+          {
+             if (iface->obj->path != next_iface->obj->path)
+               continue;
+             parent->iface_added = eina_list_remove(parent->iface_added,
+                                                    next_iface);
+             if (!_propmgr_iface_props_append(next_iface, array_iface))
+               goto error;
+          }
+
+        edbus_message_iter_container_close(main_iter, array_iface);
+        edbus_connection_send(parent->conn, msg, NULL, NULL, -1);
+        continue;
+error:
+        ERR("Error appending InterfacesAdded to msg.");
+        edbus_message_unref(msg);
+     }
+
+   while (parent->iface_removed)
+     {
+        EDBus_Message *msg;
+        EDBus_Message_Iter *array_iface, *main_iter;
+        struct iface_remove_data *iface_data, *iface_data_next;
+        Eina_List *l, *l2;
+
+        iface_data = eina_list_data_get(parent->iface_removed);
+        parent->iface_removed = eina_list_remove_list(parent->iface_removed,
+                                                      parent->iface_removed);
+
+        msg = edbus_message_signal_new(parent->path,
+                                       EDBUS_FDO_INTERFACE_OBJECT_MANAGER,
+                                       "InterfacesRemoved");
+        EINA_SAFETY_ON_NULL_GOTO(msg, error2);
+        main_iter = edbus_message_iter_get(msg);
+
+        edbus_message_iter_arguments_set(main_iter, "oas", iface_data->obj_path,
+                                         &array_iface);
+        edbus_message_iter_basic_append(array_iface, 's', iface_data->iface);
+
+        EINA_LIST_FOREACH_SAFE(parent->iface_removed, l, l2, iface_data_next)
+          {
+             if (iface_data->obj_path != iface_data_next->obj_path)
+               continue;
+             parent->iface_removed = eina_list_remove(parent->iface_removed,
+                                                      iface_data_next);
+             edbus_message_iter_basic_append(array_iface, 's',
+                                             iface_data_next->iface);
+             eina_stringshare_del(iface_data_next->iface);
+             eina_stringshare_del(iface_data_next->obj_path);
+             free(iface_data_next);
+          }
+        edbus_message_iter_container_close(main_iter, array_iface);
+        edbus_connection_send(parent->conn, msg, NULL, NULL, -1);
+error2:
+        eina_stringshare_del(iface_data->iface);
+        eina_stringshare_del(iface_data->obj_path);
+        free(iface_data);
+     }
+
+   parent->idler_iface_changed = NULL;
+   return EINA_FALSE;
+}
+
+static EDBus_Service_Object *
+_find_object_manager_parent(EDBus_Service_Object *obj)
+{
+   if (!obj->parent)
+     return NULL;
+   if (obj->parent->has_objectmanager)
+     return obj->parent;
+   return _find_object_manager_parent(obj->parent);
+}
+
 static EDBus_Service_Interface *
 _edbus_service_interface_add(EDBus_Service_Object *obj, const char *interface)
 {
    EDBus_Service_Interface *iface;
+   EDBus_Service_Object *parent;
 
    iface = eina_hash_find(obj->interfaces, interface);
    if (iface) return iface;
@@ -590,6 +831,15 @@ _edbus_service_interface_add(EDBus_Service_Object *obj, const char *interface)
    iface->properties = eina_hash_string_superfast_new(_props_free);
    iface->obj = obj;
    eina_hash_add(obj->interfaces, iface->name, iface);
+
+   parent = _find_object_manager_parent(obj);
+   if (parent)
+     {
+        if (!parent->idler_iface_changed)
+          parent->idler_iface_changed = ecore_idler_add(_iface_changed_send,
+                                                        parent);
+        parent->iface_added = eina_list_append(parent->iface_added, iface);
+     }
    return iface;
 }
 
@@ -747,10 +997,12 @@ static void
 _interface_free(EDBus_Service_Interface *interface)
 {
    unsigned size, i;
-   if (interface == introspectable || interface == properties_iface) return;
+   EDBus_Service_Object *parent;
+   if (interface == introspectable || interface == properties_iface ||
+       interface == objmanager)
+     return;
 
    eina_hash_free(interface->methods);
-   eina_stringshare_del(interface->name);
    size = eina_array_count(interface->sign_of_signals);
    for (i = 0; i < size; i++)
      eina_stringshare_del(eina_array_data_get(interface->sign_of_signals, i));
@@ -762,6 +1014,25 @@ _interface_free(EDBus_Service_Interface *interface)
      ecore_idler_del(interface->idler_propschanged);
    if (interface->prop_invalidated)
      eina_array_free(interface->prop_invalidated);
+
+   parent = _find_object_manager_parent(interface->obj);
+   if (parent)
+     {
+        struct iface_remove_data *data;
+
+        data = malloc(sizeof(struct iface_remove_data));
+        EINA_SAFETY_ON_NULL_GOTO(data, end);
+        data->obj_path = eina_stringshare_add(interface->obj->path);
+        data->iface = eina_stringshare_add(interface->name);
+
+        if (!parent->idler_iface_changed)
+          parent->idler_iface_changed = ecore_idler_add(_iface_changed_send,
+                                                        parent);
+        parent->iface_removed = eina_list_append(parent->iface_removed, data);
+        parent->iface_added = eina_list_remove(parent->iface_added, interface);
+     }
+end:
+   eina_stringshare_del(interface->name);
    free(interface);
 }
 
@@ -770,6 +1041,7 @@ _object_free(EDBus_Service_Object *obj)
 {
    Eina_Iterator *iterator;
    EDBus_Service_Interface *iface;
+   struct iface_remove_data *data;
 
    iterator = eina_hash_iterator_data_new(obj->interfaces);
    EINA_ITERATOR_FOREACH(iterator, iface)
@@ -783,7 +1055,7 @@ _object_free(EDBus_Service_Object *obj)
         if (obj->parent)
           {
              obj->parent->children = eina_inlist_append(obj->parent->children,
-                                                         EINA_INLIST_GET(child));
+                                                       EINA_INLIST_GET(child));
              child->parent = obj->parent;
           }
         else
@@ -795,13 +1067,22 @@ _object_free(EDBus_Service_Object *obj)
      }
    if (obj->parent)
      obj->parent->children = eina_inlist_remove(obj->parent->children,
-                                                 EINA_INLIST_GET(obj));
+                                               EINA_INLIST_GET(obj));
    else
      obj->conn->root_objs = eina_inlist_remove(obj->conn->root_objs,
                                                EINA_INLIST_GET(obj));
 
    edbus_data_del_all(&obj->data);
 
+   EINA_LIST_FREE(obj->iface_removed, data)
+     {
+        eina_stringshare_del(data->iface);
+        eina_stringshare_del(data->obj_path);
+        free(data);
+     }
+   eina_list_free(obj->iface_added);
+   if (obj->idler_iface_changed)
+     ecore_idler_del(obj->idler_iface_changed);
    eina_hash_free(obj->interfaces);
    eina_iterator_free(iterator);
    if (obj->introspection_data)
@@ -1150,3 +1431,33 @@ edbus_service_property_invalidate_set(EDBus_Service_Interface *iface, const char
      iface->prop_invalidated = eina_array_new(1);
    return eina_array_push(iface->prop_invalidated, prop);
 }
+
+EAPI Eina_Bool
+edbus_service_object_manager_attach(EDBus_Service_Interface *iface)
+{
+   EDBus_Service_Object *obj;
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
+
+   obj = iface->obj;
+   if (!eina_hash_find(obj->interfaces, objmanager->name))
+     if (!eina_hash_add(obj->interfaces, objmanager->name, objmanager))
+       return EINA_FALSE;
+
+   obj->has_objectmanager = EINA_TRUE;
+   obj->introspection_dirty = EINA_TRUE;
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edbus_service_object_manager_detach(EDBus_Service_Interface *iface)
+{
+   EDBus_Service_Object *obj;
+   Eina_Bool ret;
+
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
+   obj = iface->obj;
+   ret = eina_hash_del(obj->interfaces, objmanager->name, NULL);
+   obj->has_objectmanager = EINA_FALSE;
+   obj->introspection_dirty = EINA_TRUE;
+   return ret;
+}
index 415c366..79ae61c 100644 (file)
@@ -182,6 +182,22 @@ EAPI void *edbus_service_object_data_del(EDBus_Service_Interface *iface, const c
 EAPI Eina_Bool edbus_service_property_changed(EDBus_Service_Interface *iface, const char *name);
 
 EAPI Eina_Bool edbus_service_property_invalidate_set(EDBus_Service_Interface *iface, const char *name, Eina_Bool is_invalidate);
+
+/**
+ * Attach ObjectManager interface.
+ *
+ * @param iface ObjectManager will be attach in object path of this interface.
+ * @return EINA_TRUE if success
+ */
+EAPI Eina_Bool edbus_service_object_manager_attach(EDBus_Service_Interface *iface);
+
+/**
+ * Detach ObjectManager interface.
+ *
+ * @param iface ObjectManager of object path of this interface will be detach.
+ * @return EINA_TRUE if success
+ */
+EAPI Eina_Bool edbus_service_object_manager_detach(EDBus_Service_Interface *iface);
 /**
  * @}
  */