edbus: Implementation of EDBUS_PROXY_EVENTS and edbus_proxy_properties_monitor
authorJosé Roberto de Souza <zehortigoza@profusion.mobi>
Fri, 26 Oct 2012 18:19:32 +0000 (18:19 +0000)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Fri, 26 Oct 2012 18:19:32 +0000 (18:19 +0000)
Patch by: José Roberto de Souza  <zehortigoza@profusion.mobi>

SVN revision: 78544

src/examples/complex_types.c
src/examples/complex_types_server.c
src/lib/edbus_freedesktop.h
src/lib/edbus_message_to_eina_value.c
src/lib/edbus_private.h
src/lib/edbus_proxy.c

index 359dead..911f4aa 100644 (file)
@@ -179,6 +179,31 @@ on_receive_array(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
      }
 }
 
+static void
+_property_changed(void *data, EDBus_Proxy *proxy, void *event_info)
+{
+   EDBus_Proxy_Event_Property_Changed *event = event_info;
+   const char *name;
+   const Eina_Value *value;
+   printf("property changed\n");
+
+   name = event->name;
+   value = event->value;
+
+   if (!strcmp(name, "text"))
+     {
+        const char *txt;
+        eina_value_get(value, &txt);
+        printf("[%s] = %s\n", name, txt);
+     }
+   else if (!strcmp(name, "int32"))
+     {
+        int num;
+        eina_value_get(value, &num);
+        printf("[%s] = %d\n", name, num);
+     }
+}
+
 int
 main(void)
 {
@@ -271,11 +296,13 @@ main(void)
                               -1 , "i", plus_one);
 
    pending = edbus_proxy_property_get(test2_proxy, "Resp2", get_property_resp2, test2_proxy);
+   edbus_proxy_event_callback_add(test2_proxy, EDBUS_PROXY_EVENT_PROPERTY_CHANGED, _property_changed, NULL);
 
-   ecore_timer_add(5, _timer1_cb, NULL);
+   ecore_timer_add(20, _timer1_cb, NULL);
 
    ecore_main_loop_begin();
 
+   edbus_proxy_event_callback_del(test2_proxy, EDBUS_PROXY_EVENT_PROPERTY_CHANGED, _property_changed, NULL);
    edbus_connection_unref(conn);
 
    edbus_shutdown();
index dce769e..958aa2d 100644 (file)
@@ -5,7 +5,8 @@
 #define PATH "/com/profusion/Test"
 #define IFACE "com.profusion.Test"
 
-char *resp2;
+static char *resp2;
+static Ecore_Timer *timer;
 
 static EDBus_Message *
 _receive_array(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
@@ -331,11 +332,57 @@ static const EDBus_Method properties_methods[] = {
       { }
 };
 
+static const EDBus_Signal properties_signals[] = {
+   { "PropertiesChanged",
+     EDBUS_ARGS({"s", "interface"}, {"a{sv}", "data"}, {"as", "invalidate"}), 0
+   },
+   { }
+};
+
+static Eina_Bool _emmit_changed(void *data)
+{
+   EDBus_Service_Interface *iface = data;
+   EDBus_Message *sig = edbus_service_signal_new(iface, 0);
+   EDBus_Message_Iter *main_iter, *array, *entry, *var, *invalidate;
+
+   main_iter = edbus_message_iter_get(sig);
+   if (!edbus_message_iter_arguments_set(main_iter, "sa{sv}", IFACE, &array))
+     {
+        printf("Error setting arguments of signal");
+        goto end;
+     }
+
+   edbus_message_iter_arguments_set(array, "{sv}", &entry);
+   edbus_message_iter_arguments_set(entry, "s", "text");
+   var = edbus_message_iter_container_new(entry, 'v', "s");
+   edbus_message_iter_arguments_set(var, "s", "lalala text");
+   edbus_message_iter_container_close(entry, var);
+   edbus_message_iter_container_close(array, entry);
+
+   edbus_message_iter_arguments_set(array, "{sv}", &entry);
+   edbus_message_iter_arguments_set(entry, "s", "int32");
+   var = edbus_message_iter_container_new(entry, 'v', "i");
+   edbus_message_iter_arguments_set(var, "i", 35);
+   edbus_message_iter_container_close(entry, var);
+   edbus_message_iter_container_close(array, entry);
+
+   edbus_message_iter_container_close(main_iter, array);
+
+   edbus_message_iter_arguments_set(main_iter, "as", &invalidate);
+   edbus_message_iter_container_close(main_iter, invalidate);
+
+   edbus_service_signal_send(iface, sig);
+end:
+   edbus_message_unref(sig);
+   return EINA_TRUE;
+}
+
 static void
 on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
 {
    EDBus_Connection *conn = data;
    unsigned int flag;
+   EDBus_Service_Interface *piface;
 
    resp2 = malloc(sizeof(char) * 5);
    strcpy(resp2, "test");
@@ -359,7 +406,9 @@ on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
      }
 
    edbus_service_interface_register(conn, PATH, IFACE, methods, NULL);
-   edbus_service_interface_register(conn, PATH, EDBUS_FDO_INTERFACE_PROPERTIES, properties_methods, NULL);
+   piface = edbus_service_interface_register(conn, PATH, EDBUS_FDO_INTERFACE_PROPERTIES,
+                                             properties_methods, properties_signals);
+   timer = ecore_timer_add(3, _emmit_changed, piface);
 }
 
 int
