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