1 /*
2
3 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 */
32
33 #ifdef HAVE_CONFIG_H
34 # include <config.h>
35 #endif
36
37 #define UIM_XIM_USE_JAPANESE_KANA_KEYBOARD_HACK 1
38
39 #include <cctype>
40 #include <clocale>
41 #include <cstdio>
42 #include <X11/Xlib.h>
43 #include <X11/Xatom.h>
44 #include <X11/Xutil.h>
45 #include <X11/XKBlib.h>
46
47 /* workaround for pre X11R6.7 */
48 #ifndef XK_KOREAN
49 #define XK_KOREAN
50 #endif
51 #ifndef XK_KATAKANA
52 #define XK_KATAKANA
53 #endif
54 #include <X11/keysymdef.h>
55
56 #include "xim.h"
57 #include "convdisp.h"
58 #include "canddisp.h"
59 #include "ximserver.h"
60 #include "util.h"
61 #include "helper.h"
62
63 #include "uim/uim-helper.h"
64 #include "uim/uim-im-switcher.h"
65 #include "uim/uim-scm.h"
66 #include "uim/uim-x-util.h"
67
68 #ifndef XK_dead_horn
69 #define XK_dead_horn 0xfe62
70 #endif
71
72 #ifndef __GNUC__
73 # ifdef HAVE_ALLOCA_H
74 # include <alloca.h>
75 # endif
76 #endif
77
78 extern int lib_uim_fd;
79 extern Atom xim_servers;
80 InputContext *InputContext::mFocusedContext = NULL;
81
82 static int check_modifier(std::list<KeySym> list);
83 static int gMod1Mask, gMod2Mask, gMod3Mask, gMod4Mask, gMod5Mask;
84 static int gXNumLockMask;
85
86 CandWinPosType XimServer::gCandWinPosType;
87 CandWinStyle XimServer::gCandWinStyle;
88 bool XimServer::gCandWinStyleUpdated;
89
print_ustring(uString * s)90 void print_ustring(uString *s)
91 {
92 uString::iterator i;
93 printf("length=%d : ", (int)s->size());
94 uchar ch;
95 char utf8[6];
96 int nbyte;
97 for (i = s->begin(); i != s->end(); ++i) {
98 ch = *i;
99 nbyte = utf8_wctomb((unsigned char *)utf8, ch);
100 utf8[nbyte] = '\0';
101 printf("%s", utf8);
102 }
103 printf("\n");
104 }
105
erase_ustring(uString * s)106 void erase_ustring(uString *s)
107 {
108 s->erase(s->begin(), s->end());
109 }
110
append_ustring(uString * d,uString * s)111 void append_ustring(uString *d, uString *s)
112 {
113 uString::iterator i;
114 for (i = s->begin(); i !=s->end(); ++i) {
115 d->push_back(*i);
116 }
117 }
118
XimServer(const char * name,const char * lang)119 XimServer::XimServer(const char *name, const char *lang)
120 {
121 mIMName = strdup(name);
122 mIMLang = lang;
123 }
124
createContext(XimIC * xic,const char * engine)125 InputContext *XimServer::createContext(XimIC *xic, const char *engine)
126 {
127 InputContext *ic = new InputContext(this, xic, engine);
128 ic_list.push_back(ic);
129 return ic;
130 }
131
deleteContext(InputContext * ic)132 void XimServer::deleteContext(InputContext *ic)
133 {
134 std::list<InputContext *>::iterator it;
135 for (it = ic_list.begin(); it != ic_list.end(); ++it) {
136 if (*it == ic) {
137 ic_list.erase(it);
138 break;
139 }
140 }
141 }
142
changeContext(const char * engine)143 void XimServer::changeContext(const char *engine) {
144 set_im(engine);
145 std::list<InputContext *>::iterator it;
146 for (it = ic_list.begin(); it != ic_list.end(); ++it) {
147 (*it)->changeContext(engine);
148 }
149 // make sure to use appropriate locale for the focused context
150 InputContext *focusedContext = InputContext::focusedContext();
151 if (focusedContext)
152 focusedContext->focusIn();
153 }
154
customContext(const char * custom,const char * val)155 void XimServer::customContext(const char *custom, const char *val) {
156 std::list<InputContext *>::iterator it;
157 for (it = ic_list.begin(); it != ic_list.end(); ++it) {
158 (*it)->customContext(custom, val);
159 break;
160 }
161
162 // Updated global IM of XimServer
163 if (!strcmp(custom, "custom-preserved-default-im-name") &&
164 uim_scm_symbol_value_bool("custom-activate-default-im-name?"))
165 set_im(++val);
166
167 #if HAVE_XFT_UTF8_STRING
168 if (!strcmp(custom, "uim-xim-xft-font-name"))
169 update_default_xftfont();
170 #endif
171
172 if (!strcmp(custom, "bridge-show-input-state?") &&
173 !uim_scm_symbol_value_bool("bridge-show-input-state?")) {
174 Canddisp *disp = canddisp_singleton();
175 disp->hide_caret_state();
176 }
177
178 if (!strcmp(custom, "candidate-window-position"))
179 check_candwin_pos_type();
180
181 if (!strcmp(custom, "candidate-window-style"))
182 check_candwin_style();
183 }
184
reloadConfigs()185 void XimServer::reloadConfigs() {
186 #if 1
187 uim_prop_reload_configs();
188 reload_uim(0);
189 #else
190 reload_uim(1);
191 #endif
192
193 // Updated global IM of XimServer
194 char *im = uim_scm_symbol_value_str("default-im-name");
195 if (im)
196 set_im(im);
197 free(im);
198
199 #if HAVE_XFT_UTF8_STRING
200 update_default_xftfont();
201 #endif
202
203 if (!uim_scm_symbol_value_bool("bridge-show-input-state?")) {
204 Canddisp *disp = canddisp_singleton();
205 disp->hide_caret_state();
206 }
207
208 check_candwin_style();
209 check_candwin_pos_type();
210 }
211
212 bool
setupConnection(bool useDefaultIM)213 XimServer::setupConnection(bool useDefaultIM)
214 {
215 const char *buf;
216 if (!useDefaultIM) {
217 return false;
218 } else {
219 buf = "@server=uim";
220 }
221 mServerAtom = XInternAtom(XimServer::gDpy, buf, 0);
222 Window owner = XGetSelectionOwner(XimServer::gDpy, mServerAtom);
223 if (owner != None) {
224 if (!useDefaultIM)
225 printf("Another instance exists (uim-%s).\n", mIMName);
226 else
227 printf("Another instance exists (uim).\n");
228 return false;
229 }
230 mSelectionWin = XCreateSimpleWindow(XimServer::gDpy,
231 DefaultRootWindow(XimServer::gDpy),
232 0, 0, 1, 1,
233 1, 0, 0);
234 XSetSelectionOwner(XimServer::gDpy, mServerAtom, mSelectionWin, CurrentTime);
235 XSelectInput(XimServer::gDpy, DefaultRootWindow(XimServer::gDpy), 0);
236 XSync(XimServer::gDpy, False);
237
238 Atom type;
239 int format;
240 unsigned long nr_prop, nr_bytes;
241 Atom *prop;
242 int mode = PropModePrepend;
243 int valuechange = 1;
244
245 XGetWindowProperty(XimServer::gDpy, DefaultRootWindow(XimServer::gDpy),
246 xim_servers, 0, 8192 ,False,
247 XA_ATOM, &type, &format,
248 &nr_prop, &nr_bytes, (unsigned char **)(uintptr_t)&prop);
249 int i;
250 if (type != XA_ATOM || format != 32)
251 mode = PropModeReplace;
252 else {
253 for (i = 0; i < (int)nr_prop; i++) {
254 if (prop[i] == mServerAtom) {
255 mode = PropModeAppend;
256 valuechange = 0;
257 break;
258 }
259 }
260 }
261 if (nr_prop)
262 XFree(prop);
263
264 XChangeProperty(XimServer::gDpy, DefaultRootWindow(XimServer::gDpy),
265 xim_servers,
266 XA_ATOM, 32,
267 mode, (unsigned char *)&mServerAtom,
268 valuechange ? 1 : 0);
269 std::pair<Window, XimServer *> p(mSelectionWin, this);
270 gServerMap.insert(p);
271 return true;
272 }
273
274 void
strToUstring(uString * d,const char * s)275 XimServer::strToUstring(uString *d, const char *s)
276 {
277 int len;
278 int l = 0, nbyte = 0;
279 uchar ch;
280
281 len = static_cast<int>(strlen(s));
282 while (l < len && *s != 0 &&
283 (nbyte = utf8_mbtowc(&ch, (const unsigned char *)s, len - l)) > 0) {
284 d->push_back(ch);
285 s += nbyte;
286 l += nbyte;
287 }
288 }
289
findServer(Window w)290 XimServer *XimServer::findServer(Window w)
291 {
292 std::map<Window, XimServer *>::iterator it;
293 it = gServerMap.find(w);
294 if (it == gServerMap.end())
295 return NULL;
296
297 return it->second;
298 }
299
getIMName()300 const char *XimServer::getIMName()
301 {
302 return mIMName;
303 }
304
getIMLang()305 const char *XimServer::getIMLang()
306 {
307 return mIMLang;
308 }
309
set_im(const char * engine)310 void XimServer::set_im(const char *engine)
311 {
312 free(mIMName);
313
314 mIMName = strdup(engine);
315 mIMLang = get_im_lang_from_engine(engine);
316 }
317
get_im_lang_from_engine(const char * engine)318 const char *get_im_lang_from_engine(const char *engine)
319 {
320 std::list<UIMInfo>::iterator it;
321 for (it = uim_info.begin(); it != uim_info.end(); ++it) {
322 if (!strcmp(it->name, engine))
323 return it->lang;
324 }
325 return "en"; // For safety...
326 }
327
328 //
329 // Methods for InputContext
InputContext(XimServer * svr,XimIC * ic,const char * engine)330 InputContext::InputContext(XimServer *svr, XimIC *ic, const char *engine)
331 {
332 mXic = ic;
333 m_pe = new pe_stat(this);
334 mConvdisp = NULL;
335 mServer = svr;
336 mEngineName = NULL;
337 mLocaleName = NULL;
338 mFocusedContext = this;
339 createUimContext(engine);
340 mCandwinActive = false;
341 #if UIM_XIM_USE_NEW_PAGE_HANDLING
342 mNumCandidates = 0;
343 #endif
344 mNumPage = 1;
345 mDisplayLimit = 0;
346 mCaretStateShown = false;
347 }
348
~InputContext()349 InputContext::~InputContext()
350 {
351 #if UIM_XIM_USE_DELAY
352 timer_cancel();
353 #endif
354 if (mFocusedContext == this)
355 mFocusedContext = NULL;
356
357 if (mConvdisp)
358 mConvdisp->set_pe(NULL);
359
360 delete m_pe;
361 uim_release_context(mUc);
362 mServer->deleteContext(this);
363 free(mEngineName);
364 free(mLocaleName);
365 }
366
367 void
createUimContext(const char * engine)368 InputContext::createUimContext(const char *engine)
369 {
370 char *locale;
371 const char *client_locale, *engine_locales;
372 const char *encoding;
373 const char *real_im;
374
375 encoding = mXic->get_encoding();
376 client_locale = mXic->get_lang_region();
377 engine_locales = compose_localenames_from_im_lang(get_im_lang_from_engine(engine));
378
379 if (!strcmp(encoding, "UTF-8")) {
380 real_im = engine;
381 if (is_locale_included(engine_locales, client_locale))
382 locale = strdup(client_locale);
383 else {
384 locale = get_prefered_locale(engine_locales);
385 }
386 } else {
387 // Use default engine for corresponding encoding of the client
388 // unless encoding matches with selected engine.
389 if (!is_locale_included(engine_locales, client_locale)) {
390 const char *test_im = uim_get_default_im_name(client_locale);
391 const char *test_im_lang = get_im_lang_from_engine(test_im);
392 const char *test_im_locales = compose_localenames_from_im_lang(test_im_lang);
393 if (is_locale_included(test_im_locales, client_locale))
394 real_im = test_im;
395 else
396 real_im = uim_get_im_name_for_locale(client_locale);
397
398 } else
399 real_im = engine;
400
401 locale = strdup(client_locale);
402 }
403
404 locale = (char *)realloc(locale, strlen(locale) + strlen(encoding) + 2);
405 strcat(locale, ".");
406 strcat(locale, encoding);
407
408 setlocale(LC_CTYPE, locale);
409
410 free(mLocaleName);
411 mLocaleName = locale;
412
413 if (mEngineName != real_im) {
414 free(mEngineName);
415 mEngineName = strdup(real_im);
416 }
417
418 uim_context uc = uim_create_context((void *) this, "UTF-8",
419 NULL, real_im, NULL,
420 InputContext::commit_cb);
421
422 if (uc) {
423 uim_set_preedit_cb(uc,
424 InputContext::clear_cb,
425 InputContext::pushback_cb,
426 InputContext::update_cb);
427 uim_set_candidate_selector_cb(uc,
428 InputContext::candidate_activate_cb,
429 InputContext::candidate_select_cb,
430 InputContext::candidate_shift_page_cb,
431 InputContext::candidate_deactivate_cb);
432 uim_set_prop_list_update_cb(uc,
433 InputContext::update_prop_list_cb);
434 #if 0
435 uim_set_prop_label_update_cb(uc,
436 InputContext::update_prop_label_cb);
437 #endif
438 uim_set_configuration_changed_cb(uc,
439 InputContext::configuration_changed_cb);
440 uim_set_im_switch_request_cb(uc,
441 InputContext::switch_app_global_im_cb,
442 InputContext::switch_system_global_im_cb);
443 #if UIM_XIM_USE_DELAY
444 uim_set_delay_candidate_selector_cb(uc,
445 InputContext::candidate_activate_with_delay_cb);
446 #endif
447
448 if (mFocusedContext == this)
449 uim_prop_list_update(uc);
450 }
451 mUc = uc;
452 }
453
454 void
changeContext(const char * engine)455 InputContext::changeContext(const char *engine)
456 {
457 const char *encoding, *im_lang;
458
459 if (!strcmp(mEngineName, engine))
460 return;
461
462 encoding = mXic->get_encoding();
463 im_lang = get_im_lang_from_engine(engine);
464
465 // Don't change im unless encoding matches for clients with legacy locales.
466 if (strcmp(encoding, "UTF-8")) {
467 const char *client_locale = mXic->get_lang_region();
468 const char *engine_locales = compose_localenames_from_im_lang(im_lang);
469
470 if (!is_locale_included(engine_locales, client_locale))
471 return;
472 }
473
474 clear();
475 uim_release_context(mUc);
476 createUimContext(engine); // mUc, mEngineName, and locale will be set here.
477 if (mConvdisp) {
478 mConvdisp->set_im_lang(get_im_lang_from_engine(mEngineName));
479 mConvdisp->set_locale_name(mLocaleName);
480 }
481 }
482
configuration_changed()483 void InputContext::configuration_changed()
484 {
485 const char *engine = uim_get_current_im_name(mUc);
486
487 review_im(engine);
488
489 InputContext *focusedContext = InputContext::focusedContext();
490 if (this == focusedContext)
491 send_im_list();
492 }
493
switch_app_global_im(const char * name)494 void InputContext::switch_app_global_im(const char *name)
495 {
496 get_im_by_id(this->get_ic()->get_imid())->changeContext(name);
497 }
498
switch_system_global_im(const char * name)499 void InputContext::switch_system_global_im(const char *name)
500 {
501 char *msg;
502 std::map<Window, XimServer *>::iterator it;
503
504 for (it = XimServer::gServerMap.begin(); it != XimServer::gServerMap.end(); ++it)
505 (*it).second->changeContext(name);
506
507 if (asprintf(&msg, "im_change_whole_desktop\n%s\n", name) == -1) {
508 free(msg);
509 return;
510 }
511 uim_helper_send_message(lib_uim_fd, msg);
512 free(msg);
513 }
514
review_im(const char * engine)515 void InputContext::review_im(const char *engine)
516 {
517 char *locale, *prev_engine;
518 const char *client_locale, *engine_locales;
519 const char *encoding;
520
521 prev_engine = mEngineName;
522 mEngineName = strdup(engine);
523 encoding = mXic->get_encoding();
524 client_locale = mXic->get_lang_region();
525 engine_locales = compose_localenames_from_im_lang(get_im_lang_from_engine(engine));
526
527 if (!strcmp(encoding, "UTF-8")) {
528 if (is_locale_included(engine_locales, client_locale))
529 locale = strdup(client_locale);
530 else
531 locale = get_prefered_locale(engine_locales);
532 locale = (char *)realloc(locale, strlen(locale) + strlen(".UTF-8") + 1);
533 strcat(locale, ".UTF-8");
534 setlocale(LC_CTYPE, locale);
535 free(mLocaleName);
536 mLocaleName = locale;
537 } else {
538 if (!is_locale_included(engine_locales, client_locale)) {
539 clear();
540 uim_switch_im(mUc, prev_engine);
541 free(mEngineName);
542 mEngineName = strdup(prev_engine);
543 }
544 }
545 free(prev_engine);
546 }
547
548 void
customContext(const char * custom,const char * val)549 InputContext::customContext(const char *custom, const char *val)
550 {
551 uim_prop_update_custom(mUc, custom, val);
552 }
553
554 InputContext *
focusedContext()555 InputContext::focusedContext()
556 {
557 return mFocusedContext;
558 }
559
560 void
deletefocusedContext()561 InputContext::deletefocusedContext()
562 {
563 mFocusedContext = NULL;
564 }
565
566 void
focusIn()567 InputContext::focusIn()
568 {
569 setlocale(LC_CTYPE, mLocaleName);
570
571 check_helper_connection();
572 uim_helper_client_focus_in(mUc);
573 mFocusedContext = this;
574 if (mConvdisp) {
575 mConvdisp->unset_focus();
576 mConvdisp->move_candwin();
577 mConvdisp->update_caret_state();
578 }
579 uim_prop_list_update(mUc);
580 uim_prop_label_update(mUc);
581 if (hasActiveCandwin())
582 candidate_update();
583 uim_focus_in_context(mUc);
584 }
585
586 void
focusOut()587 InputContext::focusOut()
588 {
589 uim_focus_out_context(mUc);
590 uim_helper_client_focus_out(mUc);
591 if (mFocusedContext == this) {
592 Canddisp *disp = canddisp_singleton();
593 if (isCaretStateShown())
594 disp->hide_caret_state();
595 if (hasActiveCandwin())
596 disp->hide();
597 }
598 }
599
600 XimServer *
getServer()601 InputContext::getServer()
602 {
603 return mServer;
604 }
605
606 uim_context
getUC()607 InputContext::getUC()
608 {
609 return mUc;
610 }
611
612 void
commit_cb(void * ptr,const char * str)613 InputContext::commit_cb(void *ptr, const char *str)
614 {
615 InputContext *ic = (InputContext *)ptr;
616 XimIC *xic = ic->get_ic();
617
618 ic->clear_pe_stat();
619 ic->update_preedit();
620 xic->commit_string(str);
621 }
622
clear_cb(void * ptr)623 void InputContext::clear_cb(void *ptr)
624 {
625 InputContext *ic = (InputContext *)ptr;
626 ic->clear_pe_stat();
627 }
628
pushback_cb(void * ptr,int attr,const char * str)629 void InputContext::pushback_cb(void *ptr, int attr, const char *str)
630 {
631 InputContext *ic = (InputContext *)ptr;
632 ic->pushback_preedit_string(attr, str);
633 }
634
update_cb(void * ptr)635 void InputContext::update_cb(void *ptr)
636 {
637 InputContext *ic = (InputContext *)ptr;
638 ic->update_preedit();
639 }
640
candidate_activate_cb(void * ptr,int nr,int display_limit)641 void InputContext::candidate_activate_cb(void *ptr, int nr, int display_limit)
642 {
643 InputContext *ic = (InputContext *)ptr;
644 ic->candidate_activate(nr, display_limit);
645 }
646
647 #if UIM_XIM_USE_DELAY
candidate_activate_with_delay_cb(void * ptr,int delay)648 void InputContext::candidate_activate_with_delay_cb(void *ptr, int delay)
649 {
650 InputContext *ic = (InputContext *)ptr;
651 ic->candidate_activate_with_delay(delay);
652 }
653
candidate_activate_timeout_cb(void * ptr)654 void InputContext::candidate_activate_timeout_cb(void *ptr)
655 {
656 InputContext *ic = (InputContext *)ptr;
657 ic->candidate_activate_timeout();
658 }
659 #endif
660
candidate_select_cb(void * ptr,int index)661 void InputContext::candidate_select_cb(void *ptr, int index)
662 {
663 InputContext *ic = (InputContext *)ptr;
664 ic->set_need_hilite_selected_cand(true);
665 ic->candidate_select(index);
666 }
667
candidate_shift_page_cb(void * ptr,int direction)668 void InputContext::candidate_shift_page_cb(void *ptr, int direction)
669 {
670 InputContext *ic = (InputContext *)ptr;
671 ic->candidate_shift_page(direction);
672 }
673
candidate_deactivate_cb(void * ptr)674 void InputContext::candidate_deactivate_cb(void *ptr)
675 {
676 InputContext *ic = (InputContext *)ptr;
677 ic->candidate_deactivate();
678 }
679
update_prop_list_cb(void * ptr,const char * str)680 void InputContext::update_prop_list_cb(void *ptr, const char *str)
681 {
682 InputContext *ic = (InputContext *)ptr;
683 InputContext *focusedContext = InputContext::focusedContext();
684 if (ic == focusedContext)
685 ic->update_prop_list(str);
686 }
687
update_prop_label_cb(void * ptr,const char * str)688 void InputContext::update_prop_label_cb(void *ptr, const char *str)
689 {
690 InputContext *ic = (InputContext *)ptr;
691 InputContext *focusedContext = InputContext::focusedContext();
692 if (ic == focusedContext)
693 ic->update_prop_label(str);
694 }
695
configuration_changed_cb(void * ptr)696 void InputContext::configuration_changed_cb(void *ptr)
697 {
698 InputContext *ic = (InputContext *)ptr;
699
700 ic->configuration_changed();
701 }
702
switch_app_global_im_cb(void * ptr,const char * name)703 void InputContext::switch_app_global_im_cb(void *ptr, const char *name)
704 {
705 InputContext *ic = (InputContext *)ptr;
706
707 ic->switch_app_global_im(name);
708 }
709
switch_system_global_im_cb(void * ptr,const char * name)710 void InputContext::switch_system_global_im_cb(void *ptr, const char *name)
711 {
712 InputContext *ic = (InputContext *)ptr;
713
714 ic->switch_system_global_im(name);
715 }
716
clear_pe_stat()717 void InputContext::clear_pe_stat()
718 {
719 m_pe->clear();
720 }
721
clear_preedit()722 void InputContext::clear_preedit()
723 {
724 clear_pe_stat();
725 if (mConvdisp)
726 mConvdisp->clear_preedit();
727 }
728
get_preedit_string()729 uString InputContext::get_preedit_string()
730 {
731 uString str;
732
733 if (mConvdisp)
734 str = mConvdisp->get_pe();
735 return str;
736 }
737
pushback_preedit_string(int attr,const char * str)738 void InputContext::pushback_preedit_string(int attr, const char *str)
739 {
740 if (str == NULL) {
741 fprintf(stderr, "Warning: str is NULL in pushback_cb\n");
742 return;
743 }
744 // Need to check caret pos at first.
745 if (attr & UPreeditAttr_Cursor)
746 m_pe->caret_pos = m_pe->get_char_count();
747 if (!strlen(str))
748 return;
749
750 int p = 0;
751 if (attr & UPreeditAttr_UnderLine)
752 p |= PE_UNDERLINE;
753 if (attr & UPreeditAttr_Reverse)
754 p |= PE_REVERSE;
755 m_pe->new_segment(p);
756 uString js;
757 mServer->strToUstring(&js, str);
758
759 uString::iterator it;
760 for (it = js.begin(); it != js.end(); ++it) {
761 m_pe->push_uchar(*it);
762 }
763 }
764
update_preedit()765 void InputContext::update_preedit()
766 {
767 if (mConvdisp)
768 mConvdisp->update_preedit();
769 }
770
pushKey(keyState * k)771 int InputContext::pushKey(keyState *k)
772 {
773 int key = k->key();
774 int rv = 1;
775
776 if (key != UKey_Other) {
777 if (k->is_push()) {
778 rv = uim_press_key(mUc, key, k->modifier());
779 if (!(g_option_mask & OPT_ON_DEMAND_SYNC)) {
780 // Call uim_release_key here since we don't filter key
781 // release event with full-synchronous-method for now.
782 uim_release_key(mUc, key, k->modifier());
783 }
784 }
785 else
786 rv = uim_release_key(mUc, key, k->modifier());
787 }
788
789 if (rv) {
790 if (k->check_compose())
791 return UPDATE_MODE;
792 else
793 return COMMIT_RAW;
794 } else {
795 return UPDATE_MODE;
796 }
797 }
798
hasActiveCandwin()799 bool InputContext::hasActiveCandwin()
800 {
801 return mCandwinActive;
802 }
803
804 // reset
clear()805 void InputContext::clear()
806 {
807 clear_preedit();
808 candidate_deactivate();
809 uim_reset_context(mUc);
810 }
811
setConvdisp(Convdisp * c)812 void InputContext::setConvdisp(Convdisp *c)
813 {
814 mConvdisp = c;
815 if (mConvdisp)
816 mConvdisp->set_pe(m_pe);
817 }
818
commit_string(char * s)819 void InputContext::commit_string(char *s)
820 {
821 mXic->commit_string(s);
822 }
823
extra_input(char * s)824 void InputContext::extra_input(char *s)
825 {
826 mXic->extra_input(s);
827 }
828
get_ic()829 XimIC *InputContext::get_ic()
830 {
831 return mXic;
832 }
833
candidate_activate(int nr,int display_limit)834 void InputContext::candidate_activate(int nr, int display_limit)
835 {
836 int i;
837 #if !UIM_XIM_USE_NEW_PAGE_HANDLING
838 const char *cand_str;
839 const char *heading_label;
840 const char *annotation_str;
841 char *str;
842 #else
843 std::vector<CandList>::iterator slot_it;
844 #endif
845 std::vector<const char *> candidates;
846 std::vector<const char *>::iterator it;
847
848 #if UIM_XIM_USE_DELAY
849 timer_cancel();
850 #endif
851 Canddisp *disp = canddisp_singleton();
852
853 mDisplayLimit = display_limit;
854 if (display_limit)
855 mNumPage = (nr - 1) / display_limit + 1;
856 #if !UIM_XIM_USE_NEW_PAGE_HANDLING
857 /* remove old data */
858 if (!active_candidates.empty()) {
859 for (it = active_candidates.begin();
860 it != active_candidates.end();
861 ++it)
862 free((char *)*it);
863 }
864 active_candidates.clear();
865 for (i = 0; i < nr; i++) {
866 uim_candidate cand;
867 cand = uim_get_candidate(mUc, i,
868 display_limit ? i % display_limit : i);
869 cand_str = uim_candidate_get_cand_str(cand);
870 heading_label = uim_candidate_get_heading_label(cand);
871 annotation_str = uim_candidate_get_annotation(cand);
872 if (cand_str && heading_label && annotation_str) {
873 str = (char *)malloc(strlen(cand_str) + strlen(heading_label) + strlen(annotation_str) + 3);
874 sprintf(str, "%s\a%s\a%s", heading_label, cand_str, annotation_str);
875 candidates.push_back((const char *)str);
876 }
877 else {
878 fprintf(stderr, "Warning: cand_str at %d is NULL\n", i);
879 candidates.push_back((const char *)strdup("\a\a"));
880 }
881 uim_candidate_free(cand);
882 }
883 disp->activate(candidates, display_limit);
884 active_candidates = candidates;
885 #else /* !UIM_XIM_USE_NEW_PAGE_HANDLING */
886 mNumCandidates = nr;
887 /* remove old data */
888 for (slot_it = mCandidateSlot.begin();
889 slot_it != mCandidateSlot.end();
890 ++slot_it) {
891 if (*slot_it != (CandList)0) {
892 for (it = (*slot_it).begin(); it != (*slot_it).end(); ++it)
893 free((char *)*it);
894 }
895 }
896 mCandidateSlot.clear();
897
898 /* setup dummy data */
899 for (i = 0; i < mNumPage; i++)
900 mCandidateSlot.push_back((CandList)0);
901
902 prepare_page_candidates(0);
903 disp->set_nr_candidates(nr, display_limit);
904 disp->set_page_candidates(0, mCandidateSlot[0]);
905 disp->show_page(0);
906 #endif /* !UIM_XIM_USE_NEW_PAGE_HANDLING */
907 mCandwinActive = true;
908
909 current_cand_selection = 0;
910 current_page = 0;
911 need_hilite_selected_cand = false;
912 }
913
914 #if UIM_XIM_USE_DELAY
candidate_activate_with_delay(int delay)915 void InputContext::candidate_activate_with_delay(int delay)
916 {
917 timer_cancel();
918 if (delay > 0) {
919 timer_set(delay, InputContext::candidate_activate_timeout_cb, this);
920 } else {
921 candidate_activate_timeout();
922 }
923 }
924
candidate_activate_timeout()925 void InputContext::candidate_activate_timeout()
926 {
927 int nr = -1, display_limit = -1, selected_index = -1;
928 uim_delay_activating(mUc, &nr, &display_limit, &selected_index);
929 if (nr > 0) {
930 candidate_activate(nr, display_limit);
931 if (selected_index >= 0) {
932 candidate_select(selected_index);
933 }
934 }
935 }
936 #endif
937
candidate_update()938 void InputContext::candidate_update()
939 {
940 Canddisp *disp = canddisp_singleton();
941
942 #if !UIM_XIM_USE_NEW_PAGE_HANDLING
943 disp->activate(active_candidates, mDisplayLimit);
944 #else
945 prepare_page_candidates(current_page);
946 disp->set_nr_candidates(mNumCandidates, mDisplayLimit);
947 disp->set_page_candidates(current_page, mCandidateSlot[current_page]);
948 disp->show_page(current_page);
949 #endif
950 disp->select(current_cand_selection, need_hilite_selected_cand);
951 disp->show();
952 }
953
954 #if UIM_XIM_USE_NEW_PAGE_HANDLING
prepare_page_candidates(int page)955 void InputContext::prepare_page_candidates(int page)
956 {
957 int i;
958 int page_nr, start;
959 const char *cand_str;
960 const char *heading_label;
961 const char *annotation_str;
962 char *str;
963 CandList candidates;
964
965 if (page < 0)
966 return;
967
968 if (mCandidateSlot[page] != (CandList)0)
969 return;
970
971 start = page * mDisplayLimit;
972 if (mDisplayLimit && (mNumCandidates - start) > mDisplayLimit)
973 page_nr = mDisplayLimit;
974 else
975 page_nr = mNumCandidates - start;
976
977 for (i = 0; i < page_nr; i++) {
978 uim_candidate cand;
979 cand = uim_get_candidate(mUc, (i + start),
980 mDisplayLimit ? (i + start) % mDisplayLimit :
981 (i + start));
982 cand_str = uim_candidate_get_cand_str(cand);
983 heading_label = uim_candidate_get_heading_label(cand);
984 annotation_str = uim_candidate_get_annotation_str(cand);
985 if (cand_str && heading_label && annotation_str) {
986 str = (char *)malloc(strlen(cand_str) + strlen(heading_label) + strlen(annotation_str) + 3);
987 sprintf(str, "%s\a%s\a%s", heading_label, cand_str, annotation_str);
988 candidates.push_back((const char *)str);
989 }
990 else {
991 fprintf(stderr, "Warning: cand_str at %d is NULL\n", i);
992 candidates.push_back((const char *)strdup("\a\a"));
993 }
994 uim_candidate_free(cand);
995 }
996
997 mCandidateSlot[page] = candidates;
998 }
999
prepare_page_candidates_by_index(int index)1000 int InputContext::prepare_page_candidates_by_index(int index)
1001 {
1002 int page;
1003
1004 page = mDisplayLimit ? index / mDisplayLimit : 0;
1005 prepare_page_candidates(page);
1006
1007 return page;
1008 }
1009 #endif
1010
candidate_select(int index)1011 void InputContext::candidate_select(int index)
1012 {
1013 Canddisp *disp = canddisp_singleton();
1014
1015 #if UIM_XIM_USE_NEW_PAGE_HANDLING
1016 int new_page = prepare_page_candidates_by_index(index);
1017
1018 if (new_page < 0)
1019 return; // shouldn't happen
1020
1021 if (current_page != new_page)
1022 disp->set_page_candidates(new_page, mCandidateSlot[new_page]);
1023 #endif
1024 disp->select(index, need_hilite_selected_cand);
1025 current_cand_selection = index;
1026 if (mDisplayLimit)
1027 current_page = current_cand_selection / mDisplayLimit;
1028 }
1029
candidate_shift_page(int direction)1030 void InputContext::candidate_shift_page(int direction)
1031 {
1032 int new_page;
1033 int new_index;
1034
1035 if (mDisplayLimit) {
1036 if (direction)
1037 new_page = current_page + 1;
1038 else
1039 new_page = current_page - 1;
1040
1041 if (new_page < 0)
1042 current_page = mNumPage - 1;
1043 else if (new_page >= mNumPage)
1044 current_page = 0;
1045 else
1046 current_page = new_page;
1047
1048 new_index = (current_page * mDisplayLimit) + (current_cand_selection % mDisplayLimit);
1049
1050 #if !UIM_XIM_USE_NEW_PAGE_HANDLING
1051 if (new_index >= active_candidates.size())
1052 current_cand_selection = active_candidates.size() - 1;
1053 #else
1054 if (new_index >= mNumCandidates)
1055 current_cand_selection = mNumCandidates - 1;
1056 #endif
1057 else
1058 current_cand_selection = new_index;
1059 #if UIM_XIM_USE_NEW_PAGE_HANDLING
1060 Canddisp *disp = canddisp_singleton();
1061 prepare_page_candidates(current_page);
1062 disp->set_page_candidates(current_page, mCandidateSlot[current_page]);
1063 #endif
1064 }
1065 candidate_select(current_cand_selection);
1066 if (need_hilite_selected_cand)
1067 uim_set_candidate_index(mUc, current_cand_selection);
1068 }
1069
candidate_deactivate()1070 void InputContext::candidate_deactivate()
1071 {
1072 #if UIM_XIM_USE_DELAY
1073 timer_cancel();
1074 #endif
1075 if (mCandwinActive) {
1076 std::vector<const char *>::iterator i;
1077 Canddisp *disp = canddisp_singleton();
1078
1079 disp->deactivate();
1080 #if !UIM_XIM_USE_NEW_PAGE_HANDLING
1081 for (i = active_candidates.begin(); i != active_candidates.end(); ++i) {
1082 free((char *)*i);
1083 }
1084 active_candidates.clear();
1085 #else
1086 int j;
1087 for (j = 0; j < mNumPage; j++) {
1088 if ((CandList)mCandidateSlot[j] != (CandList)0) {
1089 for (i = mCandidateSlot[j].begin();
1090 i != mCandidateSlot[j].end();
1091 ++i) {
1092 free((char *)*i);
1093 }
1094 }
1095 }
1096 mCandidateSlot.clear();
1097 #endif
1098 mCandwinActive = false;
1099 current_cand_selection = 0;
1100 }
1101 }
1102
set_need_hilite_selected_cand(bool set)1103 void InputContext::set_need_hilite_selected_cand(bool set)
1104 {
1105 need_hilite_selected_cand = set;
1106 }
1107
get_caret_state_label_from_prop_list(const char * str)1108 char *InputContext::get_caret_state_label_from_prop_list(const char *str)
1109 {
1110 const char *p, *q;
1111 char *state_label = NULL;
1112 char label[10];
1113 int len, state_label_len = 0;
1114
1115 p = str;
1116 while ((p = strstr(p, "branch\t"))) {
1117 p = strchr(p + 7, '\t');
1118 if (p) {
1119 p++;
1120 q = strchr(p, '\t');
1121 len = static_cast<int>(q - p);
1122 if (q && len < 10) {
1123 strlcpy(label, p, len + 1);
1124 if (!state_label) {
1125 state_label_len = len;
1126 state_label = strdup(label);
1127 } else {
1128 state_label_len += (len + 1);
1129 state_label = (char *)realloc(state_label,
1130 state_label_len + 1);
1131 if (state_label) {
1132 strcat(state_label, "\t");
1133 strcat(state_label, label);
1134 state_label[state_label_len] = '\0';
1135 }
1136 }
1137 }
1138 }
1139 }
1140
1141 return state_label;
1142 }
1143
update_prop_list(const char * str)1144 void InputContext::update_prop_list(const char *str)
1145 {
1146 char *buf;
1147
1148 if (asprintf(&buf, "prop_list_update\ncharset=UTF-8\n%s", str) == -1) {
1149 free(buf);
1150 return;
1151 }
1152 uim_helper_send_message(lib_uim_fd, buf);
1153 free(buf);
1154
1155 #if 1
1156 // Show caret state indicator with this function instead of
1157 // InputContext::update_prop_label() to workaround the label
1158 // mismatch during IM switch caused from context-update-widgets.
1159 uim_bool show_caret_state =
1160 uim_scm_symbol_value_bool("bridge-show-input-state?");
1161 char *show_caret_with =
1162 uim_scm_c_symbol(uim_scm_symbol_value("bridge-show-with?"));
1163 uim_bool show_caret_mode = (strcmp(show_caret_with, "mode") == 0);
1164 uim_bool show_caret_mode_on = uim_scm_symbol_value_bool("bridge-show-input-state-mode-on?");
1165
1166 if (show_caret_state == UIM_TRUE && !(show_caret_mode && !show_caret_mode_on)) {
1167 char *label;
1168 int timeout;
1169 Canddisp *disp = canddisp_singleton();
1170
1171 if (strcmp(show_caret_with, "time") == 0)
1172 timeout = static_cast<int>(uim_scm_symbol_value_int(
1173 "bridge-show-input-state-time-length"));
1174 else
1175 timeout = 0;
1176
1177 label = get_caret_state_label_from_prop_list(str);
1178 disp->show_caret_state(label, timeout);
1179 free(label);
1180 mCaretStateShown = true;
1181 } else if (show_caret_mode && !show_caret_mode_on) {
1182 Canddisp *disp = canddisp_singleton();
1183 disp->hide_caret_state();
1184 }
1185 free(show_caret_with);
1186 #endif
1187 }
1188
update_prop_label(const char * str)1189 void InputContext::update_prop_label(const char *str)
1190 {
1191 char *buf;
1192
1193 if (asprintf(&buf, "prop_label_update\ncharset=UTF-8\n%s", str) == -1) {
1194 free(buf);
1195 return;
1196 }
1197 uim_helper_send_message(lib_uim_fd, buf);
1198 free(buf);
1199 #if 0
1200 uim_bool show_caret_state = uim_scm_symbol_value_bool("bridge-show-input-state?");
1201 if (show_caret_state == UIM_TRUE) {
1202 int timeout = uim_scm_symbol_value_int("bridge-show-input-state-time-length");
1203 Canddisp *disp = canddisp_singleton();
1204 disp->show_caret_state(str, timeout);
1205 mCaretStateShown = true;
1206 }
1207 #endif
1208 }
1209
get_engine_name()1210 const char *InputContext::get_engine_name()
1211 {
1212 return mEngineName;
1213 }
1214
get_locale_name()1215 const char *InputContext::get_locale_name()
1216 {
1217 return mLocaleName;
1218 }
1219
isCaretStateShown()1220 bool InputContext::isCaretStateShown()
1221 {
1222 return mCaretStateShown;
1223 }
1224
keyState(XimIC * ic)1225 keyState::keyState(XimIC *ic)
1226 {
1227 XimIM *im;
1228 DefTree *top;
1229
1230 mModState = 0;
1231 mIc = ic;
1232
1233 im = get_im_by_id(mIc->get_imid());
1234 top = im->get_compose_tree();
1235
1236 mCompose = new Compose(top, mIc);
1237 }
1238
~keyState()1239 keyState::~keyState()
1240 {
1241 delete mCompose;
1242 }
1243
check_key(keyEventX * x)1244 void keyState::check_key(keyEventX *x)
1245 {
1246 mModifier = 0;
1247 mXKeySym = x->key_sym;
1248 mXKeyState = x->state;
1249
1250 mPreModState = mModState;
1251
1252 if (x->press) {
1253 m_bPush = true;
1254
1255 if (!(x->state) || x->state == LockMask || x->state == gXNumLockMask)
1256 mModState = mPreModState = 0;
1257
1258 mPreModState = mModState;
1259 switch (x->key_sym) {
1260 case XK_Alt_L:
1261 case XK_Alt_R:
1262 mModState |= UMod_Alt;
1263 break;
1264 case XK_Meta_L:
1265 case XK_Meta_R:
1266 mModState |= UMod_Meta;
1267 break;
1268 case XK_Super_L:
1269 case XK_Super_R:
1270 mModState |= UMod_Super;
1271 break;
1272 case XK_Hyper_L:
1273 case XK_Hyper_R:
1274 mModState |= UMod_Hyper;
1275 break;
1276 default:
1277 break;
1278 }
1279 } else {
1280 m_bPush = false;
1281
1282 switch (x->key_sym) {
1283 case XK_Alt_L:
1284 case XK_Alt_R:
1285 mModState &= ~UMod_Alt;
1286 break;
1287 case XK_Meta_L:
1288 case XK_Meta_R:
1289 mModState &= ~UMod_Meta;
1290 break;
1291 case XK_Super_L:
1292 case XK_Super_R:
1293 mModState &= ~UMod_Super;
1294 break;
1295 case XK_Hyper_L:
1296 case XK_Hyper_R:
1297 mModState &= ~UMod_Hyper;
1298 break;
1299 default:
1300 break;
1301 }
1302 }
1303
1304 if (x->state & ShiftMask)
1305 mModifier |= UMod_Shift;
1306 if (x->state & ControlMask)
1307 mModifier |= UMod_Control;
1308 if (x->state & Mod1Mask)
1309 mModifier |= (gMod1Mask & mPreModState);
1310 if (x->state & Mod2Mask)
1311 mModifier |= (gMod2Mask & mPreModState);
1312 if (x->state & Mod3Mask)
1313 mModifier |= (gMod3Mask & mPreModState);
1314 if (x->state & Mod4Mask)
1315 mModifier |= (gMod4Mask & mPreModState);
1316 if (x->state & Mod5Mask)
1317 mModifier |= (gMod5Mask & mPreModState);
1318
1319 mKey = uim_x_keysym2ukey(x->key_sym);
1320
1321 #if UIM_XIM_USE_JAPANESE_KANA_KEYBOARD_HACK
1322 mKey = uim_x_kana_input_hack_translate_key(mKey,
1323 (KeyCode)x->ev.xkey.keycode);
1324 #endif
1325 }
1326
check_compose()1327 bool keyState::check_compose()
1328 {
1329 return mCompose->handleKey(mXKeySym, mXKeyState, m_bPush);
1330 }
1331
key()1332 int keyState::key()
1333 {
1334 return mKey;
1335 }
1336
modifier()1337 int keyState::modifier()
1338 {
1339 return mModifier;
1340 }
1341
is_push()1342 bool keyState::is_push()
1343 {
1344 return m_bPush;
1345 }
1346
xkeysym()1347 KeySym keyState::xkeysym()
1348 {
1349 return mXKeySym;
1350 }
1351
xkeystate()1352 int keyState::xkeystate()
1353 {
1354 return mXKeyState;
1355 }
1356
reset()1357 void keyState::reset()
1358 {
1359 mModState = 0;
1360 mCompose->reset();
1361 }
1362
print()1363 void keyState::print()
1364 {
1365 printf("key code=%x,modifier=%d.\n",
1366 mKey, mModifier);
1367 }
1368
check_modifier(std::list<KeySym> keysym_list)1369 static int check_modifier(std::list<KeySym> keysym_list)
1370 {
1371 int ret = 0;
1372 std::list<KeySym>::iterator i;
1373 for (i = keysym_list.begin(); i != keysym_list.end(); ++i) {
1374 switch (*i) {
1375 case XK_Alt_L:
1376 case XK_Alt_R:
1377 ret |= UMod_Alt;
1378 break;
1379 case XK_Meta_L:
1380 case XK_Meta_R:
1381 ret |= UMod_Meta;
1382 break;
1383 case XK_Super_L:
1384 case XK_Super_R:
1385 ret |= UMod_Super;
1386 break;
1387 case XK_Hyper_L:
1388 case XK_Hyper_R:
1389 ret |= UMod_Hyper;
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395 return ret;
1396 }
1397
init_modifier_keys()1398 void init_modifier_keys() {
1399 int i, k = 0;
1400 int min_keycode, max_keycode, keysyms_per_keycode = 0;
1401
1402 std::list<KeySym> Mod1MaskSyms, Mod2MaskSyms, Mod3MaskSyms,
1403 Mod4MaskSyms, Mod5MaskSyms;
1404
1405 gXNumLockMask = 0;
1406 XModifierKeymap *map = XGetModifierMapping(XimServer::gDpy);
1407 XDisplayKeycodes(XimServer::gDpy, &min_keycode, &max_keycode);
1408 KeySym *sym = XGetKeyboardMapping(XimServer::gDpy,
1409 static_cast<KeyCode>(min_keycode),
1410 (max_keycode - min_keycode + 1), &keysyms_per_keycode);
1411 for (i = 0; i < 8; i++) {
1412 int j;
1413 for (j = 0; j < map->max_keypermod; j++) {
1414 if (map->modifiermap[k]) {
1415 KeySym ks;
1416 int index = 0;
1417 do {
1418 ks = XkbKeycodeToKeysym(XimServer::gDpy,
1419 map->modifiermap[k], 0, index);
1420 index++;
1421 } while (!ks && index < keysyms_per_keycode);
1422
1423 switch (i) {
1424 case ShiftMapIndex: break;
1425 case LockMapIndex: break;
1426 case ControlMapIndex: break;
1427 case Mod1MapIndex: Mod1MaskSyms.push_back(ks); break;
1428 case Mod2MapIndex: Mod2MaskSyms.push_back(ks); break;
1429 case Mod3MapIndex: Mod3MaskSyms.push_back(ks); break;
1430 case Mod4MapIndex: Mod4MaskSyms.push_back(ks); break;
1431 case Mod5MapIndex: Mod5MaskSyms.push_back(ks); break;
1432 default: break;
1433 }
1434 // Check NumLock key
1435 if (ks == XK_Num_Lock)
1436 gXNumLockMask |= (1 << i);
1437 }
1438 k++;
1439 }
1440 }
1441 XFreeModifiermap(map);
1442 XFree(sym);
1443
1444 gMod1Mask = check_modifier(Mod1MaskSyms);
1445 gMod2Mask = check_modifier(Mod2MaskSyms);
1446 gMod3Mask = check_modifier(Mod3MaskSyms);
1447 gMod4Mask = check_modifier(Mod4MaskSyms);
1448 gMod5Mask = check_modifier(Mod5MaskSyms);
1449
1450 if (uim_scm_c_bool(uim_scm_callf("require-dynlib", "s", "xkb")))
1451 uim_scm_callf("%xkb-set-display", "p", XimServer::gDpy);
1452
1453 #if UIM_XIM_USE_JAPANESE_KANA_KEYBOARD_HACK
1454 // Init at here to sync with proper update timing although not a modifier.
1455 uim_x_kana_input_hack_init(XimServer::gDpy);
1456 #endif
1457 }
1458
1459 void
check_candwin_style()1460 check_candwin_style()
1461 {
1462 char *style = uim_scm_symbol_value_str("candidate-window-style");
1463 CandWinStyle PrevStyle = XimServer::gCandWinStyle;
1464
1465 if (style && !strcmp(style, "table"))
1466 XimServer::gCandWinStyle = Table;
1467 else if (style && !strcmp(style, "horizontal"))
1468 XimServer::gCandWinStyle = Horizontal;
1469 else
1470 XimServer::gCandWinStyle = Vertical;
1471
1472 XimServer::gCandWinStyleUpdated =
1473 (PrevStyle != XimServer::gCandWinStyle) ? true : false;
1474 free(style);
1475 }
1476
1477 void
check_candwin_pos_type()1478 check_candwin_pos_type()
1479 {
1480 char *candwin_pos_type = uim_scm_symbol_value_str("candidate-window-position");
1481
1482 if (candwin_pos_type && !strcmp(candwin_pos_type, "left"))
1483 XimServer::gCandWinPosType = Left;
1484 else if (candwin_pos_type && !strcmp(candwin_pos_type, "right"))
1485 XimServer::gCandWinPosType = Right;
1486 else
1487 XimServer::gCandWinPosType = Caret;
1488
1489 free(candwin_pos_type);
1490 }
1491
1492 /*
1493 * Local variables:
1494 * c-indent-level: 4
1495 * c-basic-offset: 4
1496 * End:
1497 */
1498