*** empty log message ***
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nInputMethod
25     @brief API for Input method
26
27     An input method is an object to enable inputting various
28     characters.  An input method is identified by a pair of symbols,
29     LANGUAGE and NAME.  This pair decides an input driver of the input
30     method.  An input driver is a set of functions for handling the
31     input method.  There are two kinds of input methods; internal one
32     and foreign one.
33
34     <ul>
35
36     <li> Internal Input Method
37
38     An internal input method has non @c Mnil LANGUAGE, and the body is
39     defined in the m17n database by the tag <Minput_method, LANGUAGE,
40     NAME>.  For this kind of input methods, the m17n library uses two
41     predefined input method drivers, one for CUI use and the other for
42     GUI use.  Those driver utilize the input processing engine
43     provided by the m17n library itself.  The m17n database may
44     provides an input method that is not only for a specific language.
45     The database uses @c Mt as the language of such an input method.
46
47     An internal input method accepts an input key which is a symbol
48     associated with an input event.  As there is no way for the @c
49     m17n @c library to know how input events are represented in an
50     application program, a application programmer have to convert an
51     input event to an input key by himself.  See the documentation of
52     the function minput_event_to_key () for the detail.
53
54     <li> Foreign Input Method
55
56     A foreign input method has @c Mnil LANGUAGE, and the body is
57     defined in an external resources (e.g. XIM of X Window System).
58     For this kind of input methods, the symbol NAME must have a
59     property of key @c Minput_driver, and the value must be a pointer
60     to an input driver.  So, by preparing a proper input 
61     driver, any kind of input method can be treated in the framework
62     of the @c m17n @c library.
63
64     For convenience, the m17n-X library provides an input driver that
65     enables the input style of OverTheSpot for XIM, and stores @c
66     Minput_driver property of the symbol @c Mxim with a pointer to
67     that driver.  See the documentation of m17n GUI API for the
68     detail.
69
70     </ul>
71
72     PROCESSING FLOW
73
74     The typical processing flow of handling an input method is: open
75     an input method, create an input context for the input method,
76     filter an input key, and looking up a produced text in the input
77     context.  */
78
79 /*=*/
80
81 /***ja
82     @addtogroup m17nInputMethod
83     @brief ÆþÎϥ᥽¥Ã¥ÉÍÑAPI
84
85     ÆþÎϥ᥽¥Ã¥É¤Ï¿ÍͤÊʸ»ú¤òÆþÎϤ¹¤ë¤¿¤á¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£ÆþÎÏ¥á
86     ¥½¥Ã¥É¤Ï¥·¥ó¥Ü¥ë LANGUAGE ¤È NAME ¤ÎÁȤˤè¤Ã¤Æ¼±Ê̤µ¤ì¡¢¤³¤ÎÁȤˤè¤Ã
87     ¤ÆÆþÎϥɥ饤¥Ð¤¬·è¤Þ¤ë¡£ÆþÎϥɥ饤¥Ð¤È¤Ï»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ò°·¤¦¤¿
88     ¤á¤Î´Ø¿ô¤Î½¸¤Þ¤ê¤Ç¤¢¤ë¡£
89
90     ÆþÎϥ᥽¥Ã¥É¤Ë¤ÏÆâÉô¥á¥½¥Ã¥É¤È³°Éô¥á¥½¥Ã¥É¤ÎÆóÄ̤꤬¤¢¤ë¡£
91
92     ÆâÉôÆþÎϥ᥽¥Ã¥É
93
94     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï LANGUAGE ¤¬ @c Mnil °Ê³°¤Î¤â¤Î¤Ç¤¢¤ê¡¢ËÜÂΤÏ
95     m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹¤Ë <Minput_method, LANGUAGE, NAME>¤È¤¤¤¦¥¿¥°ÉÕ
96     ¤­¤ÇÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤ËÂФ·¤Æ¡¢m17n¥é¥¤¥Ö¥é¥ê¤Ë
97     ¤ÏCUIÍѤÈGUIÍѤ½¤ì¤¾¤ì¤ÎÆþÎϥɥ饤¥Ð¤¬¤¢¤é¤«¤¸¤á½àÈ÷¤µ¤ì¤Æ¤¤¤ë¡£¤³
98     ¤ì¤é¤Î¥É¥é¥¤¥Ð¤Ïm17n¥é¥¤¥Ö¥é¥ê¼«¿È¤ÎÆþÎϽèÍý¥¨¥ó¥¸¥ó¤òÍøÍѤ¹¤ë¡£
99
100     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï¡¢¥æ¡¼¥¶¤ÎÆþÎÏ¥¤¥Ù¥ó¥È¤ËÂбþ¤·¤¿ÆþÎÏ¥­¡¼¤ò¼õ¤±¼è
101     ¤ë¡£ÆþÎÏ¥­¡¼¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÏÆþÎÏ¥¤¥Ù¥ó¥È
102     ¤¬¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¡¦¥×¥í¥°¥é¥à¤Ç¤É¤Î¤è¤¦¤Ëɽ¸½¤µ¤ì¤Æ¤¤¤ë¤«¤òÃΤë½Ñ
103     ¤ò»ý¤¿¤Ê¤¤¤Î¤Ç¡¢ÆþÎÏ¥¤¥Ù¥ó¥È¤«¤éÆþÎÏ¥­¡¼¤Ø¤ÎÊÑ´¹¤Ï¥×¥í¥°¥é¥Þ¤ÎÀÕǤ
104     ¤Ç¹Ô¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô minput_event_to_key () 
105     ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
106
107     ³°ÉôÆþÎϥ᥽¥Ã¥É
108
109     ³°ÉôÆþÎϥ᥽¥Ã¥É¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢¤ÇËÜÂΤϳ°Éô
110     ¤Î¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê¤É¡£) 
111     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver ¤ò¥­¡¼¤È
112     ¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥɥ饤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê
113     ¤é¤Ê¤¤¡£¤·¤¿¤¬¤Ã¤Æ¡¢Å¬ÀÚ¤ÊÆþÎϥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢¤¤¤«
114     ¤Ê¤ëÆþÎϥ᥽¥Ã¥É¤â @c m17n @c ¥é¥¤¥Ö¥é¥ê¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦»ö¤¬¤Ç¤­¤ë¡£
115
116     ´Êñ¤Î¤¿¤á¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤ÏXIM ¤Î OverTheSpot ¤ÎÆþÎÏ¥¹¥¿¥¤¥ë¤ò
117     ¼Â¸½¤¹¤ëÆþÎϥɥ饤¥Ð¤òÄ󶡤·¤Æ¤¤¤ë¡£¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î @c
118     Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý¤·
119     ¤Æ¤¤¤ë¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ïm17n-win API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
120
121     ½èÍý¤Îή¤ì
122
123     ÆþÎϥ᥽¥Ã¥É½èÍý¤Îŵ·¿Åª¤Ê½èÍý¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£ÆþÎϥ᥽¥Ã¥É¤Î¥ª¡¼
124     ¥×¥ó¡¢¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ÎÀ¸À®¡¢ÆþÎÏ¥¤¥Ù¥ó¥È¤Î¥Õ¥£
125     ¥ë¥¿¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ç¤ÎÀ¸À®¥Æ¥­¥¹¥È¤Î¸¡º÷¡£     */
126
127 /*=*/
128
129 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
130 /*** @addtogroup m17nInternal
131      @{ */
132
133 #include <stdio.h>
134 #include <string.h>
135 #include <dlfcn.h>
136
137 #include "config.h"
138 #include "m17n-gui.h"
139 #include "m17n-misc.h"
140 #include "internal.h"
141 #include "mtext.h"
142 #include "input.h"
143 #include "symbol.h"
144 #include "plist.h"
145
146 static MSymbol Minput_method;
147
148 /** Symbols to load an input method data.  */
149 static MSymbol Mtitle, Mmacro, Mmodule, Mstate;
150
151 /** Symbols for actions.  */
152 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
153 static MSymbol Mselect, Mshow, Mhide;
154 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
155
156 static MSymbol Mcandidate_list, Mcandidate_index;
157
158 static MSymbol Minit, Mfini;
159
160 /** Symbols for key events.  */
161 static MSymbol one_char_symbol[256];
162
163 /** Structure to hold a map.  */
164
165 struct MIMMap
166 {
167   /** List of actions to take when we reach the map.  In a root map,
168       the actions are executed only when there's no more key.  */
169   MPlist *map_actions;
170
171   /** List of deeper maps.  If NULL, this is a terminal map.  */
172   MPlist *submaps;
173
174   /** List of actions to take when we leave the map successfully.  In
175       a root map, the actions are executed only when none of submaps
176       handle the current key.  */
177   MPlist *branch_actions;
178 };
179
180 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
181
182 typedef struct
183 {
184   void *handle;
185   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
186 } MIMExternalModule;
187
188 struct MIMState
189 {
190   /** Name of the state.  */
191   MSymbol name;
192
193   /** Title of the state, or NULL.  */
194   MText *title;
195
196   /** Key translation map of the state.  Built by merging all maps of
197       branches.  */
198   MIMMap *map;
199 };
200
201
202 static int
203 marker_code (MSymbol sym)
204 {
205   char *name;
206
207   if (sym == Mnil)
208     return -1;
209   name = MSYMBOL_NAME (sym);
210   return ((name[0] == '@'
211            && ((name[1] >= '0' && name[1] <= '9')
212                || name[1] == '<' || name[1] == '>'
213                || name[1] == '=' || name[1] == '+' || name[1] == '-'
214                || name[1] == '[' || name[1] == ']')
215            && name[2] == '\0')
216           ? name[1] : -1);
217 }
218
219 int
220 integer_value (MInputContext *ic, MPlist *arg)
221 {
222   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
223   int code;
224   MText *preedit = ic->preedit;
225   int len = mtext_nbytes (preedit);
226
227   if (MPLIST_INTEGER_P (arg))
228     return MPLIST_INTEGER (arg);
229   code = marker_code (MPLIST_SYMBOL (arg));
230   if (code < 0)
231     return (int) mplist_get (ic_info->vars, MPLIST_SYMBOL (arg));
232   if (code >= '0' && code <= '9')
233     code -= '0';
234   else if (code == '=')
235     code = ic->cursor_pos;
236   else if (code == '-' || code == '[')
237     code = ic->cursor_pos - 1;
238   else if (code == '+' || code == ']')
239     code = ic->cursor_pos + 1;
240   else if (code == '<')
241     code = 0;
242   else if (code == '<')
243     code = len;
244   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
245 }
246
247
248 /* Parse PLIST as an action list while modifying the list to regularize
249    actions.  PLIST should have this form:
250       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
251    Return 0 if successfully parsed, otherwise return -1.  */
252
253 static int
254 parse_action_list (MPlist *plist, MPlist *macros)
255 {
256   MPLIST_DO (plist, plist)
257     {
258       if (MPLIST_MTEXT_P (plist))
259         {
260           /* This is a short form of (insert MTEXT).  */
261           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
262              MERROR (MERROR_IM, -1); */
263         }
264       else if (MPLIST_PLIST_P (plist)
265                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
266                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
267         {
268           MPlist *pl;
269
270           /* This is a short form of (insert (GROUPS *)).  */
271           MPLIST_DO (pl, MPLIST_PLIST (plist))
272             {
273               if (MPLIST_PLIST_P (pl))
274                 {
275                   MPlist *elt;
276
277                   MPLIST_DO (elt, MPLIST_PLIST (pl))
278                     if (! MPLIST_MTEXT_P (elt)
279                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
280                       MERROR (MERROR_IM, -1);
281                 }
282               else
283                 {
284                   if (! MPLIST_MTEXT_P (pl)
285                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
286                     MERROR (MERROR_IM, -1);
287                 }
288             }
289         }
290       else if (MPLIST_INTEGER_P (plist))
291         {
292           int c = MPLIST_INTEGER (plist);
293
294           if (c < 0 || c > MCHAR_MAX)
295             MERROR (MERROR_IM, -1);
296         }
297       else if (MPLIST_PLIST_P (plist)
298                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
299         {
300           MPlist *pl = MPLIST_PLIST (plist);
301           MSymbol action_name = MPLIST_SYMBOL (pl);
302
303           pl = MPLIST_NEXT (pl);
304
305           if (action_name == Minsert)
306             {
307               if (MPLIST_MTEXT_P (pl))
308                 {
309                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
310                     MERROR (MERROR_IM, -1);
311                 }
312               else if (MPLIST_PLIST_P (pl))
313                 {
314                   MPLIST_DO (pl, pl)
315                     {
316                       if (MPLIST_PLIST_P (pl))
317                         {
318                           MPlist *elt;
319
320                           MPLIST_DO (elt, MPLIST_PLIST (pl))
321                             if (! MPLIST_MTEXT_P (elt)
322                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
323                               MERROR (MERROR_IM, -1);
324                         }
325                       else
326                         {
327                           if (! MPLIST_MTEXT_P (pl)
328                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
329                             MERROR (MERROR_IM, -1);
330                         }
331                     }
332                 }
333               else if (! MPLIST_SYMBOL_P (pl))
334                 MERROR (MERROR_IM, -1); 
335             }
336           else if (action_name == Mselect
337                    || action_name == Mdelete
338                    || action_name == Mmove)
339             {
340               if (! MPLIST_SYMBOL_P (pl)
341                   && ! MPLIST_INTEGER_P (pl))
342                 MERROR (MERROR_IM, -1);
343             }
344           else if (action_name == Mmark
345                    || action_name == Mcall
346                    || action_name == Mshift)
347             {
348               if (! MPLIST_SYMBOL_P (pl))
349                 MERROR (MERROR_IM, -1);
350             }
351           else if (action_name == Mshow || action_name == Mhide
352                    || action_name == Mundo)
353             {
354               if (! MPLIST_TAIL_P (pl))
355                 MERROR (MERROR_IM, -1);
356             }
357           else if (action_name == Mpushback)
358             {
359               if (! MPLIST_INTEGER_P (pl))
360                 MERROR (MERROR_IM, -1);
361             }
362           else if (action_name == Mset || action_name == Madd
363                    || action_name == Msub || action_name == Mmul
364                    || action_name == Mdiv)
365             {
366               if (! (MPLIST_SYMBOL_P (pl)
367                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
368                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
369                 MERROR (MERROR_IM, -1);
370             }
371           else if (action_name == Mequal || action_name == Mless
372                    || action_name == Mgreater)
373             {
374               if (! ((MPLIST_INTEGER_P (pl) || MPLIST_SYMBOL_P (pl))
375                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
376                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
377                 MERROR (MERROR_IM, -1);
378               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
379               if (! MPLIST_PLIST_P (pl))
380                 MERROR (MERROR_IM, -1);
381               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
382                 MERROR (MERROR_IM, -1);
383               pl = MPLIST_NEXT (pl);
384               if (MPLIST_PLIST_P (pl)
385                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
386                 MERROR (MERROR_IM, -1);
387             }
388           else if (! macros || ! mplist_get (macros, action_name))
389             MERROR (MERROR_IM, -1);
390         }
391       else
392         MERROR (MERROR_IM, -1);
393     }
394
395   return 0;
396 }
397
398
399 /* Load a translation into MAP from PLIST.
400    PLIST has this form:
401       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
402
403 static int
404 load_translation (MIMMap *map, MPlist *plist, MPlist *branch_actions,
405                   MPlist *macros)
406 {
407   MSymbol *keyseq;
408   int len, i;
409
410   if (MPLIST_MTEXT_P (plist))
411     {
412       MText *mt = MPLIST_MTEXT (plist);
413
414       len = mtext_nchars (mt);
415       if (len == 0 || len != mtext_nbytes (mt))
416         MERROR (MERROR_IM, -1);
417       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
418       for (i = 0; i < len; i++)
419         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
420     }
421   else if (MPLIST_PLIST_P (plist))
422     {
423       MPlist *elt = MPLIST_PLIST (plist);
424           
425       len = MPLIST_LENGTH (elt);
426       if (len == 0)
427         MERROR (MERROR_IM, -1);
428       keyseq = (MSymbol *) alloca (sizeof (int) * len);
429       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
430         {
431           if (MPLIST_INTEGER_P (elt))
432             {
433               int c = MPLIST_INTEGER (elt);
434
435               if (c < 0 || c >= 0x100)
436                 MERROR (MERROR_IM, -1);
437               keyseq[i] = one_char_symbol[c];
438             }
439           else if (MPLIST_SYMBOL_P (elt))
440             keyseq[i] = MPLIST_SYMBOL (elt);
441           else
442             MERROR (MERROR_IM, -1);
443         }
444     }
445   else
446     MERROR (MERROR_IM, -1);
447
448   for (i = 0; i < len; i++)
449     {
450       MIMMap *deeper = NULL;
451
452       if (map->submaps)
453         deeper = mplist_get (map->submaps, keyseq[i]);
454       else
455         map->submaps = mplist ();
456       if (! deeper)
457         {
458           /* Fixme: It is better to make all deeper maps at once.  */
459           MSTRUCT_CALLOC (deeper, MERROR_IM);
460           mplist_put (map->submaps, keyseq[i], deeper);
461         }
462       map = deeper;
463     }
464
465   /* We reach a terminal map.  */
466   if (map->map_actions
467       || map->branch_actions)
468     /* This map is already defined.  We avoid overriding it.  */
469     return 0;
470
471   plist = MPLIST_NEXT (plist);
472   if (! MPLIST_TAIL_P (plist))
473     {
474       if (parse_action_list (plist, macros) < 0)
475         MERROR (MERROR_IM, -1);
476       map->map_actions = plist;
477       M17N_OBJECT_REF (plist);
478     }
479   if (branch_actions)
480     {
481       map->branch_actions = branch_actions;
482       M17N_OBJECT_REF (branch_actions);
483     }
484
485   return 0;
486 }
487
488 /* Load a branch from PLIST into MAP.  PLIST has this form:
489       PLIST ::= ( MAP-NAME BRANCH-ACTION * )
490    MAPS is a plist of raw maps.
491    STATE is the current state.  */
492
493 static int
494 load_branch (MPlist *plist, MPlist *maps, MIMMap *map, MPlist *macros)
495 {
496   MSymbol map_name;
497   MPlist *branch_actions;
498
499   if (! MPLIST_SYMBOL_P (plist))
500     MERROR (MERROR_IM, -1);
501   map_name = MPLIST_SYMBOL (plist);
502   plist = MPLIST_NEXT (plist);
503   if (MPLIST_TAIL_P (plist))
504     branch_actions = NULL;
505   else if (parse_action_list (plist, macros) < 0)
506     MERROR (MERROR_IM, -1);
507   else
508     branch_actions = plist;
509   if (map_name == Mnil)
510     {
511       map->branch_actions = branch_actions;
512       if (branch_actions)
513         M17N_OBJECT_REF (branch_actions);
514     }
515   else if (map_name == Mt)
516     {
517       map->map_actions = branch_actions;
518       if (branch_actions)
519         M17N_OBJECT_REF (branch_actions);
520     }
521   else
522     {
523       plist = (MPlist *) mplist_get (maps, map_name);
524       if (! plist || ! MPLIST_PLIST_P (plist))
525         MERROR (MERROR_IM, -1);
526       MPLIST_DO (plist, plist)
527         if (! MPLIST_PLIST_P (plist)
528             || (load_translation (map, MPLIST_PLIST (plist), branch_actions,
529                                   macros)
530                 < 0))
531           MERROR (MERROR_IM, -1);
532     }
533
534   return 0;
535 }
536
537 /* Load a macro from PLIST into MACROS.
538    PLIST has this from:
539       PLIST ::= ( MACRO-NAME ACTION * )
540    MACROS is a plist of macro names vs action list.  */
541 static int
542 load_macros (MPlist *plist, MPlist *macros)
543 {
544   MSymbol name; 
545
546   if (! MPLIST_SYMBOL_P (plist))
547     MERROR (MERROR_IM, -1);
548   name = MPLIST_SYMBOL (plist);
549   plist = MPLIST_NEXT (plist);
550   if (MPLIST_TAIL_P (plist)
551       || parse_action_list (plist, macros) < 0)
552     MERROR (MERROR_IM, -1);
553   mplist_put (macros, name, plist);
554   M17N_OBJECT_REF (plist);
555   return 0;
556 }
557
558 /* Load an external module from PLIST into EXTERNALS.
559    PLIST has this form:
560       PLIST ::= ( MODULE-NAME FUNCTION * )
561    EXTERNALS is a plist of MODULE-NAME vs (MIMExternalModule *).  */
562
563 #ifndef DLOPEN_SHLIB_EXT
564 #define DLOPEN_SHLIB_EXT ".so"
565 #endif
566
567 static int
568 load_external_module (MPlist *plist, MPlist *externals)
569 {
570   void *handle;
571   MSymbol module;
572   char *module_file;
573   MIMExternalModule *external;
574   MPlist *func_list;
575   void *func;
576
577   if (MPLIST_MTEXT_P (plist))
578     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
579   else if (MPLIST_SYMBOL_P (plist))
580     module = MPLIST_SYMBOL (plist);
581   module_file = alloca (strlen (MSYMBOL_NAME (module))
582                         + strlen (DLOPEN_SHLIB_EXT) + 1);
583   sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
584
585   handle = dlopen (module_file, RTLD_NOW);
586   if (! handle)
587     {
588       fprintf (stderr, "%s\n", dlerror ());
589       MERROR (MERROR_IM, -1);
590     }
591   func_list = mplist ();
592   MPLIST_DO (plist, MPLIST_NEXT (plist))
593     {
594       if (! MPLIST_SYMBOL_P (plist))
595         MERROR_GOTO (MERROR_IM, err_label);
596       func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist)));
597       if (! func)
598         MERROR_GOTO (MERROR_IM, err_label);
599       mplist_add (func_list, MPLIST_SYMBOL (plist), func);
600     }
601
602   MSTRUCT_MALLOC (external, MERROR_IM);
603   external->handle = handle;
604   external->func_list = func_list;
605   mplist_add (externals, module, external);
606   return 0;
607
608  err_label:
609   dlclose (handle);
610   M17N_OBJECT_UNREF (func_list);
611   return -1;
612 }
613
614
615 /** Load a state from PLIST into a newly allocated state object.
616     PLIST has this form:
617       PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * )
618       BRANCH ::= ( MAP-NAME BRANCH-ACTION * )
619    MAPS is a plist of defined maps.
620    Return the state object.  */
621
622 static MIMState *
623 load_state (MPlist *plist, MPlist *maps, MSymbol language, MPlist *macros)
624 {
625   MIMState *state;
626
627   MSTRUCT_CALLOC (state, MERROR_IM);
628   if (! MPLIST_SYMBOL_P (plist))
629     MERROR (MERROR_IM, NULL);
630   state->name = MPLIST_SYMBOL (plist);
631   plist = MPLIST_NEXT (plist);
632   if (MPLIST_MTEXT_P (plist))
633     {
634       state->title = MPLIST_MTEXT (plist);
635       mtext_put_prop (state->title, 0, mtext_nchars (state->title),
636                       Mlanguage, language);
637       M17N_OBJECT_REF (state->title);
638       plist = MPLIST_NEXT (plist);
639     }
640   MSTRUCT_CALLOC (state->map, MERROR_IM);
641   MPLIST_DO (plist, plist)
642     if (! MPLIST_PLIST_P (plist)
643         || load_branch (MPLIST_PLIST (plist), maps, state->map, macros) < 0)
644       MERROR (MERROR_IM, NULL);
645   return state;
646 }
647
648
649 static void
650 free_map (MIMMap *map)
651 {
652   MPlist *plist;
653
654   M17N_OBJECT_UNREF (map->map_actions);
655   if (map->submaps)
656     {
657       MPLIST_DO (plist, map->submaps)
658         free_map ((MIMMap *) MPLIST_VAL (plist));
659       M17N_OBJECT_UNREF (map->submaps);
660     }
661   M17N_OBJECT_UNREF (map->branch_actions);
662   free (map);
663 }
664
665 /* Load an input method from PLIST into IM_INTO, and return it.  */
666
667 static int
668 load_input_method (MSymbol language, MSymbol name, MPlist *plist,
669                    MInputMethodInfo *im_info)
670 {
671   MText *title = NULL;
672   MPlist *maps = NULL;
673   MPlist *states = NULL;
674   MPlist *externals = NULL;
675   MPlist *macros = NULL;
676   MPlist *elt;
677
678   if (! MPLIST_PLIST_P (plist))
679     MERROR (MERROR_IM, -1);
680   for (; MPLIST_PLIST_P (plist); plist = MPLIST_NEXT (plist))
681     {
682       elt = MPLIST_PLIST (plist);
683       if (! MPLIST_SYMBOL_P (elt))
684         MERROR_GOTO (MERROR_IM, err);
685       if (MPLIST_SYMBOL (elt) == Mtitle)
686         {
687           elt = MPLIST_NEXT (elt);
688           if (MPLIST_MTEXT_P (elt))
689             {
690               title = MPLIST_MTEXT (elt);
691               M17N_OBJECT_REF (title);
692             }
693           else
694             MERROR_GOTO (MERROR_IM, err);
695         }
696       else if (MPLIST_SYMBOL (elt) == Mmap)
697         {
698           maps = mplist__from_alist (MPLIST_NEXT (elt));
699           if (! maps)
700             MERROR_GOTO (MERROR_IM, err);
701         }
702       else if (MPLIST_SYMBOL (elt) == Mmacro)
703         {
704           macros = mplist ();
705           MPLIST_DO (elt, MPLIST_NEXT (elt))
706           {
707             if (! MPLIST_PLIST_P (elt)
708                 || load_macros (MPLIST_PLIST (elt), macros) < 0)
709               MERROR_GOTO (MERROR_IM, err);
710           }
711         }
712       else if (MPLIST_SYMBOL (elt) == Mmodule)
713         {
714           externals = mplist ();
715           MPLIST_DO (elt, MPLIST_NEXT (elt))
716           {
717             if (! MPLIST_PLIST_P (elt)
718                 || load_external_module (MPLIST_PLIST (elt), externals) < 0)
719               MERROR_GOTO (MERROR_IM, err);
720           }
721         }
722       else if (MPLIST_SYMBOL (elt) == Mstate)
723         {
724           states = mplist ();
725           MPLIST_DO (elt, MPLIST_NEXT (elt))
726           {
727             MIMState *state;
728
729             if (! MPLIST_PLIST_P (elt))
730               MERROR_GOTO (MERROR_IM, err);
731             state = load_state (MPLIST_PLIST (elt), maps, language, macros);
732             if (! state)
733               MERROR_GOTO (MERROR_IM, err);
734             mplist_put (states, state->name, state);
735           }
736         }
737     }
738
739   MPLIST_DO (elt, maps)
740     M17N_OBJECT_UNREF (MPLIST_VAL (elt));
741   M17N_OBJECT_UNREF (maps);
742   im_info->title = title;
743   im_info->externals = externals;
744   im_info->macros = macros;
745   im_info->states = states;
746   return 0;
747
748  err:
749   if (maps)
750     {
751       MPLIST_DO (elt, maps)
752         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
753       M17N_OBJECT_UNREF (maps);
754     }
755   if (title)
756     M17N_OBJECT_UNREF (title);
757   if (states)
758     {
759       MPLIST_DO (plist, states)
760       {
761         MIMState *state = (MIMState *) MPLIST_VAL (plist);
762
763         if (state->title)
764           M17N_OBJECT_UNREF (state->title);
765         if (state->map)
766           free_map (state->map);
767         free (state);
768       }
769       M17N_OBJECT_UNREF (states);
770     }
771   if (externals)
772     {
773       MPLIST_DO (plist, externals)
774       {
775         MIMExternalModule *external = MPLIST_VAL (plist);
776
777         dlclose (external->handle);
778         M17N_OBJECT_UNREF (external->func_list);
779         free (external);
780         MPLIST_KEY (plist) = Mt;
781       }
782       M17N_OBJECT_UNREF (externals);
783     }
784   return -1;
785 }
786
787 \f
788
789 static int take_action_list (MInputContext *ic, MPlist *action_list);
790
791 static void
792 shift_state (MInputContext *ic, MSymbol state_name)
793 {
794   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
795   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
796   MIMState *state = ic_info->state;
797
798   /* Find a state to shift to.  If not found, shift to the initial
799      state.  */
800   state = (MIMState *) mplist_get (im_info->states, state_name);
801   if (! state)
802     state = (MIMState *) MPLIST_VAL (im_info->states);
803
804   /* Enter the new state.  */
805   ic_info->state = state;
806   ic_info->map = state->map;
807   ic_info->state_key_head = ic_info->key_head;
808   if (state == (MIMState *) MPLIST_VAL (im_info->states))
809     {
810       /* We have shifted to the initial state.  */
811       MPlist *p;
812
813       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
814                              Mcandidate_list, NULL, 0);
815       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
816                              Mcandidate_index, NULL, 0);
817       mtext_cat (ic->produced, ic->preedit);
818       mtext_reset (ic->preedit);
819       ic->candidate_list = NULL;
820       ic->candidate_show = 0;
821       ic->preedit_changed = ic->candidates_changed = 1;
822       MPLIST_DO (p, ic_info->markers)
823         MPLIST_VAL (p) = 0;
824       MPLIST_DO (p, ic_info->vars)
825         MPLIST_VAL (p) = 0;
826       ic->cursor_pos = 0;
827       memmove (ic_info->keys, ic_info->keys + ic_info->state_key_head,
828                sizeof (int) * (ic_info->used - ic_info->state_key_head));
829       ic_info->used -= ic_info->state_key_head;
830       ic_info->state_key_head = ic_info->key_head = 0;
831     }
832   mtext_cpy (ic_info->preedit_saved, ic->preedit);
833   ic_info->state_pos = ic->cursor_pos;
834   ic->status = state->title;
835   if (! ic->status)
836     ic->status = im_info->title;
837   ic->status_changed = 1;
838   if (ic_info->key_head == ic_info->used
839       && ic_info->map == ic_info->state->map
840       && ic_info->map->map_actions)
841     take_action_list (ic, ic_info->map->map_actions);
842 }
843
844
845 static MPlist *
846 find_candidates_group (MPlist *plist, int index,
847                        int *start_index, int *end_index, int *group_index)
848 {
849   int i = 0, gidx = 0, len;
850
851   MPLIST_DO (plist, plist)
852     {
853       if (MPLIST_MTEXT_P (plist))
854         len = mtext_nchars (MPLIST_MTEXT (plist));
855       else
856         len = mplist_length (MPLIST_PLIST (plist));
857       if (i + len > index)
858         {
859           if (start_index)
860             *start_index = i;
861           if (end_index)
862             *end_index = i + len;
863           if (group_index)
864             *group_index = gidx;
865           return plist;
866         }
867       i += len;
868       gidx++;
869     }
870   return NULL;
871 }
872
873 static void
874 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
875 {
876   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
877   MPlist *markers;
878   int nchars = mt ? mtext_nchars (mt) : 1;
879
880   if (mt)
881     mtext_ins (ic->preedit, pos, mt);
882   else
883     mtext_ins_char (ic->preedit, pos, c, 1);
884   MPLIST_DO (markers, ic_info->markers)
885     if (MPLIST_INTEGER (markers) > pos)
886       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
887   if (ic->cursor_pos >= pos)
888     ic->cursor_pos += nchars;
889   ic->preedit_changed = 1;
890 }
891
892
893 static void
894 preedit_delete (MInputContext *ic, int from, int to)
895 {
896   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
897   MPlist *markers;
898
899   mtext_del (ic->preedit, from, to);
900   MPLIST_DO (markers, ic_info->markers)
901     {
902       if (MPLIST_INTEGER (markers) > to)
903         MPLIST_VAL (markers)
904           = (void *) (MPLIST_INTEGER (markers) - (to - from));
905       else if (MPLIST_INTEGER (markers) > from);
906         MPLIST_VAL (markers) = (void *) from;
907     }
908   if (ic->cursor_pos >= to)
909     ic->cursor_pos -= to - from;
910   else if (ic->cursor_pos > from)
911     ic->cursor_pos = from;
912   ic->preedit_changed = 1;
913 }
914
915
916 static int
917 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
918 {
919   int code = marker_code (sym);
920
921   if (mt && (code == '[' || code == ']'))
922     {
923       int pos = current;
924
925       if (code == '[' && current > 0)
926         {
927           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
928               && pos > 0)
929             current = pos;
930         }
931       else if (code == ']' && current < mtext_nchars (mt))
932         {
933           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
934             current = pos;
935         }
936       return current;
937     }
938   if (code >= 0)
939     return (code == '<' ? 0
940             : code == '>' ? limit
941             : code == '-' ? current - 1
942             : code == '+' ? current + 1
943             : code == '=' ? current
944             : code - '0' > limit ? limit
945             : code - '0');
946   if (! ic)  
947     return 0;
948   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
949 }
950
951 static void
952 udpate_candidate (MInputContext *ic, MTextProperty *prop, int idx)
953 {
954   int from = mtext_property_start (prop);
955   int to = mtext_property_end (prop);
956   int start;
957   MPlist *candidate_list = mtext_property_value (prop);
958   MPlist *group = find_candidates_group (candidate_list, idx, &start,
959                                          NULL, NULL);
960   int ingroup_index = idx - start;
961   MText *mt;
962
963   preedit_delete (ic, from, to);
964   if (MPLIST_MTEXT_P (group))
965     {
966       mt = MPLIST_MTEXT (group);
967       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
968       to = from + 1;
969     }
970   else
971     {
972       int i;
973       MPlist *plist;
974
975       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
976            i++, plist = MPLIST_NEXT (plist));
977       mt = MPLIST_MTEXT (plist);
978       preedit_insert (ic, from, mt, 0);
979       to = from + mtext_nchars (mt);
980     }
981   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
982   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
983   ic->cursor_pos = to;
984 }
985
986
987 static int
988 take_action_list (MInputContext *ic, MPlist *action_list)
989 {
990   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
991   MPlist *candidate_list = ic->candidate_list;
992   int candidate_index = ic->candidate_index;
993   int candidate_show = ic->candidate_show;
994   MTextProperty *prop;
995
996   MPLIST_DO (action_list, action_list)
997     {
998       MPlist *action;
999       MSymbol name;
1000       MPlist *args;
1001
1002       if (MPLIST_MTEXT_P (action_list)
1003           || MPLIST_INTEGER_P (action_list))
1004         name = Minsert, args = action_list;
1005       else if (MPLIST_PLIST_P (action_list)
1006                && (MPLIST_MTEXT_P (MPLIST_PLIST (action_list))
1007                    || MPLIST_PLIST_P (MPLIST_PLIST (action_list))))
1008         name = Minsert, args = action_list;
1009       else
1010         {
1011           action = MPLIST_PLIST (action_list);
1012           name = MPLIST_SYMBOL (action);
1013           args = MPLIST_NEXT (action);
1014         }
1015
1016       if (name == Minsert)
1017         {
1018           if (MPLIST_MTEXT_P (args))
1019             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1020           else if (MPLIST_INTEGER_P (args))
1021             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1022           else if (MPLIST_SYMBOL_P (args))
1023             {
1024               int c = integer_value (ic, args);
1025
1026               if (c >= 0 && c <= MCHAR_MAX)
1027                 preedit_insert (ic, ic->cursor_pos, NULL, c);
1028             }
1029           else
1030             {
1031               MText *mt;
1032               int len;
1033
1034               args = MPLIST_PLIST (args);
1035               if (MPLIST_MTEXT_P (args))
1036                 {
1037                   preedit_insert (ic, ic->cursor_pos, NULL,
1038                                   mtext_ref_char (MPLIST_MTEXT (args), 0));
1039                   len = 1;
1040                 }
1041               else
1042                 {
1043                   mt = MPLIST_MTEXT (MPLIST_PLIST (args));
1044                   preedit_insert (ic, ic->cursor_pos, mt, 0);
1045                   len = mtext_nchars (mt);
1046                 }
1047               mtext_put_prop (ic->preedit,
1048                               ic->cursor_pos - len, ic->cursor_pos,
1049                               Mcandidate_list, args);
1050               mtext_put_prop (ic->preedit,
1051                               ic->cursor_pos - len, ic->cursor_pos,
1052                               Mcandidate_index, (void *) 0);
1053             }
1054         }
1055       else if (name == Mselect)
1056         {
1057           int start, end;
1058           int code, idx, gindex;
1059           int pos = ic->cursor_pos;
1060           MPlist *group;
1061
1062           if (pos == 0
1063               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
1064                                                Mcandidate_list)))
1065             continue;
1066           if (MPLIST_SYMBOL_P (args))
1067             {
1068               code = marker_code (MPLIST_SYMBOL (args));
1069               if (code < 0)
1070                 continue;
1071             }
1072           else
1073             code = -1;
1074           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
1075           group = find_candidates_group (mtext_property_value (prop), idx,
1076                                          &start, &end, &gindex);
1077
1078           if (code != '[' && code != ']')
1079             {
1080               idx = (start
1081                      + (code >= 0
1082                         ? new_index (NULL, ic->candidate_index - start,
1083                                      end - start - 1, MPLIST_SYMBOL (args),
1084                                      NULL)
1085                         : MPLIST_INTEGER (args)));
1086               if (idx < 0
1087                   || (idx >= end
1088                       && MPLIST_TAIL_P (MPLIST_NEXT (group))))
1089                 idx = 0;
1090             }
1091           else
1092             {
1093               int ingroup_index = idx - start;
1094               int len;
1095
1096               group = mtext_property_value (prop);
1097               len = mplist_length (group);
1098               if (code == '[')
1099                 {
1100                   gindex--;
1101                   if (gindex < 0)
1102                     gindex = len - 1;;
1103                 }
1104               else
1105                 {
1106                   gindex++;
1107                   if (gindex >= len)
1108                     gindex = 0;
1109                 }
1110               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
1111                 idx += (MPLIST_MTEXT_P (group)
1112                         ? mtext_nchars (MPLIST_MTEXT (group))
1113                         : mplist_length (MPLIST_PLIST (group)));
1114               len = (MPLIST_MTEXT_P (group)
1115                      ? mtext_nchars (MPLIST_MTEXT (group))
1116                      : mplist_length (MPLIST_PLIST (group)));
1117               if (ingroup_index >= len)
1118                 ingroup_index = len - 1;
1119               idx += ingroup_index;
1120             }
1121           udpate_candidate (ic, prop, idx);
1122         }
1123       else if (name == Mshow)
1124         ic->candidate_show = 1;
1125       else if (name == Mhide)
1126         ic->candidate_show = 0;
1127       else if (name == Mdelete)
1128         {
1129           int len = mtext_nchars (ic->preedit);
1130           int to = (MPLIST_SYMBOL_P (args)
1131                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1132                                  ic->preedit)
1133                     : MPLIST_INTEGER (args));
1134
1135           if (to < 0)
1136             to = 0;
1137           else if (to > len)
1138             to = len;
1139           if (to < ic->cursor_pos)
1140             preedit_delete (ic, to, ic->cursor_pos);
1141           else if (to > ic->cursor_pos)
1142             preedit_delete (ic, ic->cursor_pos, to);
1143         }
1144       else if (name == Mmove)
1145         {
1146           int len = mtext_nchars (ic->preedit);
1147           int pos
1148             = (MPLIST_SYMBOL_P (args)
1149                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1150                             ic->preedit)
1151                : MPLIST_INTEGER (args));
1152
1153           if (pos < 0)
1154             pos = 0;
1155           else if (pos > len)
1156             pos = len;
1157           if (pos != ic->cursor_pos)
1158             {
1159               ic->cursor_pos = pos;
1160               ic->preedit_changed = 1;
1161             }
1162         }
1163       else if (name == Mmark)
1164         {
1165           int code = marker_code (MPLIST_SYMBOL (args));
1166
1167           if (code < 0)
1168             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
1169                         (void *) ic->cursor_pos);
1170         }
1171       else if (name == Mpushback)
1172         {
1173           int num = MPLIST_INTEGER (args);
1174
1175           if (num > 0)
1176             ic_info->key_head -= num;
1177           else
1178             ic_info->key_head = num;
1179           if (ic_info->key_head > ic_info->used)
1180             ic_info->key_head = ic_info->used;
1181         }
1182       else if (name == Mcall)
1183         {
1184           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1185           MIMExternalFunc func = NULL;
1186           MSymbol module, func_name;
1187           MPlist *func_args, *val;
1188           int ret = 0;
1189
1190           module = MPLIST_SYMBOL (args);
1191           args = MPLIST_NEXT (args);
1192           func_name = MPLIST_SYMBOL (args);
1193
1194           if (im_info->externals)
1195             {
1196               MIMExternalModule *external
1197                 = (MIMExternalModule *) mplist_get (im_info->externals,
1198                                                     module);
1199               if (external)
1200                 func = (MIMExternalFunc) mplist_get (external->func_list,
1201                                                      func_name);
1202             }
1203           if (! func)
1204             continue;
1205           func_args = mplist ();
1206           mplist_add (func_args, Mt, ic);
1207           MPLIST_DO (args, MPLIST_NEXT (args))
1208             {
1209               int code;
1210
1211               if (MPLIST_KEY (args) == Msymbol
1212                   && MPLIST_KEY (args) != Mnil
1213                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
1214                 {
1215                   code = new_index (ic, ic->cursor_pos, 
1216                                     mtext_nchars (ic->preedit),
1217                                     MPLIST_SYMBOL (args), ic->preedit);
1218                   mplist_add (func_args, Minteger, (void *) code);
1219                 }
1220               else
1221                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
1222             }
1223           val = (func) (func_args);
1224           M17N_OBJECT_UNREF (func_args);
1225           if (val && ! MPLIST_TAIL_P (val))
1226             ret = take_action_list (ic, val);
1227           M17N_OBJECT_UNREF (val);
1228           if (ret < 0)
1229             return ret;
1230         }
1231       else if (name == Mshift)
1232         {
1233           shift_state (ic, MPLIST_SYMBOL (args));
1234         }
1235       else if (name == Mundo)
1236         {
1237           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1238           int unhandle = 0;
1239
1240           mtext_reset (ic->preedit);
1241           mtext_reset (ic_info->preedit_saved);
1242           ic->cursor_pos = ic_info->state_pos = 0;
1243           ic_info->state_key_head = ic_info->key_head = 0;
1244           ic_info->used -= 2;
1245           if (ic_info->used < 0)
1246             {
1247               ic_info->used = 0;
1248               unhandle = 1;
1249             }
1250           shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1251           if (unhandle)
1252             return -1;
1253           break;
1254         }
1255       else if (name == Mset || name == Madd || name == Msub
1256                || name == Mmul || name == Mdiv)
1257         {
1258           MSymbol sym = MPLIST_SYMBOL (args);
1259           int val1 = (int) mplist_get (ic_info->vars, sym), val2;
1260
1261           args = MPLIST_NEXT (args);
1262           val2 = integer_value (ic, args);
1263           if (name == Mset)
1264             val1 = val2;
1265           else if (name == Madd)
1266             val1 += val2;
1267           else if (name == Msub)
1268             val1 -= val2;
1269           else if (name == Mmul)
1270             val1 *= val2;
1271           else
1272             val1 /= val2;
1273           mplist_put (ic_info->vars, sym, (void *) val1);
1274         }
1275       else if (name == Mequal || name == Mless || name == Mgreater)
1276         {
1277           int val1, val2;
1278           MPlist *actions1, *actions2;
1279           int ret;
1280
1281           val1 = integer_value (ic, args);
1282           args = MPLIST_NEXT (args);
1283           val2 = integer_value (ic, args);
1284           args = MPLIST_NEXT (args);
1285           actions1 = MPLIST_PLIST (args);
1286           args = MPLIST_NEXT (args);
1287           if (MPLIST_TAIL_P (args))
1288             actions2 = NULL;
1289           else
1290             actions2 = MPLIST_PLIST (args);
1291           if (name == Mequal ? val1 == val2
1292               : name == Mless ? val1 < val2
1293               : val1 > val2)
1294             ret = take_action_list (ic, actions1);
1295           else if (actions2)
1296             ret = take_action_list (ic, actions2);
1297           if (ret < 0)
1298             return ret;
1299         }
1300       else
1301         {
1302           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1303           MPlist *actions;
1304
1305           if (im_info->macros
1306               && (actions = mplist_get (im_info->macros, name)))
1307             {
1308               if (take_action_list (ic, actions) < 0)
1309                 return -1;
1310             };
1311         }
1312     }
1313
1314   prop = NULL;
1315   ic->candidate_list = NULL;
1316   if (ic->cursor_pos > 0
1317       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
1318                                      Mcandidate_list)))
1319     {
1320       ic->candidate_list = mtext_property_value (prop);
1321       ic->candidate_index
1322         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
1323                                 Mcandidate_index);
1324       ic->candidate_from = mtext_property_start (prop);
1325       ic->candidate_to = mtext_property_end (prop);
1326     }
1327
1328   ic->candidates_changed |= (candidate_list != ic->candidate_list
1329                              || candidate_index != ic->candidate_index
1330                              || candidate_show != ic->candidate_show);
1331   return 0;
1332 }
1333
1334
1335 /* Handle the input key KEY in the current state and map specified in
1336    the input context IC.  If KEY is handled correctly, return 0.
1337    Otherwise, return -1.  */
1338
1339 static int
1340 handle_key (MInputContext *ic)
1341 {
1342   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1343   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1344   MIMMap *map = ic_info->map;
1345   MIMMap *submap;
1346   MSymbol key = ic_info->keys[ic_info->key_head];
1347   int i;
1348
1349   submap = (map->submaps ? mplist_get (map->submaps, key) : NULL);
1350   if (submap)
1351     {
1352       mtext_cpy (ic->preedit, ic_info->preedit_saved);
1353       ic->cursor_pos = ic_info->state_pos;
1354       ic_info->key_head++;
1355       ic_info->map = map = submap;
1356       if (map->map_actions)
1357         {
1358           if (take_action_list (ic, map->map_actions) < 0)
1359             return -1;
1360         }
1361       else if (map->submaps)
1362         {
1363           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
1364             {
1365               MSymbol key = ic_info->keys[i];
1366               char *name = msymbol_name (key);
1367
1368               if (! name[0] || ! name[1])
1369                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
1370             }
1371           ic->preedit_changed = 1;
1372         }
1373
1374       /* If this is the terminal map or we have shifted to another
1375          state, perform branch actions (if any).  */
1376       if (! map->submaps || map != ic_info->map)
1377         {
1378           if (map->branch_actions)
1379             {
1380               if (take_action_list (ic, map->branch_actions) < 0)
1381                 return -1;
1382             }
1383           /* If MAP is still not the root map, shift to the current
1384              state.  */
1385           if (ic_info->map != ic_info->state->map)
1386             shift_state (ic, ic_info->state->name);
1387         }
1388     }
1389   else
1390     {
1391       /* MAP can not handle KEY.  */
1392
1393       /* If MAP is the root map of the initial state, it means that
1394          the current input method can not handle KEY.  */
1395       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
1396         return -1;
1397
1398       if (map != ic_info->state->map)
1399         {
1400           /* If MAP is not the root map... */
1401           /* If MAP has branch actions, perform them.  */
1402           if (map->branch_actions)
1403             take_action_list (ic, map->branch_actions);
1404           /* If MAP is still not the root map, shift to the current
1405              state. */
1406           if (ic_info->map != ic_info->state->map)
1407             {
1408               shift_state (ic, ic_info->state->name);
1409               /* If MAP has branch_actions, perform them.  */
1410               if (ic_info->map->branch_actions)
1411                 take_action_list (ic, ic_info->map->branch_actions);
1412             }
1413         }
1414       else
1415         {
1416           /* MAP is the root map, perform branch actions (if any) or
1417              shift to the initial state.  */
1418           if (map->branch_actions)
1419             take_action_list (ic, map->branch_actions);
1420           else
1421             shift_state (ic,
1422                          ((MIMState *) MPLIST_VAL (im_info->states))->name);
1423         }
1424     }
1425   return 0;
1426 }
1427
1428 static void
1429 reset_ic (MInputContext *ic)
1430 {
1431   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1432   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1433
1434   MLIST_RESET (ic_info);
1435   ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
1436   ic_info->map = ic_info->state->map;
1437   ic_info->state_key_head = ic_info->key_head = 0;
1438   ic->cursor_pos = ic_info->state_pos = 0;
1439   ic->status = ic_info->state->title;
1440   if (! ic->status)
1441     ic->status = im_info->title;
1442   ic->candidate_list = NULL;
1443   ic->candidate_show = 0;
1444   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
1445   if (ic_info->map->map_actions)
1446     take_action_list (ic, ic_info->map->map_actions);
1447 }
1448
1449 static int
1450 open_im (MInputMethod *im)
1451 {
1452   MDatabase *mdb;
1453   MInputMethodInfo *im_info;
1454   MPlist *plist;
1455   int result;
1456
1457   mdb = mdatabase_find (Minput_method, im->language, im->name, Mnil);
1458   if (! mdb)
1459     return -1;
1460   plist = mdatabase_load (mdb);
1461   if (! plist)
1462     MERROR (MERROR_IM, -1);
1463   MSTRUCT_CALLOC (im_info, MERROR_IM);
1464   im->info = im_info;
1465   result = load_input_method (im->language, im->name, plist, im_info);
1466   M17N_OBJECT_UNREF (plist);
1467   if (result < 0)
1468     MERROR (MERROR_IM, -1);
1469   return 0;
1470 }
1471
1472 static void
1473 close_im (MInputMethod *im)
1474 {
1475   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1476   MPlist *plist;
1477
1478   if (im_info->title)
1479     M17N_OBJECT_UNREF (im_info->title);
1480   if (im_info->states)
1481     {
1482       MPLIST_DO (plist, im_info->states)
1483         {
1484           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1485
1486           if (state->title)
1487             M17N_OBJECT_UNREF (state->title);
1488           if (state->map)
1489             free_map (state->map);
1490           free (state);
1491         }
1492       M17N_OBJECT_UNREF (im_info->states);
1493     }
1494
1495   if (im_info->macros)
1496     {
1497       MPLIST_DO (plist, im_info->macros)
1498         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1499       M17N_OBJECT_UNREF (im_info->macros);
1500     }
1501
1502   if (im_info->externals)
1503     {
1504       MPLIST_DO (plist, im_info->externals)
1505         {
1506           MIMExternalModule *external = MPLIST_VAL (plist);
1507
1508           dlclose (external->handle);
1509           M17N_OBJECT_UNREF (external->func_list);
1510           free (external);
1511           MPLIST_KEY (plist) = Mt;
1512         }
1513       M17N_OBJECT_UNREF (im_info->externals);
1514     }
1515   free (im_info);
1516   im->info = NULL;
1517 }
1518
1519
1520 static int
1521 create_ic (MInputContext *ic)
1522 {
1523   MInputMethod *im = ic->im;
1524   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1525   MInputContextInfo *ic_info;
1526
1527   if (ic->info)
1528     ic_info = (MInputContextInfo *) ic->info;
1529   else
1530     {
1531       MSTRUCT_CALLOC (ic_info, MERROR_IM);
1532       ic->info = ic_info;
1533     }
1534   MLIST_INIT1 (ic_info, keys, 8);
1535   ic_info->markers = mplist ();
1536   ic_info->vars = mplist ();
1537   ic_info->preedit_saved = mtext ();
1538   if (im_info->externals)
1539     {
1540       MPlist *func_args = mplist (), *plist;
1541
1542       mplist_add (func_args, Mt, ic);
1543       MPLIST_DO (plist, im_info->externals)
1544         {
1545           MIMExternalModule *external = MPLIST_VAL (plist);
1546           MIMExternalFunc func
1547             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
1548
1549           if (func)
1550             (func) (func_args);
1551         }
1552       M17N_OBJECT_UNREF (func_args);
1553     }
1554   reset_ic (ic);
1555   return 0;
1556 }
1557
1558 static void
1559 destroy_ic (MInputContext *ic)
1560 {
1561   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1562   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1563
1564   if (im_info->externals)
1565     {
1566       MPlist *func_args = mplist (), *plist;
1567
1568       mplist_add (func_args, Mt, ic);
1569       MPLIST_DO (plist, im_info->externals)
1570         {
1571           MIMExternalModule *external = MPLIST_VAL (plist);
1572           MIMExternalFunc func
1573             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
1574
1575           if (func)
1576             (func) (func_args);
1577         }
1578       M17N_OBJECT_UNREF (func_args);
1579     }
1580   MLIST_FREE1 (ic_info, keys);
1581   M17N_OBJECT_UNREF (ic_info->preedit_saved);
1582   M17N_OBJECT_UNREF (ic_info->markers);
1583   M17N_OBJECT_UNREF (ic_info->vars);
1584   free (ic->info);
1585 }
1586
1587
1588 /** Handle the input key KEY in the current state and map of IC->info.
1589     If KEY is handled but no text is produced, return 0, otherwise
1590     return 1.
1591
1592     Ignore ARG.  */
1593
1594 static int
1595 filter (MInputContext *ic, MSymbol key, void *arg)
1596 {
1597   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1598   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1599   int i = 0;
1600
1601   mtext_reset (ic->produced);
1602   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
1603   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
1604   ic_info->key_unhandled = 0;
1605   do {
1606     if (handle_key (ic) < 0)
1607       {
1608         /* KEY was not handled.  Reset the status and break the
1609            loop.  */
1610         reset_ic (ic);
1611         /* This forces returning 1.  */
1612         ic_info->key_unhandled = 1;
1613         break;
1614       }
1615     if (i++ == 100)
1616       {
1617         mdebug_hook ();
1618         reset_ic (ic);
1619         ic_info->key_unhandled = 1;
1620         break;
1621       }
1622     /* Break the loop if all keys were handled.  */
1623   } while (ic_info->key_head < ic_info->used);
1624
1625   /* If the current map is the root of the initial state, we should
1626      produce any preedit text in ic->produced.  */
1627   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
1628       && mtext_nchars (ic->preedit) > 0)
1629     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1630
1631   if (mtext_nchars (ic->produced) > 0)
1632     {
1633       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
1634
1635       if (lang != Mnil)
1636         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
1637                         Mlanguage, ic->im->language);
1638     }
1639
1640   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
1641 }
1642
1643
1644 /** Return 1 if the last event or key was not handled, otherwise
1645     return 0.
1646
1647     There is no need of looking up because ic->produced should already
1648     contain the produced text (if any).
1649
1650     Ignore KEY.  */
1651
1652 static int
1653 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
1654 {
1655   mtext_cat (mt, ic->produced);
1656   mtext_reset (ic->produced);
1657   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
1658 }
1659
1660 /* Support functions for mdebug_dump_im.  */
1661
1662 static void
1663 dump_im_map (MPlist *map_list, int indent)
1664 {
1665   char *prefix;
1666   MSymbol key = MPLIST_KEY (map_list);
1667   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
1668
1669   prefix = (char *) alloca (indent + 1);
1670   memset (prefix, 32, indent);
1671   prefix[indent] = '\0';
1672
1673   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
1674   if (map->map_actions)
1675     mdebug_dump_plist (map->map_actions, indent + 2);
1676   if (map->submaps)
1677     {
1678       MPLIST_DO (map_list, map->submaps)
1679         {
1680           fprintf (stderr, "\n%s  ", prefix);
1681           dump_im_map (map_list, indent + 2);
1682         }
1683     }
1684   if (map->branch_actions)
1685     {
1686       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
1687       mdebug_dump_plist (map->branch_actions, indent + 4);
1688       fprintf (stderr, ")");      
1689     }
1690   fprintf (stderr, ")");
1691 }
1692
1693
1694 static void
1695 dump_im_state (MIMState *state, int indent)
1696 {
1697   char *prefix;
1698   MPlist *map_list;
1699
1700   prefix = (char *) alloca (indent + 1);
1701   memset (prefix, 32, indent);
1702   prefix[indent] = '\0';
1703
1704   fprintf (stderr, "(%s", msymbol_name (state->name));
1705   if (state->map->submaps)
1706     {
1707       MPLIST_DO (map_list, state->map->submaps)
1708         {
1709           fprintf (stderr, "\n%s  ", prefix);
1710           dump_im_map (map_list, indent + 2);
1711         }
1712     }
1713   fprintf (stderr, ")");
1714 }
1715
1716 \f
1717
1718 int
1719 minput__init ()
1720 {
1721   char *key_names[32]
1722     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1723         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
1724         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1725         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
1726   char buf[6], buf2[256];
1727   int i;
1728
1729   Minput_method = msymbol ("input-method");
1730   Minput_driver = msymbol ("input-driver");
1731   Mtitle = msymbol ("title");
1732   Mmacro = msymbol ("macro");
1733   Mmodule = msymbol ("module");
1734   Mmap = msymbol ("map");
1735   Mstate = msymbol ("state");
1736   Minsert = msymbol ("insert");
1737   Mdelete = msymbol ("delete");
1738   Mmove = msymbol ("move");
1739   Mmark = msymbol ("mark");
1740   Mpushback = msymbol ("pushback");
1741   Mundo = msymbol ("undo");
1742   Mcall = msymbol ("call");
1743   Mshift = msymbol ("shift");
1744   Mselect = msymbol ("select");
1745   Mshow = msymbol ("show");
1746   Mhide = msymbol ("hide");
1747   Mset = msymbol ("set");
1748   Madd = msymbol ("add");
1749   Msub = msymbol ("sub");
1750   Mmul = msymbol ("mul");
1751   Mdiv = msymbol ("div");
1752   Mequal = msymbol ("=");
1753   Mless = msymbol ("<");
1754   Mgreater = msymbol (">");
1755
1756   Minput_preedit_start = msymbol ("input-preedit-start");
1757   Minput_preedit_done = msymbol ("input-preedit-done");
1758   Minput_preedit_draw = msymbol ("input-preedit-draw");
1759   Minput_status_start = msymbol ("input-status-start");
1760   Minput_status_done = msymbol ("input-status-done");
1761   Minput_status_draw = msymbol ("input-status-draw");
1762   Minput_candidates_start = msymbol ("input-candidates-start");
1763   Minput_candidates_done = msymbol ("input-candidates-done");
1764   Minput_candidates_draw = msymbol ("input-candidates-draw");
1765   Minput_set_spot = msymbol ("input-set-spot");
1766   Minput_toggle = msymbol ("input-toggle");
1767
1768   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
1769   Mcandidate_index = msymbol ("  candidate-index");
1770
1771   Minit = msymbol ("init");
1772   Mfini = msymbol ("fini");
1773
1774   buf[0] = 'C';
1775   buf[1] = '-';
1776   buf[3] = '\0';
1777   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
1778     {
1779       if (key_names[i])
1780         one_char_symbol[i] = msymbol (key_names[i]);
1781       else
1782         one_char_symbol[i] = msymbol (buf);
1783     }
1784   for (buf[2] = i; i < 127; i++, buf[2]++)
1785     one_char_symbol[i] = msymbol (buf + 2);
1786   one_char_symbol[i++] = msymbol ("Delete");
1787   buf[2] = 'M';
1788   buf[3] = '-';
1789   buf[5] = '\0';
1790   buf2[0] = 'M';
1791   buf2[1] = '-';
1792   for (buf[4] = '@'; i < 160; i++, buf[4]++)
1793     {
1794       if (key_names[i - 128])
1795         {
1796           strcpy (buf2 + 2, key_names[i - 128]);
1797           one_char_symbol[i] = msymbol (buf2);
1798         }
1799       else
1800         one_char_symbol[i] = msymbol (buf);
1801     }
1802   for (buf[4] = i - 128; i < 255; i++, buf[2]++)
1803     one_char_symbol[i] = msymbol (buf + 2);
1804   one_char_symbol[i] = msymbol ("M-Delete");
1805
1806   minput_default_driver.open_im = open_im;
1807   minput_default_driver.close_im = close_im;
1808   minput_default_driver.create_ic = create_ic;
1809   minput_default_driver.destroy_ic = destroy_ic;
1810   minput_default_driver.filter = filter;
1811   minput_default_driver.lookup = lookup;
1812   minput_default_driver.callback_list = NULL;
1813   minput_driver = &minput_default_driver;
1814   return 0;
1815 }
1816
1817 void
1818 minput__fini ()
1819 {
1820   if (minput_default_driver.callback_list)
1821     {
1822       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
1823       minput_default_driver.callback_list = NULL;
1824     }
1825   if (minput_driver->callback_list)
1826     {
1827       M17N_OBJECT_UNREF (minput_driver->callback_list);
1828       minput_driver->callback_list = NULL;
1829     }
1830 }
1831
1832 void
1833 minput__callback (MInputContext *ic, MSymbol command)
1834 {
1835   if (ic->im->driver.callback_list)
1836     {
1837       MInputCallbackFunc func
1838         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
1839                                            command);
1840
1841       if (func)
1842         (func) (ic, command);
1843     }
1844 }
1845
1846 MSymbol
1847 minput__char_to_key (int c)
1848 {
1849   if (c < 0 || c >= 0x100)
1850     return Mnil;
1851
1852   return one_char_symbol[c];
1853 }
1854
1855 /*** @} */
1856 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1857
1858 \f
1859 /* External API */
1860
1861 /*** @addtogroup m17nInputMethod */
1862 /*** @{ */
1863 /*=*/
1864
1865 /***en
1866     @name Variables: Predefined symbols for callback commands.
1867
1868     These are the predefined symbols that are used as the @c COMMAND
1869     argument of callback functions of an input method driver (see
1870     #MInputDriver::callback_list).  */ 
1871 /*** @{ */ 
1872 /*=*/
1873
1874 MSymbol Minput_preedit_start;
1875 MSymbol Minput_preedit_done;
1876 MSymbol Minput_preedit_draw;
1877 MSymbol Minput_status_start;
1878 MSymbol Minput_status_done;
1879 MSymbol Minput_status_draw;
1880 MSymbol Minput_candidates_start;
1881 MSymbol Minput_candidates_done;
1882 MSymbol Minput_candidates_draw;
1883 MSymbol Minput_set_spot;
1884 MSymbol Minput_toggle;
1885 /*** @} */
1886 /*=*/
1887
1888 /***en
1889     @brief The default input driver for internal input methods.
1890
1891     The variable #minput_default_driver is the default driver for
1892     internal input methods.
1893
1894     The member MInputDriver::open_im () searches the m17n database for
1895     an input method that matches the tag \<#Minput_method, $LANGUAGE,
1896     $NAME\> and loads it.
1897
1898     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
1899     programmers responsibility to set it to a plist of proper callback
1900     functions.  Otherwise, no feedback information (e.g. preedit text)
1901     can be shown to users.
1902
1903     The macro M17N_INIT () sets the variable #minput_driver to the
1904     pointer to this driver so that all internal input methods use it.
1905
1906     Therefore, unless @c minput_driver is set differently, the driver
1907     dependent arguments $ARG of the functions whose name begin with
1908     "minput_" are all ignored.  */
1909
1910 /***ja
1911     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥ÈÆþÎϥɥ饤¥Ð
1912
1913     ÆþÎϥɥ饤¥Ð minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë
1914     ¥È¤ÎÆþÎϥɥ饤¥Ð¤Ç¤¢¤ë¡£
1915
1916     ¤³¤Î¥É¥é¥¤¥Ð¤Î <callback> ¥á¥ó¥Ð¤Ï @c NULL ¤Ê¤Î¤Ç¡¢¥×¥í¥°¥é¥Þ¦¤Ç
1917     ÀÕǤ¤ò»ý¤Ã¤Æ, Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ËÀßÄꤷ¡¢Preedit ¥Æ¥­¥¹¥È,
1918     Status ¥Æ¥­¥¹¥È¤¬¥æ¡¼¥¶¤Ëɽ¼¨¤Ç¤­¤ë¤è¤¦¤Ë¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1919
1920     ´Ø¿ô M17N_INIT () ¤ÏÊÑ¿ô @c minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
1921     ¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
1922
1923     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
1924     ¤Ç»Ï¤Þ¤ë°Ê²¼¤Î´Ø¿ô·²¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤É¤ì¤â̵»ë¤µ¤ì
1925     ¤ë¡£  */
1926
1927 MInputDriver minput_default_driver;
1928 /*=*/
1929
1930 /***en
1931     @brief The input driver for internal input methods.
1932
1933     The variable #minput_driver is a pointer to the input method
1934     driver that is used by internal input methods.  The macro
1935     M17N_INIT () initializes it to a pointer to #minput_default_driver
1936     (if <m17n.h> is included) or to #minput_gui_driver (if
1937     <m17n-gui.h> is included).  */ 
1938
1939 MInputDriver *minput_driver;
1940
1941 MSymbol Minput_driver;
1942
1943 /*=*/
1944
1945 /***en
1946     @brief Open an input method.
1947
1948     The minput_open_im () function opens an input method that matches
1949     language $LANGUAGE and name $NAME, and returns a pointer to the
1950     input method object newly allocated.
1951
1952     This function at first decides an input driver for the input
1953     method as below.
1954
1955     If $LANGUAGE is not #Mnil, an input driver pointed by the variable
1956     #minput_driver is used.
1957
1958     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
1959     input driver pointed to by the property value is used to open the
1960     input method.  If $NAME has no such property, @c NULL is returned.
1961
1962     Then, the member MInputDriver::open_im () of the input driver is
1963     called.  
1964
1965     $ARG is set in the member @c arg of the structure MInputMethod so
1966     that the input driver can refer to it.  */
1967
1968 /***ja
1969     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë     
1970
1971     ´Ø¿ô mim_open () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME ¤ËŬ¹ç¤¹¤ëÆþÎϥ᥽¥Ã
1972     ¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¤½¤Î¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1973
1974     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ã椫¤é \<@c
1975     Minput_method, $LANGUAGE, $NAME \> ¤È¤¤¤¦¥¿¥°¤ËŬ¹ç¤¹¤ëÆþÎϥ᥽¥Ã
1976     ¥É¤òõ¤¹¡£¸«¤Ä¤«¤Ã¤¿¾ì¹ç¤Ï¡¢ÊÑ¿ô #minput_driver ¤Ç¥Ý¥¤¥ó¥È¤µ¤ì¤Æ
1977     ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤Æ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£¸«¤Ä¤«¤é¤Ê
1978     ¤¤¾ì¹ç¤ä¥ª¡¼¥×¥ó¤Ç¤­¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï @c NULL ¤òÊÖ¤¹¡£
1979
1980     ÊÑ¿ô #minput_driver ¤Ï¡¢#minput_default_driver ¤« @c
1981     minput_gui_driver ¤Î¤É¤Á¤é¤«¤ò¥Ý¥¤¥ó¥È¤·¤Æ¤¤¤ë¡£Á°¼Ô¤Ï CUI ÍѤǤ¢
1982     ¤ê¡¢´Ø¿ôm17n_initialize () ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤Æ #minput_driver ¤¬ 
1983     #minput_default_driver ¤ò¥Ý¥¤¥ó¥È¤¹¤ë¤è¤¦¤Ë¤Ê¤ë¡£¸å¼Ô¤Ï GUI ÍѤÇ
1984     ¤¢¤ê¡¢´Ø¿ô m17n_initialize_win () ¤Ë¤è¤Ã¤Æ¥Ý¥¤¥ó¥È¤µ¤ì¤ë¡£¾ÜºÙ¤Ë¤Ä
1985     ¤¤¤Æ¤Ï¤³¤ì¤é¤ÎÊÑ¿ô¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
1986
1987     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver ¤ò¥­¡¼¤È¤¹
1988     ¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǥݥ¤¥ó¥È¤µ¤ì¤Æ¤¤¤ë
1989     ÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£$NAME ¤Ë¤½¤Î¤è¤¦¤Ê
1990     ¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤ä¥ª¡¼¥×¥ó¤Ç¤­¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï @c NULL ¤ò
1991     ÊÖ¤¹¡£
1992
1993     $ARG ¤Ï¡¢ÆþÎϥɥ饤¥Ð¤¬»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¡¢¹½Â¤ÂΠMInputMethod ¤Î¥á
1994     ¥ó¥Ð @c arg ¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£
1995
1996     @latexonly \IPAlabel{minput_open} @endlatexonly
1997
1998 */
1999
2000 MInputMethod *
2001 minput_open_im (MSymbol language, MSymbol name, void *arg)
2002 {
2003   MInputMethod *im;
2004   MInputDriver *driver;
2005
2006   if (language)
2007     driver = minput_driver;
2008   else
2009     {
2010       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
2011       if (! driver)
2012         MERROR (MERROR_IM, NULL);
2013     }
2014
2015   MSTRUCT_CALLOC (im, MERROR_IM);
2016   im->language = language;
2017   im->name = name;
2018   im->arg = arg;
2019   im->driver = *driver;
2020   if ((*im->driver.open_im) (im) < 0)
2021     {
2022       free (im);
2023       return NULL;
2024     }
2025   return im;
2026 }
2027
2028 /*=*/
2029
2030 /***en
2031     @brief Close an input method.
2032
2033     The minput_close_im () function closes the input method $IM, which
2034     must have been created by minput_open_im ().  */
2035
2036 /***ja
2037     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë
2038
2039     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£¤³¤Î
2040     ÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì
2041     ¤Ð¤Ê¤é¤Ê¤¤¡£  */
2042
2043 void
2044 minput_close_im (MInputMethod *im)
2045 {
2046   (*im->driver.close_im) (im);
2047   free (im);
2048 }
2049
2050 /*=*/
2051
2052 /***en
2053     @brief Create an input context.
2054
2055     The minput_create_ic () function creates an input context object
2056     associated with input method $IM, and calls callback functions
2057     corresponding to #Minput_preedit_start, #Minput_status_start, and
2058     #Minput_status_draw in this order.
2059
2060     @return
2061
2062     If an input context is successfully created, minput_create_ic ()
2063     returns a pointer to it.  Otherwise it returns @c NULL.  */
2064
2065 /***ja
2066     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë
2067
2068     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯
2069     ¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤¹¤ë¡£
2070
2071     @return
2072     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢minput_create_ic () ¤ÏÀ¸À®¤·¤¿ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È
2073     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£  */
2074
2075 MInputContext *
2076 minput_create_ic (MInputMethod *im, void *arg)
2077 {
2078   MInputContext *ic;
2079
2080   MSTRUCT_CALLOC (ic, MERROR_IM);
2081   ic->im = im;
2082   ic->arg = arg;
2083   ic->preedit = mtext ();
2084   ic->candidate_list = NULL;
2085   ic->produced = mtext ();
2086   ic->spot.x = ic->spot.y = 0;
2087   ic->active = 1;
2088   ic->plist = mplist ();
2089   if ((*im->driver.create_ic) (ic) < 0)
2090     {
2091       M17N_OBJECT_UNREF (ic->preedit);
2092       M17N_OBJECT_UNREF (ic->produced);
2093       M17N_OBJECT_UNREF (ic->plist);
2094       free (ic);
2095       return NULL;
2096     };
2097
2098   if (im->driver.callback_list)
2099     {
2100       minput__callback (ic, Minput_preedit_start);
2101       minput__callback (ic, Minput_status_start);
2102       minput__callback (ic, Minput_status_draw);
2103     }
2104
2105   return ic;
2106 }
2107
2108 /*=*/
2109
2110 /***en
2111     @brief Destroy an input context.
2112
2113     The minput_destroy_ic () function destroys the input context $IC,
2114     which must have been created by minput_create_ic ().  It calls
2115     callback functions corresponding to #Minput_preedit_done,
2116     #Minput_status_done, and #Mcandidate_done in this order.  */
2117
2118 /***ja
2119     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë
2120
2121     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£¤³
2122     ¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê
2123     ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
2124
2125 void
2126 minput_destroy_ic (MInputContext *ic)
2127 {
2128   if (ic->im->driver.callback_list)
2129     {
2130       minput__callback (ic, Minput_preedit_done);
2131       minput__callback (ic, Minput_status_done);
2132       minput__callback (ic, Minput_candidates_done);
2133     }
2134   (*ic->im->driver.destroy_ic) (ic);
2135   M17N_OBJECT_UNREF (ic->preedit);
2136   M17N_OBJECT_UNREF (ic->produced);
2137   M17N_OBJECT_UNREF (ic->plist);
2138   free (ic);
2139 }
2140
2141 /*=*/
2142
2143 /***en
2144     @brief Filter an input key.
2145
2146     The minput_filter () function filters input key $KEY according to
2147     input context $IC, and calls callback functions corresponding to
2148     #Minput_preedit_draw, #Minput_status_draw, and #Mcandidate_draw if
2149     the preedit text, the status, and the current candidate are
2150     changed respectively.
2151
2152     @return
2153     If $KEY is filtered out, this function returns 1.  In that case,
2154     the caller should discard the key.  Otherwise, it returns 0, and
2155     the caller should handle the key, for instance, by calling the
2156     function minput_lookup () with the same $KEY.  */
2157
2158 /***ja
2159     @brief ÆþÎÏ¥­¡¼¤Î¥Õ¥£¥ë¥¿¥ê¥ó¥°¤ò¤¹¤ë
2160
2161     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Ë±þ
2162     ¤¸¤Æ¥Õ¥£¥ë¥¿¥ê¥ó¥°¤¹¤ë¡£
2163
2164     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ÎÆþÎϥ᥽¥Ã¥É¤¬ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ì¤Ð¡¢¤³
2165     ¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
2166     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤¬¡¢¤¿¤È¤¨¤ÐƱ¤¸ $KEY ¤Ç´Ø¿ô 
2167     minput_lookup () ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
2168
2169     @latexonly \IPAlabel{minput_filter} @endlatexonly
2170 */
2171
2172 int
2173 minput_filter (MInputContext *ic, MSymbol key, void *arg)
2174 {
2175   int ret;
2176
2177   if (! ic
2178       || ! ic->active)
2179     return 0;
2180   ret = (*ic->im->driver.filter) (ic, key, arg);
2181
2182   if (ic->im->driver.callback_list)
2183     {
2184       if (ic->preedit_changed)
2185         minput__callback (ic, Minput_preedit_draw);
2186       if (ic->status_changed)
2187         minput__callback (ic, Minput_status_draw);
2188       if (ic->candidates_changed)
2189         minput__callback (ic, Minput_candidates_draw);
2190       ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
2191     }
2192
2193   return ret;
2194 }
2195
2196 /*=*/
2197
2198 /***en
2199     @brief Lookup a text produced in the input context.
2200
2201     The minput_lookup () function looks up a text in the input context
2202     $IC.  $KEY must be the same one provided to the previous call of
2203     minput_filter ().
2204
2205     If a text was produced by the input method, it is concatenated
2206     to M-text $MT.
2207
2208     This function calls #MInputDriver::lookup.
2209
2210     @return
2211     If $KEY was correctly handled by the input method, this function
2212     returns 0.  Otherwise, returns -1, even in that case, some text
2213     may be produced in $MT.  */
2214
2215 /***ja
2216     @brief ÆþÎϥ᥽¥Ã¥É¤¬ºî¤Ã¤¿¥Æ¥­¥¹¥È¤Î³ÍÆÀ
2217
2218     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤ò³ÍÆÀ¤¹
2219     ¤ë¡£$KEY ¤Ï´Ø¿ôminput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î
2220     ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2221
2222     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢$IC->produced ¤ËÊÝ
2223     »ý¤µ¤ì¤Æ¤¤¤ë¡£
2224
2225      ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Î <tt>XLookupString ()</tt> ¡¢
2226     <tt>XmbLookupString ()</tt> ¡¢<tt>XwcLookupString ()</tt> ¤ËÂбþ¤¹
2227     ¤ë¡£
2228
2229     @return
2230     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤Æ¤¤¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤ò
2231     ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢¤³¤Î¾ì¹ç¤Ç¤â$IC->produced ¤Ë²¿¤é¤«
2232     ¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
2233
2234     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
2235
2236 int
2237 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2238 {
2239   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
2240 }
2241 /*=*/
2242
2243 /***en
2244     @brief Set the spot of the input context.
2245
2246     The minput_set_spot () function set the spot of input context $IC
2247     to coordinate ($X, $Y) with the height $ASCENT and $DESCENT.
2248     $FONTSIZE specfies the fontsize of a preedit text in 1/10 point.
2249     The semantics of these values depend on the input driver.
2250
2251     For instance, an input driver designed to work in CUI environment
2252     may use $X and $Y as column and row numbers, and ignore $ASCENT
2253     and $DESCENT.  An input driver designed to work on a window system
2254     may treat $X and $Y as pixel offsets relative to the origin of the
2255     client window, and treat $ASCENT and $DESCENT as ascent and
2256     descent pixels of a line at ($X . $Y).
2257
2258     $MT and $POS is an M-text and a character position at the spot.
2259     $MT may be NULL, in which case, the input method can't get
2260     information about the text around the spot.  */
2261
2262 /***ja
2263     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë
2264
2265     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂ
2266     É¸ ($X, $Y)¤Ë ¡¢¹â¤µ $ASCENT¡¢$DESCENT ¤ÇÀßÄꤹ¤ë¡£¤³¤ì¤é¤ÎÃͤΰÕ
2267     Ì£¤ÏÆþÎϥɥ饤¥Ð¤Ë°Í¸¤¹¤ë¡£
2268
2269     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ëÆþÎϥɥ饤¥Ð¤Ï $X, $Y ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô
2270     ¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT¡¢$DESCENT ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿
2271     ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤÎÆþÎϥɥ饤¥Ð¤Ï $X,$Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É
2272     ¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
2273     $ASCENT ¤È $DESCENT ¤ò ($X . $Y) ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯
2274     ¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£  */
2275
2276 void
2277 minput_set_spot (MInputContext *ic, int x, int y,
2278                  int ascent, int descent, int fontsize,
2279                  MText *mt, int pos)
2280 {
2281   ic->spot.x = x;
2282   ic->spot.y = y;
2283   ic->spot.ascent = ascent;
2284   ic->spot.descent = descent;
2285   ic->spot.fontsize = fontsize;
2286   ic->spot.mt = mt;
2287   ic->spot.pos = pos;
2288   if (ic->im->driver.callback_list)
2289     minput__callback (ic, Minput_set_spot);
2290 }
2291 /*=*/
2292
2293 /***en
2294     @brief Toggle input method.
2295
2296     The minput_toggle () function toggles the input method associated
2297     with the input context $IC.  */
2298
2299 void
2300 minput_toggle (MInputContext *ic)
2301 {
2302   if (ic->im->driver.callback_list)
2303     minput__callback (ic, Minput_toggle);
2304   ic->active = ! ic->active;
2305 }
2306
2307
2308 /*** @} */
2309 /*=*/
2310 /*** @addtogroup m17nDebug */
2311 /*=*/
2312 /*** @{  */
2313 /*=*/
2314
2315 /***en
2316     @brief Dump an input method
2317
2318     The mdebug_dump_im () function prints the input method $IM in a
2319     human readable way to the stderr.  $INDENT specifies how many
2320     columns to indent the lines but the first one.
2321
2322     @return
2323     This function returns $IM.  */
2324
2325 MInputMethod *
2326 mdebug_dump_im (MInputMethod *im, int indent)
2327 {
2328   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2329   char *prefix;
2330
2331   prefix = (char *) alloca (indent + 1);
2332   memset (prefix, 32, indent);
2333   prefix[indent] = '\0';
2334
2335   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
2336            msymbol_name (im->name));
2337   mdebug_dump_mtext (im_info->title, 0, 0);
2338   if (im->name != Mnil)
2339     {
2340       MPlist *state;
2341
2342       MPLIST_DO (state, im_info->states)
2343         {
2344           fprintf (stderr, "\n%s  ", prefix);
2345           dump_im_state (MPLIST_VAL (state), indent + 2);
2346         }
2347     }
2348   fprintf (stderr, ")");
2349   return im;
2350 }
2351
2352 /*** @} */ 
2353
2354 /*
2355   Local Variables:
2356   coding: euc-japan
2357   End:
2358 */