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