📄 qximinputcontext_x11.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************//******************************************************************************** Implementation of QXIMInputContext class**** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.**** This file is written to contribute to Trolltech ASA 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 "qdebug.h"#include "qximinputcontext_p.h"#if !defined(QT_NO_IM)#if !defined(QT_NO_XIM)#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 <stdlib.h>#include <limits.h>// #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 structextern 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.cppstatic 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<QXIMInputContext *>(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<QXIMInputContext *>(client_data); // qDebug("xim_destroy_callback"); qic->close_xim(); XRegisterIMInstantiateCallback(X11->display, 0, 0, 0, (XIMProc) xim_create_callback, reinterpret_cast<char *>(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<QInputMethodEvent::Attribute> 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); 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;}QXIMInputContext::ICData *QXIMInputContext::icData() const{ return ximData.value(focusWidget());}/* 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];}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 /* if (!noxim) */ XRegisterIMInstantiateCallback(X11->display, 0, 0, 0, (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));#else // !USE_X11R6_XIM else if (XSetLocaleModifiers ("") == 0) qWarning("Qt: Cannot set locale modifiers"); else /* if (!noxim) */ QXIMInputContext::create_xim();#endif // USE_X11R6_XIM}/*!\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 = 0; if (XSetIMValues(xim, XNDestroyCallback, &destroy, (char *) 0) != 0) qWarning("Xlib dosn'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)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -