From f67b8df3ebdba2d398b9cce686b7c644adffff08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 7 May 2011 00:02:01 +0200 Subject: library split --- src/widgets/inputmethod/qximinputcontext_x11.cpp | 885 +++++++++++++++++++++++ 1 file changed, 885 insertions(+) create mode 100644 src/widgets/inputmethod/qximinputcontext_x11.cpp (limited to 'src/widgets/inputmethod/qximinputcontext_x11.cpp') diff --git a/src/widgets/inputmethod/qximinputcontext_x11.cpp b/src/widgets/inputmethod/qximinputcontext_x11.cpp new file mode 100644 index 0000000000..155796828e --- /dev/null +++ b/src/widgets/inputmethod/qximinputcontext_x11.cpp @@ -0,0 +1,885 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/**************************************************************************** +** +** Implementation of QXIMInputContext class +** +** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved. +** +** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own +** license. You may use this file under your Qt license. Following +** description is copied from their original file headers. Contact +** immodule-qt@freedesktop.org if any conditions of this licensing are +** not clear to you. +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qdebug.h" +#include "qximinputcontext_p.h" + +#if !defined(QT_NO_IM) + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_XIM) + +QT_BEGIN_INCLUDE_NAMESPACE +#include "qplatformdefs.h" + +#include "qapplication.h" +#include "qwidget.h" +#include "qstring.h" +#include "qlist.h" +#include "qtextcodec.h" +#include "qevent.h" +#include "qtextformat.h" + +#include "qx11info_x11.h" + +#include +#include +QT_END_INCLUDE_NAMESPACE + +// #define QT_XIM_DEBUG +#ifdef QT_XIM_DEBUG +#define XIM_DEBUG qDebug +#else +#define XIM_DEBUG if (0) qDebug +#endif + +// from qapplication_x11.cpp +// #### move to X11 struct +extern XIMStyle qt_xim_preferred_style; +extern char *qt_ximServer; +extern int qt_ximComposingKeycode; +extern QTextCodec * qt_input_mapper; + +XIMStyle QXIMInputContext::xim_style = 0; +// moved from qapplication_x11.cpp +static const XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing; + + +extern "C" { +#ifdef USE_X11R6_XIM + static void xim_create_callback(XIM /*im*/, + XPointer client_data, + XPointer /*call_data*/) + { + QXIMInputContext *qic = reinterpret_cast(client_data); + // qDebug("xim_create_callback"); + qic->create_xim(); + } + + static void xim_destroy_callback(XIM /*im*/, + XPointer client_data, + XPointer /*call_data*/) + { + QXIMInputContext *qic = reinterpret_cast(client_data); + // qDebug("xim_destroy_callback"); + qic->close_xim(); + XRegisterIMInstantiateCallback(X11->display, 0, 0, 0, + (XIMProc) xim_create_callback, reinterpret_cast(qic)); + } +#endif // USE_X11R6_XIM + + static int xic_start_callback(XIC, XPointer client_data, XPointer) { + QXIMInputContext *qic = (QXIMInputContext *) client_data; + if (!qic) { + XIM_DEBUG("xic_start_callback: no qic"); + return 0; + } + QXIMInputContext::ICData *data = qic->icData(); + if (!data) { + XIM_DEBUG("xic_start_callback: no ic data"); + return 0; + } + XIM_DEBUG("xic_start_callback"); + + data->clear(); + data->composing = true; + + return 0; + } + + static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) { + QXIMInputContext *qic = (QXIMInputContext *) client_data; + if (!qic) { + XIM_DEBUG("xic_draw_callback: no qic"); + return 0; + } + QXIMInputContext::ICData *data = qic->icData(); + if (!data) { + XIM_DEBUG("xic_draw_callback: no ic data"); + return 0; + } + XIM_DEBUG("xic_draw_callback"); + + + if(!data->composing) { + data->clear(); + data->composing = true; + } + + XIMPreeditDrawCallbackStruct *drawstruct = (XIMPreeditDrawCallbackStruct *) call_data; + XIMText *text = (XIMText *) drawstruct->text; + int cursor = drawstruct->caret, sellen = 0, selstart = 0; + + if (!drawstruct->caret && !drawstruct->chg_first && !drawstruct->chg_length && !text) { + if(data->text.isEmpty()) { + XIM_DEBUG("compose emptied"); + // if the composition string has been emptied, we need + // to send an InputMethodEnd event + QInputMethodEvent e; + qic->sendEvent(e); + data->clear(); + + // if the commit string has coming after here, InputMethodStart + // will be sent dynamically + } + return 0; + } + + if (text) { + char *str = 0; + if (text->encoding_is_wchar) { + int l = wcstombs(NULL, text->string.wide_char, text->length); + if (l != -1) { + str = new char[l + 1]; + wcstombs(str, text->string.wide_char, l); + str[l] = 0; + } + } else + str = text->string.multi_byte; + + if (!str) + return 0; + + QString s = QString::fromLocal8Bit(str); + + if (text->encoding_is_wchar) + delete [] str; + + if (drawstruct->chg_length < 0) + data->text.replace(drawstruct->chg_first, INT_MAX, s); + else + data->text.replace(drawstruct->chg_first, drawstruct->chg_length, s); + + if (data->selectedChars.size() < data->text.length()) { + // expand the selectedChars array if the compose string is longer + int from = data->selectedChars.size(); + data->selectedChars.resize(data->text.length()); + for (int x = from; x < data->selectedChars.size(); ++x) + data->selectedChars.clearBit(x); + } + + // determine if the changed chars are selected based on text->feedback + for (int x = 0; x < text->length; ++x) + data->selectedChars.setBit(x + drawstruct->chg_first, + (text->feedback ? (text->feedback[x] & XIMReverse) : 0)); + + // figure out where the selection starts, and how long it is + bool started = false; + for (int x = 0; x < qMin(data->selectedChars.size(), data->text.length()); ++x) { + if (started) { + if (data->selectedChars.testBit(x)) ++sellen; + else break; + } else { + if (data->selectedChars.testBit(x)) { + selstart = x; + started = true; + sellen = 1; + } + } + } + } else { + if (drawstruct->chg_length == 0) + drawstruct->chg_length = -1; + + data->text.remove(drawstruct->chg_first, drawstruct->chg_length); + bool qt_compose_emptied = data->text.isEmpty(); + if (qt_compose_emptied) { + XIM_DEBUG("compose emptied 2 text=%s", data->text.toUtf8().constData()); + // if the composition string has been emptied, we need + // to send an InputMethodEnd event + QInputMethodEvent e; + qic->sendEvent(e); + data->clear(); + // if the commit string has coming after here, InputMethodStart + // will be sent dynamically + return 0; + } + } + + XIM_DEBUG("sending compose: '%s', cursor=%d, sellen=%d", + data->text.toUtf8().constData(), cursor, sellen); + QList attrs; + if (selstart > 0) + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, selstart, + qic->standardFormat(QInputContext::PreeditFormat)); + if (sellen) + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selstart, sellen, + qic->standardFormat(QInputContext::SelectionFormat)); + if (selstart + sellen < data->text.length()) + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + selstart + sellen, data->text.length() - selstart - sellen, + qic->standardFormat(QInputContext::PreeditFormat)); + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, sellen ? 0 : 1, QVariant()); + QInputMethodEvent e(data->text, attrs); + data->preeditEmpty = data->text.isEmpty(); + qic->sendEvent(e); + + return 0; + } + + static int xic_done_callback(XIC, XPointer client_data, XPointer) { + QXIMInputContext *qic = (QXIMInputContext *) client_data; + if (!qic) + return 0; + + XIM_DEBUG("xic_done_callback"); + // Don't send InputMethodEnd here. QXIMInputContext::x11FilterEvent() + // handles InputMethodEnd with commit string. + return 0; + } +} + +void QXIMInputContext::ICData::clear() +{ + text = QString(); + selectedChars.clear(); + composing = false; + preeditEmpty = true; +} + +QXIMInputContext::ICData *QXIMInputContext::icData() const +{ + if (QWidget *w = focusWidget()) + return ximData.value(w->effectiveWinId()); + return 0; +} +/* The cache here is needed, as X11 leaks a few kb for every + XFreeFontSet call, so we avoid creating and deletion of fontsets as + much as possible +*/ +static XFontSet fontsetCache[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static int fontsetRefCount = 0; + +static const char * const fontsetnames[] = { + "-*-fixed-medium-r-*-*-16-*,-*-*-medium-r-*-*-16-*", + "-*-fixed-medium-i-*-*-16-*,-*-*-medium-i-*-*-16-*", + "-*-fixed-bold-r-*-*-16-*,-*-*-bold-r-*-*-16-*", + "-*-fixed-bold-i-*-*-16-*,-*-*-bold-i-*-*-16-*", + "-*-fixed-medium-r-*-*-24-*,-*-*-medium-r-*-*-24-*", + "-*-fixed-medium-i-*-*-24-*,-*-*-medium-i-*-*-24-*", + "-*-fixed-bold-r-*-*-24-*,-*-*-bold-r-*-*-24-*", + "-*-fixed-bold-i-*-*-24-*,-*-*-bold-i-*-*-24-*" +}; + +static XFontSet getFontSet(const QFont &f) +{ + int i = 0; + if (f.italic()) + i |= 1; + if (f.bold()) + i |= 2; + + if (f.pointSize() > 20) + i += 4; + + if (!fontsetCache[i]) { + Display* dpy = X11->display; + int missCount; + char** missList; + fontsetCache[i] = XCreateFontSet(dpy, fontsetnames[i], &missList, &missCount, 0); + if(missCount > 0) + XFreeStringList(missList); + if (!fontsetCache[i]) { + fontsetCache[i] = XCreateFontSet(dpy, "-*-fixed-*-*-*-*-16-*", &missList, &missCount, 0); + if(missCount > 0) + XFreeStringList(missList); + if (!fontsetCache[i]) + fontsetCache[i] = (XFontSet)-1; + } + } + return (fontsetCache[i] == (XFontSet)-1) ? 0 : fontsetCache[i]; +} + +extern bool qt_use_rtl_extensions; // from qapplication_x11.cpp +#ifndef QT_NO_XKB +extern QLocale q_getKeyboardLocale(const QByteArray &layoutName, const QByteArray &variantName); +#endif + +QXIMInputContext::QXIMInputContext() +{ + if (!qt_xim_preferred_style) // no configured input style, use the default + qt_xim_preferred_style = xim_default_style; + + xim = 0; + QByteArray ximServerName(qt_ximServer); + if (qt_ximServer) + ximServerName.prepend("@im="); + else + ximServerName = ""; + + if (!XSupportsLocale()) +#ifndef QT_NO_DEBUG + qWarning("Qt: Locale not supported on X server") +#endif + ; +#ifdef USE_X11R6_XIM + else if (XSetLocaleModifiers (ximServerName.constData()) == 0) + qWarning("Qt: Cannot set locale modifiers: %s", ximServerName.constData()); + else + XRegisterIMInstantiateCallback(X11->display, 0, 0, 0, + (XIMProc) xim_create_callback, reinterpret_cast(this)); +#else // !USE_X11R6_XIM + else if (XSetLocaleModifiers ("") == 0) + qWarning("Qt: Cannot set locale modifiers"); + else + QXIMInputContext::create_xim(); +#endif // USE_X11R6_XIM + +#ifndef QT_NO_XKB + if (X11->use_xkb) { + QByteArray layoutName; + QByteArray variantName; + + Atom type = XNone; + int format = 0; + ulong nitems = 0; + ulong bytesAfter = 0; + uchar *data = 0; + if (XGetWindowProperty(X11->display, RootWindow(X11->display, 0), ATOM(_XKB_RULES_NAMES), 0, 1024, + false, XA_STRING, &type, &format, &nitems, &bytesAfter, &data) == Success + && type == XA_STRING && format == 8 && nitems > 2) { + + char *names[5] = { 0, 0, 0, 0, 0 }; + char *p = reinterpret_cast(data), *end = p + nitems; + int i = 0; + do { + names[i++] = p; + p += qstrlen(p) + 1; + } while (p < end); + + QList layoutNames = QByteArray::fromRawData(names[2], qstrlen(names[2])).split(','); + QList variantNames = QByteArray::fromRawData(names[3], qstrlen(names[3])).split(','); + for (int i = 0; i < qMin(layoutNames.count(), variantNames.count()); ++i ) { + QByteArray variantName = variantNames.at(i); + const int dashPos = variantName.indexOf("-"); + if (dashPos >= 0) + variantName.truncate(dashPos); + QLocale keyboardInputLocale = q_getKeyboardLocale(layoutNames.at(i), variantName); + if (keyboardInputLocale.textDirection() == Qt::RightToLeft) + qt_use_rtl_extensions = true; + } + } + + if (data) + XFree(data); + } +#endif // QT_NO_XKB + +} + + +/*!\internal + Creates the application input method. +*/ +void QXIMInputContext::create_xim() +{ + ++fontsetRefCount; +#ifndef QT_NO_XIM + xim = XOpenIM(X11->display, 0, 0, 0); + if (xim) { + +#ifdef USE_X11R6_XIM + XIMCallback destroy; + destroy.callback = (XIMProc) xim_destroy_callback; + destroy.client_data = XPointer(this); + if (XSetIMValues(xim, XNDestroyCallback, &destroy, (char *) 0) != 0) + qWarning("Xlib doesn't support destroy callback"); +#endif // USE_X11R6_XIM + + XIMStyles *styles = 0; + XGetIMValues(xim, XNQueryInputStyle, &styles, (char *) 0, (char *) 0); + if (styles) { + int i; + for (i = 0; !xim_style && i < styles->count_styles; i++) { + if (styles->supported_styles[i] == qt_xim_preferred_style) { + xim_style = qt_xim_preferred_style; + break; + } + } + // if the preferred input style couldn't be found, look for + // Nothing + for (i = 0; !xim_style && i < styles->count_styles; i++) { + if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) { + xim_style = XIMPreeditNothing | XIMStatusNothing; + break; + } + } + // ... and failing that, None. + for (i = 0; !xim_style && i < styles->count_styles; i++) { + if (styles->supported_styles[i] == (XIMPreeditNone | + XIMStatusNone)) { + xim_style = XIMPreeditNone | XIMStatusNone; + break; + } + } + + // qDebug("QApplication: using im style %lx", xim_style); + XFree((char *)styles); + } + + if (xim_style) { + +#ifdef USE_X11R6_XIM + XUnregisterIMInstantiateCallback(X11->display, 0, 0, 0, + (XIMProc) xim_create_callback, reinterpret_cast(this)); +#endif // USE_X11R6_XIM + + if (QWidget *focusWidget = QApplication::focusWidget()) { + // reinitialize input context after the input method + // server (like SCIM) has been launched without + // requiring the user to manually switch focus. + if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled) + && focusWidget->testAttribute(Qt::WA_WState_Created) + && focusWidget->isEnabled()) + setFocusWidget(focusWidget); + } + // following code fragment is not required for immodule + // version of XIM +#if 0 + QWidgetList list = qApp->topLevelWidgets(); + for (int i = 0; i < list.size(); ++i) { + QWidget *w = list.at(i); + w->d->createTLSysExtra(); + } +#endif + } else { + // Give up + qWarning("No supported input style found." + " See InputMethod documentation."); + close_xim(); + } + } +#endif // QT_NO_XIM +} + +/*!\internal + Closes the application input method. +*/ +void QXIMInputContext::close_xim() +{ + for(QHash::const_iterator i = ximData.constBegin(), + e = ximData.constEnd(); i != e; ++i) { + ICData *data = i.value(); + if (data->ic) + XDestroyIC(data->ic); + delete data; + } + ximData.clear(); + + if ( --fontsetRefCount == 0 ) { + Display *dpy = X11->display; + for ( int i = 0; i < 8; i++ ) { + if ( fontsetCache[i] && fontsetCache[i] != (XFontSet)-1 ) { + XFreeFontSet(dpy, fontsetCache[i]); + fontsetCache[i] = 0; + } + } + } + + setFocusWidget(0); + xim = 0; +} + + + +QXIMInputContext::~QXIMInputContext() +{ + XIM old_xim = xim; // close_xim clears xim pointer. + close_xim(); + if (old_xim) + XCloseIM(old_xim); +} + + +QString QXIMInputContext::identifierName() +{ + // the name should be "xim" rather than "XIM" to be consistent + // with corresponding immodule of GTK+ + return QLatin1String("xim"); +} + + +QString QXIMInputContext::language() +{ + QString language; + if (xim) { + QByteArray locale(XLocaleOfIM(xim)); + + if (locale.startsWith("zh")) { + // Chinese language should be formed as "zh_CN", "zh_TW", "zh_HK" + language = QLatin1String(locale.left(5)); + } else { + // other languages should be two-letter ISO 639 language code + language = QLatin1String(locale.left(2)); + } + } + return language; +} + +void QXIMInputContext::reset() +{ + QWidget *w = focusWidget(); + if (!w) + return; + + ICData *data = ximData.value(w->effectiveWinId()); + if (!data) + return; + + if (data->ic) { + char *mb = XmbResetIC(data->ic); + QInputMethodEvent e; + if (mb) { + e.setCommitString(QString::fromLocal8Bit(mb)); + XFree(mb); + data->preeditEmpty = false; // force sending an event + } + if (!data->preeditEmpty) { + sendEvent(e); + update(); + } + } + data->clear(); +} + +void QXIMInputContext::widgetDestroyed(QWidget *w) +{ + QInputContext::widgetDestroyed(w); + ICData *data = ximData.take(w->effectiveWinId()); + if (!data) + return; + + data->clear(); + if (data->ic) + XDestroyIC(data->ic); + delete data; +} + +void QXIMInputContext::mouseHandler(int pos, QMouseEvent *e) +{ + if(e->type() != QEvent::MouseButtonPress) + return; + + XIM_DEBUG("QXIMInputContext::mouseHandler pos=%d", pos); + if (QWidget *w = focusWidget()) { + ICData *data = ximData.value(w->effectiveWinId()); + if (!data) + return; + if (pos < 0 || pos > data->text.length()) + reset(); + // ##### handle mouse position + } +} + +bool QXIMInputContext::isComposing() const +{ + QWidget *w = focusWidget(); + if (!w) + return false; + + ICData *data = ximData.value(w->effectiveWinId()); + if (!data) + return false; + return data->composing; +} + +void QXIMInputContext::setFocusWidget(QWidget *w) +{ + if (!xim) + return; + QWidget *oldFocus = focusWidget(); + if (oldFocus == w) + return; + + if (language() != QLatin1String("ja")) + reset(); + + if (oldFocus) { + ICData *data = ximData.value(oldFocus->effectiveWinId()); + if (data && data->ic) + XUnsetICFocus(data->ic); + } + + QInputContext::setFocusWidget(w); + + if (!w || w->inputMethodHints() & (Qt::ImhExclusiveInputMask | Qt::ImhHiddenText)) + return; + + ICData *data = ximData.value(w->effectiveWinId()); + if (!data) + data = createICData(w); + + if (data->ic) + XSetICFocus(data->ic); + + update(); +} + + +bool QXIMInputContext::x11FilterEvent(QWidget *keywidget, XEvent *event) +{ + int xkey_keycode = event->xkey.keycode; + if (!keywidget->testAttribute(Qt::WA_WState_Created)) + return false; + if (XFilterEvent(event, keywidget->effectiveWinId())) { + qt_ximComposingKeycode = xkey_keycode; // ### not documented in xlib + + update(); + + return true; + } + if (event->type != XKeyPress || event->xkey.keycode != 0) + return false; + + QWidget *w = focusWidget(); + if (keywidget != w) + return false; + ICData *data = ximData.value(w->effectiveWinId()); + if (!data) + return false; + + // input method has sent us a commit string + QByteArray string; + string.resize(513); + KeySym key; // unused + Status status; // unused + QString text; + int count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(), + &key, &status); + + if (status == XBufferOverflow) { + string.resize(count + 1); + count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(), + &key, &status); + } + if (count > 0) { + // XmbLookupString() gave us some text, convert it to unicode + text = qt_input_mapper->toUnicode(string.constData() , count); + if (text.isEmpty()) { + // codec couldn't convert to unicode? this can happen when running in the + // C locale (or with no LANG set). try converting from latin-1 + text = QString::fromLatin1(string.constData(), count); + } + } + +#if 0 + if (!(xim_style & XIMPreeditCallbacks) || !isComposing()) { + // ############### send a regular key event here! + ; + } +#endif + + QInputMethodEvent e; + e.setCommitString(text); + sendEvent(e); + data->clear(); + + update(); + + return true; +} + + +QXIMInputContext::ICData *QXIMInputContext::createICData(QWidget *w) +{ + ICData *data = new ICData; + data->widget = w; + data->preeditEmpty = true; + + XVaNestedList preedit_attr = 0; + XIMCallback startcallback, drawcallback, donecallback; + + QFont font = w->font(); + data->fontset = getFontSet(font); + + if (xim_style & XIMPreeditArea) { + XRectangle rect; + rect.x = 0; + rect.y = 0; + rect.width = w->width(); + rect.height = w->height(); + + preedit_attr = XVaCreateNestedList(0, + XNArea, &rect, + XNFontSet, data->fontset, + (char *) 0); + } else if (xim_style & XIMPreeditPosition) { + XPoint spot; + spot.x = 1; + spot.y = 1; + + preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + XNFontSet, data->fontset, + (char *) 0); + } else if (xim_style & XIMPreeditCallbacks) { + startcallback.client_data = (XPointer) this; + startcallback.callback = (XIMProc) xic_start_callback; + drawcallback.client_data = (XPointer) this; + drawcallback.callback = (XIMProc)xic_draw_callback; + donecallback.client_data = (XPointer) this; + donecallback.callback = (XIMProc) xic_done_callback; + + preedit_attr = XVaCreateNestedList(0, + XNPreeditStartCallback, &startcallback, + XNPreeditDrawCallback, &drawcallback, + XNPreeditDoneCallback, &donecallback, + (char *) 0); + } + + if (preedit_attr) { + data->ic = XCreateIC(xim, + XNInputStyle, xim_style, + XNClientWindow, w->effectiveWinId(), + XNPreeditAttributes, preedit_attr, + (char *) 0); + XFree(preedit_attr); + } else { + data->ic = XCreateIC(xim, + XNInputStyle, xim_style, + XNClientWindow, w->effectiveWinId(), + (char *) 0); + } + + if (data->ic) { + // when resetting the input context, preserve the input state + (void) XSetICValues(data->ic, XNResetState, XIMPreserveState, (char *) 0); + } else { + qWarning("Failed to create XIC"); + } + + ximData[w->effectiveWinId()] = data; + return data; +} + +void QXIMInputContext::update() +{ + QWidget *w = focusWidget(); + if (!w) + return; + + ICData *data = ximData.value(w->effectiveWinId()); + if (!data || !data->ic) + return; + + QRect r = w->inputMethodQuery(Qt::ImMicroFocus).toRect(); + QPoint p; + if (w->nativeParentWidget()) + p = w->mapTo(w->nativeParentWidget(), QPoint((r.left() + r.right() + 1)/2, r.bottom())); + else + p = QPoint((r.left() + r.right() + 1)/2, r.bottom()); + XPoint spot; + spot.x = p.x(); + spot.y = p.y(); + + r = w->rect(); + XRectangle area; + area.x = r.x(); + area.y = r.y(); + area.width = r.width(); + area.height = r.height(); + + XFontSet fontset = getFontSet(qvariant_cast(w->inputMethodQuery(Qt::ImFont))); + if (data->fontset == fontset) + fontset = 0; + else + data->fontset = fontset; + + XVaNestedList preedit_attr; + if (fontset) + preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + XNArea, &area, + XNFontSet, fontset, + (char *) 0); + else + preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + XNArea, &area, + (char *) 0); + + XSetICValues(data->ic, XNPreeditAttributes, preedit_attr, (char *) 0); + XFree(preedit_attr); +} + + +#else +/* + When QT_NO_XIM is defined, we provide a dummy implementation for + this class. The reason for this is that the header file is moc'ed + regardless of QT_NO_XIM. The best would be to remove the file + completely from the pri file is QT_NO_XIM was defined, or for moc + to understand this preprocessor directive. Since the header does + not declare this class when QT_NO_XIM is defined, this is dead + code. +*/ +bool QXIMInputContext::isComposing() const { return false; } +QString QXIMInputContext::identifierName() { return QString(); } +void QXIMInputContext::mouseHandler(int, QMouseEvent *) {} +void QXIMInputContext::setFocusWidget(QWidget *) {} +void QXIMInputContext::reset() {} +void QXIMInputContext::update() {} +QXIMInputContext::~QXIMInputContext() {} +void QXIMInputContext::widgetDestroyed(QWidget *) {} +QString QXIMInputContext::language() { return QString(); } +bool QXIMInputContext::x11FilterEvent(QWidget *, XEvent *) { return true; } + +#endif //QT_NO_XIM + +QT_END_NAMESPACE + +#endif //QT_NO_IM -- cgit v1.2.3