1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 /*
3 * im_iiimf.c - iiimf plugin for mlterm
4 *
5 * Copyright (C) 2004 2005 Seiichi SATO <ssato@sh.rim.or.jp>
6 *
7 */
8
9 /*
10 * im_iiimf_process_event() is based on IMProcessIncomingEvent() of iiimxcf.
11 */
12
13 /*
14 * Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions: The above copyright notice and this
23 * permission notice shall be included in all copies or substantial
24 * portions of the Software.
25 *
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
30 * IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
31 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
32 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
33 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
34 * ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
35 *
36 *
37 * Except as contained in this notice, the names of The Open Group and/or
38 * Sun Microsystems, Inc. shall not be used in advertising or otherwise to
39 * promote the sale, use or other dealings in this Software without prior
40 * written authorization from The Open Group and/or Sun Microsystems,
41 * Inc., as applicable.
42 *
43 *
44 * X Window System is a trademark of The Open Group
45 *
46 * OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
47 * logo, LBX, X Window System, and Xinerama are trademarks of the Open
48 * Group. All other trademarks and registered trademarks mentioned herein
49 * are the property of their respective owners. No right, title or
50 * interest in or to any trademark, service mark, logo or trade name of
51 * Sun Microsystems, Inc. or its licensors is granted.
52 *
53 */
54
55 #include <string.h> /* strncmp */
56 #include <dirent.h>
57 #include <pobl/bl_def.h> /* WORDS_BIGENDIAN */
58 #include <pobl/bl_mem.h> /* malloc/alloca/free */
59 #include <pobl/bl_str.h> /* bl_str_sep/strdup/bl_snprintf */
60 #include <pobl/bl_locale.h> /* bl_get_lang */
61 #include <pobl/bl_debug.h>
62 #include <pobl/bl_util.h> /* bl_get_user_name */
63 #include <mef/ef_utf16_parser.h>
64 #include <mef/ef_iso8859_conv.h>
65
66 #include "im_iiimf.h"
67 #include "keymap.h"
68 #include "../im_common.h"
69 #include "../im_info.h"
70
71 #if 0
72 #define IM_IIIMF_DEBUG 1
73 #endif
74
75 /* XXX: it seems to be undefined in iiim*.h. why? */
76 #define IIIMF_SHIFT_MODIFIER 1
77 #define IIIMF_CONTROL_MODIFIER 2
78 #define IIIMF_META_MODIFIER 4
79 #define IIIMF_ALT_MODIFIER 8
80
81 /* --- static variables --- */
82
83 static int ref_count = 0;
84 static int initialized = 0;
85 static ef_parser_t * parser_utf16 = NULL;
86 static IIIMCF_handle handle = NULL;
87 /* mlterm internal symbols */
88 static ui_im_export_syms_t * syms = NULL;
89
90 static int htt_show_status_window = 0;
91 static int htt_generates_kanakey = 0;
92
93 /* --- static functions --- */
94
find_language(char * lang)95 static IIIMCF_language find_language(char * lang) {
96 IIIMCF_language * array;
97 IIIMCF_language best_result = NULL;
98 IIIMCF_language better_result = NULL;
99 char * p = NULL;
100 char * language = NULL;
101 char * country = NULL;
102 int num;
103 int i;
104
105 if (lang && (p = alloca(strlen(lang) + 1))) {
106 strcpy(p, lang);
107
108 if ((country = bl_str_sep(&p, ":"))) {
109 p = country; /* hold for free() */
110 language = bl_str_sep(&country, "_");
111 }
112 }
113
114 if (language == NULL && country == NULL) {
115 language = bl_get_lang();
116 country = bl_get_country();
117 }
118
119 if (iiimcf_get_supported_languages(handle, &num, &array) == IIIMF_STATUS_SUCCESS) {
120 for (i = 0; i < num; i++) {
121 const char * lang_id;
122
123 if (iiimcf_get_language_id(array[i], &lang_id) != IIIMF_STATUS_SUCCESS) {
124 continue;
125 }
126
127 /* At first, compare with lang_COUNTRY like "zh_CN" */
128 if (country) {
129 char buf[16];
130
131 bl_snprintf(buf, sizeof(buf), "%s_%s", language, country);
132
133 if (strcmp(buf, lang_id) == 0) {
134 best_result = array[i];
135 }
136 }
137
138 /* Next, compare with lang like "ja" */
139 if (strcmp(language, lang_id) == 0) {
140 better_result = array[i];
141 }
142 }
143 }
144
145 return (best_result ? best_result : better_result);
146 }
147
find_language_engine(char * lang)148 static IIIMCF_input_method find_language_engine(char* lang) {
149 IIIMCF_input_method * array;
150 IIIMCF_input_method result = NULL;
151 char * le_name = NULL;
152 ef_conv_t * conv;
153 int num;
154 int i;
155
156 if (!lang) {
157 return NULL;
158 }
159
160 if (!(le_name = strstr(lang, ":"))) {
161 return NULL;
162 }
163
164 /* eliminate leading ":" */
165 le_name ++;
166
167 if (!(conv = (*syms->vt_char_encoding_conv_new)(VT_ISO8859_1))) {
168 return NULL;
169 }
170
171 if (iiimcf_get_supported_input_methods(handle, &num, &array) == IIIMF_STATUS_SUCCESS) {
172 for (i = 0; i < num; i++) {
173 const IIIMP_card16 * id;
174 const IIIMP_card16 * hrn; /* human readable name */
175 const IIIMP_card16 * domain;
176
177 if (iiimcf_get_input_method_desc(array[i], &id, &hrn, &domain) == IIIMF_STATUS_SUCCESS) {
178 u_char * str;
179
180 im_convert_encoding(parser_utf16, conv, (u_char*) id, &str, strlen_utf16(id) + 1);
181
182 if (strcmp(le_name, str) == 0) {
183 #ifdef IM_IIIMF_DEBUG
184 bl_debug_printf(BL_DEBUG_TAG " found le [%s].\n", le_name);
185 #endif
186
187 result = array[i];
188 }
189
190 free(str);
191 }
192 }
193 }
194
195 (*conv->destroy)(conv);
196
197 return result;
198 }
199
show_iiimcf_version(void)200 static void show_iiimcf_version(void) {
201 #ifdef IM_IIIMF_DEBUG
202 #define SHOW_VER(flag, str) { \
203 int ver; \
204 if (iiimcf_get_version_number(handle, (flag), &ver) \
205 == IIIMF_STATUS_ARGUMENT) { \
206 bl_debug_printf(BL_DEBUG_TAG "%s\t\t:%d\n", (str), ver) { \
207 bl_debug_printf(BL_DEBUG_TAG "%s\t\t:none\n", (str));\
208 } \
209 } while (0)
210
211 SHOW_VER(IIIMCF_LIBRARY_VERSION, "library version");
212 SHOW_VER(IIIMCF_PROTOCOL_VERSION, "protocol version");
213 SHOW_VER(IIIMCF_MINOR_VERSION, "minor version");
214 SHOW_VER(IIIMCF_MAJOR_VERSION, "major version");
215 #endif
216 }
217
218 /*
219 * callback for candidate screen events
220 */
221
222 static void candidate_selected(void *p, u_int index) {
223 #ifdef IM_IIIMF_DEBUG
224 bl_debug_printf(BL_DEBUG_TAG " index : %d\n", index);
225 #endif
226
227 /* not implemented yet. */
228 }
229
230
231 /*
232 * processing event from IIIMSF
233 */
234
235 static void commit(im_iiimf_t *iiimf) {
236 IIIMCF_text iiimcf_text;
237 const IIIMP_card16 *utf16str;
238 u_char buf[256];
239 size_t filled_len;
240
241 #ifdef IM_IIIMF_DEBUG
242 bl_debug_printf(BL_DEBUG_TAG "\n");
243 #endif
244
245 if (iiimcf_get_committed_text(iiimf->context, &iiimcf_text) != IIIMF_STATUS_SUCCESS) {
246 #ifdef DEBUG
247 bl_warn_printf(BL_DEBUG_TAG " Could not get committed text.\n");
248 #endif
249 return;
250 }
251
252 if (iiimcf_get_text_utf16string(iiimcf_text, &utf16str) != IIIMF_STATUS_SUCCESS) {
253 #ifdef DEBUG
254 bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string.\n");
255 #endif
256 return;
257 }
258
259 (*iiimf->im.listener->write_to_term)(iiimf->im.listener->self,
260 (u_char*) utf16str, strlen_utf16(utf16str),
261 parser_utf16);
262 }
263
264 static void preedit_start(im_iiimf_t *iiimf) {
265 #ifdef IM_IIIMF_DEBUG
266 bl_debug_printf(BL_DEBUG_TAG "\n");
267 #endif
268
269 if (iiimf->im.preedit.chars) {
270 (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
271 }
272
273 iiimf->im.preedit.num_chars = 0;
274 iiimf->im.preedit.filled_len = 0;
275 iiimf->im.preedit.segment_offset = 0;
276 iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
277 }
278
279 static void preedit_change(im_iiimf_t *iiimf) {
280 IIIMCF_text iiimcf_text;
281 const IIIMP_card16 *utf16str;
282 u_char *str;
283 vt_char_t *p;
284 ef_char_t ch;
285 int is_underline = 0;
286 int caret_pos;
287 u_int count = 0;
288 int in_reverse = 0;
289
290 #ifdef IM_IIIMF_DEBUG
291 bl_debug_printf(BL_DEBUG_TAG "\n");
292 #endif
293
294 /*
295 * get preedit string without attribute.
296 */
297
298 if (iiimcf_get_preedit_text(iiimf->context, &iiimcf_text, &caret_pos) != IIIMF_STATUS_SUCCESS) {
299 #ifdef DEBUG
300 bl_warn_printf(BL_DEBUG_TAG " Could not get preedit text\n");
301 #endif
302 return;
303 }
304
305 if (iiimcf_get_text_utf16string(iiimcf_text, &utf16str) != IIIMF_STATUS_SUCCESS) {
306 #ifdef DEBUG
307 bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string\n");
308 #endif
309 return;
310 }
311
312 if (strlen_utf16(utf16str) == 0) {
313 /* clear */
314 (*iiimf->im.listener->draw_preedit_str)(iiimf->im.listener->self, NULL, 0, 0);
315
316 if (iiimf->im.preedit.chars) {
317 (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
318 iiimf->im.preedit.chars = NULL;
319 iiimf->im.preedit.num_chars = 0;
320 iiimf->im.preedit.filled_len = 0;
321 iiimf->im.preedit.segment_offset = 0;
322 iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
323 }
324
325 return ;
326 }
327
328 /* UTF16 -> term encoding */
329 im_convert_encoding(parser_utf16, iiimf->conv, (u_char*) utf16str, &str,
330 strlen_utf16(utf16str) + 1);
331
332
333 /*
334 * count number of characters to re-allocate im.preedit.chars
335 */
336
337 (*iiimf->parser_term->init)(iiimf->parser_term);
338 (*iiimf->parser_term->set_str)(iiimf->parser_term, str, strlen(str));
339
340 while ((*iiimf->parser_term->next_char)(iiimf->parser_term, &ch)) {
341 count ++;
342 }
343
344
345 /*
346 * allocate im.preedit.chars
347 */
348
349 if (iiimf->im.preedit.chars) {
350 (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
351 iiimf->im.preedit.chars = NULL;
352 iiimf->im.preedit.num_chars = 0;
353 iiimf->im.preedit.filled_len = 0;
354 iiimf->im.preedit.segment_offset = 0;
355 iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
356 }
357
358 if (!(iiimf->im.preedit.chars = calloc(count, sizeof(vt_char_t)))) {
359 #ifdef DEBUG
360 bl_warn_printf(BL_DEBUG_TAG "calloc failed.\n");
361 #endif
362
363 return;
364 }
365
366 iiimf->im.preedit.num_chars = count;
367 iiimf->im.preedit.filled_len = 0;
368
369 (*syms->vt_str_init)(iiimf->im.preedit.chars,
370 iiimf->im.preedit.num_chars);
371
372
373 /*
374 * IIIMP_card16(UTF16) -> vt_char_t
375 */
376
377 p = iiimf->im.preedit.chars;
378 (*syms->vt_str_init)(p, iiimf->im.preedit.num_chars);
379
380 (*iiimf->parser_term->init)(iiimf->parser_term);
381 (*iiimf->parser_term->set_str)(iiimf->parser_term,
382 str, strlen(str));
383
384 count = 0;
385
386 /* TODO: move to inputmethod/common/im_common.c */
387 while ((*iiimf->parser_term->next_char)(iiimf->parser_term, &ch)) {
388 IIIMP_card16 iiimcf_ch;
389 const IIIMP_card32 *feedback_ids;
390 const IIIMP_card32 *feedbacks;
391 int num_feedbacks;
392 vt_color_t fg_color = VT_FG_COLOR;
393 vt_color_t bg_color = VT_BG_COLOR;
394 int is_fullwidth = 0;
395 int is_comb = 0;
396 int is_bold = 0;
397
398 iiimf->im.preedit.cursor_offset = 0;
399
400 if (iiimcf_get_char_with_feedback(iiimcf_text, iiimf->im.preedit.filled_len,
401 &iiimcf_ch, &num_feedbacks, &feedback_ids,
402 &feedbacks) == IIIMF_STATUS_SUCCESS) {
403 int i;
404
405 for (i = 0; i < num_feedbacks; i++) {
406 /* IIIMP_FEEDBACK_[1,2,3...]_* don't exist? */
407 if (feedback_ids[i] != IIIMP_FEEDBACK_0_ID) {
408 continue;
409 }
410
411 switch(feedbacks[i]) {
412 case IIIMP_FEEDBACK_0_REVERSE_VIDEO:
413 if (!in_reverse) {
414 iiimf->im.preedit.segment_offset = iiimf->im.preedit.filled_len;
415 in_reverse = 1;
416 }
417 iiimf->im.preedit.cursor_offset =
418 UI_IM_PREEDIT_NOCURSOR;
419 fg_color = VT_BG_COLOR;
420 bg_color = VT_FG_COLOR;
421 break;
422 case IIIMP_FEEDBACK_0_UNDERLINE:
423 is_underline = 1;
424 break;
425 case IIIMP_FEEDBACK_0_HIGHLIGHT:
426 is_bold = 1;
427 break;
428 case IIIMP_FEEDBACK_0_NORMAL_VIDEO:
429 case IIIMP_FEEDBACK_0_PRIMARY:
430 case IIIMP_FEEDBACK_0_SECONDARY:
431 case IIIMP_FEEDBACK_0_TERTIARY:
432 /* not implemented yet */
433 default:
434 break;
435 }
436 }
437 }
438
439 if ((*syms->vt_convert_to_internal_ch)(iiimf->im.vtparser, &ch) <= 0) {
440 continue;
441 }
442
443 if (ch.cs == ISO10646_UCS4_1) {
444 if (ch.property & EF_FULLWIDTH) {
445 is_fullwidth = 1;
446 } else if (ch.property & EF_AWIDTH) {
447 /* TODO: check col_size_of_width_a */
448 is_fullwidth = 1;
449 }
450 }
451
452 if (ch.property & EF_COMBINING) {
453 is_comb = 1;
454
455 if ((*syms->vt_char_combine)(p - 1, ef_char_to_int(&ch), ch.cs, is_fullwidth,
456 (ch.property & EF_AWIDTH) ? 1 : 0, is_comb,
457 fg_color, bg_color, is_bold, 0, is_underline, 0, 0)) {
458 continue;
459 }
460
461 /*
462 * if combining failed, char is normally appended.
463 */
464 }
465
466 (*syms->vt_char_set)(p, ef_char_to_int(&ch), ch.cs, is_fullwidth,
467 (ch.property & EF_AWIDTH) ? 1 : 0, is_comb, fg_color,
468 bg_color, is_bold, 0, is_underline, 0, 0);
469
470 p++;
471 iiimf->im.preedit.filled_len++;
472 }
473
474 if (str) {
475 free(str);
476 }
477
478 if (iiimf->im.preedit.cursor_offset != UI_IM_PREEDIT_NOCURSOR) {
479 iiimf->im.preedit.cursor_offset = iiimf->im.preedit.filled_len;
480 }
481
482 (*iiimf->im.listener->draw_preedit_str)(iiimf->im.listener->self, iiimf->im.preedit.chars,
483 iiimf->im.preedit.filled_len,
484 iiimf->im.preedit.cursor_offset);
485 }
486
487 static void preedit_done(im_iiimf_t *iiimf) {
488 #ifdef IM_IIIMF_DEBUG
489 bl_debug_printf(BL_DEBUG_TAG "\n");
490 #endif
491
492 if (iiimf->im.preedit.chars) {
493 (*syms->vt_str_destroy)(iiimf->im.preedit.chars, iiimf->im.preedit.num_chars);
494 iiimf->im.preedit.chars = NULL;
495 iiimf->im.preedit.num_chars = 0;
496 iiimf->im.preedit.filled_len = 0;
497 iiimf->im.preedit.segment_offset = 0;
498 iiimf->im.preedit.cursor_offset = UI_IM_PREEDIT_NOCURSOR;
499 }
500
501 (*iiimf->im.listener->draw_preedit_str)(iiimf->im.listener->self, iiimf->im.preedit.chars,
502 iiimf->im.preedit.filled_len,
503 iiimf->im.preedit.cursor_offset);
504 }
505
506 static void lookup_choice_start(im_iiimf_t *iiimf) {
507 }
508
509 static void lookup_choice_change(im_iiimf_t *iiimf) {
510 ui_im_event_listener_t *listener = iiimf->im.listener;
511 IIIMCF_lookup_choice lookup_choice;
512 int size;
513 int index_first;
514 int index_last;
515 int index_current;
516 int x;
517 int y;
518 int i;
519 int num_per_window;
520 int row;
521 int col;
522 int direction;
523
524 #ifdef IM_IIIMF_DEBUG
525 bl_debug_printf(BL_DEBUG_TAG "\n");
526 #endif
527
528 if (iiimcf_get_lookup_choice(iiimf->context, &lookup_choice) != IIIMF_STATUS_SUCCESS) {
529 #ifdef DEBUG
530 bl_warn_printf(BL_DEBUG_TAG " Could not get lookup table\n");
531 #endif
532 return;
533 }
534
535 if (iiimcf_get_lookup_choice_size(lookup_choice, &size, &index_first, &index_last,
536 &index_current) != IIIMF_STATUS_SUCCESS) {
537 #ifdef DEBUG
538 bl_warn_printf(BL_DEBUG_TAG " Could not get lookup table.\n");
539 #endif
540 return;
541 }
542
543 if (iiimcf_get_lookup_choice_configuration(lookup_choice, &num_per_window, &row, &col,
544 &direction) != IIIMF_STATUS_SUCCESS) {
545 #ifdef DEBUG
546 bl_warn_printf(BL_DEBUG_TAG " Could not get lookup information.\n");
547 #endif
548 return;
549 }
550
551 #ifdef IM_IIIMF_DEBUG
552 bl_debug_printf(BL_DEBUG_TAG "size: %d\n", size);
553 bl_debug_printf(BL_DEBUG_TAG "index_first: %d\n", index_first);
554 bl_debug_printf(BL_DEBUG_TAG "index_last: %d\n", index_last);
555 bl_debug_printf(BL_DEBUG_TAG "index_current: %d\n", index_current);
556 bl_debug_printf(BL_DEBUG_TAG "num_per_window:%d\n", num_per_window);
557 bl_debug_printf(BL_DEBUG_TAG "row: %d\n", row);
558 bl_debug_printf(BL_DEBUG_TAG "col: %d\n", col);
559 #endif
560
561 if (num_per_window == 0) {
562 num_per_window = 10;
563 }
564
565 if (index_first == 0 && index_last == 0) {
566 return;
567 }
568
569 (*listener->get_spot)(listener->self, iiimf->im.preedit.chars,
570 iiimf->im.preedit.segment_offset, &x, &y);
571
572 if (!iiimf->im.cand_screen) {
573 int is_vertical_direction = 0;
574
575 if (direction == IIIMCF_LOOKUP_CHOICE_VERTICAL_DIRECTION) {
576 is_vertical_direction = 1;
577 }
578
579 if (iiimf->im.stat_screen) {
580 (*iiimf->im.stat_screen->destroy)(iiimf->im.stat_screen);
581 iiimf->im.stat_screen = NULL;
582 }
583
584 if (!(iiimf->im.cand_screen =
585 (*syms->ui_im_candidate_screen_new)(iiimf->im.disp, iiimf->im.font_man,
586 iiimf->im.color_man, iiimf->im.vtparser,
587 (*listener->is_vertical)(listener->self),
588 is_vertical_direction,
589 (*listener->get_line_height)(listener->self),
590 x, y))) {
591 #ifdef DEBUG
592 bl_warn_printf(BL_DEBUG_TAG " ui_im_candidate_screen_new() failed.\n");
593 #endif
594
595 return;
596 }
597
598 iiimf->im.cand_screen->listener.self = iiimf;
599 iiimf->im.cand_screen->listener.selected = candidate_selected;
600 }
601
602 if (!(*iiimf->im.cand_screen->init)(iiimf->im.cand_screen, size, num_per_window)) {
603 (*iiimf->im.cand_screen->destroy)(iiimf->im.cand_screen);
604 iiimf->im.cand_screen = NULL;
605 return;
606 }
607
608 (*iiimf->im.cand_screen->set_spot)(iiimf->im.cand_screen, x, y);
609
610 for (i = index_first; i <= index_last; i++) {
611 IIIMCF_text iiimcf_text_cand;
612 IIIMCF_text iiimcf_text_label;
613 const IIIMP_card16 *utf16str;
614 u_char *str = NULL;
615 int flag;
616
617 if (iiimcf_get_lookup_choice_item(lookup_choice, i, &iiimcf_text_cand,
618 &iiimcf_text_label, &flag) != IIIMF_STATUS_SUCCESS) {
619 #ifdef DEBUG
620 bl_warn_printf(BL_DEBUG_TAG " Could not candidate item\n");
621 #endif
622 continue;
623 }
624
625 if (iiimcf_get_text_utf16string(iiimcf_text_cand, &utf16str) != IIIMF_STATUS_SUCCESS) {
626 #ifdef DEBUG
627 bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string\n");
628 #endif
629 continue;
630 }
631
632 if (im_convert_encoding(parser_utf16, iiimf->conv, (u_char*)utf16str, &str,
633 strlen_utf16(utf16str) + 1)) {
634 (*iiimf->im.cand_screen->set)(iiimf->im.cand_screen, iiimf->parser_term, str, i);
635 free(str);
636 }
637 }
638
639 (*iiimf->im.cand_screen->select)(iiimf->im.cand_screen, index_current);
640 }
641
642 static void status_change(im_iiimf_t *iiimf);
643
644 static void lookup_choice_done(im_iiimf_t *iiimf) {
645 if (iiimf->im.cand_screen) {
646 (*iiimf->im.cand_screen->destroy)(iiimf->im.cand_screen);
647 iiimf->im.cand_screen = NULL;
648 status_change(iiimf);
649 }
650 }
651
652 static void status_start(im_iiimf_t *iiimf) {
653 }
654
655 static void status_change(im_iiimf_t *iiimf) {
656 ui_im_event_listener_t *listener = iiimf->im.listener;
657 IIIMCF_text iiimcf_text;
658 const IIIMP_card16 *utf16str;
659 u_char *str;
660 int x;
661 int y;
662
663 #ifdef IM_IIIMF_DEBUG
664 bl_debug_printf(BL_DEBUG_TAG "\n");
665 #endif
666
667 if (!iiimf->on ||
668 !htt_show_status_window ||
669 iiimcf_get_status_text(iiimf->context, &iiimcf_text) != IIIMF_STATUS_SUCCESS) {
670 if (iiimf->im.stat_screen) {
671 (*iiimf->im.stat_screen->destroy)(iiimf->im.stat_screen);
672 iiimf->im.stat_screen = NULL;
673 }
674
675 return;
676 }
677
678 (*listener->get_spot)(listener->self, iiimf->im.preedit.chars,
679 iiimf->im.preedit.segment_offset, &x, &y);
680
681 if (iiimf->im.stat_screen == NULL) {
682 if (!(iiimf->im.stat_screen =
683 (*syms->ui_im_status_screen_new)(iiimf->im.disp, iiimf->im.font_man,
684 iiimf->im.color_man, iiimf->im.vtparser,
685 (*listener->is_vertical)(listener->self),
686 (*listener->get_line_height)(listener->self),
687 x, y))) {
688 #ifdef DEBUG
689 bl_warn_printf(BL_DEBUG_TAG " ui_im_satus_screen_new() failed.\n");
690 #endif
691
692 return;
693 }
694 }
695
696 if (iiimcf_get_text_utf16string(iiimcf_text, &utf16str) != IIIMF_STATUS_SUCCESS) {
697 #ifdef DEBUG
698 bl_warn_printf(BL_DEBUG_TAG " Could not get utf16 string.\n");
699 #endif
700 return;
701 }
702
703 if (im_convert_encoding(parser_utf16, iiimf->conv, (u_char*)utf16str, &str,
704 strlen_utf16(utf16str) + 1)) {
705 (*iiimf->im.stat_screen->set)(iiimf->im.stat_screen, iiimf->parser_term, str);
706 free(str);
707 }
708 }
709
710 static void status_done(im_iiimf_t *iiimf) {
711 if (iiimf->im.stat_screen) {
712 (*iiimf->im.stat_screen->destroy)(iiimf->im.stat_screen);
713 iiimf->im.stat_screen = NULL;
714 }
715 }
716
717
718 static void dispatch(im_iiimf_t *iiimf, IIIMCF_event event, IIIMCF_event_type event_type) {
719 int trigger_flag;
720
721 switch(event_type) {
722 #if 0
723 case IIIMCF_EVENT_TYPE_DESTROY:
724 case IIIMCF_EVENT_TYPE_RESET:
725 case IIIMCF_EVENT_TYPE_EVENTLIKE:
726 /* case IIIMCF_EVENT_TYPE_KEYEVENT: */
727 /* not implemented yet */
728 break;
729 #endif
730 case IIIMCF_EVENT_TYPE_TRIGGER_NOTIFY:
731 if (iiimcf_get_trigger_notify_flag(event, &trigger_flag) == IIIMF_STATUS_SUCCESS) {
732 iiimf->on = trigger_flag ? 1 : 0;
733 status_change(iiimf);
734 }
735 break;
736 #if 0
737 case IIIMCF_EVENT_TYPE_OPERATION:
738 case IIIMCF_EVENT_TYPE_SETICFOCUS:
739 case IIIMCF_EVENT_TYPE_UNSETICFOCUS:
740 #ifdef HAVE_HOTKEY_NOTFY_EVENT
741 case IIIMCF_EVENT_TYPE_HOTKEY_NOTIFY:
742 #endif
743 /* not implemented yet */
744 break;
745 #endif
746 case IIIMCF_EVENT_TYPE_UI_PREEDIT_START:
747 preedit_start(iiimf);
748 break;
749 case IIIMCF_EVENT_TYPE_UI_PREEDIT_CHANGE:
750 preedit_change(iiimf);
751 break;
752 case IIIMCF_EVENT_TYPE_UI_PREEDIT_DONE:
753 preedit_done(iiimf);
754 break;
755 case IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_START:
756 lookup_choice_start(iiimf);
757 break;
758 case IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_CHANGE:
759 lookup_choice_change(iiimf);
760 break;
761 case IIIMCF_EVENT_TYPE_UI_LOOKUP_CHOICE_DONE:
762 lookup_choice_done(iiimf);
763 break;
764 case IIIMCF_EVENT_TYPE_UI_STATUS_START:
765 status_start(iiimf);
766 break;
767 case IIIMCF_EVENT_TYPE_UI_STATUS_CHANGE:
768 status_change(iiimf);
769 break;
770 case IIIMCF_EVENT_TYPE_UI_STATUS_DONE:
771 status_done(iiimf);
772 break;
773 case IIIMCF_EVENT_TYPE_UI_COMMIT:
774 commit(iiimf);
775 break;
776 case IIIMCF_EVENT_TYPE_AUX_START:
777 case IIIMCF_EVENT_TYPE_AUX_DRAW:
778 case IIIMCF_EVENT_TYPE_AUX_SETVALUES:
779 case IIIMCF_EVENT_TYPE_AUX_DONE:
780 #ifdef HAVE_AUX_GETVALUES_EVENT
781 case IIIMCF_EVENT_TYPE_AUX_GETVALUES:
782 #endif
783 if (iiimf->aux == NULL) {
784 iiimf->aux = aux_new(iiimf);
785 }
786 if (iiimf->aux) {
787 aux_event(iiimf->aux, event, event_type);
788 }
789 break;
790 default:
791 break;
792 }
793 }
794
795
796 /*
797 * methods of ui_im_t
798 */
799
800 static void destroy(ui_im_t *im) {
801 im_iiimf_t *iiimf;
802
803 iiimf = (im_iiimf_t*) im;
804
805 if (iiimf->parser_term) {
806 (*iiimf->parser_term->destroy)(iiimf->parser_term);
807 }
808
809 if (iiimf->conv) {
810 (*iiimf->conv->destroy)(iiimf->conv);
811 }
812
813 if (iiimf->aux) {
814 aux_destroy(iiimf->aux);
815 }
816
817 if (iiimf->context) {
818 iiimcf_destroy_context(iiimf->context);
819 }
820
821 free(iiimf);
822
823 ref_count--;
824
825 #ifdef IM_IIIMF_DEBUG
826 bl_debug_printf(BL_DEBUG_TAG " An object was destroyed. ref_count is %d\n", ref_count);
827 #endif
828
829 if (ref_count == 0 && initialized) {
830 iiimcf_destroy_handle(handle);
831
832 handle = NULL;
833
834 iiimcf_finalize();
835
836 if (parser_utf16) {
837 (*parser_utf16->destroy)(parser_utf16);
838 parser_utf16 = NULL;
839 }
840
841 aux_quit();
842
843 initialized = 0;
844 }
845 }
846
847 static int key_event(ui_im_t *im, u_char key_char, KeySym ksym, XKeyEvent *xevent) {
848 im_iiimf_t *iiimf;
849 IIIMCF_keyevent key;
850 IIIMCF_event event;
851 IIIMF_status status;
852
853 int is_shift;
854 int is_lock;
855 int is_ctl;
856 int is_alt;
857 int is_meta;
858 int is_super;
859 int is_hyper;
860
861 iiimf = (im_iiimf_t*) im;
862
863 key.keycode = 0;
864 key.keychar = 0;
865 key.modifier = 0;
866
867 (*iiimf->im.listener->compare_key_state_with_modmap)(iiimf->im.listener->self,
868 xevent->state, &is_shift, &is_lock,
869 &is_ctl, &is_alt, &is_meta, NULL,
870 &is_super, &is_hyper);
871
872 if (is_shift) key.modifier |= IIIMF_SHIFT_MODIFIER;
873 if (is_ctl) key.modifier |= IIIMF_CONTROL_MODIFIER;
874 if (is_alt) key.modifier |= IIIMF_ALT_MODIFIER;
875 if (is_meta) key.modifier |= IIIMF_META_MODIFIER;
876
877 #if 0
878 if (htt_generates_kanakey && is_shift) {
879 if (!xksym_to_iiimfkey_kana_shift(ksym, &key.keychar, &key.keycode)) {
880 xksym_to_iiimfkey(ksym, &key.keychar, &key.keycode);
881 }
882 }
883 #endif
884
885 xksym_to_iiimfkey(ksym, &key.keychar, &key.keycode);
886
887 #if defined(USE_XLIB) || defined(USE_WAYLAND)
888 key.time_stamp = xevent->time;
889 #else
890 key.time_stamp = 0;
891 #endif
892
893 #if 1
894 /*
895 * ignore Ctrl+] defined as default hotkey.
896 * (see iiimsf/src/IIIMP_hotkey_profile.cpp)
897 */
898 if (!iiimf->on &&
899 key.keycode == IIIMF_KEYCODE_CLOSE_BRACKET &&
900 (key.modifier & IIIMF_CONTROL_MODIFIER)) {
901 return 1;
902 }
903 #endif
904
905 if (iiimcf_create_keyevent(&key, &event) == IIIMF_STATUS_SUCCESS) {
906 status = iiimcf_forward_event(iiimf->context, event);
907
908 switch(status) {
909 case IIIMF_STATUS_SUCCESS:
910 return im_iiimf_process_event(iiimf);
911 case IIIMF_STATUS_EVENT_NOT_FORWARDED:
912 break;
913 case IIIMF_STATUS_IC_INVALID:
914 bl_error_printf("Invalid IIIMCF context\n");
915 break;
916 case IIIMF_STATUS_MALLOC:
917 #ifdef DEBUG
918 bl_warn_printf(BL_DEBUG_TAG " iiimcf internal error [IIIMF_STATUS_MALLOC]\n");
919 #endif
920 break;
921 default:
922 bl_error_printf("Could not send key event to IIIMSF\n");
923 break;
924 }
925 }
926
927 return 1;
928 }
929
930 static int switch_mode(ui_im_t *im) {
931 return 0;
932 }
933
934 static int is_active(ui_im_t *im) {
935 return 0;
936 }
937
938 static void focused(ui_im_t *im) {
939 im_iiimf_t *iiimf;
940 IIIMCF_event event;
941
942 #ifdef IM_IIIMF_DEBUG
943 bl_debug_printf(BL_DEBUG_TAG "\n");
944 #endif
945
946 iiimf = (im_iiimf_t*) im;
947
948 if (iiimf->aux) {
949 aux_set_focus(iiimf->aux);
950 }
951
952 if (iiimcf_create_seticfocus_event(&event) == IIIMF_STATUS_SUCCESS) {
953 if (iiimcf_forward_event(iiimf->context, event) == IIIMF_STATUS_SUCCESS) {
954 im_iiimf_process_event(iiimf);
955 }
956 }
957
958 if (iiimf->im.stat_screen) {
959 (*iiimf->im.stat_screen->show)(iiimf->im.stat_screen);
960 }
961
962 if (iiimf->im.cand_screen) {
963 (*iiimf->im.cand_screen->show)(iiimf->im.cand_screen);
964 }
965 }
966
967 static void unfocused(ui_im_t *im) {
968 im_iiimf_t *iiimf;
969 IIIMCF_event event;
970
971 #ifdef IM_IIIMF_DEBUG
972 bl_debug_printf(BL_DEBUG_TAG "\n");
973 #endif
974
975 iiimf = (im_iiimf_t*) im;
976
977 if (iiimf->aux) {
978 aux_unset_focus(iiimf->aux);
979 }
980
981 if (iiimcf_create_unseticfocus_event(&event) == IIIMF_STATUS_SUCCESS) {
982 if (iiimcf_forward_event(iiimf->context, event) == IIIMF_STATUS_SUCCESS) {
983 im_iiimf_process_event(iiimf);
984 }
985 }
986
987 if (iiimf->im.stat_screen) {
988 (*iiimf->im.stat_screen->hide)(iiimf->im.stat_screen);
989 }
990
991 if (iiimf->im.cand_screen) {
992 (*iiimf->im.cand_screen->hide)(iiimf->im.cand_screen);
993 }
994 }
995
996 static int create_handle(IIIMCF_attr attr) {
997 char *env;
998
999 if ((env = getenv("HTT_SERVER_ADDRESS"))) {
1000 if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_SERVER_ADDRESS, env)
1001 != IIIMF_STATUS_SUCCESS) {
1002 return 0;
1003 }
1004 }
1005
1006 if (iiimcf_create_handle(attr, &handle) != IIIMF_STATUS_SUCCESS) {
1007 const char *user;
1008
1009 if (env == NULL && (user = bl_get_user_name()) &&
1010 (env = alloca(12 + strlen(user) + 5 + 1))) {
1011 DIR *dir;
1012
1013 sprintf(env, "/tmp/.iiim-%s/", user);
1014 if ((dir = opendir(env))) {
1015 char *p = env + strlen(env);
1016 struct dirent *ent;
1017
1018 while ((ent = readdir(dir))) {
1019 if (!strchr(ent->d_name, '.') && strlen(ent->d_name) <= 5) {
1020 strcpy(p, ent->d_name);
1021 if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_SERVER_ADDRESS, env)
1022 == IIIMF_STATUS_SUCCESS &&
1023 iiimcf_create_handle(attr, &handle) == IIIMF_STATUS_SUCCESS) {
1024 return 1;
1025 }
1026 }
1027 }
1028 }
1029 }
1030
1031 return 0;
1032 }
1033
1034 return 1;
1035 }
1036
1037 /* --- global functions --- */
1038
1039 ui_im_t *im_iiimf_new(u_int64_t magic, vt_char_encoding_t term_encoding,
1040 ui_im_export_syms_t *export_syms,
1041 char *lang, /* <language id(rfc1766)>:<language engine> */
1042 u_int mod_ignore_mask) {
1043 im_iiimf_t *iiimf = NULL;
1044 IIIMCF_attr attr = NULL;
1045 IIIMCF_language language;
1046 IIIMCF_input_method language_engine;
1047
1048 if (magic != (u_int64_t) IM_API_COMPAT_CHECK_MAGIC) {
1049 bl_error_printf("Incompatible input method API.\n");
1050
1051 return NULL;
1052 }
1053
1054 if (!initialized) {
1055 char *env;
1056
1057 if (iiimcf_initialize(IIIMCF_ATTR_NULL) != IIIMF_STATUS_SUCCESS) {
1058 #ifdef DEBUG
1059 bl_warn_printf(BL_DEBUG_TAG " Could not initialize\n");
1060 #endif
1061 return NULL;
1062 }
1063
1064 initialized = 1;
1065
1066 if (iiimcf_create_attr(&attr) != IIIMF_STATUS_SUCCESS) {
1067 #ifdef DEBUG
1068 bl_warn_printf(BL_DEBUG_TAG " Could not create attribute\n");
1069 #endif
1070 goto error;
1071 }
1072
1073 if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_CLIENT_TYPE,
1074 "IIIMF plugin for mlterm") != IIIMF_STATUS_SUCCESS) {
1075 #ifdef DEBUG
1076 bl_warn_printf(BL_DEBUG_TAG " Could not append a string to the attribute\n");
1077 #endif
1078 goto error;
1079 }
1080
1081 #ifdef USE_XLIB
1082 if ((env = getenv("DISPLAY")) &&
1083 iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_CLIENT_X_DISPLAY_NAME, env)
1084 != IIIMF_STATUS_SUCCESS) {
1085 #ifdef DEBUG
1086 bl_warn_printf(BL_DEBUG_TAG " Could not append a string to the attribute\n");
1087 #endif
1088 }
1089 #endif
1090
1091 if (iiimcf_attr_put_string_value(attr, IIIMCF_ATTR_SERVER_SERVICE, "") !=
1092 IIIMF_STATUS_SUCCESS) {
1093 #ifdef DEBUG
1094 bl_warn_printf(BL_DEBUG_TAG " Could not append a server service to the attribute\n");
1095 #endif
1096 goto error;
1097 }
1098
1099 if (!create_handle(attr)) {
1100 bl_error_printf("Could not create handle for IIIMF. Try to setenv HTT_SERVER_ADDRESS.\n");
1101 goto error;
1102 }
1103
1104 iiimcf_destroy_attr(attr);
1105 attr = NULL;
1106
1107 /*
1108 * Note: The byte order is the same as client.
1109 * (see lib/iiimp/data/im-connect.c:iiimp_connect_new())
1110 */
1111 #ifdef WORDS_BIGENDIAN
1112 if (!(parser_utf16 = ef_utf16_parser_new()))
1113 #else
1114 if (!(parser_utf16 = ef_utf16le_parser_new()))
1115 #endif
1116 {
1117 goto error;
1118 }
1119
1120 if ((env = getenv("HTT_SHOW_STATUS_WINDOW"))) {
1121 if (*env == 't' || *env == 'T') {
1122 htt_show_status_window = 1;
1123 }
1124 }
1125
1126 if ((env = getenv("HTT_GENERATES_KANAKEY"))) {
1127 if (*env == 't' || *env == 'T') {
1128 htt_generates_kanakey = 1;
1129 }
1130 }
1131
1132 syms = export_syms;
1133 aux_init(handle, syms, parser_utf16);
1134
1135 show_iiimcf_version();
1136 }
1137
1138 language = find_language(lang);
1139 language_engine = find_language_engine(lang);
1140
1141 if (!(iiimf = malloc(sizeof(im_iiimf_t)))) {
1142 goto error;
1143 }
1144
1145 /*
1146 * set methods of ui_im_t
1147 */
1148 iiimf->im.destroy = destroy;
1149 iiimf->im.key_event = key_event;
1150 iiimf->im.switch_mode = switch_mode;
1151 iiimf->im.is_active = is_active;
1152 iiimf->im.focused = focused;
1153 iiimf->im.unfocused = unfocused;
1154
1155 iiimf->context = NULL;
1156 iiimf->parser_term = NULL;
1157 iiimf->conv = NULL;
1158 iiimf->aux = NULL;
1159 iiimf->on = 0;
1160
1161 if (!(iiimf->parser_term = (*syms->vt_char_encoding_parser_new)(term_encoding))) {
1162 goto error;
1163 }
1164
1165 if (!(iiimf->conv = (*syms->vt_char_encoding_conv_new)(term_encoding))) {
1166 goto error;
1167 }
1168
1169 if (iiimcf_create_attr(&attr) != IIIMF_STATUS_SUCCESS) {
1170 #ifdef DEBUG
1171 bl_warn_printf(BL_DEBUG_TAG " Could not create attribute\n");
1172 #endif
1173 goto error;
1174 }
1175
1176 if (language) {
1177 if (iiimcf_attr_put_ptr_value(attr, IIIMCF_ATTR_INPUT_LANGUAGE,
1178 language) != IIIMF_STATUS_SUCCESS) {
1179 #ifdef DEBUG
1180 bl_warn_printf(BL_DEBUG_TAG " Could not append value to the attribute\n");
1181 #endif
1182 }
1183 }
1184
1185 if (language_engine) {
1186 if (iiimcf_attr_put_ptr_value(attr, IIIMCF_ATTR_INPUT_METHOD,
1187 language_engine) != IIIMF_STATUS_SUCCESS) {
1188 #ifdef DEBUG
1189 bl_warn_printf(BL_DEBUG_TAG " Could not append value to the attribute\n");
1190 #endif
1191 }
1192 }
1193
1194 if (iiimcf_create_context(handle, attr, &iiimf->context) != IIIMF_STATUS_SUCCESS) {
1195 #ifdef DEBUG
1196 bl_warn_printf(BL_DEBUG_TAG " Could not create context\n");
1197 #endif
1198 goto error;
1199 }
1200
1201 iiimcf_destroy_attr(attr);
1202 attr = NULL;
1203
1204 ref_count++;
1205
1206 #ifdef IM_IIIMF_DEBUG
1207 bl_debug_printf(BL_DEBUG_TAG " New object was created. ref_count is %d.\n", ref_count);
1208 #endif
1209
1210 return (ui_im_t*) iiimf;
1211
1212 error:
1213 if (attr) {
1214 iiimcf_destroy_attr(attr);
1215 }
1216
1217 if (initialized && ref_count == 0) {
1218 if (handle) {
1219 iiimcf_destroy_handle(handle);
1220 }
1221
1222 handle = NULL;
1223
1224 if (parser_utf16) {
1225 (*parser_utf16->destroy)(parser_utf16);
1226 }
1227
1228 iiimcf_finalize();
1229
1230 aux_quit();
1231
1232 initialized = 0;
1233 }
1234
1235 if (iiimf) {
1236 if (iiimf->parser_term) {
1237 (*iiimf->parser_term->destroy)(iiimf->parser_term);
1238 }
1239
1240 if (iiimf->conv) {
1241 (*iiimf->conv->destroy)(iiimf->conv);
1242 }
1243
1244 free(iiimf);
1245 }
1246
1247 return NULL;
1248 }
1249
1250 int im_iiimf_process_event(im_iiimf_t *iiimf) {
1251 int ret = 0;
1252 IIIMCF_event received_event;
1253 IIIMCF_event_type type;
1254
1255 while (iiimcf_get_next_event(iiimf->context, &received_event) == IIIMF_STATUS_SUCCESS) {
1256 if (iiimcf_get_event_type(received_event, &type) != IIIMF_STATUS_SUCCESS) {
1257 ret = 1;
1258 continue;
1259 }
1260
1261 if (type == IIIMCF_EVENT_TYPE_KEYEVENT) {
1262 ret = 1;
1263 }
1264 dispatch(iiimf, received_event, type);
1265
1266 /*
1267 * IIICF library specification said:
1268 *
1269 * NOTICE: old version of libiiimcf had discarded any events
1270 * dispatched by iiimcf_dispatch_event. But in the new
1271 * version, you MUST call iiimcf_ignore_event to all events
1272 * that are obtained by iiimcf_get_next_event even though they
1273 * are dispatched by iiimcf_dispatch_event.
1274 *
1275 */
1276 if (iiimcf_dispatch_event(iiimf->context, received_event) != IIIMF_STATUS_SUCCESS) {
1277 #ifdef DEBUG
1278 bl_warn_printf(BL_DEBUG_TAG " Could not dispatch event\n");
1279 #endif
1280 }
1281
1282 if (iiimcf_ignore_event(received_event) != IIIMF_STATUS_SUCCESS) {
1283 #ifdef DEBUG
1284 bl_warn_printf(BL_DEBUG_TAG " Could not dispatch event\n");
1285 #endif
1286 }
1287 }
1288
1289 return ret;
1290 }
1291
1292 /* --- API for external tools --- */
1293
1294 im_info_t *im_iiimf_get_info(char *locale, char *encoding) {
1295 im_info_t *result = NULL;
1296 IIIMCF_input_method *input_methods;
1297 IIIMCF_language *langs;
1298 ef_conv_t *conv = NULL;
1299 int num_ims;
1300 int num_langs;
1301 int total = 0;
1302 int idx;
1303 int auto_idx = 0;
1304 int i;
1305 int j;
1306
1307 if (iiimcf_initialize(IIIMCF_ATTR_NULL) != IIIMF_STATUS_SUCCESS) {
1308 return NULL;
1309 }
1310
1311 if (iiimcf_create_handle(IIIMCF_ATTR_NULL, &handle) != IIIMF_STATUS_SUCCESS) {
1312 iiimcf_finalize();
1313 return NULL;
1314 }
1315
1316 if (iiimcf_get_supported_input_methods(handle, &num_ims,
1317 &input_methods) != IIIMF_STATUS_SUCCESS) {
1318 goto error;
1319 }
1320
1321 for (i = 0; i < num_ims; i++) {
1322 if (iiimcf_get_input_method_languages(input_methods[i], &num_langs,
1323 &langs) != IIIMF_STATUS_SUCCESS) {
1324 goto error;
1325 }
1326
1327 total += num_langs;
1328 }
1329
1330 /*
1331 * Note: The byte order is the same as client.
1332 * (see lib/iiimp/data/im-connect.c:iiimp_connect_new())
1333 */
1334 #ifdef WORDS_BIGENDIAN
1335 if (!(parser_utf16 = ef_utf16_parser_new()))
1336 #else
1337 if (!(parser_utf16 = ef_utf16le_parser_new()))
1338 #endif
1339 {
1340 goto error;
1341 }
1342
1343 if (!(conv = ef_iso8859_1_conv_new())) {
1344 goto error;
1345 }
1346
1347 if (!(result = malloc(sizeof(im_info_t)))) {
1348 goto error;
1349 }
1350
1351 result->id = strdup("iiimf");
1352 result->name = strdup("IIIMF");
1353 result->num_args = total + 1;
1354 result->args = NULL;
1355 result->readable_args = NULL;
1356
1357 if (!(result->args = calloc(result->num_args, sizeof(char*)))) {
1358 goto error;
1359 }
1360
1361 if (!(result->readable_args = calloc(result->num_args, sizeof(char*)))) {
1362 goto error;
1363 }
1364
1365 idx = 1;
1366
1367 for (i = 0; i < num_ims; i++) {
1368 const IIIMP_card16 *im_id;
1369 const IIIMP_card16 *im_hrn;
1370 const IIIMP_card16 *im_domain;
1371 u_char *im;
1372
1373 if (iiimcf_get_input_method_desc(input_methods[i], &im_id, &im_hrn,
1374 &im_domain) != IIIMF_STATUS_SUCCESS) {
1375 continue;
1376 }
1377
1378 if (iiimcf_get_input_method_languages(input_methods[i], &num_langs,
1379 &langs) != IIIMF_STATUS_SUCCESS) {
1380 continue;
1381 }
1382
1383 im_convert_encoding(parser_utf16, conv, (u_char*)im_id, &im, strlen_utf16(im_id) + 1);
1384
1385 for (j = 0; j < num_langs; j++) {
1386 const char *lang_id;
1387 size_t len;
1388
1389 iiimcf_get_language_id(langs[j], &lang_id);
1390
1391 if (strncmp(lang_id, locale, 2) == 0 && auto_idx == 0) {
1392 auto_idx = idx;
1393 }
1394
1395 len = strlen(im) + strlen(lang_id) + 4;
1396
1397 if ((result->args[idx] = malloc(len))) {
1398 bl_snprintf(result->args[idx], len, "%s:%s", lang_id, im);
1399 } else {
1400 result->args[idx] = strdup("error");
1401 }
1402
1403 if ((result->readable_args[idx] = malloc(len))) {
1404 bl_snprintf(result->readable_args[idx], len, "%s (%s)", lang_id, im);
1405 } else {
1406 result->readable_args[i] = strdup("error");
1407 }
1408
1409 idx ++;
1410 }
1411
1412 free(im);
1413 }
1414
1415 result->args[0] = strdup("");
1416 if (auto_idx) {
1417 result->readable_args[0] = strdup(result->readable_args[auto_idx]);
1418 } else {
1419 result->readable_args[0] = strdup("unknown");
1420 }
1421
1422 if (total != idx - 1) {
1423 free(result->id);
1424 free(result->name);
1425
1426 for (i = 0; i < idx - 1; i++) {
1427 free(result->args[i]);
1428 free(result->readable_args[i]);
1429 }
1430
1431 free(result->args);
1432 free(result->readable_args);
1433
1434 free(result);
1435
1436 result = NULL;
1437 }
1438
1439 iiimcf_destroy_handle(handle);
1440
1441 iiimcf_finalize();
1442
1443 return result;
1444
1445 error:
1446 if (parser_utf16) {
1447 (*parser_utf16->destroy)(parser_utf16);
1448 }
1449
1450 if (conv) {
1451 (*conv->destroy)(conv);
1452 }
1453
1454 if (handle) {
1455 iiimcf_destroy_handle(handle);
1456 }
1457
1458 iiimcf_finalize();
1459
1460 if (result) {
1461 if (result->args) {
1462 free(result->args);
1463 }
1464
1465 if (result->readable_args) {
1466 free(result->readable_args);
1467 }
1468
1469 free(result);
1470 }
1471
1472 return NULL;
1473 }
1474