move around - flatter.
[framework/uifw/ecore.git] / src / lib / ecore_imf / ecore_imf_context.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include <locale.h>
6 #include <stdlib.h>
7
8 #include "config.h"
9
10 #include "Ecore_IMF.h"
11 #include "ecore_imf_private.h"
12
13 #include <Ecore.h>
14
15 /**
16  * @defgroup Ecore_IMF_Context_Group Ecore Input Method Context Functions
17  *
18  * Functions that operate on Ecore Input Method Context objects.
19  */
20
21 /**
22  * Get the list of the available Input Method Context ids.
23  *
24  * Note that the caller is responsible for freeing the Ecore_List
25  * when finished with it. There is no need to finish the list strings.
26  *
27  * @return Return an Ecore_List of strings;
28  *         on failure it returns NULL.
29  * @ingroup Ecore_IMF_Context_Group
30  */
31 EAPI Ecore_List *
32 ecore_imf_context_available_ids_get(void)
33 {
34    return ecore_imf_module_context_ids_get();
35 }
36
37 EAPI Ecore_List *
38 ecore_imf_context_available_ids_by_canvas_type_get(const char *canvas_type)
39 {
40    return ecore_imf_module_context_ids_by_canvas_type_get(canvas_type);
41 }
42
43 /*
44  * Match @locale against @against.
45  *
46  * 'en_US' against 'en_US'       => 4
47  * 'en_US' against 'en'          => 3
48  * 'en', 'en_UK' against 'en_US' => 2
49  *  all locales, against '*'     => 1
50  */
51 static int
52 _ecore_imf_context_match_locale(const char *locale, const char *against, int against_len)
53 {
54   if (strcmp(against, "*") == 0)
55     return 1;
56
57   if (strcasecmp(locale, against) == 0)
58     return 4;
59
60   if (strncasecmp(locale, against, 2) == 0)
61     return (against_len == 2) ? 3 : 2;
62
63   return 0;
64 }
65
66 /**
67  * Get the id of the default Input Method Context.
68  * The id may to used to create a new instance of an Input Method
69  * Context object.
70  *
71  * @return Return a string containing the id of the default Input
72  *         Method Context; on failure it returns NULL.
73  * @ingroup Ecore_IMF_Context_Group
74  */
75 EAPI const char *
76 ecore_imf_context_default_id_get(void)
77 {
78    return ecore_imf_context_default_id_by_canvas_type_get(NULL);
79 }
80
81 EAPI const char *
82 ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type)
83 {
84    const char *id;
85    Ecore_List *modules;
86    Ecore_IMF_Module *module;
87    char *locale;
88    char *tmp;
89    int best_goodness = 0;
90
91    id = getenv("ECORE_IMF_MODULE");
92    if (id)
93      {
94         if (strcmp(id, "none") == 0) return NULL;
95         if (ecore_imf_module_get(id)) return id;
96      }
97
98    modules = ecore_imf_module_available_get();
99    if (!modules) return NULL;
100
101    locale = setlocale(LC_CTYPE, NULL);
102    if (!locale) return NULL;
103
104    locale = strdup(locale);
105
106    tmp = strchr(locale, '.');
107    if (tmp) *tmp = '\0';
108    tmp = strchr(locale, '@');
109    if (tmp) *tmp = '\0';
110
111    id = NULL;
112
113    ecore_list_first_goto(modules);
114    while ((module = ecore_list_next(modules)))
115      {
116         if (canvas_type &&
117             strcmp(module->info->canvas_type, canvas_type) == 0)
118           continue;
119
120         const char *p = module->info->default_locales;
121         while (p)
122           {
123              const char *q = strchr(p, ':');
124              int goodness = _ecore_imf_context_match_locale(locale, p, q ? q - p : strlen (p));
125
126               if (goodness > best_goodness)
127                 {
128                    id = module->info->id;
129                    best_goodness = goodness;
130                 }
131
132               p = q ? q + 1 : NULL;
133           }
134      }
135    ecore_list_destroy(modules);
136
137    free(locale);
138    return id;
139 }
140
141 /**
142  * Retrieve the info for the Input Method Context with @p id.
143  *
144  * @param id The Input Method Context id to query for.
145  * @return Return a #Ecore_IMF_Context_Info for the Input Method Context with @p id;
146  *         on failure it returns NULL.
147  * @ingroup Ecore_IMF_Context_Group
148  */
149 EAPI const Ecore_IMF_Context_Info *
150 ecore_imf_context_info_by_id_get(const char *id)
151 {
152    Ecore_IMF_Module *module;
153
154    if (!id) return NULL;
155    module = ecore_imf_module_get(id);
156    if (!module) return NULL;
157    return module->info;
158 }
159
160 /**
161  * Create a new Input Method Context defined by the given id.
162  *
163  * @param id The Input Method Context id.
164  * @return A newly allocated Input Method Context;
165  *         on failure it returns NULL.
166  * @ingroup Ecore_IMF_Context_Group
167  */
168 EAPI Ecore_IMF_Context *
169 ecore_imf_context_add(const char *id)
170 {
171    Ecore_IMF_Context *ctx;
172
173    if (!id) return NULL;
174    ctx = ecore_imf_module_context_create(id);
175    if (!ctx || !ctx->klass) return NULL;
176    if (ctx->klass->add) ctx->klass->add(ctx);
177    /* default use_preedit is 1, so let's make sure it's
178     * set on the immodule */
179    ecore_imf_context_use_preedit_set(ctx, 1);
180    /* default input_mode is ECORE_IMF_INPUT_MODE_FULL, so let's make sure it's
181     * set on the immodule */
182    ecore_imf_context_input_mode_set(ctx, ECORE_IMF_INPUT_MODE_FULL);
183    return ctx;
184 }
185
186 /**
187  * Retrieve the info for the given Input Method Context.
188  *
189  * @param ctx An #Ecore_IMF_Context.
190  * @return Return a #Ecore_IMF_Context_Info for the given Input Method Context;
191  *         on failure it returns NULL.
192  * @ingroup Ecore_IMF_Context_Group
193  */
194 EAPI const Ecore_IMF_Context_Info *
195 ecore_imf_context_info_get(Ecore_IMF_Context *ctx)
196 {
197    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
198      {
199         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
200                          "ecore_imf_context_info_get");
201         return NULL;
202      }
203    return ctx->module->info;
204 }
205
206 /**
207  * Delete the given Input Method Context and free its memory.
208  *
209  * @param ctx An #Ecore_IMF_Context.
210  * @ingroup Ecore_IMF_Context_Group
211  */
212 EAPI void
213 ecore_imf_context_del(Ecore_IMF_Context *ctx)
214 {
215    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
216      {
217         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
218                          "ecore_imf_context_del");
219         return;
220      }
221    if (ctx->klass->del) ctx->klass->del(ctx);
222    ECORE_MAGIC_SET(ctx, ECORE_MAGIC_NONE);
223    free(ctx);
224 }
225
226 /**
227  * Set the client window for the Input Method Context; this is the
228  * Ecore_X_Window when using X11, Ecore_Win32_Window when using Win32, etc.
229  * This window is used in order to correctly position status windows, and may
230  * also be used for purposes internal to the Input Method Context.
231  *
232  * @param ctx An #Ecore_IMF_Context.
233  * @param window The client window. This may be NULL to indicate
234  *               that the previous client window no longer exists.
235  * @ingroup Ecore_IMF_Context_Group
236  */
237 EAPI void
238 ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
239 {
240    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
241      {
242         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
243                          "ecore_imf_context_client_window_set");
244         return;
245      }
246    if (ctx->klass->client_window_set) ctx->klass->client_window_set(ctx, window);
247 }
248
249 /**
250  * Set the client canvas for the Input Method Context; this is the
251  * canvas in which the input appears.
252  * The canvas type can be determined by using the context canvas type.
253  * Actually only canvas with type "evas" (Evas *) is supported.
254  * This canvas may be used in order to correctly position status windows, and may
255  * also be used for purposes internal to the Input Method Context.
256  *
257  * @param ctx An #Ecore_IMF_Context.
258  * @param canas The client canvas. This may be NULL to indicate
259  *              that the previous client canvas no longer exists.
260  * @ingroup Ecore_IMF_Context_Group
261  */
262 EAPI void
263 ecore_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
264 {
265    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
266      {
267         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
268                          "ecore_imf_context_client_window_set");
269         return;
270      }
271    if (ctx->klass->client_canvas_set) ctx->klass->client_canvas_set(ctx, canvas);
272 }
273
274 /**
275  * Ask the Input Method Context to show itself.
276  *
277  * @param ctx An #Ecore_IMF_Context.
278  * @ingroup Ecore_IMF_Context_Group
279  */
280 EAPI void
281 ecore_imf_context_show(Ecore_IMF_Context *ctx)
282 {
283    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
284      {
285         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
286                          "ecore_imf_context_show");
287         return;
288      }
289    if (ctx->klass->show) ctx->klass->show(ctx);
290 }
291
292 /**
293  * Ask the Input Method Context to hide itself.
294  *
295  * @param ctx An #Ecore_IMF_Context.
296  * @ingroup Ecore_IMF_Context_Group
297  */
298 EAPI void
299 ecore_imf_context_hide(Ecore_IMF_Context *ctx)
300 {
301    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
302      {
303         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
304                          "ecore_imf_context_hide");
305         return;
306      }
307    if (ctx->klass->hide) ctx->klass->hide(ctx);
308 }
309
310 /*
311  * Retrieve the current preedit string and cursor position
312  * for the Input Method Context.
313  *
314  * @param ctx An #Ecore_IMF_Context.
315  * @param str Location to store the retrieved string. The
316  *            string retrieved must be freed with free().
317  * @param cursor_pos Location to store position of cursor (in characters)
318  *                   within the preedit string.
319  * @ingroup Ecore_IMF_Context_Group
320  */
321 EAPI void
322 ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cursor_pos)
323 {
324    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
325      {
326         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
327                          "ecore_imf_context_preedit_string_get");
328         return;
329      }
330    if (ctx->klass->preedit_string_get)
331      ctx->klass->preedit_string_get(ctx, str, cursor_pos);
332    else
333      {
334         if (str) *str = strdup("");
335         if (cursor_pos) *cursor_pos = 0;
336      }
337 }
338
339 /**
340  * Notify the Input Method Context that the widget to which its
341  * correspond has gained focus.
342  *
343  * @param ctx An #Ecore_IMF_Context.
344  * @ingroup Ecore_IMF_Context_Group
345  */
346 EAPI void
347 ecore_imf_context_focus_in(Ecore_IMF_Context *ctx)
348 {
349    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
350      {
351         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
352                          "ecore_imf_context_focus_in");
353         return;
354      }
355    if (ctx->klass->focus_in) ctx->klass->focus_in(ctx);
356 }
357
358 /**
359  * Notify the Input Method Context that the widget to which its
360  * correspond has lost focus.
361  *
362  * @param ctx An #Ecore_IMF_Context.
363  * @ingroup Ecore_IMF_Context_Group
364  */
365 EAPI void
366 ecore_imf_context_focus_out(Ecore_IMF_Context *ctx)
367 {
368    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
369      {
370         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
371                          "ecore_imf_context_focus_out");
372         return;
373      }
374    if (ctx->klass->focus_out) ctx->klass->focus_out(ctx);
375 }
376
377 /**
378  * Notify the Input Method Context that a change such as a
379  * change in cursor position has been made. This will typically
380  * cause the Input Method Context to clear the preedit state.
381  *
382  * @param ctx An #Ecore_IMF_Context.
383  * @ingroup Ecore_IMF_Context_Group
384  */
385 EAPI void
386 ecore_imf_context_reset(Ecore_IMF_Context *ctx)
387 {
388    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
389      {
390         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
391                          "ecore_imf_context_reset");
392         return;
393      }
394    if (ctx->klass->reset) ctx->klass->reset(ctx);
395 }
396
397 /**
398  * Notify the Input Method Context that a change in the cursor
399  * position has been made.
400  *
401  * @param ctx An #Ecore_IMF_Context.
402  * @param cursor_pos New cursor position in characters.
403  * @ingroup Ecore_IMF_Context_Group
404  */
405 EAPI void
406 ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
407 {
408    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
409      {
410         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
411                          "ecore_imf_context_cursor_position_set");
412         return;
413      }
414    if (ctx->klass->cursor_position_set) ctx->klass->cursor_position_set(ctx, cursor_pos);
415 }
416
417 /**
418  * Set whether the IM context should use the preedit string
419  * to display feedback. If @use_preedit is 0 (default
420  * is 1), then the IM context may use some other method to display
421  * feedback, such as displaying it in a child of the root window.
422  *
423  * @param ctx An #Ecore_IMF_Context.
424  * @param use_preedit Whether the IM context should use the preedit string.
425  * @ingroup Ecore_IMF_Context_Group
426  */
427 EAPI void
428 ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, int use_preedit)
429 {
430    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
431      {
432         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
433                          "ecore_imf_context_use_preedit_set");
434         return;
435      }
436    if (ctx->klass->use_preedit_set) ctx->klass->use_preedit_set(ctx, use_preedit);
437 }
438
439 /**
440  * Set the callback to be used on get_surrounding request.
441  *
442  * This callback will be called when the Input Method Context
443  * module requests the surrounding context.
444  *
445  * @param ctx An #Ecore_IMF_Context.
446  * @param func The callback to be called.
447  * @param data The data pointer to be passed to @p func
448  * @ingroup Ecore_IMF_Context_Group
449  */
450 EAPI void
451 ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, int (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data)
452 {
453    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
454      {
455         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
456                          "ecore_imf_context_retrieve_surrounding_callback_set");
457         return;
458      }
459
460    ctx->retrieve_surrounding_func = func;
461    ctx->retrieve_surrounding_data = (void *) data;
462 }
463
464 /**
465  * Set the input mode used by the Ecore Input Context.
466  *
467  * The input mode can be one of the input modes defined in
468  * #Ecore_IMF_Input_Mode. The default input mode is
469  * ECORE_IMF_INPUT_MODE_FULL.
470  *
471  * @param ctx An #Ecore_IMF_Context.
472  * @param input_mode The input mode to be used by @p ctx.
473  * @ingroup Ecore_IMF_Context_Group
474  */
475 EAPI void
476 ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
477 {
478    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
479      {
480         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
481                          "ecore_imf_context_input_mode_set");
482         return;
483      }
484    if (ctx->klass->input_mode_set) ctx->klass->input_mode_set(ctx, input_mode);
485    ctx->input_mode = input_mode;
486 }
487
488 /**
489  * Get the input mode being used by the Ecore Input Context.
490  *
491  * See @ref ecore_imf_context_input_mode_set for more details.
492  *
493  * @param ctx An #Ecore_IMF_Context.
494  * @return The input mode being used by @p ctx.
495  * @ingroup Ecore_IMF_Context_Group
496  */
497 EAPI Ecore_IMF_Input_Mode
498 ecore_imf_context_input_mode_get(Ecore_IMF_Context *ctx)
499 {
500    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
501      {
502         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
503                          "ecore_imf_context_input_mode_set");
504         return 0;
505      }
506    return ctx->input_mode;
507 }
508
509 /**
510  * Allow an Ecore Input Context to internally handle an event.
511  * If this function returns 1, then no further processing
512  * should be done for this event.
513  *
514  * Input methods must be able to accept all types of events (simply
515  * returning 0 if the event was not handled), but there is no
516  * obligation of any events to be submitted to this function.
517  *
518  * @param ctx An #Ecore_IMF_Context.
519  * @param type The type of event defined by #Ecore_IMF_Event_Type.
520  * @param event The event itself.
521  * @return 1 if the event was handled; otherwise 0.
522  * @ingroup Ecore_IMF_Context_Group
523  */
524 EAPI int
525 ecore_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
526 {
527    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
528      {
529         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
530                          "ecore_imf_context_filter_event");
531         return 0;
532      }
533    if (ctx->klass->filter_event) return ctx->klass->filter_event(ctx, type, event);
534    return 0;
535 }
536
537 /**
538  * @defgroup Ecore_IMF_Context_Module_Group Ecore Input Method Context Module Functions
539  *
540  * Functions that should be used by Ecore Input Method Context modules.
541  */
542
543 /**
544  * Creates a new Input Method Context with klass specified by @p ctxc.
545  *
546  * This method should be used by modules implementing the Input
547  * Method Context interface.
548  *
549  * @param ctxc An #Ecore_IMF_Context_Class.
550  * @return A new #Ecore_IMF_Context; on failure it returns NULL.
551  * @ingroup Ecore_IMF_Context_Module_Group
552  */
553 EAPI Ecore_IMF_Context *
554 ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc)
555 {
556    Ecore_IMF_Context *ctx;
557
558    if (!ctxc) return NULL;
559    ctx = malloc(sizeof(Ecore_IMF_Context));
560    if (!ctx) return NULL;
561    ECORE_MAGIC_SET(ctx, ECORE_MAGIC_CONTEXT);
562    ctx->klass = ctxc;
563    ctx->data = NULL;
564    ctx->retrieve_surrounding_func = NULL;
565    ctx->retrieve_surrounding_data = NULL;
566    return ctx;
567 }
568
569 /**
570  * Set the Input Method Context specific data.
571  *
572  * Note that this method should be used by modules to set
573  * the Input Method Context specific data and it's not meant to
574  * be used by applications to store application specific data.
575  *
576  * @param ctx An #Ecore_IMF_Context.
577  * @param data The Input Method Context specific data.
578  * @return A new #Ecore_IMF_Context; on failure it returns NULL.
579  * @ingroup Ecore_IMF_Context_Module_Group
580  */
581 EAPI void
582 ecore_imf_context_data_set(Ecore_IMF_Context *ctx, void *data)
583 {
584    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
585      {
586         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
587                          "ecore_imf_context_data_set");
588         return;
589      }
590    ctx->data = data;
591 }
592
593 /**
594  * Get the Input Method Context specific data.
595  *
596  * See @ref ecore_imf_context_data_set for more details.
597  *
598  * @param ctx An #Ecore_IMF_Context.
599  * @return The Input Method Context specific data.
600  * @ingroup Ecore_IMF_Context_Module_Group
601  */
602 EAPI void *ecore_imf_context_data_get(Ecore_IMF_Context *ctx)
603 {
604    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
605      {
606         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
607                          "ecore_imf_context_data_get");
608         return NULL;
609      }
610    return ctx->data;
611 }
612
613 /**
614  * Retrieve context around insertion point.
615  *
616  * This function is implemented by calling the
617  * Ecore_IMF_Context::retrieve_surrounding_func (
618  * set using #ecore_imf_context_retrieve_surrounding_callback_set).
619  *
620  * There is no obligation for a widget to respond to the
621  * ::retrieve_surrounding_func, so input methods must be prepared
622  * to function without context.
623  *
624  * @param ctx An #Ecore_IMF_Context.
625  * @param text Location to store a UTF-8 encoded string of text
626  *             holding context around the insertion point.
627  *             If the function returns 1, then you must free
628  *             the result stored in this location with free().
629  * @param cursor_pos Location to store the position in characters of
630  *                   the insertion cursor within @text.
631  * @return 1 if surrounding text was provided; otherwise 0.
632  * @ingroup Ecore_IMF_Context_Module_Group
633  */
634 EAPI int
635 ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos)
636 {
637    int result = 0;
638
639    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
640      {
641         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
642                          "ecore_imf_context_surrounding_get");
643         return 0;
644      }
645
646    if (ctx->retrieve_surrounding_func)
647      {
648         result = ctx->retrieve_surrounding_func(ctx->retrieve_surrounding_data, ctx, text, cursor_pos);
649         if (!result)
650           {
651              if (text) *text = NULL;
652              if (cursor_pos) *cursor_pos = 0;
653           }
654      }
655    return result;
656 }
657
658 static void
659 _ecore_imf_event_free_preedit(void *data __UNUSED__, void *event)
660 {
661    free(event);
662 }
663
664 /**
665  * Adds ECORE_IMF_EVENT_PREEDIT_START to the event queue.
666  *
667  * @param ctx An #Ecore_IMF_Context.
668  * @ingroup Ecore_IMF_Context_Module_Group
669  */
670 EAPI void
671 ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx)
672 {
673    Ecore_IMF_Event_Commit *ev;
674
675    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
676      {
677         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
678                          "ecore_imf_context_preedit_start_event_add");
679         return;
680      }
681
682    ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Start));
683    ev->ctx = ctx;
684    ecore_event_add(ECORE_IMF_EVENT_PREEDIT_START,
685                    ev, _ecore_imf_event_free_preedit, NULL);
686 }
687
688 /**
689  * Adds ECORE_IMF_EVENT_PREEDIT_END to the event queue.
690  *
691  * @param ctx An #Ecore_IMF_Context.
692  * @ingroup Ecore_IMF_Context_Module_Group
693  */
694 EAPI void
695 ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx)
696 {
697    Ecore_IMF_Event_Commit *ev;
698
699    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
700      {
701         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
702                          "ecore_imf_context_preedit_end_event_add");
703         return;
704      }
705
706    ev = malloc(sizeof(Ecore_IMF_Event_Preedit_End));
707    ev->ctx = ctx;
708    ecore_event_add(ECORE_IMF_EVENT_PREEDIT_END,
709                    ev, _ecore_imf_event_free_preedit, NULL);
710 }
711
712 /**
713  * Adds ECORE_IMF_EVENT_PREEDIT_CHANGED to the event queue.
714  *
715  * @param ctx An #Ecore_IMF_Context.
716  * @ingroup Ecore_IMF_Context_Module_Group
717  */
718 EAPI void
719 ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx)
720 {
721    Ecore_IMF_Event_Commit *ev;
722
723    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
724      {
725         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
726                          "ecore_imf_context_preedit_changed_event_add");
727         return;
728      }
729
730    ev = malloc(sizeof(Ecore_IMF_Event_Preedit_Changed));
731    ev->ctx = ctx;
732    ecore_event_add(ECORE_IMF_EVENT_PREEDIT_CHANGED,
733                    ev, _ecore_imf_event_free_preedit, NULL);
734 }
735
736 static void
737 _ecore_imf_event_free_commit(void *data __UNUSED__, void *event)
738 {
739    Ecore_IMF_Event_Commit *ev;
740
741    ev = event;
742    if (ev->str) free(ev->str);
743    free(ev);
744 }
745
746 /**
747  * Adds ECORE_IMF_EVENT_COMMIT to the event queue.
748  *
749  * @param ctx An #Ecore_IMF_Context.
750  * @param str The committed string.
751  * @ingroup Ecore_IMF_Context_Module_Group
752  */
753 EAPI void
754 ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str)
755 {
756    Ecore_IMF_Event_Commit *ev;
757
758    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
759      {
760         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
761                          "ecore_imf_context_commit_event_add");
762         return;
763      }
764
765    ev = malloc(sizeof(Ecore_IMF_Event_Commit));
766    ev->ctx = ctx;
767    ev->str = str ? strdup(str) : NULL;
768    ecore_event_add(ECORE_IMF_EVENT_COMMIT,
769                    ev, _ecore_imf_event_free_commit, NULL);
770
771 }
772
773 static void
774 _ecore_imf_event_free_delete_surrounding(void *data __UNUSED__, void *event)
775 {
776    free(event);
777 }
778
779 /**
780  * Adds ECORE_IMF_EVENT_DELETE_SURROUNDING to the event queue.
781  *
782  * @param ctx An #Ecore_IMF_Context.
783  * @param offset The start offset of surrounding to be deleted.
784  * @param n_chars The number of characters to be deleted.
785  * @ingroup Ecore_IMF_Context_Module_Group
786  */
787 EAPI void
788 ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offset, int n_chars)
789 {
790    Ecore_IMF_Event_Delete_Surrounding *ev;
791
792    if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT))
793      {
794         ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT,
795                          "ecore_imf_context_delete_surrounding_event_add");
796         return;
797      }
798
799    ev = malloc(sizeof(Ecore_IMF_Event_Delete_Surrounding));
800    ev->ctx = ctx;
801    ev->offset = offset;
802    ev->n_chars = n_chars;
803    ecore_event_add(ECORE_IMF_EVENT_DELETE_SURROUNDING,
804                    ev, _ecore_imf_event_free_delete_surrounding, NULL);
805 }