Use pkg-config (if available) for Xft.
[m17n/m17n-lib.git] / example / mimx-anthy.c
1 /* mimx-anthy.c -- Anthy input method external module.  -*- coding: euc-jp; -*-
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     @enpage mimx-anthy external module for the input method <ja, anthy>
25
26     @section mimx-anthy-description DESCRIPTION
27
28     The shared library mimx-anthy.so is an external module used by the
29     input method <ja, anthy>.  It exports these functions.
30
31     <ul>
32     <li> init
33
34     Initialize this module.
35
36     <li> fini
37
38     Finalize this module.
39
40     <li> convert
41
42     Convert the current preedit text (Hiragana sequence) into
43     Kana-Kanji mixed text.
44
45     <li> change
46
47     Record the change of candidate of the current segment.
48
49     <li> resize
50
51     Enlarge or shorten the length of the current segment.
52
53     <li> commit
54
55     Commit the lastly selected candidates of all the segments.
56
57     </ul>
58
59     @section mimx-anthy-seealso See also
60     @ref mdbIM
61 */
62 /***ja
63     @japage mimx-anthy ÆþÎϥ᥽¥Ã¥É <ja, anthy> Íѳ°Éô¥â¥¸¥å¡¼¥ë.
64
65     @section mimx-anthy-description DESCRIPTION
66
67     ¶¦Í­¥é¥¤¥Ö¥é¥ê mimx-anthy.so ¤ÏÆþÎϥ᥽¥Ã¥É<ja, anthy> ¤ËÍѤ¤¤é¤ì 
68     ¤ë³°Éô¥â¥¸¥å¡¼¥ë¤Ç¤¢¤ê¡¢°Ê²¼¤Î´Ø¿ô¤ò export ¤·¤Æ¤¤¤ë¡£
69
70     <ul>
71     <li> init
72
73     ¥â¥¸¥å¡¼¥ë¤Î½é´ü²½¡£ 
74
75     <li> fini
76
77     ¥â¥¸¥å¡¼¥ë¤Î½ªÎ»¡£ 
78
79     <li> convert
80
81     ¸½ºß¤Î preedit ¥Æ¥­¥¹¥È (¤Ò¤é¤¬¤ÊÎó) ¤ò¤«¤Ê´Á»ú¥Æ¥­¥¹¥È¤ËÊÑ´¹¤¹¤ë¡£ 
82
83     <li> change
84
85     ¸½ºß¤Î¥»¥°¥á¥ó¥È¤Î¸õÊä¤ÎÊÑÁ«¤òµ­Ï¿¤¹¤ë¡£ 
86
87     <li> resize
88
89     ¸½ºß¤Î¥»¥°¥á¥ó¥È¤ÎŤµ¤òÊѹ¹¤¹¤ë¡£ 
90
91     <li> commit
92
93     Á´¥»¥°¥á¥ó¥È¤ÎºÇ¿·¤Î¸õÊä¤ò¥³¥ß¥Ã¥È¤¹¤ë¡£
94
95     </ul>
96
97     @section mimx-anthy-seealso »²¾È
98     @ref mdbIM
99 */
100
101 #ifndef FOR_DOXYGEN
102
103 #include <stdio.h>
104 #include <string.h>
105 #include <config.h>
106 #include <m17n.h>
107
108 #ifdef HAVE_ANTHY
109
110 #include <anthy/anthy.h>
111
112 static int initialized;
113 static MSymbol Manthy, Msegment;
114
115 /* A structure to record in MInputContext->plist with key Manthy.  */
116
117 typedef struct {
118   anthy_context_t ac;
119   /* Which candidate is selected in each segment.  */
120   int *candidate_numbers;
121   /* Size of the above array.  */
122   int num_segments;
123   /* Converter for this context.  */
124   MConverter *converter;
125 } AnthyContext;
126
127 static AnthyContext *
128 new_context (MInputContext *ic)
129 {
130   AnthyContext *context = NULL;
131   MSymbol euc_jp = msymbol ("euc-jp");
132   /* Rebound to an actual buffer just before being used.  */
133   MConverter *converter = mconv_buffer_converter (euc_jp, NULL, 0);
134
135   if (converter)
136     {
137       context = calloc (1, sizeof (AnthyContext));
138       context->ac = anthy_create_context ();
139       context->num_segments = 0;
140       context->candidate_numbers = NULL;
141       context->converter = converter;
142     }
143   return context;
144 }
145
146 static void
147 free_context (AnthyContext *context)
148 {
149   anthy_release_context (context->ac);
150   if (context->candidate_numbers)
151     free (context->candidate_numbers);
152   mconv_free_converter (context->converter);
153   free (context);
154 }
155
156 static void
157 allocate_candidate_numbers (AnthyContext *context, int num)
158 {
159   if (context->num_segments < num)
160     {
161       if (context->num_segments == 0)
162         context->candidate_numbers = malloc (sizeof (int) * num);
163       else
164         context->candidate_numbers = realloc (context->candidate_numbers,
165                                               sizeof (int) * num);
166       context->num_segments = num;
167     }
168 }
169
170 static void
171 add_action (MPlist *actions, MSymbol name, MSymbol key, void *val)
172 {
173   MPlist *action = mplist ();
174
175   mplist_add (action, Msymbol, name);
176   mplist_add (action, key, val);
177   mplist_add (actions, Mplist, action);
178   m17n_object_unref (action);
179 }
180
181 /* Return a list of all candidates of the Nth segment.  The return
182    value is a plist whose elements are plists who contains at most 5
183    candidates.  */
184
185 static MPlist *
186 make_candidate_list (AnthyContext *context, int n)
187 {
188   MPlist *plist = mplist (), *pl;
189   int i;
190   char buf[1024];
191   struct anthy_segment_stat ss;
192   MText *mt;
193   
194   anthy_get_segment_stat (context->ac, n, &ss);
195   for (i = 0, pl = mplist (); i < ss.nr_candidate; i++)
196     {
197       anthy_get_segment (context->ac, n, i, buf, sizeof (buf));
198       mconv_rebind_buffer (context->converter,
199                            (unsigned char *) buf, strlen (buf));
200       mt = mconv_decode (context->converter, mtext ());
201       mtext_put_prop (mt, 0, mtext_len (mt), Msegment, (void *) (n + 1));
202       mplist_add (pl, Mtext, mt);
203       m17n_object_unref (mt);
204       if (i % 5 == 4)
205         {
206           mplist_add (plist, Mplist, pl);
207           m17n_object_unref (pl);
208           pl = mplist ();
209         }
210     }
211   if (mplist_key (pl) != Mnil)
212     mplist_add (plist, Mplist, pl);
213   m17n_object_unref (pl);
214   return plist;
215 }
216
217 MPlist *
218 init (MPlist *args)
219 {
220   MInputContext *ic = mplist_value (args);
221
222   if (! initialized)
223     {
224       anthy_init ();
225       Manthy = msymbol (" anthy");
226       Msegment = msymbol (" segment");
227       initialized = 1;
228     }
229   mplist_push (ic->plist, Manthy, new_context (ic));
230   return NULL;
231 }
232
233 MPlist *
234 fini (MPlist *args)
235 {
236   MInputContext *ic = mplist_value (args);
237   AnthyContext *context = mplist_get (ic->plist, Manthy);
238
239   if (context)
240     free_context (context);
241   return NULL;
242 }
243
244 MPlist *
245 convert (MPlist *args)
246 {
247   MInputContext *ic = mplist_value (args);
248   AnthyContext *context = mplist_get (ic->plist, Manthy);
249   struct anthy_conv_stat cs;
250   MPlist *action, *actions;
251   int i;
252   unsigned char buf[1024];
253
254   if (! context)
255     return NULL;
256
257   mconv_rebind_buffer (context->converter, buf, sizeof (buf));
258   mconv_encode (context->converter, ic->preedit);
259   buf[context->converter->nbytes] = '\0';
260   anthy_set_string (context->ac, (char *) buf);
261   anthy_get_stat (context->ac, &cs);
262   allocate_candidate_numbers (context, cs.nr_segment);
263
264   actions = mplist ();
265   add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
266   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
267   for (i = 0; i < cs.nr_segment; i++)
268     {
269       context->candidate_numbers[i] = 0;
270       if (i == 1)
271         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
272       action = make_candidate_list (context, i);
273       mplist_add (actions, Mplist, action);
274       m17n_object_unref (action);
275     }
276   if (cs.nr_segment > 1)
277     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
278
279   return actions;
280 }
281
282 MPlist *
283 change (MPlist *args)
284 {
285   MInputContext *ic = mplist_value (args);
286   AnthyContext *context = mplist_get (ic->plist, Manthy);
287   int segment;
288
289   if (! context)
290     return NULL;
291   if (! ic->candidate_list || ic->cursor_pos == 0)
292     return NULL;
293   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
294   if (segment == 0)
295     return NULL;
296   segment--;
297   context->candidate_numbers[segment] = ic->candidate_index;
298   return NULL;
299 }
300
301 MPlist *
302 resize (MPlist *args)
303 {
304   MInputContext *ic = mplist_value (args);
305   AnthyContext *context = mplist_get (ic->plist, Manthy);
306   struct anthy_conv_stat cs;
307   MSymbol shorten;
308   int segment;
309   MPlist *actions, *action;
310   int i;
311
312   if (! context)
313     return NULL;
314   if (! ic->candidate_list || ic->cursor_pos == 0)
315     return NULL;
316   segment = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1, Msegment);
317   if (segment == 0)
318     return NULL;
319   segment--;
320   args = mplist_next (args);
321   shorten = mplist_value (args);
322   anthy_resize_segment (context->ac, segment, shorten == Mt ? -1 : 1);
323   anthy_get_stat (context->ac, &cs);
324   allocate_candidate_numbers (context, cs.nr_segment);
325
326   actions = mplist ();
327   if (segment == 0)
328     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@<"));
329   else
330     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@["));
331   add_action (actions, msymbol ("delete"), Msymbol, msymbol ("@>"));
332   for (i = segment; i < cs.nr_segment; i++)
333     {
334       context->candidate_numbers[i] = 0;
335       if (i == segment + 1)
336         add_action (actions, msymbol ("mark"), Msymbol, msymbol ("@anthy"));
337       action = make_candidate_list (context, i);
338       mplist_add (actions, Mplist, action);
339       m17n_object_unref (action);
340     }
341   if (segment + 1 < cs.nr_segment)
342     add_action (actions, msymbol ("move"), Msymbol, msymbol ("@anthy"));
343   return actions;
344 }
345
346 MPlist *
347 commit (MPlist *args)
348 {
349   MInputContext *ic = mplist_value (args);
350   AnthyContext *context = mplist_get (ic->plist, Manthy);
351   struct anthy_conv_stat cs;
352   int i;
353
354   anthy_get_stat (context->ac, &cs);
355   for (i = 0; i < cs.nr_segment; i++)
356     anthy_commit_segment (context->ac, i, context->candidate_numbers[i]);
357   return NULL;
358 }
359
360 #else  /* not HAVE_ANTHY */
361
362 MPlist *convert (MPlist *args) { return NULL; }
363 MPlist *change (MPlist *args) { return NULL; }
364 MPlist *resize (MPlist *args) { return NULL; }
365 MPlist *commit (MPlist *args) { return NULL; }
366
367 #endif /* not HAVE_ANTHY */
368 #endif /* not FOR_DOXYGEN */