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 // Handle IM procedure defined in XIM protocol
34
35 #ifdef HAVE_CONFIG_H
36 # include <config.h>
37 #endif
38
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <map>
43
44 #include "xim.h"
45 #include <X11/Xutil.h>
46 #define NEED_EVENTS // for declaration of xEvent
47 #include <X11/Xproto.h>
48
49 #ifdef HAVE_ALLOCA_H
50 # include <alloca.h>
51 #endif
52
53 static std::map<C16, XimIM *> g_ims;
54
55 // tables
56 static input_style input_style_tab_with_over_the_spot[] = {
57 {XIMPreeditNothing|XIMStatusNothing, IS_ROOT_WINDOW},
58 //{XIMPreeditPosition|XIMStatusArea, IS_OVER_THE_SPOT},// emacs
59 {XIMPreeditPosition|XIMStatusNothing, IS_OVER_THE_SPOT},
60 //{XIMPreeditCallbacks|XIMStatusCallbacks, IS_ON_THE_SPOT},// OOo
61 //{XIMPreeditArea|XIMStatusArea, IS_ROOT_WINDOW},
62 {XIMPreeditCallbacks|XIMStatusNothing, IS_ON_THE_SPOT},
63 {0, 0},
64 };
65 static input_style input_style_tab_without_over_the_spot[] = {
66 {XIMPreeditNothing|XIMStatusNothing, IS_ROOT_WINDOW},
67 //{XIMPreeditPosition|XIMStatusArea, IS_OVER_THE_SPOT},// emacs
68 //{XIMPreeditPosition|XIMStatusNothing, IS_OVER_THE_SPOT},
69 //{XIMPreeditCallbacks|XIMStatusCallbacks, IS_ON_THE_SPOT},// OOo
70 //{XIMPreeditArea|XIMStatusArea, IS_ROOT_WINDOW},
71 {XIMPreeditCallbacks|XIMStatusNothing, IS_ON_THE_SPOT},
72 {0, 0},
73 };
74 // XIMPreeditArea,XIMPreeditCallbacks,XIMPreeditPosition
75 // XIMPreeditNothing,XIMPreeditNone
76 // XIMStatusArea,XIMStatusCallbacks
77 // XIMStatusNothing,XIMStatusNone
78
79
80 class XimIM_impl : public XimIM {
81 public:
82 XimIM_impl(Connection *c, C16 id);
83 virtual ~XimIM_impl();
84 virtual void create_ic(RxPacket *);
85 virtual void destroy_ic(C16);
86 virtual void set_ic_focus(C16 icid);
87 virtual void set_ic_values(RxPacket *);
88 virtual void get_ic_values(RxPacket *);
89 virtual void unset_ic_focus(C16 icid);
90 virtual void forward_event(RxPacket *);
91 virtual void send_sync_reply(C16 icid);
92 virtual void send_sync(C16 icid);
93 virtual XimIC *get_ic_by_id(C16 id);
94 virtual void onSendPacket();
95 virtual void changeContext(const char *);
96
97 private:
98 C16 unused_ic_id();
99 void free_all_ic();
100 void delete_ic(XimIC *);
101 char *mEngineName;
102 std::map<C16, XimIC *> m_ics;
103 };
104
XimIM_impl(Connection * c,C16 id)105 XimIM_impl::XimIM_impl(Connection *c, C16 id) : XimIM(c, id)
106 {
107 mEngineName = strdup(mConn->getXimServer()->getIMName());
108 }
109
~XimIM_impl()110 XimIM_impl::~XimIM_impl()
111 {
112 free_all_ic();
113 free(mEngineName);
114 }
115
create_ic(RxPacket * p)116 void XimIM_impl::create_ic(RxPacket *p)
117 {
118 XimIC *ic;
119 C16 icid= unused_ic_id();
120
121 // create compose table with the first ic
122 if (icid == 1)
123 create_compose_tree();
124
125 ic = ::create_ic(mConn, p, mID, icid, mEngineName);
126 if (!ic) {
127 mConn->push_error_packet(mID, icid,
128 ERR_Style, "invalid im style");
129 return;
130 }
131 std::pair<C16, XimIC *> n(ic->get_icid(), ic);
132 m_ics.insert(n);
133
134 TxPacket *t;
135 t = createTxPacket(XIM_CREATE_IC_REPLY, 0);
136 t->pushC16(mID);
137 t->pushC16(ic->get_icid());
138 mConn->push_packet(t);
139 }
140
destroy_ic(C16 icid)141 void XimIM_impl::destroy_ic(C16 icid)
142 {
143 TxPacket *t;
144 t = createTxPacket(XIM_DESTROY_IC_REPLY, 0);
145 t->pushC16(mID);
146 t->pushC16(icid);
147 mConn->push_packet(t);
148 // destruct IC
149 XimIC *ic;
150 ic = get_ic_by_id(icid);
151 delete_ic(ic);
152 }
153
changeContext(const char * engine)154 void XimIM_impl::changeContext(const char *engine)
155 {
156 std::map<C16, XimIC *>::iterator i;
157 for (i = m_ics.begin(); i != m_ics.end(); ++i) {
158 (*i).second->changeContext(engine);
159 }
160 free(mEngineName);
161 mEngineName = strdup(engine);
162 }
163
set_ic_values(RxPacket * p)164 void XimIM_impl::set_ic_values(RxPacket *p)
165 {
166 C16 imid, icid;
167 XimIC *ic;
168 p->rewind();
169 imid = p->getC16();
170 icid = p->getC16();
171 ic = get_ic_by_id(icid);
172
173 int atr_len;
174 atr_len = p->getC16();
175 p->getC16();
176
177 unsigned char *v;
178 v = (unsigned char *)alloca(atr_len);
179
180 int i;
181 for (i = 0; i < atr_len; i++) {
182 v[i] = p->getC8();
183 }
184
185 ic->setICAttrs((void *)v, atr_len);
186
187 TxPacket *t = createTxPacket(XIM_SET_IC_VALUES_REPLY, 0);
188 t->pushC16(imid);
189 t->pushC16(icid);
190 mConn->push_packet(t);
191 }
192
get_ic_values(RxPacket * p)193 void XimIM_impl::get_ic_values(RxPacket *p)
194 {
195 C16 icid;
196 XimIC *ic;
197 p->rewind();
198 p->getC16();
199 icid = p->getC16();
200 ic = get_ic_by_id(icid);
201
202 int len;
203 len = p->getC16();
204
205 TxPacket *t = createTxPacket(XIM_GET_IC_VALUES_REPLY, 0);
206 t->pushC16(mID);
207 t->pushC16(icid);
208 int i, l;
209 C16 id;
210 l = 0;
211 for (i = 0; i < len / 2; i++) {
212 id = p->getC16();
213 l += ic->get_ic_atr(id, 0);
214 l += 4;
215 }
216 t->pushC16((C16)l);
217 t->pushC16(0);
218
219 p->rewind();
220 p->getC16(); // imid
221 p->getC16(); // icid
222 p->getC16(); // n
223
224 for (i = 0; i < len / 2; i++) {
225 id = p->getC16();
226 t->pushC16(id);
227 t->pushC16(ic->get_ic_atr(id, 0));
228 l += ic->get_ic_atr(id, t);
229 }
230 mConn->push_packet(t);
231 }
232
unused_ic_id()233 C16 XimIM_impl::unused_ic_id()
234 {
235 std::map<C16, XimIC *>::iterator i;
236 C16 max_id = 1; // Does ID of input-context start with 1?
237 for (i = m_ics.begin(); i != m_ics.end(); ++i) {
238 if (max_id <= (*i).first)
239 max_id = (C16)((*i).first + 1);
240 }
241 return max_id;
242 }
243
set_ic_focus(C16 icid)244 void XimIM_impl::set_ic_focus(C16 icid)
245 {
246 XimIC *ic = get_ic_by_id(icid);
247 if (ic)
248 ic->setFocus();
249 }
250
unset_ic_focus(C16 icid)251 void XimIM_impl::unset_ic_focus(C16 icid)
252 {
253 XimIC *ic = get_ic_by_id(icid);
254 if (ic)
255 ic->unsetFocus();
256 }
257
get_ic_by_id(C16 icid)258 XimIC *XimIM_impl::get_ic_by_id(C16 icid)
259 {
260 std::map<C16, XimIC *>::iterator it;
261 it = m_ics.find(icid);
262 if (it == m_ics.end())
263 return 0;
264
265 return it->second;
266 }
267
forward_event(RxPacket * p)268 void XimIM_impl::forward_event(RxPacket *p)
269 {
270 unsigned char *c;
271 int i;
272 keyEventX k;
273 xEvent ev_raw;
274
275 C16 imid, icid;
276 int flag;
277
278 XimIC *ic;
279 imid = p->getC16();
280 icid = p->getC16();
281 flag = p->getC16();
282 ic = get_ic_by_id(icid);
283 k.serial = p->getC16();
284
285 // keep copy of the xEvent
286 c = (unsigned char *)&ev_raw;
287 for (i = 0; i < (int)sizeof(ev_raw); i++) {
288 *c = p->getC8();
289 c++;
290 }
291
292 k.ev.type = ev_raw.u.u.type & 0x7f;
293 k.ev.xany.serial = (k.serial << 16) | mConn->to_hs(ev_raw.u.u.sequenceNumber);
294 k.ev.xany.display = XimServer::gDpy;
295 k.ev.xany.send_event = ev_raw.u.u.type > 127;
296
297 switch (k.ev.type) {
298 case KeyPress:
299 case KeyRelease:
300 k.ev.xkey.window =
301 mConn->to_hl(ev_raw.u.keyButtonPointer.event);
302 k.ev.xkey.root =
303 mConn->to_hl(ev_raw.u.keyButtonPointer.root);
304 k.ev.xkey.subwindow =
305 mConn->to_hl(ev_raw.u.keyButtonPointer.child);
306 k.ev.xkey.time =
307 mConn->to_hl(ev_raw.u.keyButtonPointer.time);
308 k.ev.xkey.x =
309 mConn->to_hs(ev_raw.u.keyButtonPointer.eventX);
310 k.ev.xkey.y =
311 mConn->to_hs(ev_raw.u.keyButtonPointer.eventY);
312 k.ev.xkey.x_root =
313 mConn->to_hs(ev_raw.u.keyButtonPointer.rootX);
314 k.ev.xkey.y_root =
315 mConn->to_hs(ev_raw.u.keyButtonPointer.rootY);
316 k.ev.xkey.state = mConn->to_hs(ev_raw.u.keyButtonPointer.state);
317 k.ev.xkey.keycode = ev_raw.u.u.detail;
318 k.ev.xkey.same_screen = ev_raw.u.keyButtonPointer.sameScreen;
319 char buf[10];
320 KeySym ks;
321 XLookupString(&k.ev.xkey, buf, 10, &ks, 0);
322 k.state = mConn->to_hs(ev_raw.u.keyButtonPointer.state);
323 k.press = (k.ev.type == KeyPress);
324 k.key_sym = ks;
325
326 if (ic) {
327 InputContext *focusedContext = InputContext::focusedContext();
328 if (!focusedContext)
329 ic->setFocus(); // workaround for some buggy applications
330 ic->OnKeyEvent(k);
331 }
332 if (!(g_option_mask & OPT_ON_DEMAND_SYNC))
333 send_sync_reply(icid);
334 break;
335 default:
336 printf("unknown type of forwarded event.(%d)\n", k.ev.type);
337 if (!(g_option_mask & OPT_ON_DEMAND_SYNC))
338 send_sync_reply(icid);
339 break;
340 }
341 }
342
free_all_ic()343 void XimIM_impl::free_all_ic()
344 {
345 std::map<C16, XimIC *>::iterator i;
346 for (i = m_ics.begin(); i != m_ics.end(); ++i) {
347 (*i).second->unsetFocus();
348 delete (*i).second;
349 }
350 m_ics.erase(m_ics.begin(), m_ics.end());
351 }
352
delete_ic(XimIC * ic)353 void XimIM_impl::delete_ic(XimIC *ic)
354 {
355 std::map<C16, XimIC *>::iterator it;
356 for (it = m_ics.begin(); it != m_ics.end(); ++it) {
357 if (it->second == ic) {
358 it->second->unsetFocus();
359 delete it->second;
360 m_ics.erase(it);
361 return;
362 }
363 }
364 }
365
send_sync_reply(C16 icid)366 void XimIM_impl::send_sync_reply(C16 icid)
367 {
368 TxPacket *t = createTxPacket(XIM_SYNC_REPLY, 0);
369 t->pushC16(mID);
370 t->pushC16(icid);
371 mConn->push_packet(t);
372 }
373
send_sync(C16 icid)374 void XimIM_impl::send_sync(C16 icid)
375 {
376 TxPacket *t = createTxPacket(XIM_SYNC, 0);
377 t->pushC16(mID);
378 t->pushC16(icid);
379 mConn->push_packet(t);
380 }
381
onSendPacket()382 void XimIM_impl::onSendPacket()
383 {
384 std::map<C16, XimIC *>::iterator i;
385 for (i = m_ics.begin(); i != m_ics.end(); ++i) {
386 (*i).second->onSendPacket();
387 }
388 }
389
XimIM(Connection * c,C16 id)390 XimIM::XimIM(Connection *c, C16 id)
391 {
392 mConn = c;
393 mID = id;
394 mEncoding = NULL;
395 mLangRegion = NULL;
396 mTreeTop = NULL;
397 mLocale = NULL;
398 }
399
~XimIM()400 XimIM::~XimIM()
401 {
402 free(mEncoding);
403 free(mLangRegion);
404 FreeComposeTree(mTreeTop);
405 delete mLocale;
406 }
407
FreeComposeTree(DefTree * top)408 void XimIM::FreeComposeTree(DefTree *top)
409 {
410 if (!top)
411 return;
412
413 if (top->succession)
414 FreeComposeTree(top->succession);
415 if (top->next)
416 FreeComposeTree(top->next);
417 free(top->mb);
418 free(top->utf8);
419 free(top);
420 }
421
set_encoding(const char * encoding)422 void XimIM::set_encoding(const char *encoding)
423 {
424 free(mEncoding);
425 mEncoding = strdup(encoding);
426
427 // set iconv environment
428 if (mLocale)
429 delete mLocale;
430 // workaround for Solaris 10 (bug #7558)
431 char *p;
432 if (!strcasecmp(encoding, "EUC") && mLangRegion &&
433 (p = strchr(mLangRegion, '_'))) {
434 char *iconv_encoding = (char *)malloc(3 + strlen(p + 1) + 1);
435 if (iconv_encoding) {
436 sprintf(iconv_encoding, "euc%s", p + 1);
437 mLocale = createLocale(iconv_encoding);
438 free(iconv_encoding);
439 } else {
440 mLocale = createLocale(mEncoding);
441 }
442 } else {
443 mLocale = createLocale(mEncoding);
444 }
445 }
446
get_encoding()447 const char *XimIM::get_encoding()
448 {
449 return mEncoding;
450 }
451
set_lang_region(const char * lang_and_region)452 void XimIM::set_lang_region(const char *lang_and_region)
453 {
454 free(mLangRegion);
455 mLangRegion = strdup(lang_and_region);
456 }
457
get_lang_region()458 const char *XimIM::get_lang_region()
459 {
460 return mLangRegion;
461 }
462
getInputStyles()463 struct input_style *XimIM::getInputStyles()
464 {
465 if (mLocale && mLocale->supportOverTheSpot())
466 return input_style_tab_with_over_the_spot;
467
468 return input_style_tab_without_over_the_spot;
469 }
470
uStringToCtext(uString * us)471 char *XimIM::uStringToCtext(uString *us)
472 {
473 char *ret = NULL;
474 if (mLocale)
475 ret = mLocale->uStringToCtext(us);
476
477 return ret;
478 }
479
utf8_to_native_str(char * str)480 char *XimIM::utf8_to_native_str(char *str)
481 {
482 char *ret = NULL;
483 if (mLocale)
484 ret = mLocale->utf8_to_native_str(str);
485
486 return ret;
487 }
488
unused_im_id()489 C16 unused_im_id()
490 {
491 C16 max_id;
492 std::map<C16, XimIM *>::iterator i;
493 max_id = 1;
494 for (i = g_ims.begin(); i != g_ims.end(); ++i) {
495 if ((*i).first == max_id)
496 max_id = (C16)((*i).first + 1);
497 }
498 return max_id;
499 }
500
create_im(Connection * c,C16 id)501 XimIM *create_im(Connection *c, C16 id)
502 {
503 XimIM *im;
504 im = new XimIM_impl(c, id);
505 std::pair<C16, XimIM *> p(id, im);
506 g_ims.insert(p);
507 return im;
508 }
509
get_im_by_id(C16 id)510 XimIM *get_im_by_id(C16 id)
511 {
512 std::map<C16, XimIM *>::iterator it;
513 it = g_ims.find(id);
514 if (it == g_ims.end())
515 return NULL;
516
517 return it->second;
518 }
519
close_im(C16 id)520 void close_im(C16 id)
521 {
522 XimIM *im;
523
524 im = get_im_by_id(id);
525 if (im)
526 delete im;
527
528 std::map<C16, XimIM *>::iterator it;
529 it = g_ims.find(id);
530 if (it != g_ims.end())
531 g_ims.erase(it);
532 }
533 /*
534 * Local variables:
535 * c-indent-level: 4
536 * c-basic-offset: 4
537 * End:
538 */
539