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 sales@trolltech.com. +** +** 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 +} | 
