From: Jihoon Kim <imfine98@gmail.com>
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 18 Jan 2012 04:38:04 +0000 (04:38 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 18 Jan 2012 04:38:04 +0000 (04:38 +0000)
Long time ago, in
http://www.mail-archive.com/enlightenment-devel@lists.sourceforge.net/msg32795.html
mail thread and IRC,

I talked with about problem of asynchronous event API such as
ecore_imf_context_commit_event_add,
ecore_imf_context_preedit_changed_event_add, so on.

In short, The problem is that key event and text_set APIs are processed
immediately, but commit event and preedit changed event is processed
asynchronously  because those APIs add each event to ecore event queue.

To fix these problems, I've decided to create synchronous event APIs such
as ecore_imf_context_event_callback_add, del and call.

For considering compatibility, sync and async event callback functions are
used in xim and scim immodule.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/ecore@67290 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore_imf/Ecore_IMF.h
src/lib/ecore_imf/ecore_imf_context.c
src/lib/ecore_imf/ecore_imf_private.h
src/modules/immodules/scim/scim_imcontext.cpp
src/modules/immodules/xim/ecore_imf_xim.c

index 8bd29ae..adea35d 100644 (file)
@@ -64,6 +64,17 @@ EAPI extern int ECORE_IMF_EVENT_PREEDIT_CHANGED;
 EAPI extern int ECORE_IMF_EVENT_COMMIT;
 EAPI extern int ECORE_IMF_EVENT_DELETE_SURROUNDING;
 
+typedef void (*Ecore_IMF_Event_Cb) (void *data, Ecore_IMF_Context *ctx, void *event_info);
+
+typedef enum
+{
+    ECORE_IMF_CALLBACK_PREEDIT_START,
+    ECORE_IMF_CALLBACK_PREEDIT_END,
+    ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
+    ECORE_IMF_CALLBACK_COMMIT,
+    ECORE_IMF_CALLBACK_DELETE_SURROUNDING
+} Ecore_IMF_Callback_Type;
+
 typedef enum
 {
    ECORE_IMF_EVENT_MOUSE_DOWN,
@@ -388,6 +399,9 @@ EAPI void                          ecore_imf_context_preedit_end_event_add(Ecore
 EAPI void                          ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx);
 EAPI void                          ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str);
 EAPI void                          ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars);
+EAPI void                          ecore_imf_context_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func, const void *data);
+EAPI void                         *ecore_imf_context_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func);
+EAPI void                          ecore_imf_context_event_callback_call(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, void *event_info);
 EAPI void                          ecore_imf_context_prediction_allow_set(Ecore_IMF_Context *ctx, Eina_Bool prediction);
 EAPI Eina_Bool                     ecore_imf_context_prediction_allow_get(Ecore_IMF_Context *ctx);
 EAPI void                          ecore_imf_context_autocapital_type_set(Ecore_IMF_Context *ctx, Ecore_IMF_Autocapital_Type autocapital_type);
index a96e701..b65ee26 100644 (file)
@@ -223,6 +223,8 @@ ecore_imf_context_info_get(Ecore_IMF_Context *ctx)
 EAPI void
 ecore_imf_context_del(Ecore_IMF_Context *ctx)
 {
+   Ecore_IMF_Func_Node *fn;
+
    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
      {
         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
@@ -230,6 +232,13 @@ ecore_imf_context_del(Ecore_IMF_Context *ctx)
         return;
      }
    if (ctx->klass->del) ctx->klass->del(ctx);
+
+   if (ctx->callbacks)
+     {
+        EINA_LIST_FREE(ctx->callbacks, fn)
+           free(fn);
+     }
+
    ECORE_MAGIC_SET(ctx, ECORE_MAGIC_NONE);
    free(ctx);
 }
