85aca2765c250b9f7672ebbd952a911c6196663b
[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   if (! title)
743     title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
744                              MTEXT_FORMAT_US_ASCII);
745   im_info->title = title;
746   im_info->externals = externals;
747   im_info->macros = macros;
748   im_info->states = states;
749   return 0;
750
751  err:
752   if (maps)
753     {
754       MPLIST_DO (elt, maps)
755         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
756       M17N_OBJECT_UNREF (maps);
757     }
758   if (title)
759     M17N_OBJECT_UNREF (title);
760   if (states)
761     {
762       MPLIST_DO (plist, states)
763       {
764         MIMState *state = (MIMState *) MPLIST_VAL (plist);
765
766         if (state->title)
767           M17N_OBJECT_UNREF (state->title);
768         if (state->map)
769           free_map (state->map);
770         free (state);
771       }
772       M17N_OBJECT_UNREF (states);
773     }
774   if (externals)
775     {
776       MPLIST_DO (plist, externals)
777       {
778         MIMExternalModule *external = MPLIST_VAL (plist);
779
780         dlclose (external->handle);
781         M17N_OBJECT_UNREF (external->func_list);
782         free (external);
783         MPLIST_KEY (plist) = Mt;
784       }
785       M17N_OBJECT_UNREF (externals);
786     }
787   return -1;
788 }
789
790 \f
791
792 static int take_action_list (MInputContext *ic, MPlist *action_list);
793
794 static void
795 shift_state (MInputContext *ic, MSymbol state_name)
796 {
797   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
798   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
799   MIMState *state = ic_info->state;
800
801   /* Find a state to shift to.  If not found, shift to the initial
802      state.  */
803   state = (MIMState *) mplist_get (im_info->states, state_name);
804   if (! state)
805     state = (MIMState *) MPLIST_VAL (im_info->states);
806
807   /* Enter the new state.  */
808   ic_info->state = state;
809   ic_info->map = state->map;
810   ic_info->state_key_head = ic_info->key_head;
811   if (state == (MIMState *) MPLIST_VAL (im_info->states))
812     {
813       /* We have shifted to the initial state.  */
814       MPlist *p;
815
816       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
817                              Mcandidate_list, NULL, 0);
818       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
819                              Mcandidate_index, NULL, 0);
820       mtext_cat (ic->produced, ic->preedit);
821       mtext_reset (ic->preedit);
822       ic->candidate_list = NULL;
823       ic->candidate_show = 0;
824       ic->preedit_changed = ic->candidates_changed = 1;
825       MPLIST_DO (p, ic_info->markers)
826         MPLIST_VAL (p) = 0;
827       MPLIST_DO (p, ic_info->vars)
828         MPLIST_VAL (p) = 0;
829       ic->cursor_pos = 0;
830       memmove (ic_info->keys, ic_info->keys + ic_info->state_key_head,
831                sizeof (int) * (ic_info->used - ic_info->state_key_head));
832       ic_info->used -= ic_info->state_key_head;
833       ic_info->state_key_head = ic_info->key_head = 0;
834     }
835   mtext_cpy (ic_info->preedit_saved, ic->preedit);
836   ic_info->state_pos = ic->cursor_pos;
837   ic->status = state->title;
838   if (! ic->status)
839     ic->status = im_info->title;
840   ic->status_changed = 1;
841   if (ic_info->key_head == ic_info->used
842       && ic_info->map == ic_info->state->map
843       && ic_info->map->map_actions)
844     take_action_list (ic, ic_info->map->map_actions);
845 }
846
847
848 static MPlist *
849 find_candidates_group (MPlist *plist, int index,
850                        int *start_index, int *end_index, int *group_index)
851 {
852   int i = 0, gidx = 0, len;
853
854   MPLIST_DO (plist, plist)
855     {
856       if (MPLIST_MTEXT_P (plist))
857         len = mtext_nchars (MPLIST_MTEXT (plist));
858       else
859         len = mplist_length (MPLIST_PLIST (plist));
860       if (i + len > index)
861         {
862           if (start_index)
863             *start_index = i;
864           if (end_index)
865             *end_index = i + len;
866           if (group_index)
867             *group_index = gidx;
868           return plist;
869         }
870       i += len;
871       gidx++;
872     }
873   return NULL;
874 }
875
876 static void
877 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
878 {
879   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
880   MPlist *markers;
881   int nchars = mt ? mtext_nchars (mt) : 1;
882
883   if (mt)
884     mtext_ins (ic->preedit, pos, mt);
885   else
886     mtext_ins_char (ic->preedit, pos, c, 1);
887   MPLIST_DO (markers, ic_info->markers)
888     if (MPLIST_INTEGER (markers) > pos)
889       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
890   if (ic->cursor_pos >= pos)
891     ic->cursor_pos += nchars;
892   ic->preedit_changed = 1;
893 }
894
895
896 static void
897 preedit_delete (MInputContext *ic, int from, int to)
898 {
899   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
900   MPlist *markers;
901
902   mtext_del (ic->preedit, from, to);
903   MPLIST_DO (markers, ic_info->markers)
904     {
905       if (MPLIST_INTEGER (markers) > to)
906         MPLIST_VAL (markers)
907           = (void *) (MPLIST_INTEGER (markers) - (to - from));
908       else if (MPLIST_INTEGER (markers) > from);
909         MPLIST_VAL (markers) = (void *) from;
910     }
911   if (ic->cursor_pos >= to)
912     ic->cursor_pos -= to - from;
913   else if (ic->cursor_pos > from)
914     ic->cursor_pos = from;
915   ic->preedit_changed = 1;
916 }
917
918
919 static int
920 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
921 {
922   int code = marker_code (sym);
923
924   if (mt && (code == '[' || code == ']'))
925     {
926       int pos = current;
927
928       if (code == '[' && current > 0)
929         {
930           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
931               && pos > 0)
932             current = pos;
933         }
934       else if (code == ']' && current < mtext_nchars (mt))
935         {
936           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
937             current = pos;
938         }
939       return current;
940     }
941   if (code >= 0)
942     return (code == '<' ? 0
943             : code == '>' ? limit
944             : code == '-' ? current - 1
945             : code == '+' ? current + 1
946             : code == '=' ? current
947             : code - '0' > limit ? limit
948             : code - '0');
949   if (! ic)  
950     return 0;
951   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
952 }
953
954 static void
955 udpate_candidate (MInputContext *ic, MTextProperty *prop, int idx)
956 {
957   int from = mtext_property_start (prop);
958   int to = mtext_property_end (prop);
959   int start;
960   MPlist *candidate_list = mtext_property_value (prop);
961   MPlist *group = find_candidates_group (candidate_list, idx, &start,
962                                          NULL, NULL);
963   int ingroup_index = idx - start;
964   MText *mt;
965
966   preedit_delete (ic, from, to);
967   if (MPLIST_MTEXT_P (group))
968     {
969       mt = MPLIST_MTEXT (group);
970       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
971       to = from + 1;
972     }
973   else
974     {
975       int i;
976       MPlist *plist;
977
978       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
979            i++, plist = MPLIST_NEXT (plist));
980       mt = MPLIST_MTEXT (plist);
981       preedit_insert (ic, from, mt, 0);
982       to = from + mtext_nchars (mt);
983     }
984   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
985   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
986   ic->cursor_pos = to;
987 }
988
989
990 static int
991 take_action_list (MInputContext *ic, MPlist *action_list)
992 {
993   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
994   MPlist *candidate_list = ic->candidate_list;
995   int candidate_index = ic->candidate_index;
996   int candidate_show = ic->candidate_show;
997   MTextProperty *prop;
998
999   MPLIST_DO (action_list, action_list)
1000     {
1001       MPlist *action;
1002       MSymbol name;
1003       MPlist *args;
1004
1005       if (MPLIST_MTEXT_P (action_list)
1006           || MPLIST_INTEGER_P (action_list))
1007         name = Minsert, args = action_list;
1008       else if (MPLIST_PLIST_P (action_list)
1009                && (MPLIST_MTEXT_P (MPLIST_PLIST (action_list))
1010                    || MPLIST_PLIST_P (MPLIST_PLIST (action_list))))
1011         name = Minsert, args = action_list;
1012       else
1013         {
1014           action = MPLIST_PLIST (action_list);
1015           name = MPLIST_SYMBOL (action);
1016           args = MPLIST_NEXT (action);
1017         }
1018
1019       if (name == Minsert)
1020         {
1021           if (MPLIST_MTEXT_P (args))
1022             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1023           else if (MPLIST_INTEGER_P (args))
1024             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1025           else if (MPLIST_SYMBOL_P (args))
1026             {
1027               int c = integer_value (ic, args);
1028
1029               if (c >= 0 && c <= MCHAR_MAX)
1030                 preedit_insert (ic, ic->cursor_pos, NULL, c);
1031             }
1032           else
1033             {
1034               MText *mt;
1035               int len;
1036
1037               args = MPLIST_PLIST (args);
1038               if (MPLIST_MTEXT_P (args))
1039                 {
1040                   preedit_insert (ic, ic->cursor_pos, NULL,
1041                                   mtext_ref_char (MPLIST_MTEXT (args), 0));
1042                   len = 1;
1043                 }
1044               else
1045                 {
1046                   mt = MPLIST_MTEXT (MPLIST_PLIST (args));
1047                   preedit_insert (ic, ic->cursor_pos, mt, 0);
1048                   len = mtext_nchars (mt);
1049                 }
1050               mtext_put_prop (ic->preedit,
1051                               ic->cursor_pos - len, ic->cursor_pos,
1052                               Mcandidate_list, args);
1053               mtext_put_prop (ic->preedit,
1054                               ic->cursor_pos - len, ic->cursor_pos,
1055                               Mcandidate_index, (void *) 0);
1056             }
1057         }
1058       else if (name == Mselect)
1059         {
1060           int start, end;
1061           int code, idx, gindex;
1062           int pos = ic->cursor_pos;
1063           MPlist *group;
1064
1065           if (pos == 0
1066               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
1067                                                Mcandidate_list)))
1068             continue;
1069           if (MPLIST_SYMBOL_P (args))
1070             {
1071               code = marker_code (MPLIST_SYMBOL (args));
1072               if (code < 0)
1073                 continue;
1074             }
1075           else
1076             code = -1;
1077           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
1078           group = find_candidates_group (mtext_property_value (prop), idx,
1079                                          &start, &end, &gindex);
1080
1081           if (code != '[' && code != ']')
1082             {
1083               idx = (start
1084                      + (code >= 0
1085                         ? new_index (NULL, ic->candidate_index - start,
1086                                      end - start - 1, MPLIST_SYMBOL (args),
1087                                      NULL)
1088                         : MPLIST_INTEGER (args)));
1089               if (idx < 0
1090                   || (idx >= end
1091                       && MPLIST_TAIL_P (MPLIST_NEXT (group))))
1092                 idx = 0;
1093             }
1094           else
1095             {
1096               int ingroup_index = idx - start;
1097               int len;
1098
1099               group = mtext_property_value (prop);
1100               len = mplist_length (group);
1101               if (code == '[')
1102                 {
1103                   gindex--;
1104                   if (gindex < 0)
1105                     gindex = len - 1;;
1106                 }
1107               else
1108                 {
1109                   gindex++;
1110                   if (gindex >= len)
1111                     gindex = 0;
1112                 }
1113               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
1114                 idx += (MPLIST_MTEXT_P (group)
1115                         ? mtext_nchars (MPLIST_MTEXT (group))
1116                         : mplist_length (MPLIST_PLIST (group)));
1117               len = (MPLIST_MTEXT_P (group)
1118                      ? mtext_nchars (MPLIST_MTEXT (group))
1119                      : mplist_length (MPLIST_PLIST (group)));
1120               if (ingroup_index >= len)
1121                 ingroup_index = len - 1;
1122               idx += ingroup_index;
1123             }
1124           udpate_candidate (ic, prop, idx);
1125         }
1126       else if (name == Mshow)
1127         ic->candidate_show = 1;
1128       else if (name == Mhide)
1129         ic->candidate_show = 0;
1130       else if (name == Mdelete)
1131         {
1132           int len = mtext_nchars (ic->preedit);
1133           int to = (MPLIST_SYMBOL_P (args)
1134                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1135                                  ic->preedit)
1136                     : MPLIST_INTEGER (args));
1137
1138           if (to < 0)
1139             to = 0;
1140           else if (to > len)
1141             to = len;
1142           if (to < ic->cursor_pos)
1143             preedit_delete (ic, to, ic->cursor_pos);
1144           else if (to > ic->cursor_pos)
1145             preedit_delete (ic, ic->cursor_pos, to);
1146         }
1147       else if (name == Mmove)
1148         {
1149           int len = mtext_nchars (ic->preedit);
1150           int pos
1151             = (MPLIST_SYMBOL_P (args)
1152                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1153                             ic->preedit)
1154                : MPLIST_INTEGER (args));
1155
1156           if (pos < 0)
1157             pos = 0;
1158           else if (pos > len)
1159             pos = len;
1160           if (pos != ic->cursor_pos)
1161             {
1162               ic->cursor_pos = pos;
1163               ic->preedit_changed = 1;
1164             }
1165         }
1166       else if (name == Mmark)
1167         {
1168           int code = marker_code (MPLIST_SYMBOL (args));
1169
1170           if (code < 0)
1171             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
1172                         (void *) ic->cursor_pos);
1173         }
1174       else if (name == Mpushback)
1175         {
1176           int num = MPLIST_INTEGER (args);
1177
1178           if (num > 0)
1179             ic_info->key_head -= num;
1180           else
1181             ic_info->key_head = num;
1182           if (ic_info->key_head > ic_info->used)
1183             ic_info->key_head = ic_info->used;
1184         }
1185       else if (name == Mcall)
1186         {
1187           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1188           MIMExternalFunc func = NULL;
1189           MSymbol module, func_name;
1190           MPlist *func_args, *val;
1191           int ret = 0;
1192
1193           module = MPLIST_SYMBOL (args);
1194           args = MPLIST_NEXT (args);
1195           func_name = MPLIST_SYMBOL (args);
1196
1197           if (im_info->externals)
1198             {
1199               MIMExternalModule *external
1200                 = (MIMExternalModule *) mplist_get (im_info->externals,
1201                                                     module);
1202               if (external)
1203                 func = (MIMExternalFunc) mplist_get (external->func_list,
1204                                                      func_name);
1205             }
1206           if (! func)
1207             continue;
1208           func_args = mplist ();
1209           mplist_add (func_args, Mt, ic);
1210           MPLIST_DO (args, MPLIST_NEXT (args))
1211             {
1212               int code;
1213
1214               if (MPLIST_KEY (args) == Msymbol
1215                   && MPLIST_KEY (args) != Mnil
1216                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
1217                 {
1218                   code = new_index (ic, ic->cursor_pos, 
1219                                     mtext_nchars (ic->preedit),
1220                                     MPLIST_SYMBOL (args), ic->preedit);
1221                   mplist_add (func_args, Minteger, (void *) code);
1222                 }
1223               else
1224                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
1225             }
1226           val = (func) (func_args);
1227           M17N_OBJECT_UNREF (func_args);
1228           if (val && ! MPLIST_TAIL_P (val))
1229             ret = take_action_list (ic, val);
1230           M17N_OBJECT_UNREF (val);
1231           if (ret < 0)
1232             return ret;
1233         }
1234       else if (name == Mshift)
1235         {
1236           shift_state (ic, MPLIST_SYMBOL (args));
1237         }
1238       else if (name == Mundo)
1239         {
1240           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1241           int unhandle = 0;
1242
1243           mtext_reset (ic->preedit);
1244           mtext_reset (ic_info->preedit_saved);
1245           ic->cursor_pos = ic_info->state_pos = 0;
1246           ic_info->state_key_head = ic_info->key_head = 0;
1247           ic_info->used -= 2;
1248           if (ic_info->used < 0)
1249             {
1250               ic_info->used = 0;
1251               unhandle = 1;
1252             }
1253           shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1254           if (unhandle)
1255             return -1;
1256           break;
1257         }
1258       else if (name == Mset || name == Madd || name == Msub
1259                || name == Mmul || name == Mdiv)
1260         {
1261           MSymbol sym = MPLIST_SYMBOL (args);
1262           int val1 = (int) mplist_get (ic_info->vars, sym), val2;
1263
1264           args = MPLIST_NEXT (args);
1265           val2 = integer_value (ic, args);
1266           if (name == Mset)
1267             val1 = val2;
1268           else if (name == Madd)
1269             val1 += val2;
1270           else if (name == Msub)
1271             val1 -= val2;
1272           else if (name == Mmul)
1273             val1 *= val2;
1274           else
1275             val1 /= val2;
1276           mplist_put (ic_info->vars, sym, (void *) val1);
1277         }
1278       else if (name == Mequal || name == Mless || name == Mgreater)
1279         {
1280           int val1, val2;
1281           MPlist *actions1, *actions2;
1282           int ret;
1283
1284           val1 = integer_value (ic, args);
1285           args = MPLIST_NEXT (args);
1286           val2 = integer_value (ic, args);
1287           args = MPLIST_NEXT (args);
1288           actions1 = MPLIST_PLIST (args);
1289           args = MPLIST_NEXT (args);
1290           if (MPLIST_TAIL_P (args))
1291             actions2 = NULL;
1292           else
1293             actions2 = MPLIST_PLIST (args);
1294           if (name == Mequal ? val1 == val2
1295               : name == Mless ? val1 < val2
1296               : val1 > val2)
1297             ret = take_action_list (ic, actions1);
1298           else if (actions2)
1299             ret = take_action_list (ic, actions2);
1300           if (ret < 0)
1301             return ret;
1302         }
1303       else
1304         {
1305           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1306           MPlist *actions;
1307
1308           if (im_info->macros
1309               && (actions = mplist_get (im_info->macros, name)))
1310             {
1311               if (take_action_list (ic, actions) < 0)
1312                 return -1;
1313             };
1314         }
1315     }
1316
1317   prop = NULL;
1318   ic->candidate_list = NULL;
1319   if (ic->cursor_pos > 0
1320       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
1321                                      Mcandidate_list)))
1322     {
1323       ic->candidate_list = mtext_property_value (prop);
1324       ic->candidate_index
1325         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
1326                                 Mcandidate_index);
1327       ic->candidate_from = mtext_property_start (prop);
1328       ic->candidate_to = mtext_property_end (prop);
1329     }
1330
1331   ic->candidates_changed |= (candidate_list != ic->candidate_list
1332                              || candidate_index != ic->candidate_index
1333                              || candidate_show != ic->candidate_show);
1334   return 0;
1335 }
1336
1337
1338 /* Handle the input key KEY in the current state and map specified in
1339    the input context IC.  If KEY is handled correctly, return 0.
1340    Otherwise, return -1.  */
1341
1342 static int
1343 handle_key (MInputContext *ic)
1344 {
1345   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1346   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1347   MIMMap *map = ic_info->map;
1348   MIMMap *submap;
1349   MSymbol key = ic_info->keys[ic_info->key_head];
1350   int i;
1351
1352   submap = (map->submaps ? mplist_get (map->submaps, key) : NULL);
1353   if (submap)
1354     {
1355       mtext_cpy (ic->preedit, ic_info->preedit_saved);
1356       ic->cursor_pos = ic_info->state_pos;
1357       ic_info->key_head++;
1358       ic_info->map = map = submap;
1359       if (map->map_actions)
1360         {
1361           if (take_action_list (ic, map->map_actions) < 0)
1362             return -1;
1363         }
1364       else if (map->submaps)
1365         {
1366           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
1367             {
1368               MSymbol key = ic_info->keys[i];
1369               char *name = msymbol_name (key);
1370
1371               if (! name[0] || ! name[1])
1372                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
1373             }
1374           ic->preedit_changed = 1;
1375         }
1376
1377       /* If this is the terminal map or we have shifted to another
1378          state, perform branch actions (if any).  */
1379       if (! map->submaps || map != ic_info->map)
1380         {
1381           if (map->branch_actions)
1382             {
1383               if (take_action_list (ic, map->branch_actions) < 0)
1384                 return -1;
1385             }
1386           /* If MAP is still not the root map, shift to the current
1387              state.  */
1388           if (ic_info->map != ic_info->state->map)
1389             shift_state (ic, ic_info->state->name);
1390         }
1391     }
1392   else
1393     {
1394       /* MAP can not handle KEY.  */
1395
1396       /* If MAP is the root map of the initial state, it means that
1397          the current input method can not handle KEY.  */
1398       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
1399         return -1;
1400
1401       if (map != ic_info->state->map)
1402         {
1403           /* If MAP is not the root map... */
1404           /* If MAP has branch actions, perform them.  */
1405           if (map->branch_actions)
1406             take_action_list (ic, map->branch_actions);
1407           /* If MAP is still not the root map, shift to the current
1408              state. */
1409           if (ic_info->map != ic_info->state->map)
1410             {
1411               shift_state (ic, ic_info->state->name);
1412               /* If MAP has branch_actions, perform them.  */
1413               if (ic_info->map->branch_actions)
1414                 take_action_list (ic, ic_info->map->branch_actions);
1415             }
1416         }
1417       else
1418         {
1419           /* MAP is the root map, perform branch actions (if any) or
1420              shift to the initial state.  */
1421           if (map->branch_actions)
1422             take_action_list (ic, map->branch_actions);
1423           else
1424             shift_state (ic,
1425                          ((MIMState *) MPLIST_VAL (im_info->states))->name);
1426         }
1427     }
1428   return 0;
1429 }
1430
1431 static void
1432 reset_ic (MInputContext *ic)
1433 {
1434   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1435   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1436
1437   MLIST_RESET (ic_info);
1438   ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
1439   ic_info->map = ic_info->state->map;
1440   ic_info->state_key_head = ic_info->key_head = 0;
1441   ic->cursor_pos = ic_info->state_pos = 0;
1442   ic->status = ic_info->state->title;
1443   if (! ic->status)
1444     ic->status = im_info->title;
1445   ic->candidate_list = NULL;
1446   ic->candidate_show = 0;
1447   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
1448   if (ic_info->map->map_actions)
1449     take_action_list (ic, ic_info->map->map_actions);
1450 }
1451
1452 static int
1453 open_im (MInputMethod *im)
1454 {
1455   MDatabase *mdb;
1456   MInputMethodInfo *im_info;
1457   MPlist *plist;
1458   int result;
1459
1460   mdb = mdatabase_find (Minput_method, im->language, im->name, Mnil);
1461   if (! mdb)
1462     return -1;
1463   plist = mdatabase_load (mdb);
1464   if (! plist)
1465     MERROR (MERROR_IM, -1);
1466   MSTRUCT_CALLOC (im_info, MERROR_IM);
1467   im->info = im_info;
1468   result = load_input_method (im->language, im->name, plist, im_info);
1469   M17N_OBJECT_UNREF (plist);
1470   if (result < 0)
1471     MERROR (MERROR_IM, -1);
1472   return 0;
1473 }
1474
1475 static void
1476 close_im (MInputMethod *im)
1477 {
1478   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1479   MPlist *plist;
1480
1481   if (im_info->title)
1482     M17N_OBJECT_UNREF (im_info->title);
1483   if (im_info->states)
1484     {
1485       MPLIST_DO (plist, im_info->states)
1486         {
1487           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1488
1489           if (state->title)
1490             M17N_OBJECT_UNREF (state->title);
1491           if (state->map)
1492             free_map (state->map);
1493           free (state);
1494         }
1495       M17N_OBJECT_UNREF (im_info->states);
1496     }
1497
1498   if (im_info->macros)
1499     {
1500       MPLIST_DO (plist, im_info->macros)
1501         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1502       M17N_OBJECT_UNREF (im_info->macros);
1503     }
1504
1505   if (im_info->externals)
1506     {
1507       MPLIST_DO (plist, im_info->externals)
1508         {
1509           MIMExternalModule *external = MPLIST_VAL (plist);
1510
1511           dlclose (external->handle);
1512           M17N_OBJECT_UNREF (external->func_list);
1513           free (external);
1514           MPLIST_KEY (plist) = Mt;
1515         }
1516       M17N_OBJECT_UNREF (im_info->externals);
1517     }
1518   free (im_info);
1519   im->info = NULL;
1520 }
1521
1522
1523 static int
1524 create_ic (MInputContext *ic)
1525 {
1526   MInputMethod *im = ic->im;
1527   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1528   MInputContextInfo *ic_info;
1529
1530   if (ic->info)
1531     ic_info = (MInputContextInfo *) ic->info;
1532   else
1533     {
1534       MSTRUCT_CALLOC (ic_info, MERROR_IM);
1535       ic->info = ic_info;
1536     }
1537   MLIST_INIT1 (ic_info, keys, 8);
1538   ic_info->markers = mplist ();
1539   ic_info->vars = mplist ();
1540   ic_info->preedit_saved = mtext ();
1541   if (im_info->externals)
1542     {
1543       MPlist *func_args = mplist (), *plist;
1544
1545       mplist_add (func_args, Mt, ic);
1546       MPLIST_DO (plist, im_info->externals)
1547         {
1548           MIMExternalModule *external = MPLIST_VAL (plist);
1549           MIMExternalFunc func
1550             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
1551
1552           if (func)
1553             (func) (func_args);
1554         }
1555       M17N_OBJECT_UNREF (func_args);
1556     }
1557   reset_ic (ic);
1558   return 0;
1559 }
1560
1561 static void
1562 destroy_ic (MInputContext *ic)
1563 {
1564   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1565   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1566
1567   if (im_info->externals)
1568     {
1569       MPlist *func_args = mplist (), *plist;
1570
1571       mplist_add (func_args, Mt, ic);
1572       MPLIST_DO (plist, im_info->externals)
1573         {
1574           MIMExternalModule *external = MPLIST_VAL (plist);
1575           MIMExternalFunc func
1576             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
1577
1578           if (func)
1579             (func) (func_args);
1580         }
1581       M17N_OBJECT_UNREF (func_args);
1582     }
1583   MLIST_FREE1 (ic_info, keys);
1584   M17N_OBJECT_UNREF (ic_info->preedit_saved);
1585   M17N_OBJECT_UNREF (ic_info->markers);
1586   M17N_OBJECT_UNREF (ic_info->vars);
1587   free (ic->info);
1588 }
1589
1590
1591 /** Handle the input key KEY in the current state and map of IC->info.
1592     If KEY is handled but no text is produced, return 0, otherwise
1593     return 1.
1594
1595     Ignore ARG.  */
1596
1597 static int
1598 filter (MInputContext *ic, MSymbol key, void *arg)
1599 {
1600   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1601   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1602   int i = 0;
1603
1604   mtext_reset (ic->produced);
1605   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
1606   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
1607   ic_info->key_unhandled = 0;
1608   do {
1609     if (handle_key (ic) < 0)
1610       {
1611         /* KEY was not handled.  Reset the status and break the
1612            loop.  */
1613         reset_ic (ic);
1614         /* This forces returning 1.  */
1615         ic_info->key_unhandled = 1;
1616         break;
1617       }
1618     if (i++ == 100)
1619       {
1620         mdebug_hook ();
1621         reset_ic (ic);
1622         ic_info->key_unhandled = 1;
1623         break;
1624       }
1625     /* Break the loop if all keys were handled.  */
1626   } while (ic_info->key_head < ic_info->used);
1627
1628   /* If the current map is the root of the initial state, we should
1629      produce any preedit text in ic->produced.  */
1630   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
1631       && mtext_nchars (ic->preedit) > 0)
1632     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1633
1634   if (mtext_nchars (ic->produced) > 0)
1635     {
1636       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
1637
1638       if (lang != Mnil)
1639         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
1640                         Mlanguage, ic->im->language);
1641     }
1642
1643   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
1644 }
1645
1646
1647 /** Return 1 if the last event or key was not handled, otherwise
1648     return 0.
1649
1650     There is no need of looking up because ic->produced should already
1651     contain the produced text (if any).
1652
1653     Ignore KEY.  */
1654
1655 static int
1656 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
1657 {
1658   mtext_cat (mt, ic->produced);
1659   mtext_reset (ic->produced);
1660   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
1661 }
1662
1663 /* Support functions for mdebug_dump_im.  */
1664
1665 static void
1666 dump_im_map (MPlist *map_list, int indent)
1667 {
1668   char *prefix;
1669   MSymbol key = MPLIST_KEY (map_list);
1670   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
1671
1672   prefix = (char *) alloca (indent + 1);
1673   memset (prefix, 32, indent);
1674   prefix[indent] = '\0';
1675
1676   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
1677   if (map->map_actions)
1678     mdebug_dump_plist (map->map_actions, indent + 2);
1679   if (map->submaps)
1680     {
1681       MPLIST_DO (map_list, map->submaps)
1682         {
1683           fprintf (stderr, "\n%s  ", prefix);
1684           dump_im_map (map_list, indent + 2);
1685         }
1686     }
1687   if (map->branch_actions)
1688     {
1689       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
1690       mdebug_dump_plist (map->branch_actions, indent + 4);
1691       fprintf (stderr, ")");      
1692     }
1693   fprintf (stderr, ")");
1694 }
1695
1696
1697 static void
1698 dump_im_state (MIMState *state, int indent)
1699 {
1700   char *prefix;
1701   MPlist *map_list;
1702
1703   prefix = (char *) alloca (indent + 1);
1704   memset (prefix, 32, indent);
1705   prefix[indent] = '\0';
1706
1707   fprintf (stderr, "(%s", msymbol_name (state->name));
1708   if (state->map->submaps)
1709     {
1710       MPLIST_DO (map_list, state->map->submaps)
1711         {
1712           fprintf (stderr, "\n%s  ", prefix);
1713           dump_im_map (map_list, indent + 2);
1714         }
1715     }
1716   fprintf (stderr, ")");
1717 }
1718
1719 \f
1720
1721 int
1722 minput__init ()
1723 {
1724   char *key_names[32]
1725     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1726         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
1727         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1728         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
1729   char buf[6], buf2[256];
1730   int i;
1731
1732   Minput_method = msymbol ("input-method");
1733   Minput_driver = msymbol ("input-driver");
1734   Mtitle = msymbol ("title");
1735   Mmacro = msymbol ("macro");
1736   Mmodule = msymbol ("module");
1737   Mmap = msymbol ("map");
1738   Mstate = msymbol ("state");
1739   Minsert = msymbol ("insert");
1740   Mdelete = msymbol ("delete");
1741   Mmove = msymbol ("move");
1742   Mmark = msymbol ("mark");
1743   Mpushback = msymbol ("pushback");
1744   Mundo = msymbol ("undo");
1745   Mcall = msymbol ("call");
1746   Mshift = msymbol ("shift");
1747   Mselect = msymbol ("select");
1748   Mshow = msymbol ("show");
1749   Mhide = msymbol ("hide");
1750   Mset = msymbol ("set");
1751   Madd = msymbol ("add");
1752   Msub = msymbol ("sub");
1753   Mmul = msymbol ("mul");
1754   Mdiv = msymbol ("div");
1755   Mequal = msymbol ("=");
1756   Mless = msymbol ("<");
1757   Mgreater = msymbol (">");
1758
1759   Minput_preedit_start = msymbol ("input-preedit-start");
1760   Minput_preedit_done = msymbol ("input-preedit-done");
1761   Minput_preedit_draw = msymbol ("input-preedit-draw");
1762   Minput_status_start = msymbol ("input-status-start");
1763   Minput_status_done = msymbol ("input-status-done");
1764   Minput_status_draw = msymbol ("input-status-draw");
1765   Minput_candidates_start = msymbol ("input-candidates-start");
1766   Minput_candidates_done = msymbol ("input-candidates-done");
1767   Minput_candidates_draw = msymbol ("input-candidates-draw");
1768   Minput_set_spot = msymbol ("input-set-spot");
1769   Minput_toggle = msymbol ("input-toggle");
1770
1771   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
1772   Mcandidate_index = msymbol ("  candidate-index");
1773
1774   Minit = msymbol ("init");
1775   Mfini = msymbol ("fini");
1776
1777   buf[0] = 'C';
1778   buf[1] = '-';
1779   buf[3] = '\0';
1780   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
1781     {
1782       if (key_names[i])
1783         one_char_symbol[i] = msymbol (key_names[i]);
1784       else
1785         one_char_symbol[i] = msymbol (buf);
1786     }
1787   for (buf[2] = i; i < 127; i++, buf[2]++)
1788     one_char_symbol[i] = msymbol (buf + 2);
1789   one_char_symbol[i++] = msymbol ("Delete");
1790   buf[2] = 'M';
1791   buf[3] = '-';
1792   buf[5] = '\0';
1793   buf2[0] = 'M';
1794   buf2[1] = '-';
1795   for (buf[4] = '@'; i < 160; i++, buf[4]++)
1796     {
1797       if (key_names[i - 128])
1798         {
1799           strcpy (buf2 + 2, key_names[i - 128]);
1800           one_char_symbol[i] = msymbol (buf2);
1801         }
1802       else
1803         one_char_symbol[i] = msymbol (buf);
1804     }
1805   for (buf[4] = i - 128; i < 255; i++, buf[2]++)
1806     one_char_symbol[i] = msymbol (buf + 2);
1807   one_char_symbol[i] = msymbol ("M-Delete");
1808
1809   minput_default_driver.open_im = open_im;
1810   minput_default_driver.close_im = close_im;
1811   minput_default_driver.create_ic = create_ic;
1812   minput_default_driver.destroy_ic = destroy_ic;
1813   minput_default_driver.filter = filter;
1814   minput_default_driver.lookup = lookup;
1815   minput_default_driver.callback_list = NULL;
1816   minput_driver = &minput_default_driver;
1817   return 0;
1818 }
1819
1820 void
1821 minput__fini ()
1822 {
1823   if (minput_default_driver.callback_list)
1824     {
1825       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
1826       minput_default_driver.callback_list = NULL;
1827     }
1828   if (minput_driver->callback_list)
1829     {
1830       M17N_OBJECT_UNREF (minput_driver->callback_list);
1831       minput_driver->callback_list = NULL;
1832     }
1833 }
1834
1835 void
1836 minput__callback (MInputContext *ic, MSymbol command)
1837 {
1838   if (ic->im->driver.callback_list)
1839     {
1840       MInputCallbackFunc func
1841         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
1842                                            command);
1843
1844       if (func)
1845         (func) (ic, command);
1846     }
1847 }
1848
1849 MSymbol
1850 minput__char_to_key (int c)
1851 {
1852   if (c < 0 || c >= 0x100)
1853     return Mnil;
1854
1855   return one_char_symbol[c];
1856 }
1857
1858 /*** @} */
1859 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1860
1861 \f
1862 /* External API */
1863
1864 /*** @addtogroup m17nInputMethod */
1865 /*** @{ */
1866 /*=*/
1867
1868 /***en
1869     @name Variables: Predefined symbols for callback commands.
1870
1871     These are the predefined symbols that are used as the @c COMMAND
1872     argument of callback functions of an input method driver (see
1873     #MInputDriver::callback_list).  */ 
1874 /*** @{ */ 
1875 /*=*/
1876
1877 MSymbol Minput_preedit_start;
1878 MSymbol Minput_preedit_done;
1879 MSymbol Minput_preedit_draw;
1880 MSymbol Minput_status_start;
1881 MSymbol Minput_status_done;
1882 MSymbol Minput_status_draw;
1883 MSymbol Minput_candidates_start;
1884 MSymbol Minput_candidates_done;
1885 MSymbol Minput_candidates_draw;
1886 MSymbol Minput_set_spot;
1887 MSymbol Minput_toggle;
1888 /*** @} */
1889 /*=*/
1890
1891 /***en
1892     @brief The default input driver for internal input methods.
1893
1894     The variable #minput_default_driver is the default driver for
1895     internal input methods.
1896
1897     The member MInputDriver::open_im () searches the m17n database for
1898     an input method that matches the tag \<#Minput_method, $LANGUAGE,
1899     $NAME\> and loads it.
1900
1901     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
1902     programmers responsibility to set it to a plist of proper callback
1903     functions.  Otherwise, no feedback information (e.g. preedit text)
1904     can be shown to users.
1905
1906     The macro M17N_INIT () sets the variable #minput_driver to the
1907     pointer to this driver so that all internal input methods use it.
1908
1909     Therefore, unless @c minput_driver is set differently, the driver
1910     dependent arguments $ARG of the functions whose name begin with
1911     "minput_" are all ignored.  */
1912
1913 /***ja
1914     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥ÈÆþÎϥɥ饤¥Ð
1915
1916     ÆþÎϥɥ饤¥Ð minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë
1917     ¥È¤ÎÆþÎϥɥ饤¥Ð¤Ç¤¢¤ë¡£
1918
1919     ¤³¤Î¥É¥é¥¤¥Ð¤Î <callback> ¥á¥ó¥Ð¤Ï @c NULL ¤Ê¤Î¤Ç¡¢¥×¥í¥°¥é¥Þ¦¤Ç
1920     ÀÕǤ¤ò»ý¤Ã¤Æ, Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ËÀßÄꤷ¡¢Preedit ¥Æ¥­¥¹¥È,
1921     Status ¥Æ¥­¥¹¥È¤¬¥æ¡¼¥¶¤Ëɽ¼¨¤Ç¤­¤ë¤è¤¦¤Ë¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
1922
1923     ´Ø¿ô M17N_INIT () ¤ÏÊÑ¿ô @c minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
1924     ¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
1925
1926     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
1927     ¤Ç»Ï¤Þ¤ë°Ê²¼¤Î´Ø¿ô·²¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤É¤ì¤â̵»ë¤µ¤ì
1928     ¤ë¡£  */
1929
1930 MInputDriver minput_default_driver;
1931 /*=*/
1932
1933 /***en
1934     @brief The input driver for internal input methods.
1935
1936     The variable #minput_driver is a pointer to the input method
1937     driver that is used by internal input methods.  The macro
1938     M17N_INIT () initializes it to a pointer to #minput_default_driver
1939     (if <m17n.h> is included) or to #minput_gui_driver (if
1940     <m17n-gui.h> is included).  */ 
1941
1942 MInputDriver *minput_driver;
1943
1944 MSymbol Minput_driver;
1945
1946 /*=*/
1947
1948 /***en
1949     @brief Open an input method.
1950
1951     The minput_open_im () function opens an input method that matches
1952     language $LANGUAGE and name $NAME, and returns a pointer to the
1953     input method object newly allocated.
1954
1955     This function at first decides an input driver for the input
1956     method as below.
1957
1958     If $LANGUAGE is not #Mnil, an input driver pointed by the variable
1959     #minput_driver is used.
1960
1961     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
1962     input driver pointed to by the property value is used to open the
1963     input method.  If $NAME has no such property, @c NULL is returned.
1964
1965     Then, the member MInputDriver::open_im () of the input driver is
1966     called.  
1967
1968     $ARG is set in the member @c arg of the structure MInputMethod so
1969     that the input driver can refer to it.  */
1970
1971 /***ja
1972     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë     
1973
1974     ´Ø¿ô mim_open () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME ¤ËŬ¹ç¤¹¤ëÆþÎϥ᥽¥Ã
1975     ¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¤½¤Î¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1976
1977     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢m17n ¸À¸ì¾ðÊó¥Ù¡¼¥¹Ã椫¤é \<@c
1978     Minput_method, $LANGUAGE, $NAME \> ¤È¤¤¤¦¥¿¥°¤ËŬ¹ç¤¹¤ëÆþÎϥ᥽¥Ã
1979     ¥É¤òõ¤¹¡£¸«¤Ä¤«¤Ã¤¿¾ì¹ç¤Ï¡¢ÊÑ¿ô #minput_driver ¤Ç¥Ý¥¤¥ó¥È¤µ¤ì¤Æ
1980     ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤Æ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£¸«¤Ä¤«¤é¤Ê
1981     ¤¤¾ì¹ç¤ä¥ª¡¼¥×¥ó¤Ç¤­¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï @c NULL ¤òÊÖ¤¹¡£
1982
1983     ÊÑ¿ô #minput_driver ¤Ï¡¢#minput_default_driver ¤« @c
1984     minput_gui_driver ¤Î¤É¤Á¤é¤«¤ò¥Ý¥¤¥ó¥È¤·¤Æ¤¤¤ë¡£Á°¼Ô¤Ï CUI ÍѤǤ¢
1985     ¤ê¡¢´Ø¿ôm17n_initialize () ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤Æ #minput_driver ¤¬ 
1986     #minput_default_driver ¤ò¥Ý¥¤¥ó¥È¤¹¤ë¤è¤¦¤Ë¤Ê¤ë¡£¸å¼Ô¤Ï GUI ÍѤÇ
1987     ¤¢¤ê¡¢´Ø¿ô m17n_initialize_win () ¤Ë¤è¤Ã¤Æ¥Ý¥¤¥ó¥È¤µ¤ì¤ë¡£¾ÜºÙ¤Ë¤Ä
1988     ¤¤¤Æ¤Ï¤³¤ì¤é¤ÎÊÑ¿ô¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
1989
1990     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver ¤ò¥­¡¼¤È¤¹
1991     ¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǥݥ¤¥ó¥È¤µ¤ì¤Æ¤¤¤ë
1992     ÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£$NAME ¤Ë¤½¤Î¤è¤¦¤Ê
1993     ¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤ä¥ª¡¼¥×¥ó¤Ç¤­¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¤Ï @c NULL ¤ò
1994     ÊÖ¤¹¡£
1995
1996     $ARG ¤Ï¡¢ÆþÎϥɥ饤¥Ð¤¬»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¡¢¹½Â¤ÂΠMInputMethod ¤Î¥á
1997     ¥ó¥Ð @c arg ¤Ë¥»¥Ã¥È¤µ¤ì¤ë¡£
1998
1999     @latexonly \IPAlabel{minput_open} @endlatexonly
2000
2001 */
2002
2003 MInputMethod *
2004 minput_open_im (MSymbol language, MSymbol name, void *arg)
2005 {
2006   MInputMethod *im;
2007   MInputDriver *driver;
2008
2009   if (language)
2010     driver = minput_driver;
2011   else
2012     {
2013       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
2014       if (! driver)
2015         MERROR (MERROR_IM, NULL);
2016     }
2017
2018   MSTRUCT_CALLOC (im, MERROR_IM);
2019   im->language = language;
2020   im->name = name;
2021   im->arg = arg;
2022   im->driver = *driver;
2023   if ((*im->driver.open_im) (im) < 0)
2024     {
2025       free (im);
2026       return NULL;
2027     }
2028   return im;
2029 }
2030
2031 /*=*/
2032
2033 /***en
2034     @brief Close an input method.
2035
2036     The minput_close_im () function closes the input method $IM, which
2037     must have been created by minput_open_im ().  */
2038
2039 /***ja
2040     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë
2041
2042     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£¤³¤Î
2043     ÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì
2044     ¤Ð¤Ê¤é¤Ê¤¤¡£  */
2045
2046 void
2047 minput_close_im (MInputMethod *im)
2048 {
2049   (*im->driver.close_im) (im);
2050   free (im);
2051 }
2052
2053 /*=*/
2054
2055 /***en
2056     @brief Create an input context.
2057
2058     The minput_create_ic () function creates an input context object
2059     associated with input method $IM, and calls callback functions
2060     corresponding to #Minput_preedit_start, #Minput_status_start, and
2061     #Minput_status_draw in this order.
2062
2063     @return
2064
2065     If an input context is successfully created, minput_create_ic ()
2066     returns a pointer to it.  Otherwise it returns @c NULL.  */
2067
2068 /***ja
2069     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë
2070
2071     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯
2072     ¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤¹¤ë¡£
2073
2074     @return
2075     ½èÍý¤¬À®¸ù¤·¤¿¾ì¹ç¡¢minput_create_ic () ¤ÏÀ¸À®¤·¤¿ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È
2076     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£  */
2077
2078 MInputContext *
2079 minput_create_ic (MInputMethod *im, void *arg)
2080 {
2081   MInputContext *ic;
2082
2083   MSTRUCT_CALLOC (ic, MERROR_IM);
2084   ic->im = im;
2085   ic->arg = arg;
2086   ic->preedit = mtext ();
2087   ic->candidate_list = NULL;
2088   ic->produced = mtext ();
2089   ic->spot.x = ic->spot.y = 0;
2090   ic->active = 1;
2091   ic->plist = mplist ();
2092   if ((*im->driver.create_ic) (ic) < 0)
2093     {
2094       M17N_OBJECT_UNREF (ic->preedit);
2095       M17N_OBJECT_UNREF (ic->produced);
2096       M17N_OBJECT_UNREF (ic->plist);
2097       free (ic);
2098       return NULL;
2099     };
2100
2101   if (im->driver.callback_list)
2102     {
2103       minput__callback (ic, Minput_preedit_start);
2104       minput__callback (ic, Minput_status_start);
2105       minput__callback (ic, Minput_status_draw);
2106     }
2107
2108   return ic;
2109 }
2110
2111 /*=*/
2112
2113 /***en
2114     @brief Destroy an input context.
2115
2116     The minput_destroy_ic () function destroys the input context $IC,
2117     which must have been created by minput_create_ic ().  It calls
2118     callback functions corresponding to #Minput_preedit_done,
2119     #Minput_status_done, and #Mcandidate_done in this order.  */
2120
2121 /***ja
2122     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë
2123
2124     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£¤³
2125     ¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê
2126     ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£  */
2127
2128 void
2129 minput_destroy_ic (MInputContext *ic)
2130 {
2131   if (ic->im->driver.callback_list)
2132     {
2133       minput__callback (ic, Minput_preedit_done);
2134       minput__callback (ic, Minput_status_done);
2135       minput__callback (ic, Minput_candidates_done);
2136     }
2137   (*ic->im->driver.destroy_ic) (ic);
2138   M17N_OBJECT_UNREF (ic->preedit);
2139   M17N_OBJECT_UNREF (ic->produced);
2140   M17N_OBJECT_UNREF (ic->plist);
2141   free (ic);
2142 }
2143
2144 /*=*/
2145
2146 /***en
2147     @brief Filter an input key.
2148
2149     The minput_filter () function filters input key $KEY according to
2150     input context $IC, and calls callback functions corresponding to
2151     #Minput_preedit_draw, #Minput_status_draw, and #Mcandidate_draw if
2152     the preedit text, the status, and the current candidate are
2153     changed respectively.
2154
2155     @return
2156     If $KEY is filtered out, this function returns 1.  In that case,
2157     the caller should discard the key.  Otherwise, it returns 0, and
2158     the caller should handle the key, for instance, by calling the
2159     function minput_lookup () with the same $KEY.  */
2160
2161 /***ja
2162     @brief ÆþÎÏ¥­¡¼¤Î¥Õ¥£¥ë¥¿¥ê¥ó¥°¤ò¤¹¤ë
2163
2164     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Ë±þ
2165     ¤¸¤Æ¥Õ¥£¥ë¥¿¥ê¥ó¥°¤¹¤ë¡£
2166
2167     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ÎÆþÎϥ᥽¥Ã¥É¤¬ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ì¤Ð¡¢¤³
2168     ¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£
2169     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤¬¡¢¤¿¤È¤¨¤ÐƱ¤¸ $KEY ¤Ç´Ø¿ô 
2170     minput_lookup () ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
2171
2172     @latexonly \IPAlabel{minput_filter} @endlatexonly
2173 */
2174
2175 int
2176 minput_filter (MInputContext *ic, MSymbol key, void *arg)
2177 {
2178   int ret;
2179
2180   if (! ic
2181       || ! ic->active)
2182     return 0;
2183   ret = (*ic->im->driver.filter) (ic, key, arg);
2184
2185   if (ic->im->driver.callback_list)
2186     {
2187       if (ic->preedit_changed)
2188         minput__callback (ic, Minput_preedit_draw);
2189       if (ic->status_changed)
2190         minput__callback (ic, Minput_status_draw);
2191       if (ic->candidates_changed)
2192         minput__callback (ic, Minput_candidates_draw);
2193       ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
2194     }
2195
2196   return ret;
2197 }
2198
2199 /*=*/
2200
2201 /***en
2202     @brief Lookup a text produced in the input context.
2203
2204     The minput_lookup () function looks up a text in the input context
2205     $IC.  $KEY must be the same one provided to the previous call of
2206     minput_filter ().
2207
2208     If a text was produced by the input method, it is concatenated
2209     to M-text $MT.
2210
2211     This function calls #MInputDriver::lookup.
2212
2213     @return
2214     If $KEY was correctly handled by the input method, this function
2215     returns 0.  Otherwise, returns -1, even in that case, some text
2216     may be produced in $MT.  */
2217
2218 /***ja
2219     @brief ÆþÎϥ᥽¥Ã¥É¤¬ºî¤Ã¤¿¥Æ¥­¥¹¥È¤Î³ÍÆÀ
2220
2221     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤ò³ÍÆÀ¤¹
2222     ¤ë¡£$KEY ¤Ï´Ø¿ôminput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î
2223     ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2224
2225     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢$IC->produced ¤ËÊÝ
2226     »ý¤µ¤ì¤Æ¤¤¤ë¡£
2227
2228      ¤³¤Î´Ø¿ô¤Ï¡¢X ¥¦¥£¥ó¥É¥¦¤Î <tt>XLookupString ()</tt> ¡¢
2229     <tt>XmbLookupString ()</tt> ¡¢<tt>XwcLookupString ()</tt> ¤ËÂбþ¤¹
2230     ¤ë¡£
2231
2232     @return
2233     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤Æ¤¤¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤ò
2234     ÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢¤³¤Î¾ì¹ç¤Ç¤â$IC->produced ¤Ë²¿¤é¤«
2235     ¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
2236
2237     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
2238
2239 int
2240 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2241 {
2242   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
2243 }
2244 /*=*/
2245
2246 /***en
2247     @brief Set the spot of the input context.
2248
2249     The minput_set_spot () function set the spot of input context $IC
2250     to coordinate ($X, $Y) with the height $ASCENT and $DESCENT.
2251     $FONTSIZE specfies the fontsize of a preedit text in 1/10 point.
2252     The semantics of these values depend on the input driver.
2253
2254     For instance, an input driver designed to work in CUI environment
2255     may use $X and $Y as column and row numbers, and ignore $ASCENT
2256     and $DESCENT.  An input driver designed to work on a window system
2257     may treat $X and $Y as pixel offsets relative to the origin of the
2258     client window, and treat $ASCENT and $DESCENT as ascent and
2259     descent pixels of a line at ($X . $Y).
2260
2261     $MT and $POS is an M-text and a character position at the spot.
2262     $MT may be NULL, in which case, the input method can't get
2263     information about the text around the spot.  */
2264
2265 /***ja
2266     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë
2267
2268     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂ
2269     É¸ ($X, $Y)¤Ë ¡¢¹â¤µ $ASCENT¡¢$DESCENT ¤ÇÀßÄꤹ¤ë¡£¤³¤ì¤é¤ÎÃͤΰÕ
2270     Ì£¤ÏÆþÎϥɥ饤¥Ð¤Ë°Í¸¤¹¤ë¡£
2271
2272     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ëÆþÎϥɥ饤¥Ð¤Ï $X, $Y ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô
2273     ¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT¡¢$DESCENT ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿
2274     ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤÎÆþÎϥɥ饤¥Ð¤Ï $X,$Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É
2275     ¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
2276     $ASCENT ¤È $DESCENT ¤ò ($X . $Y) ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯
2277     ¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£  */
2278
2279 void
2280 minput_set_spot (MInputContext *ic, int x, int y,
2281                  int ascent, int descent, int fontsize,
2282                  MText *mt, int pos)
2283 {
2284   ic->spot.x = x;
2285   ic->spot.y = y;
2286   ic->spot.ascent = ascent;
2287   ic->spot.descent = descent;
2288   ic->spot.fontsize = fontsize;
2289   ic->spot.mt = mt;
2290   ic->spot.pos = pos;
2291   if (ic->im->driver.callback_list)
2292     minput__callback (ic, Minput_set_spot);
2293 }
2294 /*=*/
2295
2296 /***en
2297     @brief Toggle input method.
2298
2299     The minput_toggle () function toggles the input method associated
2300     with the input context $IC.  */
2301
2302 void
2303 minput_toggle (MInputContext *ic)
2304 {
2305   if (ic->im->driver.callback_list)
2306     minput__callback (ic, Minput_toggle);
2307   ic->active = ! ic->active;
2308 }
2309
2310
2311 /*** @} */
2312 /*=*/
2313 /*** @addtogroup m17nDebug */
2314 /*=*/
2315 /*** @{  */
2316 /*=*/
2317
2318 /***en
2319     @brief Dump an input method
2320
2321     The mdebug_dump_im () function prints the input method $IM in a
2322     human readable way to the stderr.  $INDENT specifies how many
2323     columns to indent the lines but the first one.
2324
2325     @return
2326     This function returns $IM.  */
2327
2328 MInputMethod *
2329 mdebug_dump_im (MInputMethod *im, int indent)
2330 {
2331   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2332   char *prefix;
2333
2334   prefix = (char *) alloca (indent + 1);
2335   memset (prefix, 32, indent);
2336   prefix[indent] = '\0';
2337
2338   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
2339            msymbol_name (im->name));
2340   mdebug_dump_mtext (im_info->title, 0, 0);
2341   if (im->name != Mnil)
2342     {
2343       MPlist *state;
2344
2345       MPLIST_DO (state, im_info->states)
2346         {
2347           fprintf (stderr, "\n%s  ", prefix);
2348           dump_im_state (MPLIST_VAL (state), indent + 2);
2349         }
2350     }
2351   fprintf (stderr, ")");
2352   return im;
2353 }
2354
2355 /*** @} */ 
2356
2357 /*
2358   Local Variables:
2359   coding: euc-japan
2360   End:
2361 */