@@ -377,6 +426,7 @@ main(void)
    ecore_main_loop_begin();
 
    free(resp2);
+   ecore_timer_del(timer);
    edbus_connection_unref(conn);
 
    edbus_shutdown();
index 9709425..2e3cff9 100644 (file)
@@ -86,26 +86,13 @@ EAPI EDBus_Pending        *edbus_object_introspect(EDBus_Object *obj, EDBus_Mess
 
 /**
  * @defgroup EDBus_FDO_Properties org.freedesktop.DBus.Properties
- *
- * Whenever edbus_proxy_properties_monitor() is called on a
- * proxy to an object it will automatically listen for properties
- * changed on that interface, emitting events with
- * edbus_object_event_type being
- * #EDBUS_OBJECT_EVENT_PROPERTY_CHANGED and
- * #EDBUS_OBJECT_EVENT_PROPERTY_REMOVED, as well as
- * #EDBUS_PROXY_EVENT_PROPERTY_CHANGED and
- * #EDBUS_PROXY_EVENT_PROPERTY_REMOVED.
- *
- * One may manually query the properties
- * edbus_proxy_property_get() and edbus_proxy_property_get_all()
- * or listen for changes with
- * edbus_proxy_properties_changed_callback_add().
- *
- * To set property call edbus_proxy_property_set().
- *
  * @{
  */
-EAPI void                  edbus_proxy_properties_monitor(EDBus_Proxy *proxy);
+
+/**
+ * Enable or disable local cache of properties.
+ */
+EAPI void edbus_proxy_properties_monitor(EDBus_Proxy *proxy, Eina_Bool enable);
 
 EAPI EDBus_Pending        *edbus_proxy_property_get(EDBus_Proxy *proxy, const char *name, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 3);
 EAPI EDBus_Pending        *edbus_proxy_property_set(EDBus_Proxy *proxy, const char *name, char type, const void *value, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 4);
index 8a38745..d3d0663 100644 (file)
@@ -3,7 +3,6 @@
 
 static void _message_iter_basic_array_to_eina_value(char type, Eina_Value *value, EDBus_Message_Iter *iter);
 static void _eina_value_struct_free(Eina_Value *value, Eina_Array *array);
-static Eina_Value *_message_iter_struct_to_eina_value(EDBus_Message_Iter *iter);
 
 static const Eina_Value_Type *
 _dbus_type_to_eina_value_type(char type)
@@ -217,7 +216,7 @@ _message_iter_basic_array_to_eina_value(char type, Eina_Value *value, EDBus_Mess
 
 #define ARG "arg%d"
 
-static Eina_Value *
+Eina_Value *
 _message_iter_struct_to_eina_value(EDBus_Message_Iter *iter)
 {
    int type;
index 3a65672..1e10bfa 100644 (file)
@@ -73,6 +73,7 @@ void                   edbus_connection_name_owner_monitor(EDBus_Connection *con
 EDBus_Pending         *_edbus_connection_send(EDBus_Connection *conn, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout);
 
 EDBus_Message_Iter    *edbus_message_iter_sub_iter_get(EDBus_Message_Iter *iter);
+Eina_Value            *_message_iter_struct_to_eina_value(EDBus_Message_Iter *iter);
 
 #ifdef HAVE_VA_LIST_AS_ARRAY
 #define MAKE_PTR_FROM_VA_LIST(arg) ((va_list *)(arg))
index 40b3bcf..88940ba 100644 (file)
@@ -30,6 +30,9 @@ struct _EDBus_Proxy
    Eina_List                *handlers;
    Eina_Inlist              *cbs_free;
    EDBus_Proxy_Context_Event event_handlers[EDBUS_PROXY_EVENT_LAST];
+   Eina_Hash *props;
+   EDBus_Signal_Handler *properties_changed;
+   Eina_Bool monitor_enabled:1;
 };
 
 #define EDBUS_PROXY_CHECK(proxy)                         \
@@ -85,6 +88,7 @@ edbus_proxy_shutdown(void)
 static void _edbus_proxy_event_callback_call(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, const void *event_info);
 static void _edbus_proxy_context_event_cb_del(EDBus_Proxy_Context_Event *ce, EDBus_Proxy_Context_Event_Cb *ctx);
 static void _on_signal_handler_free(void *data, const void *dead_pointer);
+static EDBus_Proxy *get_properties_proxy(EDBus_Proxy *proxy);
 
 static void
 _edbus_proxy_call_del(EDBus_Proxy *proxy)
@@ -139,6 +143,10 @@ _edbus_proxy_clear(EDBus_Proxy *proxy)
      }
 
    edbus_cbs_free_dispatch(&(proxy->cbs_free), proxy);
+   if (proxy->props)
+     eina_hash_free(proxy->props);
+   if (proxy->properties_changed)
+     edbus_signal_handler_del(proxy->properties_changed);
    proxy->refcount = 0;
 }
 
@@ -267,6 +275,87 @@ edbus_proxy_cb_free_del(EDBus_Proxy *proxy, EDBus_Free_Cb cb, const void *data)
    proxy->cbs_free = edbus_cbs_free_del(proxy->cbs_free, cb, data);
 }
 
