source: trunk/src/gui/inputmethod/qximinputcontext_x11.cpp@ 441

Last change on this file since 441 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 26.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/****************************************************************************
43**
44** Implementation of QXIMInputContext class
45**
46** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
47**
48** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
49** license. You may use this file under your Qt license. Following
50** description is copied from their original file headers. Contact
51** [email protected] if any conditions of this licensing are
52** not clear to you.
53**
54****************************************************************************/
55
56#include "qdebug.h"
57#include "qximinputcontext_p.h"
58
59#if !defined(QT_NO_IM)
60
61QT_BEGIN_NAMESPACE
62
63#if !defined(QT_NO_XIM)
64
65QT_BEGIN_INCLUDE_NAMESPACE
66#include "qplatformdefs.h"
67
68#include "qapplication.h"
69#include "qwidget.h"
70#include "qstring.h"
71#include "qlist.h"
72#include "qtextcodec.h"
73#include "qevent.h"
74#include "qtextformat.h"
75
76#include "qx11info_x11.h"
77
78#include <stdlib.h>
79#include <limits.h>
80QT_END_INCLUDE_NAMESPACE
81
82// #define QT_XIM_DEBUG
83#ifdef QT_XIM_DEBUG
84#define XIM_DEBUG qDebug
85#else
86#define XIM_DEBUG if (0) qDebug
87#endif
88
89// from qapplication_x11.cpp
90// #### move to X11 struct
91extern XIMStyle qt_xim_preferred_style;
92extern char *qt_ximServer;
93extern int qt_ximComposingKeycode;
94extern QTextCodec * qt_input_mapper;
95
96XIMStyle QXIMInputContext::xim_style = 0;
97// moved from qapplication_x11.cpp
98static const XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing;
99
100
101extern "C" {
102#ifdef USE_X11R6_XIM
103 static void xim_create_callback(XIM /*im*/,
104 XPointer client_data,
105 XPointer /*call_data*/)
106 {
107 QXIMInputContext *qic = reinterpret_cast<QXIMInputContext *>(client_data);
108 // qDebug("xim_create_callback");
109 qic->create_xim();
110 }
111
112 static void xim_destroy_callback(XIM /*im*/,
113 XPointer client_data,
114 XPointer /*call_data*/)
115 {
116 QXIMInputContext *qic = reinterpret_cast<QXIMInputContext *>(client_data);
117 // qDebug("xim_destroy_callback");
118 qic->close_xim();
119 XRegisterIMInstantiateCallback(X11->display, 0, 0, 0,
120 (XIMProc) xim_create_callback, reinterpret_cast<char *>(qic));
121 }
122#endif // USE_X11R6_XIM
123
124 static int xic_start_callback(XIC, XPointer client_data, XPointer) {
125 QXIMInputContext *qic = (QXIMInputContext *) client_data;
126 if (!qic) {
127 XIM_DEBUG("xic_start_callback: no qic");
128 return 0;
129 }
130 QXIMInputContext::ICData *data = qic->icData();
131 if (!data) {
132 XIM_DEBUG("xic_start_callback: no ic data");
133 return 0;
134 }
135 XIM_DEBUG("xic_start_callback");
136
137 data->clear();
138 data->composing = true;
139
140 return 0;
141 }
142
143 static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) {
144 QXIMInputContext *qic = (QXIMInputContext *) client_data;
145 if (!qic) {
146 XIM_DEBUG("xic_draw_callback: no qic");
147 return 0;
148 }
149 QXIMInputContext::ICData *data = qic->icData();
150 if (!data) {
151 XIM_DEBUG("xic_draw_callback: no ic data");
152 return 0;
153 }
154 XIM_DEBUG("xic_draw_callback");
155
156
157 if(!data->composing) {
158 data->clear();
159 data->composing = true;
160 }
161
162 XIMPreeditDrawCallbackStruct *drawstruct = (XIMPreeditDrawCallbackStruct *) call_data;
163 XIMText *text = (XIMText *) drawstruct->text;
164 int cursor = drawstruct->caret, sellen = 0, selstart = 0;
165
166 if (!drawstruct->caret && !drawstruct->chg_first && !drawstruct->chg_length && !text) {
167 if(data->text.isEmpty()) {
168 XIM_DEBUG("compose emptied");
169 // if the composition string has been emptied, we need
170 // to send an InputMethodEnd event
171 QInputMethodEvent e;
172 qic->sendEvent(e);
173 data->clear();
174
175 // if the commit string has coming after here, InputMethodStart
176 // will be sent dynamically
177 }
178 return 0;
179 }
180
181 if (text) {
182 char *str = 0;
183 if (text->encoding_is_wchar) {
184 int l = wcstombs(NULL, text->string.wide_char, text->length);
185 if (l != -1) {
186 str = new char[l + 1];
187 wcstombs(str, text->string.wide_char, l);
188 str[l] = 0;
189 }
190 } else
191 str = text->string.multi_byte;
192
193 if (!str)
194 return 0;
195
196 QString s = QString::fromLocal8Bit(str);
197
198 if (text->encoding_is_wchar)
199 delete [] str;
200
201 if (drawstruct->chg_length < 0)
202 data->text.replace(drawstruct->chg_first, INT_MAX, s);
203 else
204 data->text.replace(drawstruct->chg_first, drawstruct->chg_length, s);
205
206 if (data->selectedChars.size() < data->text.length()) {
207 // expand the selectedChars array if the compose string is longer
208 int from = data->selectedChars.size();
209 data->selectedChars.resize(data->text.length());
210 for (int x = from; x < data->selectedChars.size(); ++x)
211 data->selectedChars.clearBit(x);
212 }
213
214 // determine if the changed chars are selected based on text->feedback
215 for (int x = 0; x < text->length; ++x)
216 data->selectedChars.setBit(x + drawstruct->chg_first,
217 (text->feedback ? (text->feedback[x] & XIMReverse) : 0));
218
219 // figure out where the selection starts, and how long it is
220 bool started = false;
221 for (int x = 0; x < qMin(data->selectedChars.size(), data->text.length()); ++x) {
222 if (started) {
223 if (data->selectedChars.testBit(x)) ++sellen;
224 else break;
225 } else {
226 if (data->selectedChars.testBit(x)) {
227 selstart = x;
228 started = true;
229 sellen = 1;
230 }
231 }
232 }
233 } else {
234 if (drawstruct->chg_length == 0)
235 drawstruct->chg_length = -1;
236
237 data->text.remove(drawstruct->chg_first, drawstruct->chg_length);
238 bool qt_compose_emptied = data->text.isEmpty();
239 if (qt_compose_emptied) {
240 XIM_DEBUG("compose emptied 2 text=%s", data->text.toUtf8().constData());
241 // if the composition string has been emptied, we need
242 // to send an InputMethodEnd event
243 QInputMethodEvent e;
244 qic->sendEvent(e);
245 data->clear();
246 // if the commit string has coming after here, InputMethodStart
247 // will be sent dynamically
248 return 0;
249 }
250 }
251
252 XIM_DEBUG("sending compose: '%s', cursor=%d, sellen=%d",
253 data->text.toUtf8().constData(), cursor, sellen);
254 QList<QInputMethodEvent::Attribute> attrs;
255 if (selstart > 0)
256 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, selstart,
257 qic->standardFormat(QInputContext::PreeditFormat));
258 if (sellen)
259 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selstart, sellen,
260 qic->standardFormat(QInputContext::SelectionFormat));
261 if (selstart + sellen < data->text.length())
262 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
263 selstart + sellen, data->text.length() - selstart - sellen,
264 qic->standardFormat(QInputContext::PreeditFormat));
265 attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, sellen ? 0 : 1, QVariant());
266 QInputMethodEvent e(data->text, attrs);
267 data->preeditEmpty = data->text.isEmpty();
268 qic->sendEvent(e);
269
270 return 0;
271 }
272
273 static int xic_done_callback(XIC, XPointer client_data, XPointer) {
274 QXIMInputContext *qic = (QXIMInputContext *) client_data;
275 if (!qic)
276 return 0;
277
278 XIM_DEBUG("xic_done_callback");
279 // Don't send InputMethodEnd here. QXIMInputContext::x11FilterEvent()
280 // handles InputMethodEnd with commit string.
281 return 0;
282 }
283}
284
285void QXIMInputContext::ICData::clear()
286{
287 text = QString();
288 selectedChars.clear();
289 composing = false;
290 preeditEmpty = true;
291}
292
293QXIMInputContext::ICData *QXIMInputContext::icData() const
294{
295 if (QWidget *w = focusWidget())
296 return ximData.value(w->effectiveWinId());
297 return 0;
298}
299/* The cache here is needed, as X11 leaks a few kb for every
300 XFreeFontSet call, so we avoid creating and deletion of fontsets as
301 much as possible
302*/
303static XFontSet fontsetCache[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
304static int fontsetRefCount = 0;
305
306static const char * const fontsetnames[] = {
307 "-*-fixed-medium-r-*-*-16-*,-*-*-medium-r-*-*-16-*",
308 "-*-fixed-medium-i-*-*-16-*,-*-*-medium-i-*-*-16-*",
309 "-*-fixed-bold-r-*-*-16-*,-*-*-bold-r-*-*-16-*",
310 "-*-fixed-bold-i-*-*-16-*,-*-*-bold-i-*-*-16-*",
311 "-*-fixed-medium-r-*-*-24-*,-*-*-medium-r-*-*-24-*",
312 "-*-fixed-medium-i-*-*-24-*,-*-*-medium-i-*-*-24-*",
313 "-*-fixed-bold-r-*-*-24-*,-*-*-bold-r-*-*-24-*",
314 "-*-fixed-bold-i-*-*-24-*,-*-*-bold-i-*-*-24-*"
315};
316
317static XFontSet getFontSet(const QFont &f)
318{
319 int i = 0;
320 if (f.italic())
321 i |= 1;
322 if (f.bold())
323 i |= 2;
324
325 if (f.pointSize() > 20)
326 i += 4;
327
328 if (!fontsetCache[i]) {
329 Display* dpy = X11->display;
330 int missCount;
331 char** missList;
332 fontsetCache[i] = XCreateFontSet(dpy, fontsetnames[i], &missList, &missCount, 0);
333 if(missCount > 0)
334 XFreeStringList(missList);
335 if (!fontsetCache[i]) {
336 fontsetCache[i] = XCreateFontSet(dpy, "-*-fixed-*-*-*-*-16-*", &missList, &missCount, 0);
337 if(missCount > 0)
338 XFreeStringList(missList);
339 if (!fontsetCache[i])
340 fontsetCache[i] = (XFontSet)-1;
341 }
342 }
343 return (fontsetCache[i] == (XFontSet)-1) ? 0 : fontsetCache[i];
344}
345
346
347
348QXIMInputContext::QXIMInputContext()
349{
350 if (!qt_xim_preferred_style) // no configured input style, use the default
351 qt_xim_preferred_style = xim_default_style;
352
353 xim = 0;
354 QByteArray ximServerName(qt_ximServer);
355 if (qt_ximServer)
356 ximServerName.prepend("@im=");
357 else
358 ximServerName = "";
359
360 if (!XSupportsLocale())
361#ifndef QT_NO_DEBUG
362 qWarning("Qt: Locale not supported on X server")
363#endif
364 ;
365#ifdef USE_X11R6_XIM
366 else if (XSetLocaleModifiers (ximServerName.constData()) == 0)
367 qWarning("Qt: Cannot set locale modifiers: %s", ximServerName.constData());
368 else
369 XRegisterIMInstantiateCallback(X11->display, 0, 0, 0,
370 (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));
371#else // !USE_X11R6_XIM
372 else if (XSetLocaleModifiers ("") == 0)
373 qWarning("Qt: Cannot set locale modifiers");
374 else
375 QXIMInputContext::create_xim();
376#endif // USE_X11R6_XIM
377}
378
379
380/*!\internal
381 Creates the application input method.
382*/
383void QXIMInputContext::create_xim()
384{
385 ++fontsetRefCount;
386#ifndef QT_NO_XIM
387 xim = XOpenIM(X11->display, 0, 0, 0);
388 if (xim) {
389
390#ifdef USE_X11R6_XIM
391 XIMCallback destroy;
392 destroy.callback = (XIMProc) xim_destroy_callback;
393 destroy.client_data = XPointer(this);
394 if (XSetIMValues(xim, XNDestroyCallback, &destroy, (char *) 0) != 0)
395 qWarning("Xlib doesn't support destroy callback");
396#endif // USE_X11R6_XIM
397
398 XIMStyles *styles = 0;
399 XGetIMValues(xim, XNQueryInputStyle, &styles, (char *) 0, (char *) 0);
400 if (styles) {
401 int i;
402 for (i = 0; !xim_style && i < styles->count_styles; i++) {
403 if (styles->supported_styles[i] == qt_xim_preferred_style) {
404 xim_style = qt_xim_preferred_style;
405 break;
406 }
407 }
408 // if the preferred input style couldn't be found, look for
409 // Nothing
410 for (i = 0; !xim_style && i < styles->count_styles; i++) {
411 if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) {
412 xim_style = XIMPreeditNothing | XIMStatusNothing;
413 break;
414 }
415 }
416 // ... and failing that, None.
417 for (i = 0; !xim_style && i < styles->count_styles; i++) {
418 if (styles->supported_styles[i] == (XIMPreeditNone |
419 XIMStatusNone)) {
420 xim_style = XIMPreeditNone | XIMStatusNone;
421 break;
422 }
423 }
424
425 // qDebug("QApplication: using im style %lx", xim_style);
426 XFree((char *)styles);
427 }
428
429 if (xim_style) {
430
431#ifdef USE_X11R6_XIM
432 XUnregisterIMInstantiateCallback(X11->display, 0, 0, 0,
433 (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));
434#endif // USE_X11R6_XIM
435
436 if (QWidget *focusWidget = QApplication::focusWidget()) {
437 // reinitialize input context after the input method
438 // server (like SCIM) has been launched without
439 // requiring the user to manually switch focus.
440 if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled)
441 && focusWidget->testAttribute(Qt::WA_WState_Created))
442 setFocusWidget(focusWidget);
443 }
444 // following code fragment is not required for immodule
445 // version of XIM
446#if 0
447 QWidgetList list = qApp->topLevelWidgets();
448 for (int i = 0; i < list.size(); ++i) {
449 QWidget *w = list.at(i);
450 w->d->createTLSysExtra();
451 }
452#endif
453 } else {
454 // Give up
455 qWarning("No supported input style found."
456 " See InputMethod documentation.");
457 close_xim();
458 }
459 }
460#endif // QT_NO_XIM
461}
462
463/*!\internal
464 Closes the application input method.
465*/
466void QXIMInputContext::close_xim()
467{
468 for(QHash<WId, ICData *>::const_iterator i = ximData.constBegin(),
469 e = ximData.constEnd(); i != e; ++i) {
470 ICData *data = i.value();
471 if (data->ic)
472 XDestroyIC(data->ic);
473 delete data;
474 }
475 ximData.clear();
476
477 if ( --fontsetRefCount == 0 ) {
478 Display *dpy = X11->display;
479 for ( int i = 0; i < 8; i++ ) {
480 if ( fontsetCache[i] && fontsetCache[i] != (XFontSet)-1 ) {
481 XFreeFontSet(dpy, fontsetCache[i]);
482 fontsetCache[i] = 0;
483 }
484 }
485 }
486
487 setFocusWidget(0);
488 xim = 0;
489}
490
491
492
493QXIMInputContext::~QXIMInputContext()
494{
495 XIM old_xim = xim; // close_xim clears xim pointer.
496 close_xim();
497 if (old_xim)
498 XCloseIM(old_xim);
499}
500
501
502QString QXIMInputContext::identifierName()
503{
504 // the name should be "xim" rather than "XIM" to be consistent
505 // with corresponding immodule of GTK+
506 return QLatin1String("xim");
507}
508
509
510QString QXIMInputContext::language()
511{
512 QString language;
513 if (xim) {
514 QByteArray locale(XLocaleOfIM(xim));
515
516 if (locale.startsWith("zh")) {
517 // Chinese language should be formed as "zh_CN", "zh_TW", "zh_HK"
518 language = QLatin1String(locale.left(5));
519 } else {
520 // other languages should be two-letter ISO 639 language code
521 language = QLatin1String(locale.left(2));
522 }
523 }
524 return language;
525}
526
527void QXIMInputContext::reset()
528{
529 QWidget *w = focusWidget();
530 if (!w)
531 return;
532
533 ICData *data = ximData.value(w->effectiveWinId());
534 if (!data)
535 return;
536
537 if (data->ic) {
538 char *mb = XmbResetIC(data->ic);
539 QInputMethodEvent e;
540 if (mb) {
541 e.setCommitString(QString::fromLocal8Bit(mb));
542 XFree(mb);
543 data->preeditEmpty = false; // force sending an event
544 }
545 if (!data->preeditEmpty) {
546 sendEvent(e);
547 update();
548 }
549 }
550 data->clear();
551}
552
553void QXIMInputContext::widgetDestroyed(QWidget *w)
554{
555 QInputContext::widgetDestroyed(w);
556 ICData *data = ximData.take(w->effectiveWinId());
557 if (!data)
558 return;
559
560 data->clear();
561 if (data->ic)
562 XDestroyIC(data->ic);
563 delete data;
564}
565
566void QXIMInputContext::mouseHandler(int pos, QMouseEvent *e)
567{
568 if(e->type() != QEvent::MouseButtonPress)
569 return;
570
571 XIM_DEBUG("QXIMInputContext::mouseHandler pos=%d", pos);
572 if (QWidget *w = focusWidget()) {
573 ICData *data = ximData.value(w->effectiveWinId());
574 if (!data)
575 return;
576 if (pos < 0 || pos > data->text.length())
577 reset();
578 // ##### handle mouse position
579 }
580}
581
582bool QXIMInputContext::isComposing() const
583{
584 QWidget *w = focusWidget();
585 if (!w)
586 return false;
587
588 ICData *data = ximData.value(w->effectiveWinId());
589 if (!data)
590 return false;
591 return data->composing;
592}
593
594void QXIMInputContext::setFocusWidget(QWidget *w)
595{
596 if (!xim)
597 return;
598 QWidget *oldFocus = focusWidget();
599 if (oldFocus == w)
600 return;
601
602 if (language() != QLatin1String("ja"))
603 reset();
604
605 if (oldFocus) {
606 ICData *data = ximData.value(oldFocus->effectiveWinId());
607 if (data && data->ic)
608 XUnsetICFocus(data->ic);
609 }
610
611 QInputContext::setFocusWidget(w);
612
613 if (!w)
614 return;
615
616 ICData *data = ximData.value(w->effectiveWinId());
617 if (!data)
618 data = createICData(w);
619
620 if (data->ic)
621 XSetICFocus(data->ic);
622
623 update();
624}
625
626
627bool QXIMInputContext::x11FilterEvent(QWidget *keywidget, XEvent *event)
628{
629 int xkey_keycode = event->xkey.keycode;
630 if (!keywidget->testAttribute(Qt::WA_WState_Created))
631 return false;
632 if (XFilterEvent(event, keywidget->effectiveWinId())) {
633 qt_ximComposingKeycode = xkey_keycode; // ### not documented in xlib
634
635 update();
636
637 return true;
638 }
639 if (event->type != XKeyPress || event->xkey.keycode != 0)
640 return false;
641
642 QWidget *w = focusWidget();
643 if (keywidget != w)
644 return false;
645 ICData *data = ximData.value(w->effectiveWinId());
646 if (!data)
647 return false;
648
649 // input method has sent us a commit string
650 QByteArray string;
651 string.resize(513);
652 KeySym key; // unused
653 Status status; // unused
654 QString text;
655 int count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(),
656 &key, &status);
657
658 if (status == XBufferOverflow) {
659 string.resize(count + 1);
660 count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(),
661 &key, &status);
662 }
663 if (count > 0) {
664 // XmbLookupString() gave us some text, convert it to unicode
665 text = qt_input_mapper->toUnicode(string.constData() , count);
666 if (text.isEmpty()) {
667 // codec couldn't convert to unicode? this can happen when running in the
668 // C locale (or with no LANG set). try converting from latin-1
669 text = QString::fromLatin1(string.constData(), count);
670 }
671 }
672
673#if 0
674 if (!(xim_style & XIMPreeditCallbacks) || !isComposing()) {
675 // ############### send a regular key event here!
676 ;
677 }
678#endif
679
680 QInputMethodEvent e;
681 e.setCommitString(text);
682 sendEvent(e);
683 data->clear();
684
685 update();
686
687 return true;
688}
689
690
691QXIMInputContext::ICData *QXIMInputContext::createICData(QWidget *w)
692{
693 ICData *data = new ICData;
694 data->widget = w;
695 data->preeditEmpty = true;
696
697 XVaNestedList preedit_attr = 0;
698 XIMCallback startcallback, drawcallback, donecallback;
699
700 QFont font = w->font();
701 data->fontset = getFontSet(font);
702
703 if (xim_style & XIMPreeditArea) {
704 XRectangle rect;
705 rect.x = 0;
706 rect.y = 0;
707 rect.width = w->width();
708 rect.height = w->height();
709
710 preedit_attr = XVaCreateNestedList(0,
711 XNArea, &rect,
712 XNFontSet, data->fontset,
713 (char *) 0);
714 } else if (xim_style & XIMPreeditPosition) {
715 XPoint spot;
716 spot.x = 1;
717 spot.y = 1;
718
719 preedit_attr = XVaCreateNestedList(0,
720 XNSpotLocation, &spot,
721 XNFontSet, data->fontset,
722 (char *) 0);
723 } else if (xim_style & XIMPreeditCallbacks) {
724 startcallback.client_data = (XPointer) this;
725 startcallback.callback = (XIMProc) xic_start_callback;
726 drawcallback.client_data = (XPointer) this;
727 drawcallback.callback = (XIMProc)xic_draw_callback;
728 donecallback.client_data = (XPointer) this;
729 donecallback.callback = (XIMProc) xic_done_callback;
730
731 preedit_attr = XVaCreateNestedList(0,
732 XNPreeditStartCallback, &startcallback,
733 XNPreeditDrawCallback, &drawcallback,
734 XNPreeditDoneCallback, &donecallback,
735 (char *) 0);
736 }
737
738 if (preedit_attr) {
739 data->ic = XCreateIC(xim,
740 XNInputStyle, xim_style,
741 XNClientWindow, w->effectiveWinId(),
742 XNPreeditAttributes, preedit_attr,
743 (char *) 0);
744 XFree(preedit_attr);
745 } else {
746 data->ic = XCreateIC(xim,
747 XNInputStyle, xim_style,
748 XNClientWindow, w->effectiveWinId(),
749 (char *) 0);
750 }
751
752 if (data->ic) {
753 // when resetting the input context, preserve the input state
754 (void) XSetICValues(data->ic, XNResetState, XIMPreserveState, (char *) 0);
755 } else {
756 qWarning("Failed to create XIC");
757 }
758
759 ximData[w->effectiveWinId()] = data;
760 return data;
761}
762
763void QXIMInputContext::update()
764{
765 QWidget *w = focusWidget();
766 if (!w)
767 return;
768
769 ICData *data = ximData.value(w->effectiveWinId());
770 if (!data || !data->ic)
771 return;
772
773 QRect r = w->inputMethodQuery(Qt::ImMicroFocus).toRect();
774 QPoint p;
775 if (w->nativeParentWidget())
776 p = w->mapTo(w->nativeParentWidget(), QPoint((r.left() + r.right() + 1)/2, r.bottom()));
777 else
778 p = QPoint((r.left() + r.right() + 1)/2, r.bottom());
779 XPoint spot;
780 spot.x = p.x();
781 spot.y = p.y();
782
783 r = w->rect();
784 XRectangle area;
785 area.x = r.x();
786 area.y = r.y();
787 area.width = r.width();
788 area.height = r.height();
789
790 XFontSet fontset = getFontSet(qvariant_cast<QFont>(w->inputMethodQuery(Qt::ImFont)));
791 if (data->fontset == fontset)
792 fontset = 0;
793 else
794 data->fontset = fontset;
795
796 XVaNestedList preedit_attr;
797 if (fontset)
798 preedit_attr = XVaCreateNestedList(0,
799 XNSpotLocation, &spot,
800 XNArea, &area,
801 XNFontSet, fontset,
802 (char *) 0);
803 else
804 preedit_attr = XVaCreateNestedList(0,
805 XNSpotLocation, &spot,
806 XNArea, &area,
807 (char *) 0);
808
809 XSetICValues(data->ic, XNPreeditAttributes, preedit_attr, (char *) 0);
810 XFree(preedit_attr);
811}
812
813
814#else
815/*
816 When QT_NO_XIM is defined, we provide a dummy implementation for
817 this class. The reason for this is that the header file is moc'ed
818 regardless of QT_NO_XIM. The best would be to remove the file
819 completely from the pri file is QT_NO_XIM was defined, or for moc
820 to understand this preprocessor directive. Since the header does
821 not declare this class when QT_NO_XIM is defined, this is dead
822 code.
823*/
824bool QXIMInputContext::isComposing() const { return false; }
825QString QXIMInputContext::identifierName() { return QString(); }
826void QXIMInputContext::mouseHandler(int, QMouseEvent *) {}
827void QXIMInputContext::setFocusWidget(QWidget *) {}
828void QXIMInputContext::reset() {}
829void QXIMInputContext::update() {}
830QXIMInputContext::~QXIMInputContext() {}
831void QXIMInputContext::widgetDestroyed(QWidget *) {}
832QString QXIMInputContext::language() { return QString(); }
833bool QXIMInputContext::x11FilterEvent(QWidget *, XEvent *) { return true; }
834
835#endif //QT_NO_XIM
836
837QT_END_NAMESPACE
838
839#endif //QT_NO_IM
Note: See TracBrowser for help on using the repository browser.