Eo legacy events: Fix broken callback comparison
authorTom Hacohen <tom@stosb.com>
Mon, 28 Sep 2015 23:45:34 +0000 (00:45 +0100)
committerTom Hacohen <tom@stosb.com>
Tue, 29 Sep 2015 00:01:05 +0000 (01:01 +0100)
Commit 37f84b7e966372384e2dfe5d191a6f907a17962e introduced a few changes
to the callback matching mechanism that made it so sometimes callbacks
would be triggered for the wrong events. The problem was there because
of the support for legacy events that forces to do string comparison
instead of the usual pointer comparison. We should only do string
comparison when we are certain one of the callbacks is a legacy
generated one.

Regression tests will follow tomorrow. Way too late here for that.

Thanks to cedric for reporting.

src/lib/eo/Eo.h
src/lib/eo/eo_base_class.c
src/tests/eo/suite/eo_test_general.c

index 3f551f4..66be6ff 100644 (file)
@@ -919,6 +919,8 @@ typedef void (*eo_key_data_free_func)(void *);
 
 /**
  * Don't use.
+ * The values of the returned event structure are also internal, don't assume
+ * anything about them.
  * @internal
  */
 EAPI const Eo_Event_Description *eo_base_legacy_only_event_description_get(const char *_event_name);
index f85aa4e..f0a4030 100644 (file)
@@ -401,11 +401,16 @@ _wref_destruct(Eo_Base_Data *pd)
 
 /* XXX: Legacy support, remove when legacy is dead. */
 static Eina_Hash *_legacy_events_hash = NULL;
+#define _LEGACY_EVENT_FIRST_CHAR 1
 
 EAPI const Eo_Event_Description *
 eo_base_legacy_only_event_description_get(const char *_event_name)
 {
-   Eina_Stringshare *event_name = eina_stringshare_add(_event_name);
+   char buf[1024];
+   buf[0] = _LEGACY_EVENT_FIRST_CHAR; /* Encode it's a legacy event */
+   strncpy(buf + 1, _event_name, sizeof(buf) - 1);
+   buf[sizeof(buf) - 1] = '\0';
+   Eina_Stringshare *event_name = eina_stringshare_add(buf);
    Eo_Event_Description *event_desc = eina_hash_find(_legacy_events_hash, event_name);
    if (!event_desc)
      {
@@ -421,6 +426,26 @@ eo_base_legacy_only_event_description_get(const char *_event_name)
    return event_desc;
 }
 
+static Eina_Bool
+_legacy_event_desc_is(const Eo_Event_Description *desc)
+{
+   return (desc->name[0] == _LEGACY_EVENT_FIRST_CHAR);
+}
+
+/* Also supports non legacy. */
+static const char *
+_legacy_event_desc_name_get(const Eo_Event_Description *desc)
+{
+   if (_legacy_event_desc_is(desc))
+     {
+        return desc->name + 1;
+     }
+   else
+     {
+        return desc->name;
+     }
+}
+
 static void
 _legacy_events_hash_free_cb(void *_desc)
 {
@@ -641,13 +666,19 @@ _cb_desc_match(const Eo_Event_Description *a, const Eo_Event_Description *b)
    if (!a)
       return EINA_FALSE;
 
-   if (a == b)
+   if (_legacy_event_desc_is(a) && _legacy_event_desc_is(b))
+     {
+        return (a->name == b->name);
+     }
+   else if (_legacy_event_desc_is(a) || _legacy_event_desc_is(b))
      {
-        return EINA_TRUE;
+        const char *aname = _legacy_event_desc_name_get(a);
+        const char *bname = _legacy_event_desc_name_get(b);
+        return !strcmp(aname, bname);
      }
    else
      {
-        return !strcmp(a->name, b->name);
+        return (a == b);
      }
 }
 
index ccd6af2..b483a80 100644 (file)
@@ -125,12 +125,12 @@ START_TEST(eo_signals)
      {
         const Eo_Event_Description *a_desc = eo_base_legacy_only_event_description_get("a,changed");
         fail_if(!a_desc);
-        ck_assert_str_eq(a_desc->name, "a,changed");
+        ck_assert_str_eq(a_desc->name, "\x01" "a,changed");
         fail_if(a_desc == EV_A_CHANGED);
 
         const Eo_Event_Description *bad_desc = eo_base_legacy_only_event_description_get("bad");
         fail_if(!bad_desc);
-        ck_assert_str_eq(bad_desc->name, "bad");
+        ck_assert_str_eq(bad_desc->name, "\x01" "bad");
 
         /* Call Eo event with legacy and non-legacy callbacks. */
         _eo_signals_cb_current = 0;