+static void
+_property_changed_iter(void *data, const void *key, EDBus_Message_Iter *var)
+{
+   EDBus_Proxy *proxy = data;
+   const char *skey = key;
+   Eina_Value *st_value, stack_value, *value;
+   EDBus_Proxy_Event_Property_Changed event;
+
+   st_value = _message_iter_struct_to_eina_value(var);
+   eina_value_struct_value_get(st_value, "arg0", &stack_value);
+
+   value = eina_hash_find(proxy->props, skey);
+   if (value)
+     {
+        eina_value_flush(value);
+        eina_value_copy(&stack_value, value);
+     }
+   else
+     {
+        value = calloc(1, sizeof(Eina_Value));
+        eina_value_copy(&stack_value, value);
+        eina_hash_add(proxy->props, skey, value);
+     }
+
+   event.name = skey;
+   event.value = value;
+   _edbus_proxy_event_callback_call(proxy, EDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+                                    &event);
+
+   edbus_message_to_eina_value_free(st_value);
+   //TODO if value have any STRUCT at this point it will not be accessible
+   eina_value_flush(&stack_value);
+}
+
+static void
+_properties_changed(void *data, const EDBus_Message *msg)
+{
+   EDBus_Proxy *proxy = data;
+   EDBus_Message_Iter *array, *invalidate;
+   const char *iface;
+   const char *invalidate_prop;
+
+   if (!edbus_message_arguments_get(msg, "sa{sv}as", &iface, &array, &invalidate))
+     {
+        ERR("Error getting data from properties changed signal.");
+        return;
+     }
+   if (proxy->props)
+     edbus_message_iter_dict_iterate(array, "sv", _property_changed_iter,
+                                     proxy);
+
+   while (edbus_message_iter_get_and_next(invalidate, 's', &invalidate_prop))
+     {
+        EDBus_Proxy_Event_Property_Removed event;
+        event.interface = proxy->interface;
+        event.name = invalidate_prop;
+        event.proxy = proxy;
+        if (proxy->props)
+          eina_hash_del(proxy->props, event.name, NULL);
+        _edbus_proxy_event_callback_call(proxy, EDBUS_PROXY_EVENT_PROPERTY_REMOVED,
+                                         &event);
+     }
+}
+
+static void
+_props_cache_free(void *data)
+{
+   Eina_Value *value = data;
+   eina_value_free(value);
+}
+
+static void
+_properties_changed_add(EDBus_Proxy *proxy)
+{
+   proxy->properties_changed =
+            edbus_proxy_signal_handler_add(get_properties_proxy(proxy),
+            "PropertiesChanged", _properties_changed, proxy);
+   edbus_signal_handler_match_extra_set(proxy->properties_changed, "arg0",
+                                        proxy->interface, NULL);
+}
+
 EAPI void
 edbus_proxy_event_callback_add(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, EDBus_Proxy_Event_Cb cb, const void *cb_data)
 {
@@ -285,6 +374,19 @@ edbus_proxy_event_callback_add(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type,
    ctx->cb_data = cb_data;
 
    ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
+
+   if (type == EDBUS_PROXY_EVENT_PROPERTY_CHANGED)
+     {
+        if (proxy->properties_changed) return;
+        if (!proxy->props)
+          proxy->props = eina_hash_string_superfast_new(_props_cache_free);
+        _properties_changed_add(proxy);
+     }
+   else if (type == EDBUS_PROXY_EVENT_PROPERTY_REMOVED)
+     {
+        if (proxy->properties_changed) return;
+        _properties_changed_add(proxy);
+     }
 }
 
 static void
@@ -326,6 +428,36 @@ edbus_proxy_event_callback_del(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type,
      }
 
    _edbus_proxy_context_event_cb_del(ce, found);
+
+   if (type == EDBUS_PROXY_EVENT_PROPERTY_CHANGED)
+     {
+        EDBus_Proxy_Context_Event *ce_prop_remove;
+        ce_prop_remove = proxy->event_handlers +
+                 EDBUS_PROXY_EVENT_PROPERTY_REMOVED;
+        if (!ce->list && !proxy->monitor_enabled)
+          {
+             eina_hash_free(proxy->props);
+             proxy->props = NULL;
+          }
+
+        if (!ce_prop_remove->list && !ce->list && !proxy->monitor_enabled)
+          {
+             edbus_signal_handler_unref(proxy->properties_changed);
+             proxy->properties_changed = NULL;
+          }
+     }
+   else if (type == EDBUS_PROXY_EVENT_PROPERTY_REMOVED)
+     {
+        EDBus_Proxy_Context_Event *ce_prop_changed;
+        ce_prop_changed = proxy->event_handlers +
+                 EDBUS_PROXY_EVENT_PROPERTY_CHANGED;
+
+        if (!ce_prop_changed->list && !ce->list && !proxy->monitor_enabled)
+          {
+             edbus_signal_handler_unref(proxy->properties_changed);
+             proxy->properties_changed = NULL;
+          }
+     }
 }
 
 static void
