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