@@ -1016,6 +1025,134 @@ ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offse
 }
 
 /**
+ * Add (register) a callback function to a given context event.
+ *
+ * This function adds a function callback to the context @p ctx when the
+ * event of type @p type occurs on it. The function pointer is @p
+ * func.
+ *
+ * The event type @p type to trigger the function may be one of
+ * #ECORE_IMF_CALLBACK_PREEDIT_START, #ECORE_IMF_CALLBACK_PREEDIT_END,
+ * #ECORE_IMF_CALLBACK_PREEDIT_CHANGED, #ECORE_IMF_CALLBACK_COMMIT and
+ * #ECORE_IMF_CALLBACK_DELETE_SURROUNDING.
+ *
+ * @param ctx Ecore_IMF_Context to attach a callback to.
+ * @param type The type of event that will trigger the callback
+ * @param func The (callback) function to be called when the event is
+ *        triggered
+ * @param data The data pointer to be passed to @p func
+ * @ingroup Ecore_IMF_Context_Module_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_event_callback_add(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func, const void *data)
+{
+   Ecore_IMF_Func_Node *fn = NULL;
+
+   if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+     {
+        ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+                         "ecore_imf_context_event_callback_add");
+        return;
+     }
+
+   if (!func) return;
+
+   fn = calloc(1, sizeof (Ecore_IMF_Func_Node));
+   if (!fn) return;
+
+   fn->func = func;
+   fn->data = data;
+   fn->type = type;
+
+   ctx->callbacks = eina_list_append(ctx->callbacks, fn);
+}
+
+/**
+ * Delete (unregister) a callback function registered to a given
+ * context event.
+ *
+ * This function removes a function callback from the context @p ctx when the
+ * event of type @p type occurs on it. The function pointer is @p
+ * func.
+ *
+ * @see ecore_imf_context_event_callback_add() for more details
+ *
+ * @param ctx Ecore_IMF_Context to remove a callback from.
+ * @param type The type of event that was trigerring the callback
+ * @param func The (callback) function that was to be called when the event was triggered
+ * @return the data pointer
+ * @ingroup Ecore_IMF_Context_Module_Group
+ * @since 1.2.0
+ */
+EAPI void *
+ecore_imf_context_event_callback_del(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, Ecore_IMF_Event_Cb func)
+{
+   Eina_List *l = NULL;
+   Eina_List *l_next = NULL;
+   Ecore_IMF_Func_Node *fn = NULL;
+
+   if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+     {
+        ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+                         "ecore_imf_context_event_callback_del");
+        return;
+     }
+
+   if (!func) return NULL;
+   if (!ctx->callbacks) return NULL;
+
+   EINA_LIST_FOREACH_SAFE(ctx->callbacks, l, l_next, fn)
+     {
+        if ((fn) && (fn->func == func) && (fn->type == type))
+          {
+             void *tmp = fn->data;
+             free(fn);
+             ctx->callbacks = eina_list_remove_list(ctx->callbacks, l);
+             return tmp;
+          }
+     }
+   return NULL;
+}
+
+/**
+ * Call a given callback on the context @p ctx.
+ *
+ * ecore_imf_context_preedit_start_event_add, ecore_imf_context_preedit_end_event_add, 
+ * ecore_imf_context_preedit_changed_event_add, ecore_imf_context_commit_event_add and
+ * ecore_imf_context_delete_surrounding_event_add APIs are asynchronous 
+ * because those API adds each event to the event queue.
+ *
+ * This API provides the way to call each callback function immediately.
+ *
+ * @param ctx Ecore_IMF_Context.
+ * @param type The type of event that will trigger the callback
+ * @param event_info The pointer to event specific struct or information to
+ *        pass to the callback functions registered on this event
+ * @ingroup Ecore_IMF_Context_Module_Group
+ * @since 1.2.0
+ */
+EAPI void
+ecore_imf_context_event_callback_call(Ecore_IMF_Context *ctx, Ecore_IMF_Callback_Type type, void *event_info)
+{
+   Ecore_IMF_Func_Node *fn = NULL;
+   Eina_List *l = NULL;
+
+   if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
+     {
+        ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
+                         "ecore_imf_context_event_callback_call");
+        return;
+     }
+
+   EINA_LIST_FOREACH(ctx->callbacks, l, fn)
+     {
+        if ((fn) && (fn->type == type) && (fn->func))
+          fn->func(fn->data, ctx, event_info);
+     }
+}
+
+/**
  * Ask the Input Method Context to show the control panel of using Input Method.
  *
  * @param ctx An #Ecore_IMF_Context.
index 07a5b09..d9dae80 100644 (file)
@@ -35,6 +35,7 @@ extern int _ecore_imf_log_dom;
 #define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_imf_log_dom, __VA_ARGS__)
 
 typedef struct _Ecore_IMF_Module Ecore_IMF_Module;
+typedef struct _Ecore_IMF_Func_Node Ecore_IMF_Func_Node;
 
 struct _Ecore_IMF_Context
 {
@@ -47,6 +48,7 @@ struct _Ecore_IMF_Context
    void                          *client_canvas;
    Eina_Bool                    (*retrieve_surrounding_func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
    void                          *retrieve_surrounding_data;
+   Eina_List                     *callbacks;
    Ecore_IMF_Autocapital_Type     autocapital_type;
    Ecore_IMF_Input_Panel_Layout   input_panel_layout;
    Ecore_IMF_Input_Panel_Lang     input_panel_lang;
@@ -61,6 +63,13 @@ struct _Ecore_IMF_Module
    Ecore_IMF_Context            *(*exit)(void);
 };
 
+struct _Ecore_IMF_Func_Node
+{
+   void (*func) ();
+   const void *data;
+   Ecore_IMF_Callback_Type type;
+};
+
 void               ecore_imf_module_init(void);
 void               ecore_imf_module_shutdown(void);
 Eina_List         *ecore_imf_module_available_get(void);
index b4edfe4..6cb72c2 100644 (file)
@@ -806,8 +806,10 @@ isf_imf_context_reset (Ecore_IMF_Context *ctx)
         if (context_scim->impl->need_commit_preedit)
           {
              if (wstr.length ())
-               ecore_imf_context_commit_event_add (context_scim->ctx, utf8_wcstombs (wstr).c_str ());
-
+               {
+                  ecore_imf_context_commit_event_add (context_scim->ctx, utf8_wcstombs (wstr).c_str ());
+                  ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
+               }
              _panel_client.prepare (context_scim->id);
              _panel_client.send ();
           }
@@ -951,8 +953,10 @@ isf_imf_context_focus_out (Ecore_IMF_Context *ctx)
         if (context_scim->impl->need_commit_preedit)
           {
              if (wstr.length ())
-               ecore_imf_context_commit_event_add (context_scim->ctx, utf8_wcstombs (wstr).c_str ());
-
+               {
+                  ecore_imf_context_commit_event_add (context_scim->ctx, utf8_wcstombs (wstr).c_str ());
+                  ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
+               }
              _panel_client.prepare (context_scim->id);
              _panel_client.send ();
           }
@@ -1520,6 +1524,7 @@ panel_slot_commit_string (int context, const WideString &wstr)
           return;
 
         ecore_imf_context_commit_event_add (ic->ctx, utf8_wcstombs (wstr).c_str ());
+        ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
      }
 }
 
@@ -1818,7 +1823,9 @@ turn_on_ic (EcoreIMFContextISF *ic)
         if (ic->impl->use_preedit && ic->impl->preedit_string.length ())
           {
              ecore_imf_context_preedit_start_event_add (ic->ctx);
+             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
              ecore_imf_context_preedit_changed_event_add (ic->ctx);
+             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
              ic->impl->preedit_started = true;
           }
      }
@@ -1848,7 +1855,9 @@ turn_off_ic (EcoreIMFContextISF *ic)
         if (ic->impl->use_preedit && ic->impl->preedit_string.length ())
           {
              ecore_imf_context_preedit_changed_event_add (ic->ctx);
+             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
              ecore_imf_context_preedit_end_event_add (ic->ctx);
+             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
              ic->impl->preedit_started = false;
           }
      }
@@ -2183,7 +2192,9 @@ open_specific_factory (EcoreIMFContextISF *ic,
              if (ic->impl->use_preedit && ic->impl->preedit_string.length ())
                {
                   ecore_imf_context_preedit_changed_event_add (ic->ctx);
+                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
                   ecore_imf_context_preedit_end_event_add (ic->ctx);
+                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
                   ic->impl->preedit_started = false;
                }
           }
@@ -2452,6 +2463,7 @@ slot_show_preedit_string (IMEngineInstanceBase *si)
              if (!ic->impl->preedit_started)
                {
                   ecore_imf_context_preedit_start_event_add (_focused_ic->ctx);
+                  ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
                   ic->impl->preedit_started = true;
                }
           }
@@ -2502,10 +2514,14 @@ slot_hide_preedit_string (IMEngineInstanceBase *si)
         if (ic->impl->use_preedit)
           {
              if (emit)
-               ecore_imf_context_preedit_changed_event_add (ic->ctx);
+               {
+                  ecore_imf_context_preedit_changed_event_add (ic->ctx);
+                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+               }
              if (ic->impl->preedit_started)
                {
                   ecore_imf_context_preedit_end_event_add (ic->ctx);
+                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
                   ic->impl->preedit_started = false;
                }
           }
@@ -2551,9 +2567,11 @@ slot_update_preedit_caret (IMEngineInstanceBase *si, int caret)
              if (!ic->impl->preedit_started)
                {
                   ecore_imf_context_preedit_start_event_add (ic->ctx);
+                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
                   ic->impl->preedit_started = true;
                }
              ecore_imf_context_preedit_changed_event_add (ic->ctx);
+             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
           }
         else
           _panel_client.update_preedit_caret (ic->id, caret);
@@ -2578,11 +2596,13 @@ slot_update_preedit_string (IMEngineInstanceBase *si,
              if (!ic->impl->preedit_started)
                {
                   ecore_imf_context_preedit_start_event_add (_focused_ic->ctx);
+                  ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
                   ic->impl->preedit_started = true;
                }
              ic->impl->preedit_caret    = str.length ();
              ic->impl->preedit_updating = true;
              ecore_imf_context_preedit_changed_event_add (ic->ctx);
+             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
              ic->impl->preedit_updating = false;
           }
         else
@@ -2614,7 +2634,10 @@ slot_commit_string (IMEngineInstanceBase *si,
    EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
 
    if (ic && ic->ctx)
-     ecore_imf_context_commit_event_add (ic->ctx, utf8_wcstombs (str).c_str ());
+     {
+        ecore_imf_context_commit_event_add (ic->ctx, utf8_wcstombs (str).c_str ());
+        ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
+     }
 }
 
 static void
@@ -2761,7 +2784,12 @@ slot_delete_surrounding_text (IMEngineInstanceBase *si,
 
    if (ic && ic->impl && _focused_ic == ic)
      {
+        Ecore_IMF_Event_Delete_Surrounding ev;
+        ev.ctx = _focused_ic->ctx;
+        ev.n_chars = len;
+        ev.offset = offset;
         ecore_imf_context_delete_surrounding_event_add (_focused_ic->ctx, offset, len);
+        ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
         return true;
      }
    return false;
@@ -2803,6 +2831,9 @@ fallback_commit_string_cb (IMEngineInstanceBase  *si __UNUSED__,
    SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
 
    if (_focused_ic && _focused_ic->impl)
-     ecore_imf_context_commit_event_add (_focused_ic->ctx, utf8_wcstombs (str).c_str ());
+     {
+        ecore_imf_context_commit_event_add (_focused_ic->ctx, utf8_wcstombs (str).c_str ());
+        ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
+     }
 }
 
index e81e486..ea7ee7f 100644 (file)
@@ -389,6 +389,7 @@ _ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
         imf_context_data->preedit_chars = NULL;
 
         ecore_imf_context_preedit_changed_event_add(ctx);
+        ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
      }
 
    if (result)
@@ -397,6 +398,7 @@ _ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
         if (result_utf8)
           {
              ecore_imf_context_commit_event_add(ctx, result_utf8);
+             ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8);
              free(result_utf8);
           }
      }
@@ -707,6 +709,7 @@ _ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx,
              if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
                {
                   ecore_imf_context_commit_event_add(ctx, compose);
+                  ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
                   result = EINA_TRUE;
                }
              free(compose);
@@ -872,8 +875,10 @@ preedit_start_callback(XIC xic __UNUSED__,
    imf_context_data = ecore_imf_context_data_get(ctx);
 
    if (imf_context_data->finalizing == EINA_FALSE)
-     ecore_imf_context_preedit_start_event_add(ctx);
-
+     {
+        ecore_imf_context_preedit_start_event_add(ctx);
+        ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
+     }
    return -1;
 }
 
@@ -893,10 +898,14 @@ preedit_done_callback(XIC xic __UNUSED__,
         free(imf_context_data->preedit_chars);
         imf_context_data->preedit_chars = NULL;
         ecore_imf_context_preedit_changed_event_add(ctx);
+        ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
      }
 
    if (imf_context_data->finalizing == EINA_FALSE)
-     ecore_imf_context_preedit_end_event_add(ctx);
+     {
+        ecore_imf_context_preedit_end_event_add(ctx);
+        ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
+     }
 }
 
 /* FIXME */
@@ -1023,6 +1032,7 @@ done:
           }
 
         ecore_imf_context_preedit_changed_event_add(ctx);
+        ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
      }
 
    free(new_text);
@@ -1044,7 +1054,10 @@ preedit_caret_callback(XIC xic __UNUSED__,
         // printf("call_data->position:%d\n", call_data->position);
         imf_context_data->preedit_cursor = call_data->position;
         if (imf_context_data->finalizing == EINA_FALSE)
-          ecore_imf_context_preedit_changed_event_add(ctx);
+          {
+             ecore_imf_context_preedit_changed_event_add(ctx);
+             ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
+          }
      }
 }
 
@@ -1210,6 +1223,7 @@ reinitialize_ic(Ecore_IMF_Context *ctx)
              free(imf_context_data->preedit_chars);
              imf_context_data->preedit_chars = NULL;
              ecore_imf_context_preedit_changed_event_add(ctx);
+             ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
           }
      }
 }