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