@@ -543,3 +675,81 @@ edbus_proxy_property_get_all(EDBus_Proxy *proxy, EDBus_Message_Cb cb, const void
    return edbus_proxy_call(get_properties_proxy(proxy), "GetAll", cb, data, -1,
                            "s", proxy->interface);
 }
+
+static void
+_property_iter(void *data, const void *key, EDBus_Message_Iter *var)
+{
+   EDBus_Proxy *proxy = data;
+   const char *skey = key;
+   Eina_Value *st_value, stack_value, *value;
+
+   st_value = _message_iter_struct_to_eina_value(var);
+   eina_value_struct_value_get(st_value, "arg0", &stack_value);
+
+   value = eina_hash_find(proxy->props, skey);
+   if (value)
+     {
+        eina_value_flush(value);
+        eina_value_copy(&stack_value, value);
+     }
+   else
+     {
+        value = calloc(1, sizeof(Eina_Value));
+        eina_value_copy(&stack_value, value);
+        eina_hash_add(proxy->props, skey, value);
+     }
+
+   edbus_message_to_eina_value_free(st_value);
+   eina_value_flush(&stack_value);
+}
+
+static void
+_props_get_all(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Proxy *proxy = data;
+   EDBus_Message_Iter *dict;
+
+   if (!edbus_message_arguments_get(msg, "a{sv}", &dict))
+     {
+        ERR("Error getting data from properties getAll.");
+        return;
+     }
+   edbus_message_iter_dict_iterate(dict, "sv", _property_iter, proxy);
+}
+
+EAPI void
+edbus_proxy_properties_monitor(EDBus_Proxy *proxy, Eina_Bool enable)
+{
+   EDBUS_PROXY_CHECK(proxy);
+   if (proxy->monitor_enabled == enable)
+     return;
+
+   proxy->monitor_enabled = enable;
+   if (enable)
+     {
+        if (!proxy->props)
+          proxy->props = eina_hash_string_superfast_new(_props_cache_free);
+        edbus_proxy_property_get_all(proxy, _props_get_all, proxy);
+
+        if (proxy->properties_changed)
+          return;
+        _properties_changed_add(proxy);
+     }
+   else
+     {
+        EDBus_Proxy_Context_Event *ce_prop_changed, *ce_prop_removed;
+        ce_prop_changed = proxy->event_handlers + EDBUS_PROXY_EVENT_PROPERTY_CHANGED;
+        ce_prop_removed = proxy->event_handlers + EDBUS_PROXY_EVENT_PROPERTY_REMOVED;
+
+        if (!ce_prop_changed->list)
+          {
+             eina_hash_free(proxy->props);
+             proxy->props = NULL;
+          }
+        if (!ce_prop_changed->list && !ce_prop_removed->list)
+          {
+             edbus_signal_handler_unref(proxy->properties_changed);
+             proxy->properties_changed = NULL;
+          }
+     }
+}