diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp')
-rw-r--r-- | tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp b/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp new file mode 100644 index 0000000..758b56d --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Implementation of TQInputContext class +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** 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 [email protected]. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqplatformdefs.h" + +#include "tqapplication.h" +#include "tqwidget.h" +#include "tqinputcontext_p.h" + +#include <stdlib.h> +#include <limits.h> + + +bool qt_compose_emptied = FALSE; + +#if !defined(TQT_NO_XIM) + +#define XK_MISCELLANY +#define XK_LATIN1 +#include <X11/keysymdef.h> + +// #define TQT_XIM_DEBUG + +// from qapplication_x11.cpp +extern XIM qt_xim; +extern XIMStyle qt_xim_style; + +/* 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 TQFont &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 = TQPaintDevice::x11AppDisplay(); + 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]; +} + + +#ifdef TQ_C_CALLBACKS +extern "C" { +#endif // TQ_C_CALLBACKS + + static int xic_start_callback(XIC, XPointer client_data, XPointer) { + TQInputContext *qic = (TQInputContext *) client_data; + if (! qic) { +#ifdef TQT_XIM_DEBUG + qDebug("compose start: no qic"); +#endif // TQT_XIM_DEBUG + + return 0; + } + + qic->composing = TRUE; + qic->text = TQString::null; + qic->tqfocusWidget = 0; + + if ( qic->selectedChars.size() < 128 ) + qic->selectedChars.resize( 128 ); + qic->selectedChars.fill( 0 ); + +#ifdef TQT_XIM_DEBUG + qDebug("compose start"); +#endif // TQT_XIM_DEBUG + + return 0; + } + + static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) { + TQInputContext *qic = (TQInputContext *) client_data; + if (! qic) { +#ifdef TQT_XIM_DEBUG + qDebug("compose event: invalid compose event %p", qic); +#endif // TQT_XIM_DEBUG + + return 0; + } + + bool send_imstart = FALSE; + if (tqApp->tqfocusWidget() != qic->tqfocusWidget && qic->text.isEmpty()) { + if (qic->tqfocusWidget) { +#ifdef TQT_XIM_DEBUG + qDebug( "sending IMEnd (empty) to %p", qic->tqfocusWidget ); +#endif // TQT_XIM_DEBUG + + TQIMEvent endevent(TQEvent::IMEnd, TQString::null, -1); + TQApplication::sendEvent(qic->tqfocusWidget, &endevent); + } + + qic->text = TQString::null; + qic->tqfocusWidget = tqApp->tqfocusWidget(); + qic->composing = FALSE; + + if ( qic->selectedChars.size() < 128 ) + qic->selectedChars.resize( 128 ); + qic->selectedChars.fill( 0 ); + + if (qic->tqfocusWidget) { + qic->composing = TRUE; + send_imstart = TRUE; + } + } + + if (! qic->composing || ! qic->tqfocusWidget) { +#ifdef TQT_XIM_DEBUG + qDebug("compose event: invalid compose event %d %p", + qic->composing, qic->tqfocusWidget); +#endif // TQT_XIM_DEBUG + + return 0; + } + + if ( send_imstart ) { +#ifdef TQT_XIM_DEBUG + qDebug( "sending IMStart to %p", qic->tqfocusWidget ); +#endif // TQT_XIM_DEBUG + + qt_compose_emptied = FALSE; + TQIMEvent startevent(TQEvent::IMStart, TQString::null, -1); + TQApplication::sendEvent(qic->tqfocusWidget, &startevent); + } + + XIMPreeditDrawCallbackStruct *drawstruct = + (XIMPreeditDrawCallbackStruct *) call_data; + XIMText *text = (XIMText *) drawstruct->text; + int cursor = drawstruct->caret, sellen = 0; + + if ( ! drawstruct->caret && ! drawstruct->chg_first && + ! drawstruct->chg_length && ! text ) { + // nothing to do + 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; + + TQString s = TQString::fromLocal8Bit(str); + + if (text->encoding_is_wchar) + delete [] str; + + if (drawstruct->chg_length < 0) + qic->text.tqreplace(drawstruct->chg_first, UINT_MAX, s); + else + qic->text.tqreplace(drawstruct->chg_first, drawstruct->chg_length, s); + + if ( qic->selectedChars.size() < qic->text.length() ) { + // expand the selectedChars array if the compose string is longer + uint from = qic->selectedChars.size(); + qic->selectedChars.resize( qic->text.length() ); + for ( uint x = from; from < qic->selectedChars.size(); ++x ) + qic->selectedChars[x] = 0; + } + + uint x; + bool *p = qic->selectedChars.data() + drawstruct->chg_first; + // determine if the changed chars are selected based on text->feedback + for ( x = 0; x < s.length(); ++x ) + *p++ = ( text->feedback ? ( text->feedback[x] & XIMReverse ) : 0 ); + + // figure out where the selection starts, and how long it is + p = qic->selectedChars.data(); + bool started = FALSE; + for ( x = 0; x < TQMIN(qic->text.length(), qic->selectedChars.size()); ++x ) { + if ( started ) { + if ( *p ) ++sellen; + else break; + } else { + if ( *p ) { + cursor = x; + started = TRUE; + sellen = 1; + } + } + ++p; + } + } else { + if (drawstruct->chg_length == 0) + drawstruct->chg_length = -1; + + qic->text.remove(drawstruct->chg_first, drawstruct->chg_length); + qt_compose_emptied = qic->text.isEmpty(); + if ( qt_compose_emptied ) { +#ifdef TQT_XIM_DEBUG + qDebug( "compose emptied" ); +#endif // TQT_XIM_DEBUG + + // don't send an empty compose, since we will send an IMEnd with + // either the correct compose text (or null text if the user has + // cancelled the compose or deleted all chars). + return 0; + } + } + +#ifdef TQT_XIM_DEBUG + qDebug( "sending IMCompose to %p with %d chars", + qic->tqfocusWidget, qic->text.length() ); +#endif // TQT_XIM_DEBUG + + TQIMComposeEvent event( TQEvent::IMCompose, qic->text, cursor, sellen ); + TQApplication::sendEvent(qic->tqfocusWidget, &event); + return 0; + } + + static int xic_done_callback(XIC, XPointer client_data, XPointer) { + TQInputContext *qic = (TQInputContext *) client_data; + if (! qic) + return 0; + + if (qic->composing && qic->tqfocusWidget) { +#ifdef TQT_XIM_DEBUG + qDebug( "sending IMEnd (empty) to %p", qic->tqfocusWidget ); +#endif // TQT_XIM_DEBUG + + TQIMEvent event(TQEvent::IMEnd, TQString::null, -1); + TQApplication::sendEvent(qic->tqfocusWidget, &event); + } + + qic->composing = FALSE; + qic->tqfocusWidget = 0; + + if ( qic->selectedChars.size() < 128 ) + qic->selectedChars.resize( 128 ); + qic->selectedChars.fill( 0 ); + + return 0; + } + +#ifdef TQ_C_CALLBACKS +} +#endif // TQ_C_CALLBACKS + +#endif // !TQT_NO_XIM + + + +TQInputContext::TQInputContext(TQWidget *widget) + : ic(0), tqfocusWidget(0), composing(FALSE), fontset(0) +{ +#if !defined(TQT_NO_XIM) + fontsetRefCount++; + if (! qt_xim) { + qWarning("TQInputContext: no input method context available"); + return; + } + + if (! widget->isTopLevel()) { + qWarning("TQInputContext: cannot create input context for non-toplevel widgets"); + return; + } + + XPoint spot; + XRectangle rect; + XVaNestedList preedit_attr = 0; + XIMCallback startcallback, drawcallback, donecallback; + + font = widget->font(); + fontset = getFontSet( font ); + + if (qt_xim_style & XIMPreeditArea) { + rect.x = 0; + rect.y = 0; + rect.width = widget->width(); + rect.height = widget->height(); + + preedit_attr = XVaCreateNestedList(0, + XNArea, &rect, + XNFontSet, fontset, + (char *) 0); + } else if (qt_xim_style & XIMPreeditPosition) { + spot.x = 1; + spot.y = 1; + + preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + XNFontSet, fontset, + (char *) 0); + } else if (qt_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) { + ic = XCreateIC(qt_xim, + XNInputStyle, qt_xim_style, + XNClientWindow, widget->winId(), + XNPreeditAttributes, preedit_attr, + (char *) 0); + XFree(preedit_attr); + } else + ic = XCreateIC(qt_xim, + XNInputStyle, qt_xim_style, + XNClientWindow, widget->winId(), + (char *) 0); + + if (! ic) + qFatal("Failed to create XIM input context!"); + + // when resetting the input context, preserve the input state + (void) XSetICValues((XIC) ic, XNResetState, XIMPreserveState, (char *) 0); +#endif // !TQT_NO_XIM +} + + +TQInputContext::~TQInputContext() +{ + +#if !defined(TQT_NO_XIM) + if (ic) + XDestroyIC((XIC) ic); + + if ( --fontsetRefCount == 0 ) { + Display *dpy = TQPaintDevice::x11AppDisplay(); + for ( int i = 0; i < 8; i++ ) { + if ( fontsetCache[i] && fontsetCache[i] != (XFontSet)-1 ) { + XFreeFontSet(dpy, fontsetCache[i]); + fontsetCache[i] = 0; + } + } + } + +#endif // !TQT_NO_XIM + + ic = 0; + tqfocusWidget = 0; + composing = FALSE; +} + + +void TQInputContext::reset() +{ +#if !defined(TQT_NO_XIM) + if (tqfocusWidget && composing && ! text.isNull()) { +#ifdef TQT_XIM_DEBUG + qDebug("TQInputContext::reset: composing - sending IMEnd (empty) to %p", + tqfocusWidget); +#endif // TQT_XIM_DEBUG + + TQIMEvent endevent(TQEvent::IMEnd, TQString::null, -1); + TQApplication::sendEvent(tqfocusWidget, &endevent); + tqfocusWidget = 0; + text = TQString::null; + if ( selectedChars.size() < 128 ) + selectedChars.resize( 128 ); + selectedChars.fill( 0 ); + + char *mb = XmbResetIC((XIC) ic); + if (mb) + XFree(mb); + } +#endif // !TQT_NO_XIM +} + + +void TQInputContext::setComposePosition(int x, int y) +{ +#if !defined(TQT_NO_XIM) + if (qt_xim && ic) { + XPoint point; + point.x = x; + point.y = y; + + XVaNestedList preedit_attr = + XVaCreateNestedList(0, + XNSpotLocation, &point, + + (char *) 0); + XSetICValues((XIC) ic, XNPreeditAttributes, preedit_attr, (char *) 0); + XFree(preedit_attr); + } +#endif // !TQT_NO_XIM +} + + +void TQInputContext::setComposeArea(int x, int y, int w, int h) +{ +#if !defined(TQT_NO_XIM) + if (qt_xim && ic) { + XRectangle rect; + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + + XVaNestedList preedit_attr = XVaCreateNestedList(0, + XNArea, &rect, + + (char *) 0); + XSetICValues((XIC) ic, XNPreeditAttributes, preedit_attr, (char *) 0); + XFree(preedit_attr); + } +#endif +} + + +int TQInputContext::lookupString(XKeyEvent *event, TQCString &chars, + KeySym *key, Status *status) const +{ + int count = 0; + +#if !defined(TQT_NO_XIM) + if (qt_xim && ic) { + count = XmbLookupString((XIC) ic, event, chars.data(), + chars.size(), key, status); + + if ((*status) == XBufferOverflow ) { + chars.resize(count + 1); + count = XmbLookupString((XIC) ic, event, chars.data(), + chars.size(), key, status); + } + } + +#endif // TQT_NO_XIM + + return count; +} + +void TQInputContext::setFocus() +{ +#if !defined(TQT_NO_XIM) + if (qt_xim && ic) + XSetICFocus((XIC) ic); +#endif // !TQT_NO_XIM +} + +void TQInputContext::setXFontSet(const TQFont &f) +{ +#if !defined(TQT_NO_XIM) + if (font == f) return; // nothing to do + font = f; + + XFontSet fs = getFontSet(font); + if (fontset == fs) return; // nothing to do + fontset = fs; + + XVaNestedList preedit_attr = XVaCreateNestedList(0, XNFontSet, fontset, (char *) 0); + XSetICValues((XIC) ic, XNPreeditAttributes, preedit_attr, (char *) 0); + XFree(preedit_attr); +#else + TQ_UNUSED( f ); +#endif +} |