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 // classes for preedit draw
34
35 #ifdef HAVE_CONFIG_H
36 # include <config.h>
37 #endif
38
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/extensions/shape.h>
42 #if HAVE_XFT_UTF8_STRING
43 #include <X11/Xft/Xft.h>
44 #endif
45 #include <clocale>
46 #include <cstdlib>
47 #include "xim.h"
48 #include "ximserver.h"
49 #include "convdisp.h"
50 #include "canddisp.h"
51 #include "xdispatch.h"
52 #include "util.h"
53
54 #include "uim/uim-scm.h"
55
56 #define UNDERLINE_HEIGHT 2
57 #define DEFAULT_FONT_SIZE 16
58 // Temporal hack for flashplayer plugin's broken over-the-spot XIM style
59 #define FLASHPLAYER7_WORKAROUND
60 #define FLASHPLAYER9_WORKAROUND
61
62 //
63 // PeWin: Base class for preedit window
64 // PeLineWin: Child class for root window style preedit window
65 // PeOvWin: Child class for over the spot style preedit window
66
67 #ifdef FLASHPLAYER7_WORKAROUND
68 static Window getTopWindow(Display *, Window);
69 #endif
70
71 const char *fontset_zhCN = "-sony-fixed-medium-r-normal--16-*-*-*-c-80-iso8859-1, -isas-fangsong ti-medium-r-normal--16-160-72-72-c-160-gb2312.1980-0";
72 const char *fontset_zhTW = "-sony-fixed-medium-r-normal--16-*-*-*-c-80-iso8859-1, -taipei-fixed-medium-r-normal--16-150-75-75-c-160-big5-0";
73 const char *fontset_ja = "-sony-fixed-medium-r-normal--16-*-*-*-c-80-iso8859-1, -jis-fixed-medium-r-normal--16-*-75-75-c-160-jisx0208.1983-0, -sony-fixed-medium-r-normal--16-*-*-*-c-80-jisx0201.1976-0";
74 const char *fontset_ko = "-sony-fixed-medium-r-normal--16-*-*-*-c-80-iso8859-1, -daewoo-gothic-medium-r-normal--16-120-100-100-c-160-ksc5601.1987-0";
75
76
77 #if HAVE_XFT_UTF8_STRING
78 XftFont *gXftFont;
79 char *gXftFontName;
80 char *gXftFontLocale;
81
82 void
init_default_xftfont()83 init_default_xftfont() {
84 char *fontname = uim_scm_symbol_value_str("uim-xim-xft-font-name");
85 gXftFontName = fontname;
86
87 gXftFont = XftFontOpen(XimServer::gDpy, DefaultScreen(XimServer::gDpy),
88 XFT_FAMILY, XftTypeString, fontname,
89 XFT_PIXEL_SIZE, XftTypeDouble, (double)DEFAULT_FONT_SIZE,
90 (char *)NULL);
91 gXftFontLocale = strdup(setlocale(LC_CTYPE, NULL));
92 // maybe not needed, but in case it return NULL...
93 if (!gXftFont) {
94 gXftFont = XftFontOpen(XimServer::gDpy, DefaultScreen(XimServer::gDpy),
95 XFT_FAMILY, XftTypeString, "Sans",
96 XFT_PIXEL_SIZE, XftTypeDouble, (double)DEFAULT_FONT_SIZE,
97 (char *)NULL);
98 }
99 }
100
101 void
update_default_xftfont()102 update_default_xftfont() {
103 char *fontname;
104
105 if (!uim_scm_symbol_value_bool("uim-xim-use-xft-font?"))
106 return;
107
108 fontname = uim_scm_symbol_value_str("uim-xim-xft-font-name");
109
110 if (fontname) {
111 XftFont *xftfont = XftFontOpen(XimServer::gDpy,
112 DefaultScreen(XimServer::gDpy),
113 XFT_FAMILY, XftTypeString, fontname,
114 XFT_PIXEL_SIZE, XftTypeDouble, (double)DEFAULT_FONT_SIZE,
115 (char *)NULL);
116 if (xftfont) {
117 if (gXftFont)
118 XftFontClose(XimServer::gDpy, gXftFont);
119 free(gXftFontName);
120 free(gXftFontLocale);
121 gXftFont = xftfont;
122 gXftFontName = fontname;
123 gXftFontLocale = strdup(setlocale(LC_CTYPE, NULL));
124 } else {
125 free(fontname);
126 }
127 }
128 }
129 #endif
130
131 static XFontSet
create_default_fontset(const char * im_lang,const char * locale)132 create_default_fontset(const char *im_lang, const char *locale) {
133 char *orig_locale;
134 const char *name;
135 XFontSet ret;
136
137 orig_locale = strdup(setlocale(LC_CTYPE, NULL));
138
139 if (strcmp(locale, orig_locale))
140 setlocale(LC_CTYPE, locale);
141
142 if (!strcmp(im_lang, "ja"))
143 name = fontset_ja;
144 else if (!strcmp(im_lang, "ko"))
145 name = fontset_ko;
146 else if (!strcmp(im_lang, "zh_CN"))
147 name = fontset_zhCN;
148 else if (!strcmp(im_lang, "zh_TW:zh_HK"))
149 name = fontset_zhTW;
150 else
151 name = fontset_ja; // XXX fallback fontset
152
153 ret = get_font_set(name, locale);
154
155 if (strcmp(locale, orig_locale))
156 setlocale(LC_CTYPE, orig_locale);
157 free(orig_locale);
158
159 return ret;
160 }
161
162 static XFontSet
choose_default_fontset(const char * im_lang,const char * locale)163 choose_default_fontset(const char *im_lang, const char *locale) {
164 return create_default_fontset(im_lang, locale);
165 }
166
167 struct char_ent {
168 uchar c;
169 int stat;
170 int width;
171 int height;
172 int x, y;
173 };
174
175 // Preedit Window
176 class PeWin : public WindowIf {
177 public:
178 PeWin(Window pw, const char *im_lang, const char *encoding, const char *locale, Convdisp *cd);
179 virtual ~PeWin();
180
181 virtual void release();
182
183 virtual void destroy(Window w);
184 virtual void expose(Window w);
185
186 void draw_char(int x, int y, uchar ch, int stat);
187 void set_back(unsigned long p);
188 void set_fore(unsigned long p);
189 #if HAVE_XFT_UTF8_STRING
190 void set_xftfont(const char *xfld);
191 #endif
192 void set_fontset(XFontSet f);
193
194 virtual void set_size(int w, int h);
195 void set_pos(int x, int y);
196
197 void do_map();
198
199 void clear();
200 void draw();
201 void unmap();
202
203 #if HAVE_XFT_UTF8_STRING
204 XftFont *mXftFont;
205 int mXftFontSize;
206 #endif
207 protected:
208 #if HAVE_XFT_UTF8_STRING
209 int get_fontsize(const char *xfld);
210 #endif
211 Window mParentWin;
212 Window mWin;
213 Pixmap mPixmap;
214 GC mGC, mClearGC;
215 unsigned int mFore, mBack;
216 #if HAVE_XFT_UTF8_STRING
217 XftDraw *mXftDraw;
218 XftColor mXftColorFg;
219 XftColor mXftColorFgRev;
220 #endif
221 XFontSet mFontset;
222 const char *mEncoding;
223 int mWidth, mHeight;
224 bool mIsMapped;
225 Convdisp *mConvdisp;
226 };
227
228 // one line preedit window for RootWindowStyle
229 class PeLineWin : public PeWin {
230 public:
231 PeLineWin(Window w, const char *im_lang, const char *encoding, const char *locale, Convdisp *cd);
232 virtual ~PeLineWin();
233
234 void draw_pe(pe_stat *p);
235 int mCandWinXOff;
236
237 private:
238 void calc_extent(pe_stat *p);
239 int calc_segment_extent(pe_ustring *s);
240 void draw_segment(pe_ustring *s);
241 void draw_cursor();
242 int get_char_width(uchar ch);
243
244 int m_x;
245 int mCharPos;
246 int mCursorX;
247 };
248
249 // window for over the spot style
250 class PeOvWin : public PeWin {
251 public:
252 PeOvWin(Window w, const char *im_lang, const char *encoding, const char *locale, Convdisp *cd);
253
254 void draw_ce(char_ent *ce, int len);
255 virtual void set_size(int w, int h);
256 virtual ~PeOvWin();
257 private:
258 void draw_a_ce(char_ent *ce);
259 void draw_cursor(char_ent *ce);
260 Pixmap m_mask_pix;
261 GC m_mask_pix_gc;
262 };
263
264 class ConvdispOv : public Convdisp {
265 public:
266 ConvdispOv(InputContext *, icxatr *);
267 virtual ~ConvdispOv();
268 virtual void update_preedit();
269 virtual void clear_preedit();
270 virtual void update_icxatr();
271 virtual void move_candwin();
272 virtual bool use_xft();
273 private:
274 bool check_win();
275 bool check_atr();
276 void layoutCharEnt();
277 void make_ce_array();
278 void draw_preedit();
279 void do_draw_preedit();
280 #ifdef FLASHPLAYER7_WORKAROUND
281 int get_ce_font_height(char_ent *ce, int len);
282 int revised_spot_y;
283 #endif
284
285 void validate_area();
286
287 char_ent *m_ce;
288 int m_ce_len;
289 int m_candwin_x_off;
290 int m_candwin_y_off;
291 PeOvWin *m_ov_win;
292 };
293
294 // Preedit window for RootWindowStyle
295 class ConvdispRw : public Convdisp {
296 public:
297 ConvdispRw(InputContext *, icxatr *);
298 virtual ~ConvdispRw();
299
300 virtual void update_preedit();
301 virtual void clear_preedit();
302 virtual void update_icxatr();
303 virtual void move_candwin();
304 virtual bool use_xft();
305 private:
306 PeLineWin *mPeWin;
307 };
308
309 class ConvdispOs : public Convdisp {
310 public:
311 ConvdispOs(InputContext *, icxatr *, Connection *);
312 virtual ~ConvdispOs();
313 virtual void update_preedit();
314 virtual void clear_preedit();
315 virtual void update_icxatr();
316 virtual void move_candwin();
317 virtual bool use_xft();
318
319 private:
320 void compose_preedit_array(TxPacket *);
321 void compose_feedback_array(TxPacket *);
322
323 Connection *mConn;
324 C16 mImid, mIcid;
325 int mPrevLen;
326 };
327
create_convdisp(int style,InputContext * k,icxatr * a,Connection * c)328 Convdisp *create_convdisp(int style, InputContext *k,
329 icxatr *a, Connection *c)
330 {
331 switch (style) {
332 case IS_ROOT_WINDOW:
333 return new ConvdispRw(k, a);
334 case IS_OVER_THE_SPOT:
335 return new ConvdispOv(k, a);
336 case IS_ON_THE_SPOT:
337 return new ConvdispOs(k, a, c);
338 default:
339 break;
340 }
341 return 0;
342 }
343
344 //
345 // PeWin(PreEdit Window)
346 //
PeWin(Window pw,const char * im_lang,const char * encoding,const char * locale,Convdisp * cd)347 PeWin::PeWin(Window pw, const char *im_lang, const char *encoding, const char *locale, Convdisp *cd)
348 {
349 mParentWin = pw;
350 mConvdisp = cd;
351 int scr_num = DefaultScreen(XimServer::gDpy);
352 // tentative
353 mWidth = 1;
354 mHeight = 1;
355 mWin = XCreateSimpleWindow(XimServer::gDpy, mParentWin,
356 0, 0, mWidth, mHeight, 0,
357 BlackPixel(XimServer::gDpy, scr_num),
358 WhitePixel(XimServer::gDpy, scr_num));
359 XSetWindowAttributes attr;
360 attr.override_redirect = True;
361 XChangeWindowAttributes(XimServer::gDpy, mWin, CWOverrideRedirect,
362 &attr);
363 mPixmap = XCreatePixmap(XimServer::gDpy, DefaultRootWindow(XimServer::gDpy),
364 mWidth, mHeight,
365 DefaultDepth(XimServer::gDpy, scr_num));
366
367 mGC = XCreateGC(XimServer::gDpy, mPixmap, 0, 0);
368 mClearGC = XCreateGC(XimServer::gDpy, mPixmap, 0, 0);
369
370 XSetBackground(XimServer::gDpy, mGC, WhitePixel(XimServer::gDpy, scr_num));
371 XSetForeground(XimServer::gDpy, mGC, BlackPixel(XimServer::gDpy, scr_num));
372 XSetForeground(XimServer::gDpy, mClearGC, WhitePixel(XimServer::gDpy, scr_num));
373 XSetBackground(XimServer::gDpy, mClearGC, BlackPixel(XimServer::gDpy, scr_num));
374
375 add_window_watch(mWin, this, EXPOSE_MASK|STRUCTURE_NOTIFY_MASK);
376 mIsMapped = false; //not mapped now
377
378 if (mConvdisp->use_xft() == true) {
379 #if HAVE_XFT_UTF8_STRING
380 mXftFontSize = DEFAULT_FONT_SIZE;
381 if (!gXftFont)
382 init_default_xftfont();
383 if (!strcmp(gXftFontLocale, locale)) {
384 mXftFont = gXftFont;
385 } else {
386 mXftFont = XftFontOpen(XimServer::gDpy,
387 DefaultScreen(XimServer::gDpy),
388 XFT_FAMILY, XftTypeString, gXftFontName,
389 XFT_PIXEL_SIZE, XftTypeDouble, (double)mXftFontSize,
390 (char *)NULL);
391 }
392 mXftDraw = XftDrawCreate(XimServer::gDpy, mPixmap,
393 DefaultVisual(XimServer::gDpy, scr_num),
394 DefaultColormap(XimServer::gDpy, scr_num));
395 XColor dummyc, fg;
396 XAllocNamedColor(XimServer::gDpy, DefaultColormap(XimServer::gDpy, scr_num),"black", &fg, &dummyc);
397 mXftColorFg.color.red = dummyc.red;
398 mXftColorFg.color.green = dummyc.green;
399 mXftColorFg.color.blue = dummyc.blue;
400 mXftColorFg.color.alpha = 0xffff;
401 mXftColorFg.pixel = fg.pixel;
402
403 XAllocNamedColor(XimServer::gDpy, DefaultColormap(XimServer::gDpy, scr_num),"white", &fg, &dummyc);
404 mXftColorFgRev.color.red = dummyc.red;
405 mXftColorFgRev.color.green = dummyc.green;
406 mXftColorFgRev.color.blue = dummyc.blue;
407 mXftColorFgRev.color.alpha = 0xffff;
408 mXftColorFgRev.pixel = fg.pixel;
409 #endif
410 } else {
411 mFontset = choose_default_fontset(im_lang, locale);
412 }
413
414 mEncoding = encoding;
415
416 XFlush(XimServer::gDpy);
417 }
418
~PeWin()419 PeWin::~PeWin()
420 {
421 if (mWin)
422 release();
423
424 XFreePixmap(XimServer::gDpy, mPixmap);
425
426 XFreeGC(XimServer::gDpy, mGC);
427 XFreeGC(XimServer::gDpy, mClearGC);
428 #if HAVE_XFT_UTF8_STRING
429 if (mConvdisp->use_xft() == true) {
430 XftDrawDestroy(mXftDraw);
431 if (mXftFont != gXftFont)
432 XftFontClose(XimServer::gDpy, mXftFont);
433 }
434 #endif
435
436 XFlush(XimServer::gDpy);
437 }
438
release()439 void PeWin::release()
440 {
441 remove_window_watch(mWin);
442 XDestroyWindow(XimServer::gDpy, mWin);
443 mWin = 0;
444 }
445
destroy(Window w)446 void PeWin::destroy(Window w)
447 {
448 if (mWin && mWin == w)
449 mWin = 0;
450 }
451
expose(Window w)452 void PeWin::expose(Window w)
453 {
454 XCopyArea(XimServer::gDpy, mPixmap, w, mGC,
455 0, 0, mWidth, mHeight, 0, 0);
456
457 XFlush(XimServer::gDpy);
458 }
459
draw_char(int x,int y,uchar ch,int stat)460 void PeWin::draw_char(int x, int y, uchar ch, int stat)
461 {
462 GC gc = mGC;
463 if (stat & PE_REVERSE)
464 gc = mClearGC;
465
466 char utf8[6];
467 int len = utf8_wctomb((unsigned char *)utf8, ch);
468 utf8[len] = '\0';
469
470 if (mConvdisp->use_xft() == true) {
471 #ifdef HAVE_XFT_UTF8_STRING
472 XGlyphInfo ginfo;
473 XftTextExtentsUtf8(XimServer::gDpy, mXftFont, (unsigned char *)utf8, len, &ginfo);
474 if (stat & PE_REVERSE) {
475 XftDrawRect(mXftDraw, &mXftColorFg, x, y - (mXftFontSize - 2), ginfo.xOff, mXftFontSize);
476 XftDrawStringUtf8(mXftDraw, &mXftColorFgRev, mXftFont, x, y, (unsigned char *)utf8, len);
477 } else {
478 XftDrawStringUtf8(mXftDraw, &mXftColorFg, mXftFont, x, y, (unsigned char *)utf8, len);
479 }
480 #endif
481 } else {
482 if (!strcmp(mEncoding, "UTF-8")) {
483 XwcDrawImageString(XimServer::gDpy, mPixmap, mFontset,
484 gc, x, y, &ch, 1);
485 } else {
486 char *native_str;
487 XimIM *im = get_im_by_id(mConvdisp->get_context()->get_ic()->get_imid());
488
489 native_str = im->utf8_to_native_str(utf8);
490 if (!native_str)
491 return;
492 len = static_cast<int>(strlen(native_str));
493 XmbDrawImageString(XimServer::gDpy, mPixmap, mFontset,
494 gc, x, y, native_str, len);
495 free(native_str);
496 }
497 }
498 }
499
set_back(unsigned long p)500 void PeWin::set_back(unsigned long p)
501 {
502 mBack = static_cast<unsigned int>(p);
503 XSetBackground(XimServer::gDpy, mGC, p);
504 XSetForeground(XimServer::gDpy, mClearGC, p);
505 #if HAVE_XFT_UTF8_STRING
506 if (mConvdisp->use_xft() == true) {
507 XColor xcolor;
508 xcolor.pixel = p;
509 XQueryColor(XimServer::gDpy, DefaultColormap(XimServer::gDpy, DefaultScreen(XimServer::gDpy)), &xcolor);
510 mXftColorFgRev.pixel = p;
511 mXftColorFgRev.color.red = xcolor.red;
512 mXftColorFgRev.color.green = xcolor.green;
513 mXftColorFgRev.color.blue = xcolor.blue;
514 mXftColorFgRev.color.alpha = 0xffff;
515 }
516 #endif
517 }
518
set_fore(unsigned long p)519 void PeWin::set_fore(unsigned long p)
520 {
521 mFore = static_cast<unsigned int>(p);
522 XSetForeground(XimServer::gDpy, mGC, p);
523 XSetBackground(XimServer::gDpy, mClearGC, p);
524 #if HAVE_XFT_UTF8_STRING
525 if (mConvdisp->use_xft() == true) {
526 XColor xcolor;
527 xcolor.pixel = p;
528 XQueryColor(XimServer::gDpy, DefaultColormap(XimServer::gDpy, DefaultScreen(XimServer::gDpy)), &xcolor);
529 mXftColorFg.pixel = p;
530 mXftColorFg.color.red = xcolor.red;
531 mXftColorFg.color.green = xcolor.green;
532 mXftColorFg.color.blue = xcolor.blue;
533 mXftColorFg.color.alpha = 0xffff;
534 }
535 #endif
536 }
537
set_fontset(XFontSet f)538 void PeWin::set_fontset(XFontSet f)
539 {
540 if (f)
541 mFontset = f;
542 }
543
544 #if HAVE_XFT_UTF8_STRING
set_xftfont(const char * xfld)545 void PeWin::set_xftfont(const char *xfld)
546 {
547 int size = get_fontsize(xfld);
548 const char *locale = mConvdisp->get_locale_name();
549
550 if (!gXftFont)
551 init_default_xftfont();
552 if (size != -1 && (mXftFontSize != size || strcmp(locale, gXftFontLocale))) {
553 if (mXftFont != gXftFont)
554 XftFontClose(XimServer::gDpy, mXftFont);
555
556 mXftFont = XftFontOpen(XimServer::gDpy,
557 DefaultScreen(XimServer::gDpy),
558 XFT_FAMILY, XftTypeString, gXftFontName,
559 XFT_PIXEL_SIZE, XftTypeDouble, (double)size,
560 (char *)NULL);
561 mXftFontSize = size;
562 }
563 }
564
get_fontsize(const char * xfld)565 int PeWin::get_fontsize(const char *xfld)
566 {
567 #define MAX_DIGIT_OF_PIXEL_SIZE 3
568 int size;
569 char str[MAX_DIGIT_OF_PIXEL_SIZE + 1];
570 const char *p = xfld;
571 int count = 0;
572 int i, j = 0;
573
574 for (i = 0; i < (int)strlen(xfld); i++) {
575 if (p[i] == '-')
576 count++;
577 if (count == 7) {
578 i++;
579 while (p[i] != '-' && p[i] != '\0') {
580 str[j] = p[i];
581 i++;
582 j++;
583 if (j > MAX_DIGIT_OF_PIXEL_SIZE)
584 return -1;
585 }
586 str[j] = '\0';
587 break;
588 }
589 }
590 if (!sscanf(str, "%d", &size))
591 return -1;
592 return size;
593 }
594 #endif
595
set_size(int w,int h)596 void PeWin::set_size(int w, int h)
597 {
598 if (w == mWidth && h == mHeight)
599 return;
600
601 XResizeWindow(XimServer::gDpy, mWin, w, h);
602 XFreePixmap(XimServer::gDpy, mPixmap);
603 mPixmap = XCreatePixmap(XimServer::gDpy, DefaultRootWindow(XimServer::gDpy), w, h,
604 DefaultDepth(XimServer::gDpy, DefaultScreen(XimServer::gDpy)));
605 #if HAVE_XFT_UTF8_STRING
606 if (mConvdisp->use_xft() == true)
607 XftDrawChange(mXftDraw, mPixmap);
608 #endif
609 mWidth = w;
610 mHeight = h;
611 clear();
612 }
613
set_pos(int x,int y)614 void PeWin::set_pos(int x, int y)
615 {
616 XWindowChanges ch;
617 ch.x = x;
618 ch.y = y;
619 XConfigureWindow(XimServer::gDpy, mWin, CWX|CWY, &ch);
620 }
621
do_map()622 void PeWin::do_map()
623 {
624 if (!mIsMapped) {
625 XFlush(XimServer::gDpy);
626 XMapRaised(XimServer::gDpy, mWin);
627 mIsMapped = true;
628 }
629 }
630
clear()631 void PeWin::clear()
632 {
633 XFillRectangle(XimServer::gDpy, mPixmap, mClearGC,
634 0, 0, mWidth, mHeight);
635 }
636
draw()637 void PeWin::draw()
638 {
639 if (!mIsMapped)
640 do_map();
641 else
642 expose(mWin);
643 }
644
unmap()645 void PeWin::unmap()
646 {
647 if (mIsMapped) {
648 XUnmapWindow(XimServer::gDpy, mWin);
649 XFlush(XimServer::gDpy);
650 mIsMapped = false;
651 }
652 }
653
654 //
655 // PeLineWin
656 //
657 #define PE_LINE_WIN_WIDTH 400
658 #define PE_LINE_WIN_HEIGHT 28
659 #define PE_LINE_WIN_FONT_POS_Y 20
660 #define PE_LINE_WIN_MARGIN_X 2
661
PeLineWin(Window w,const char * im_lang,const char * encoding,const char * locale,Convdisp * cd)662 PeLineWin::PeLineWin(Window w, const char *im_lang, const char *encoding, const char *locale, Convdisp *cd) : PeWin(w, im_lang, encoding, locale, cd)
663 {
664 set_size(PE_LINE_WIN_WIDTH, PE_LINE_WIN_HEIGHT);
665 clear();
666 }
667
~PeLineWin()668 PeLineWin::~PeLineWin()
669 {
670 }
671
draw_pe(pe_stat * p)672 void PeLineWin::draw_pe(pe_stat *p)
673 {
674 clear();
675 calc_extent(p);
676 m_x = PE_LINE_WIN_MARGIN_X;
677 mCursorX = m_x;
678 mCharPos = 0;
679 std::list<pe_ustring>::iterator i;
680 for (i = p->ustrings.begin(); i != p->ustrings.end(); ++i) {
681 draw_segment(&(*i));
682 }
683 draw_cursor();
684 }
685
draw_cursor()686 void PeLineWin::draw_cursor()
687 {
688 XDrawLine(XimServer::gDpy, mPixmap, mGC,
689 mCursorX,
690 (PE_LINE_WIN_HEIGHT - PE_LINE_WIN_FONT_POS_Y) / 2 + 1,
691 mCursorX,
692 PE_LINE_WIN_FONT_POS_Y + 1);
693 }
694
get_char_width(uchar ch)695 int PeLineWin::get_char_width(uchar ch)
696 {
697 int width = 0;
698 char utf8[6];
699
700 int len = utf8_wctomb((unsigned char *)utf8, ch);
701 utf8[len] = '\0';
702
703 if (mConvdisp->use_xft() == true) {
704 #ifdef HAVE_XFT_UTF8_STRING
705 XGlyphInfo ginfo;
706 XftTextExtentsUtf8(XimServer::gDpy, mXftFont, (unsigned char *)utf8,
707 len, &ginfo);
708 width = ginfo.xOff;
709 #endif
710 } else {
711 XRectangle ink, logical;
712
713 if (!strcmp(mEncoding, "UTF-8")) {
714 XwcTextExtents(mFontset, &ch, 1, &ink, &logical);
715 } else {
716 char *native_str;
717 XimIM *im = get_im_by_id(mConvdisp->get_context()->get_ic()->get_imid());
718
719 native_str = im->utf8_to_native_str(utf8);
720 if (!native_str)
721 return 0;
722 len = static_cast<int>(strlen(native_str));
723 XmbTextExtents(mFontset, native_str, len, &ink, &logical);
724 free(native_str);
725 }
726 width = logical.width;
727 }
728
729 return width;
730 }
731
draw_segment(pe_ustring * s)732 void PeLineWin::draw_segment(pe_ustring *s)
733 {
734 uString::iterator i;
735 int caret_pos = mConvdisp->get_caret_pos();
736
737 for (i = s->s.begin(); i != s->s.end(); ++i) {
738 uchar ch = *i;
739 int width = get_char_width(ch);
740 draw_char(m_x, PE_LINE_WIN_FONT_POS_Y, ch, s->stat);
741 mCharPos++;
742
743 if (s->stat & PE_UNDERLINE) {
744 XDrawLine(XimServer::gDpy, mPixmap, mGC,
745 m_x, PE_LINE_WIN_FONT_POS_Y + UNDERLINE_HEIGHT,
746 m_x + width, PE_LINE_WIN_FONT_POS_Y + UNDERLINE_HEIGHT);
747 }
748 m_x += width;
749 if (mCharPos == caret_pos)
750 mCursorX= m_x;
751 }
752
753 switch (XimServer::gCandWinPosType) {
754 case Caret:
755 mCandWinXOff = mCursorX;
756 break;
757 case Right:
758 mCandWinXOff = m_x;
759 break;
760 case Left:
761 default:
762 mCandWinXOff = 0;
763 break;
764 }
765 }
766
calc_segment_extent(pe_ustring * s)767 int PeLineWin::calc_segment_extent(pe_ustring *s)
768 {
769 int width = 0;
770 uString::iterator i;
771
772 for (i = s->s.begin(); i != s->s.end(); ++i) {
773 uchar ch = *i;
774 width += get_char_width(ch);
775 }
776 return width;
777 }
778
calc_extent(pe_stat * p)779 void PeLineWin::calc_extent(pe_stat *p)
780 {
781 int width = 0;
782 std::list<pe_ustring>::iterator i;
783
784 for (i = p->ustrings.begin(); i != p->ustrings.end(); ++i)
785 width += calc_segment_extent(&(*i));
786
787 if (width < PE_LINE_WIN_WIDTH)
788 set_size(PE_LINE_WIN_WIDTH, PE_LINE_WIN_HEIGHT);
789 else
790 set_size(width + PE_LINE_WIN_MARGIN_X * 2, PE_LINE_WIN_HEIGHT);
791 }
792
793
794 //
795 // PeOvWin
796 //
PeOvWin(Window w,const char * im_lang,const char * encoding,const char * locale,Convdisp * cd)797 PeOvWin::PeOvWin(Window w, const char *im_lang, const char *encoding, const char *locale, Convdisp *cd) : PeWin(w, im_lang, encoding, locale, cd)
798 {
799 m_mask_pix = 0;
800 m_mask_pix_gc = 0;
801 }
802
~PeOvWin()803 PeOvWin::~PeOvWin()
804 {
805 if (m_mask_pix) {
806 XFreePixmap(XimServer::gDpy, m_mask_pix);
807 XFreeGC(XimServer::gDpy, m_mask_pix_gc);
808 }
809 }
810
set_size(int w,int h)811 void PeOvWin::set_size(int w, int h)
812 {
813 if (w == mWidth && h == mHeight)
814 return;
815
816 PeWin::set_size(w, h);
817 if (m_mask_pix) {
818 XFreePixmap(XimServer::gDpy, m_mask_pix);
819 m_mask_pix = XCreatePixmap(XimServer::gDpy, mWin,
820 mWidth, mHeight, 1);
821 }
822 }
823
draw_ce(char_ent * ce,int len)824 void PeOvWin::draw_ce(char_ent *ce, int len)
825 {
826 if (m_mask_pix == 0) {
827 m_mask_pix = XCreatePixmap(XimServer::gDpy, mWin, mWidth, mHeight, 1);
828 m_mask_pix_gc = XCreateGC(XimServer::gDpy, m_mask_pix, 0, 0);
829 }
830
831
832 clear();
833 XSetForeground(XimServer::gDpy, m_mask_pix_gc,
834 BlackPixel(XimServer::gDpy,
835 DefaultScreen(XimServer::gDpy)));
836 XFillRectangle(XimServer::gDpy, m_mask_pix,
837 m_mask_pix_gc, 0, 0, mWidth, mHeight);
838 XSetForeground(XimServer::gDpy, m_mask_pix_gc,
839 WhitePixel(XimServer::gDpy,
840 DefaultScreen(XimServer::gDpy)));
841 int i;
842 for (i = 0; i < len; i++) {
843 draw_a_ce(&ce[i]);
844 }
845 draw_cursor(ce);
846 XShapeCombineMask(XimServer::gDpy, mWin, ShapeBounding,
847 0, 0, m_mask_pix, ShapeSet);
848 do_map();
849 }
850
851 #define CURSOR_WIDTH 1
draw_a_ce(char_ent * ce)852 void PeOvWin::draw_a_ce(char_ent *ce)
853 {
854 draw_char(ce->x, ce->y, ce->c, ce->stat);
855
856 XFillRectangle(XimServer::gDpy, m_mask_pix, m_mask_pix_gc,
857 ce->x, ce->y - ce->height + 2,
858 ce->width + CURSOR_WIDTH, ce->height + UNDERLINE_HEIGHT - 1);
859 if (ce->stat & PE_UNDERLINE) {
860 XDrawLine(XimServer::gDpy, mPixmap, mGC,
861 ce->x, ce->y + UNDERLINE_HEIGHT,
862 ce->x + ce->width, ce->y + UNDERLINE_HEIGHT);
863 }
864 }
865
draw_cursor(char_ent * ce)866 void PeOvWin::draw_cursor(char_ent *ce)
867 {
868 int x;
869 int caret_pos = mConvdisp->get_caret_pos();
870 char_ent *caret_ce;
871
872 if (caret_pos == 0) {
873 caret_ce = &ce[caret_pos];
874 x = caret_ce->x;
875 } else {
876 caret_ce = &ce[caret_pos - 1];
877 x = caret_ce->x + caret_ce->width;
878 }
879
880 XDrawLine(XimServer::gDpy, mPixmap, mGC,
881 x, caret_ce->y - caret_ce->height,
882 x, caret_ce->y);
883 }
884
885 //
886 //
887 //
Convdisp(InputContext * k,icxatr * a)888 Convdisp::Convdisp(InputContext *k, icxatr *a)
889 {
890 mKkContext = k;
891 m_atr = a;
892 mIMLang = get_im_lang_from_engine(k->get_engine_name());
893 mEncoding = k->get_ic()->get_encoding();
894 mLocaleName = k->get_locale_name();
895 }
896
~Convdisp()897 Convdisp::~Convdisp()
898 {
899 }
900
set_im_lang(const char * im_lang)901 void Convdisp::set_im_lang(const char *im_lang)
902 {
903 mIMLang = im_lang;
904 }
905
set_locale_name(const char * locale)906 void Convdisp::set_locale_name(const char *locale)
907 {
908 mLocaleName = locale;
909 }
910
get_locale_name()911 const char *Convdisp::get_locale_name()
912 {
913 return mLocaleName;
914 }
915
set_pe(pe_stat * p)916 void Convdisp::set_pe(pe_stat *p)
917 {
918 m_pe = p;
919 }
920
get_pe()921 uString Convdisp::get_pe()
922 {
923 uString s;
924 std::list<pe_ustring>::iterator it;
925 for (it = m_pe->ustrings.begin(); it != m_pe->ustrings.end(); ++it) {
926 append_ustring(&s, &(*it).s);
927 }
928 return s;
929 }
930
set_focus()931 void Convdisp::set_focus()
932 {
933 Canddisp *disp = canddisp_singleton();
934 disp->show();
935 }
936
unset_focus()937 void Convdisp::unset_focus()
938 {
939 Canddisp *disp = canddisp_singleton();
940 disp->hide();
941 }
942
get_context()943 InputContext *Convdisp::get_context()
944 {
945 return mKkContext;
946 }
947
get_caret_pos()948 int Convdisp::get_caret_pos()
949 {
950 if (!m_pe)
951 return 0;
952 return m_pe->caret_pos;
953 }
954
update_caret_state()955 void Convdisp::update_caret_state()
956 {
957 if (!uim_scm_symbol_value_bool("bridge-show-input-state?"))
958 return;
959
960 Canddisp *disp = canddisp_singleton();
961 InputContext *focusedContext = InputContext::focusedContext();
962
963 if (focusedContext && focusedContext == mKkContext) {
964 if (mKkContext->isCaretStateShown())
965 disp->update_caret_state();
966 else
967 disp->hide_caret_state();
968 }
969 }
970
971 // Root window style
ConvdispRw(InputContext * k,icxatr * a)972 ConvdispRw::ConvdispRw(InputContext *k, icxatr *a) : Convdisp(k, a)
973 {
974 mPeWin = NULL;
975 }
976
~ConvdispRw()977 ConvdispRw::~ConvdispRw()
978 {
979 if (mPeWin)
980 delete mPeWin;
981 }
982
update_preedit()983 void ConvdispRw::update_preedit()
984 {
985 if (!m_pe)
986 return;
987
988 if (!m_pe->get_char_count()) {
989 clear_preedit();
990 move_candwin(); // reset candwin position
991 update_caret_state();
992 return;
993 }
994
995 // preedit string exists
996 if (!mPeWin)
997 mPeWin = new PeLineWin(DefaultRootWindow(XimServer::gDpy), mIMLang, mEncoding, mLocaleName, this);
998
999 if (m_atr->has_atr(ICA_ClientWindow)) {
1000 int x, y;
1001 Window win;
1002 XWindowAttributes xattr;
1003
1004 XGetWindowAttributes(XimServer::gDpy, m_atr->client_window, &xattr);
1005 XTranslateCoordinates(XimServer::gDpy, m_atr->client_window, DefaultRootWindow(XimServer::gDpy), 0, 0, &x, &y, &win);
1006 mPeWin->set_pos(x, y + xattr.height);
1007 }
1008
1009 mPeWin->do_map();
1010 mPeWin->draw_pe(m_pe);
1011 mPeWin->draw();
1012
1013 move_candwin();
1014 update_caret_state();
1015 }
1016
clear_preedit()1017 void ConvdispRw::clear_preedit()
1018 {
1019 delete mPeWin;
1020 mPeWin = NULL;
1021 }
1022
update_icxatr()1023 void ConvdispRw::update_icxatr()
1024 {
1025 }
1026
move_candwin()1027 void ConvdispRw::move_candwin()
1028 {
1029 InputContext *focusedContext = InputContext::focusedContext();
1030 if (!focusedContext || focusedContext != mKkContext)
1031 return;
1032
1033 if (m_atr->has_atr(ICA_ClientWindow)) {
1034 int x, y;
1035 Window win;
1036 XWindowAttributes xattr;
1037
1038 XTranslateCoordinates(XimServer::gDpy, m_atr->client_window,
1039 DefaultRootWindow(XimServer::gDpy),
1040 0, 0, &x, &y, &win);
1041
1042 Canddisp *disp = canddisp_singleton();
1043
1044 XGetWindowAttributes(XimServer::gDpy, m_atr->client_window, &xattr);
1045
1046 if (mPeWin)
1047 x += mPeWin->mCandWinXOff;
1048 disp->move(x, y + xattr.height + 28); // lower-left side under the preedit window
1049 }
1050 }
1051
use_xft()1052 bool ConvdispRw::use_xft()
1053 {
1054 return m_atr->use_xft();
1055 }
1056
1057 // Over the spot style
ConvdispOv(InputContext * k,icxatr * a)1058 ConvdispOv::ConvdispOv(InputContext *k, icxatr *a) : Convdisp(k, a)
1059 {
1060 m_ov_win = 0;
1061 m_candwin_x_off = 0;
1062 m_candwin_y_off = 0;
1063 #ifdef FLASHPLAYER7_WORKAROUND
1064 revised_spot_y = -1;
1065 #endif
1066 }
1067
~ConvdispOv()1068 ConvdispOv::~ConvdispOv()
1069 {
1070 if (m_ov_win)
1071 delete m_ov_win;
1072 }
1073
update_preedit()1074 void ConvdispOv::update_preedit()
1075 {
1076 draw_preedit();
1077 move_candwin();
1078 update_caret_state();
1079 }
1080
move_candwin()1081 void ConvdispOv::move_candwin()
1082 {
1083 InputContext *focusedContext = InputContext::focusedContext();
1084 if (!focusedContext || focusedContext != mKkContext)
1085 return;
1086
1087 if (m_atr->has_atr(ICA_SpotLocation) ) {
1088 int x = -1, y = -1;
1089 Window win;
1090
1091 if (m_atr->has_atr(ICA_ClientWindow)) {
1092
1093 XTranslateCoordinates(XimServer::gDpy, m_atr->client_window,
1094 DefaultRootWindow(XimServer::gDpy),
1095 m_atr->spot_location.x,
1096 m_atr->spot_location.y,
1097 &x, &y, &win);
1098 }
1099
1100 if (m_atr->has_atr(ICA_FocusWindow)) {
1101
1102 XTranslateCoordinates(XimServer::gDpy, m_atr->focus_window,
1103 DefaultRootWindow(XimServer::gDpy),
1104 m_atr->spot_location.x,
1105 m_atr->spot_location.y,
1106 &x, &y, &win);
1107 }
1108 #ifdef FLASHPLAYER7_WORKAROUND
1109 if (revised_spot_y != -1) {
1110 XTranslateCoordinates(XimServer::gDpy, m_atr->client_window,
1111 DefaultRootWindow(XimServer::gDpy),
1112 m_atr->spot_location.x,
1113 revised_spot_y,
1114 &x, &y, &win);
1115 }
1116 #endif
1117 if (x > -1 && y > -1) {
1118 x += m_candwin_x_off;
1119 y += m_candwin_y_off;
1120
1121 Canddisp *disp = canddisp_singleton();
1122 disp->move(x, y + UNDERLINE_HEIGHT + 1);
1123 m_atr->unset_change_mask(ICA_SpotLocation);
1124 }
1125 #if 0
1126 } else if (m_atr->has_atr(ICA_SpotLocation)) {
1127 int x = -1, y = -1;
1128 Window win;
1129 if (revised_spot_y != -1) {
1130 XTranslateCoordinates(XimServer::gDpy, m_atr->client_window,
1131 DefaultRootWindow(XimServer::gDpy),
1132 m_atr->spot_location.x,
1133 revised_spot_y,
1134 &x, &y, &win);
1135 Canddisp *disp = canddisp_singleton();
1136 disp->move(x, y + UNDERLINE_HEIGHT + 1);
1137 }
1138 #endif
1139 }
1140 }
1141
clear_preedit()1142 void ConvdispOv::clear_preedit()
1143 {
1144 delete m_ov_win;
1145 m_ov_win = NULL;
1146 m_candwin_x_off = 0;
1147 m_candwin_y_off = 0;
1148 }
1149
validate_area()1150 void ConvdispOv::validate_area()
1151 {
1152 Window r, win;
1153 int x;
1154 unsigned int w, h, tmp;
1155 if (m_atr->has_atr(ICA_FocusWindow))
1156 win = m_atr->focus_window;
1157 else
1158 win = m_atr->client_window;
1159
1160 XGetGeometry(XimServer::gDpy, win,
1161 &r, &x, &x, &w, &h, &tmp, &tmp);
1162 // Absurd... (cope with Qt from RedHat7.3, and maybe some other)
1163 m_atr->area.width = (unsigned short)w;
1164 m_atr->area.height = (unsigned short)h;
1165 }
1166
update_icxatr()1167 void ConvdispOv::update_icxatr()
1168 {
1169
1170 if (m_atr->is_changed(ICA_SpotLocation)) {
1171 move_candwin();
1172 update_caret_state();
1173 }
1174
1175 if (!m_ov_win)
1176 return;
1177
1178 if (m_atr->is_changed(ICA_FocusWindow)) {
1179 // Some clients send FocusWindow later
1180 if (!check_win())
1181 return;
1182 }
1183
1184 if (m_atr->is_changed(ICA_Area)) {
1185 if (m_atr->area.width == 0)
1186 validate_area();
1187 #ifdef FLASHPLAYER9_WORKAROUND
1188 if (m_atr->area.width == 500 && m_atr->area.height == 40) {
1189 validate_area();
1190 m_atr->area.x = 0;
1191 m_atr->area.y = 0;
1192 }
1193 #endif
1194 m_ov_win->set_size(m_atr->area.width, m_atr->area.height);
1195 m_atr->unset_change_mask(ICA_Area);
1196 }
1197
1198 if (m_atr->is_changed(ICA_Foreground)) {
1199 m_ov_win->set_fore(m_atr->foreground_pixel);
1200 m_atr->unset_change_mask(ICA_Foreground);
1201 }
1202 if (m_atr->is_changed(ICA_Background)) {
1203 m_ov_win->set_back(m_atr->background_pixel);
1204 m_atr->unset_change_mask(ICA_Background);
1205 }
1206 if (m_atr->is_changed(ICA_FontSet)) {
1207 if (use_xft() == true) {
1208 #if HAVE_XFT_UTF8_STRING
1209 m_ov_win->set_xftfont(m_atr->font_set_name);
1210 #endif
1211 } else {
1212 m_ov_win->set_fontset(m_atr->font_set);
1213 }
1214 m_atr->unset_change_mask(ICA_FontSet);
1215 }
1216
1217 if (m_atr->is_changed(ICA_SpotLocation))
1218 move_candwin();
1219
1220 draw_preedit();
1221 }
1222
draw_preedit()1223 void ConvdispOv::draw_preedit()
1224 {
1225 if (!m_pe)
1226 return;
1227
1228 m_ce_len = m_pe->get_char_count();
1229 if (!m_ce_len) {
1230 clear_preedit();
1231 return;
1232 }
1233
1234 if (!check_win())
1235 return;
1236
1237 m_ce = (char_ent *)malloc(sizeof(char_ent) * m_ce_len);
1238 make_ce_array();
1239 layoutCharEnt();
1240 do_draw_preedit();
1241 free(m_ce);
1242 m_ov_win->draw();
1243 XFlush(XimServer::gDpy);
1244 }
1245
do_draw_preedit()1246 void ConvdispOv::do_draw_preedit()
1247 {
1248 #ifdef FLASHPLAYER7_WORKAROUND
1249 revised_spot_y = -1;
1250 #endif
1251
1252 if (m_atr->has_atr(ICA_Area)) {
1253 #ifdef FLASHPLAYER7_WORKAROUND
1254 // Workaround for brain damaged flash player plugin (at least
1255 // version 7.0 r25). --ekato
1256 //
1257 // Background: flashplayer plugin set same values for
1258 // m_atr->area.y and m_atr->spot_location.y.
1259 //
1260 // 1. If preedit area goes beyond the parent window (browser),
1261 // set the area at the upper side of client window.
1262 //
1263 // 2. If height for preedit is too narrow, make sure to set
1264 // preedit within the client window.
1265
1266 if (m_atr->has_atr(ICA_SpotLocation) && (m_atr->area.y == m_atr->spot_location.y)) {
1267 XWindowAttributes clientattr, topattr;
1268 Window clientwin, topwin, win;
1269 int x, y;
1270 int font_height;
1271
1272 topattr.height = 0;
1273 if (m_atr->has_atr(ICA_FocusWindow))
1274 clientwin = m_atr->focus_window;
1275 else
1276 clientwin = m_atr->client_window;
1277
1278 XGetWindowAttributes(XimServer::gDpy, clientwin, &clientattr);
1279 topwin = getTopWindow(XimServer::gDpy, clientwin);
1280 if (topwin)
1281 XGetWindowAttributes(XimServer::gDpy, topwin, &topattr);
1282 XTranslateCoordinates(XimServer::gDpy, clientwin,
1283 DefaultRootWindow(XimServer::gDpy),
1284 m_atr->area.x,
1285 m_atr->area.y,
1286 &x, &y, &win);
1287 font_height = get_ce_font_height(m_ce, m_ce_len);
1288
1289 if (topattr.height) {
1290 if (y > (topattr.height + topattr.y)) {
1291 // preedit area goes beyond the top window's geometry
1292 if ((y - m_atr->area.y) < topattr.y) {
1293 // Set preedit at upper side of the top
1294 // window. But it may not work because it
1295 // lacks height for window manager's title bar
1296 // and some toolbars of browser...
1297 m_ov_win->set_pos(m_atr->area.x, topattr.y - (y - m_atr->area.y));
1298 revised_spot_y = font_height + topattr.y - (y - m_atr->area.y);
1299 } else {
1300 // Set preedit at upper side of the flash
1301 // player's window.
1302 m_ov_win->set_pos(m_atr->area.x, 0);
1303 revised_spot_y = font_height;
1304 }
1305 } else {
1306 // preedit area is visible within the browser
1307 if ((clientattr.height - m_atr->area.y) < font_height + UNDERLINE_HEIGHT) {
1308 // Make sure preedit+underline to be fit
1309 // within the client window.
1310 m_ov_win->set_pos(m_atr->area.x, clientattr.height - font_height - (UNDERLINE_HEIGHT + 1));
1311 revised_spot_y = clientattr.height - (UNDERLINE_HEIGHT + 1);
1312 } else {
1313 m_ov_win->set_pos(m_atr->area.x, m_atr->area.y);
1314 revised_spot_y = font_height;
1315 }
1316 }
1317 }
1318 } else
1319 #endif // FLASHPLAYER7_WORKAROUND
1320 m_ov_win->set_pos(m_atr->area.x, m_atr->area.y);
1321 } else {
1322 m_ov_win->set_pos(0, 0);
1323 }
1324 m_ov_win->draw_ce(m_ce, m_ce_len);
1325 }
1326
check_win()1327 bool ConvdispOv::check_win()
1328 {
1329 if (!check_atr())
1330 return false; // not enough information to map preedit
1331
1332 if (m_ov_win && !m_atr->is_changed(ICA_FocusWindow))
1333 return true; // no need to update window
1334
1335 if (m_ov_win)
1336 delete m_ov_win;
1337
1338 m_atr->unset_change_mask(ICA_FocusWindow);
1339 m_atr->unset_change_mask(ICA_Foreground);
1340 m_atr->unset_change_mask(ICA_Background);
1341 m_atr->unset_change_mask(ICA_FontSet);
1342
1343 Window w;
1344 if (m_atr->has_atr(ICA_FocusWindow))
1345 w = m_atr->focus_window;
1346 else
1347 w = m_atr->client_window;
1348
1349 m_ov_win = new PeOvWin(w, mIMLang, mEncoding, mLocaleName, this);
1350 m_ov_win->set_size(m_atr->area.width, m_atr->area.height);
1351 m_ov_win->set_fore(m_atr->foreground_pixel);
1352 m_ov_win->set_back(m_atr->background_pixel);
1353 if (use_xft() == true) {
1354 #if HAVE_XFT_UTF8_STRING
1355 m_ov_win->set_xftfont(m_atr->font_set_name);
1356 #endif
1357 } else {
1358 m_ov_win->set_fontset(m_atr->font_set);
1359 }
1360
1361 return true;
1362 }
1363
check_atr()1364 bool ConvdispOv::check_atr()
1365 {
1366 if (!m_atr->has_atr(ICA_FocusWindow) &&
1367 !m_atr->has_atr(ICA_ClientWindow))
1368 return false;
1369
1370 if (!m_atr->has_atr(ICA_SpotLocation)) {
1371 // set at top-left corner unless SpotLocation is available
1372 m_atr->spot_location.x = 0;
1373 m_atr->spot_location.y = 0;
1374 }
1375 if (!m_atr->has_atr(ICA_Area) ||
1376 m_atr->area.width == 0) {
1377 validate_area();
1378 m_atr->area.x = 0;
1379 m_atr->area.y = 0;
1380 }
1381 #ifdef FLASHPLAYER9_WORKAROUND
1382 if (m_atr->has_atr(ICA_Area) &&
1383 m_atr->area.width == 500 && m_atr->area.height == 40) {
1384 validate_area();
1385 m_atr->area.x = 0;
1386 m_atr->area.y = 0;
1387 }
1388 #endif
1389 if (!m_atr->has_atr(ICA_FontSet)) {
1390 if (use_xft() == false)
1391 m_atr->font_set = choose_default_fontset(mIMLang, mLocaleName);
1392 }
1393 if (!m_atr->has_atr(ICA_LineSpace)) {
1394 m_atr->line_space = DEFAULT_FONT_SIZE;
1395 }
1396
1397 if (!m_atr->has_atr(ICA_Foreground))
1398 m_atr->foreground_pixel
1399 = static_cast<C32>(BlackPixel(XimServer::gDpy,
1400 DefaultScreen(XimServer::gDpy)));
1401
1402 if (!m_atr->has_atr(ICA_Background))
1403 m_atr->background_pixel
1404 = static_cast<C32>(WhitePixel(XimServer::gDpy,
1405 DefaultScreen(XimServer::gDpy)));
1406
1407 return true;
1408 }
1409
make_ce_array()1410 void ConvdispOv::make_ce_array()
1411 {
1412 std::list<pe_ustring>::iterator i;
1413 uString::iterator j;
1414 int s;
1415 int c = 0;
1416 for (i = m_pe->ustrings.begin(); i != m_pe->ustrings.end(); ++i) {
1417 s = (*i).stat;
1418 for (j = (*i).s.begin(); j != (*i).s.end(); ++j) {
1419 m_ce[c].c = *j;
1420 m_ce[c].stat = s;
1421 c++;
1422 }
1423 }
1424 }
1425
1426 // Dirty,,,
layoutCharEnt()1427 void ConvdispOv::layoutCharEnt()
1428 {
1429 int i;
1430 int x, y;
1431 int caret_pos = get_caret_pos();
1432 int right_limit = m_atr->area.width + m_atr->area.x;
1433
1434 x = m_atr->spot_location.x;
1435 y = m_atr->spot_location.y;
1436
1437 for (i = 0; i < m_ce_len; i++) {
1438 uchar ch = m_ce[i].c;
1439
1440 char utf8[6];
1441 int len;
1442 if (use_xft() == true) {
1443 #if HAVE_XFT_UTF8_STRING
1444 len = utf8_wctomb((unsigned char *)utf8, ch);
1445 utf8[len] = '\0';
1446
1447 XGlyphInfo ginfo;
1448 XftTextExtentsUtf8(XimServer::gDpy, m_ov_win->mXftFont, (unsigned char *)utf8, len, &ginfo);
1449 m_ce[i].width = ginfo.xOff;
1450 m_ce[i].height = m_ov_win->mXftFontSize;
1451 #endif
1452 } else {
1453 XRectangle ink, logical;
1454
1455 if (!strcmp(mEncoding, "UTF-8")) {
1456 XwcTextExtents(m_atr->font_set, &ch, 1, &ink, &logical);
1457 m_ce[i].width = logical.width;
1458 m_ce[i].height = logical.height;
1459 } else {
1460 len = utf8_wctomb((unsigned char *)utf8, ch);
1461 utf8[len] = '\0';
1462 XimIM *im = get_im_by_id(mKkContext->get_ic()->get_imid());
1463 char *str = im->utf8_to_native_str(utf8);
1464 if (!str) {
1465 logical.width = 0;
1466 logical.height = (unsigned short)((i > 0) ? m_ce[i - 1].height : 0);
1467 } else {
1468 len = static_cast<int>(strlen(str));
1469 XmbTextExtents(m_atr->font_set, str, len, &ink, &logical);
1470 free(str);
1471 }
1472 m_ce[i].width = logical.width;
1473 m_ce[i].height = logical.height;
1474 }
1475 }
1476
1477 if (m_ce[i].width + x > right_limit) {
1478 // goto next line
1479 x = m_atr->area.x;
1480 y += (m_atr->line_space + UNDERLINE_HEIGHT);
1481 }
1482 m_ce[i].x = x - m_atr->area.x;
1483 m_ce[i].y = y - m_atr->area.y;
1484 #ifdef FLASHPLAYER7_WORKAROUND
1485 // workaround for brain damaged flash player plugin
1486 if (m_ce[i].y == 0)
1487 m_ce[i].y += m_ce[i].height;
1488 #endif
1489 x += m_ce[i].width;
1490 }
1491
1492 switch (XimServer::gCandWinPosType) {
1493 case Caret:
1494 if (caret_pos == 0) {
1495 m_candwin_x_off = m_ce[caret_pos].x - m_atr->spot_location.x;
1496 m_candwin_y_off = m_ce[caret_pos].y - m_atr->spot_location.y;
1497 } else {
1498 m_candwin_x_off = m_ce[caret_pos - 1].x + m_ce[caret_pos - 1].width - m_atr->spot_location.x;
1499 m_candwin_y_off = m_ce[caret_pos - 1].y - m_atr->spot_location.y;
1500 }
1501 break;
1502 case Right:
1503 m_candwin_x_off = m_ce[m_ce_len - 1].x + m_ce[m_ce_len - 1].width - m_atr->spot_location.x;
1504 m_candwin_y_off = m_ce[m_ce_len - 1].y - m_atr->spot_location.y;
1505 break;
1506 case Left:
1507 default:
1508 break;
1509 }
1510 }
1511
1512 #ifdef FLASHPLAYER7_WORKAROUND
get_ce_font_height(char_ent * ce,int len)1513 int ConvdispOv::get_ce_font_height(char_ent *ce, int len)
1514 {
1515 int i, h = 0;
1516 for (i = 0; i < len; i++) {
1517 if (ce[i].height > h)
1518 h = ce[i].height;
1519 }
1520 return h;
1521 }
1522 #endif
1523
use_xft()1524 bool ConvdispOv::use_xft()
1525 {
1526 return m_atr->use_xft();
1527 }
1528
1529 // On the spot style
ConvdispOs(InputContext * k,icxatr * a,Connection * c)1530 ConvdispOs::ConvdispOs(InputContext *k, icxatr *a, Connection *c)
1531 : Convdisp(k, a)
1532 {
1533 XimIC *ic = k->get_ic();
1534 mConn = c;
1535 mImid = ic->get_imid();
1536 mIcid = ic->get_icid();
1537 mPrevLen = 0;
1538 }
1539
~ConvdispOs()1540 ConvdispOs::~ConvdispOs()
1541 {
1542 }
1543
update_preedit()1544 void ConvdispOs::update_preedit()
1545 {
1546 move_candwin();
1547 if (!m_pe)
1548 return;
1549
1550 TxPacket *t;
1551
1552 int len, caret_pos;
1553 len = m_pe->get_char_count();
1554 caret_pos = m_pe->caret_pos;
1555
1556 if (mPrevLen == 0 && len == 0)
1557 return;
1558
1559 if (mPrevLen == 0 && len) {
1560 t = createTxPacket(XIM_PREEDIT_START, 0);
1561 t->pushC16(mImid);
1562 t->pushC16(mIcid);
1563 mConn->push_passive_packet(t);
1564 }
1565
1566 t = createTxPacket(XIM_PREEDIT_DRAW, 0);
1567 t->pushC16(mImid);
1568 t->pushC16(mIcid);
1569 t->pushC32(caret_pos);// caret
1570 t->pushC32(0); // chg_first
1571 t->pushC32(mPrevLen); // chg_length
1572
1573 if (!m_pe->ustrings.empty())
1574 t->pushC32(0);
1575 else
1576 t->pushC32(3);
1577
1578 compose_preedit_array(t);
1579 compose_feedback_array(t);
1580 mConn->push_passive_packet(t);
1581
1582 if (mPrevLen && len == 0) {
1583 t = createTxPacket(XIM_PREEDIT_DONE, 0);
1584 t->pushC16(mImid);
1585 t->pushC16(mIcid);
1586 mConn->push_passive_packet(t);
1587 }
1588 mPrevLen = len;
1589
1590 if (len) {
1591 t = createTxPacket(XIM_PREEDIT_CARET, 0);
1592 t->pushC16(mImid);
1593 t->pushC16(mIcid);
1594 t->pushC32(caret_pos);
1595 t->pushC32(XIMAbsolutePosition);
1596 t->pushC32(XIMIsPrimary);
1597 mConn->push_passive_packet(t);
1598 }
1599 }
1600
move_candwin()1601 void ConvdispOs::move_candwin()
1602 {
1603 InputContext *focusedContext = InputContext::focusedContext();
1604 if (!focusedContext || focusedContext != mKkContext)
1605 return;
1606
1607 if (m_atr->has_atr(ICA_ClientWindow)) {
1608 int x, y;
1609 Window win;
1610 XWindowAttributes xattr;
1611
1612 if (!m_atr->has_atr(ICA_SpotLocation)) {
1613 m_atr->spot_location.x = 0;
1614 m_atr->spot_location.y = 0;
1615 }
1616
1617 XTranslateCoordinates(XimServer::gDpy, m_atr->client_window,
1618 DefaultRootWindow(XimServer::gDpy),
1619 m_atr->spot_location.x,
1620 m_atr->spot_location.y,
1621 &x, &y, &win);
1622
1623 Canddisp *disp = canddisp_singleton();
1624
1625 if (m_atr->has_atr(ICA_SpotLocation))
1626 disp->move(x, y + 36); // 36 pixel seems too long.
1627 // Is there any way to get current preedit
1628 // height?
1629 else {
1630 XGetWindowAttributes(XimServer::gDpy, m_atr->client_window,
1631 &xattr);
1632 //disp->move(x + xattr.width + 2, y + 2); //upper-right side
1633 disp->move(x, y + xattr.height + 2); //lower-left side
1634 }
1635 }
1636
1637 }
1638
clear_preedit()1639 void ConvdispOs::clear_preedit()
1640 {
1641 mPrevLen = 0;
1642 }
1643
update_icxatr()1644 void ConvdispOs::update_icxatr()
1645 {
1646 }
1647
compose_preedit_array(TxPacket * t)1648 void ConvdispOs::compose_preedit_array(TxPacket *t)
1649 {
1650 uString s;
1651 std::list<pe_ustring>::iterator it;
1652 for (it = m_pe->ustrings.begin(); it != m_pe->ustrings.end(); ++it) {
1653 append_ustring(&s, &(*it).s);
1654 }
1655
1656 XimIM *im = get_im_by_id(mKkContext->get_ic()->get_imid());
1657 char *c = im->uStringToCtext(&s);
1658 int i, len = 0;
1659 if (c)
1660 len = static_cast<int>(strlen(c));
1661 t->pushC16((C16)len); // LENGTH
1662 for (i = 0; i < len; i++) {
1663 t->pushC8(c[i]); // CTEXT
1664 }
1665 len = pad4(len + 2);
1666 for (i = 0; i < len; i++) {
1667 t->pushC8(0); // PADDING
1668 }
1669 free(c);
1670 }
1671
compose_feedback_array(TxPacket * t)1672 void ConvdispOs::compose_feedback_array(TxPacket *t)
1673 {
1674 int i, len, stat, xstat;
1675 len = m_pe->get_char_count();
1676 t->pushC16((C16)(len * 4));
1677 t->pushC16(0);
1678 std::list<pe_ustring>::iterator it;
1679 for (it = m_pe->ustrings.begin(); it != m_pe->ustrings.end(); ++it) {
1680 len = static_cast<int>((*it).s.size());
1681 stat = (*it).stat;
1682 xstat = FB_None;
1683 if (stat & PE_REVERSE)
1684 xstat |= FB_Reverse;
1685
1686 if (stat & PE_UNDERLINE)
1687 xstat |= FB_Underline;
1688
1689 if (stat & PE_HILIGHT)
1690 xstat |= FB_Highlight;
1691
1692 for (i = 0; i < len; i++) {
1693 t->pushC32(xstat);
1694 }
1695 }
1696 }
1697
use_xft()1698 bool ConvdispOs::use_xft()
1699 {
1700 return true;
1701 }
1702
1703 #ifdef FLASHPLAYER7_WORKAROUND
getTopWindow(Display * d,Window w)1704 static Window getTopWindow(Display *d, Window w)
1705 {
1706 Window root, parent, *children;
1707 unsigned int nchild;
1708 Status retval;
1709
1710 for (;;) {
1711 retval = XQueryTree(d, w, &root, &parent, &children, &nchild);
1712 if (retval == 0)
1713 return 0;
1714 if (children)
1715 XFree(children);
1716 if (parent == root)
1717 break;
1718 w = parent;
1719 }
1720 return w;
1721 };
1722 #endif
1723
1724 /*
1725 * Local variables:
1726 * c-indent-level: 4
1727 * c-basic-offset: 4
1728 * End:
1729 */
1730