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