You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tqt3/plugins/src/inputmethods/xim/qximinputcontext_x11.cpp

931 lines
24 KiB

/****************************************************************************
** $Id: qximinputcontext_x11.cpp,v 1.10 2004/06/22 06:47:27 daisuke Exp $
**
** Implementation of TQXIMInputContext class
**
** Copyright (C) 2000-2003 Trolltech AS. All rights reserved.
**
** This file is part of the input method module of the TQt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.TQPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition
** licenses for Unix/X11 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
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about TQt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for TQPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "qximinputcontext.h"
const int XKeyPress = KeyPress;
const int XKeyRelease = KeyRelease;
#undef KeyPress
#undef KeyRelease
#if !defined(QT_NO_IM)
#include "qplatformdefs.h"
#include "ntqapplication.h"
#include "ntqwidget.h"
#include "ntqstring.h"
#include "ntqptrlist.h"
#include "ntqintdict.h"
#include "ntqtextcodec.h"
#include <stdlib.h>
#include <limits.h>
#if !defined(QT_NO_XIM)
#define XK_MISCELLANY
#define XK_LATIN1
#include <X11/keysymdef.h>
// #define QT_XIM_DEBUG
// from qapplication_x11.cpp
static XIM qt_xim = 0;
extern XIMStyle qt_xim_style;
extern XIMStyle qt_xim_preferred_style;
extern char *qt_ximServer;
static bool isInitXIM = FALSE;
static TQPtrList<TQXIMInputContext> *ximContextList = 0;
#endif
extern int qt_ximComposingKeycode;
extern TQTextCodec * qt_input_mapper;
#if !defined(QT_NO_XIM)
#if defined(Q_C_CALLBACKS)
extern "C" {
#endif // Q_C_CALLBACKS
#ifdef USE_X11R6_XIM
static void xim_create_callback(XIM /*im*/,
XPointer /*client_data*/,
XPointer /*call_data*/)
{
// qDebug("xim_create_callback");
TQXIMInputContext::create_xim();
}
static void xim_destroy_callback(XIM /*im*/,
XPointer /*client_data*/,
XPointer /*call_data*/)
{
// qDebug("xim_destroy_callback");
TQXIMInputContext::close_xim();
Display *dpy = TQPaintDevice::x11AppDisplay();
XRegisterIMInstantiateCallback(dpy, 0, 0, 0,
(XIMProc) xim_create_callback, 0);
}
#endif // USE_X11R6_XIM
#if defined(Q_C_CALLBACKS)
}
#endif // Q_C_CALLBACKS
#endif // QT_NO_XIM
#ifndef QT_NO_XIM
/* 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 Q_C_CALLBACKS
extern "C" {
#endif // Q_C_CALLBACKS
// These static functions should be rewritten as member of
// TQXIMInputContext
static int xic_start_callback(XIC, XPointer client_data, XPointer) {
TQXIMInputContext *qic = (TQXIMInputContext *) client_data;
if (! qic) {
#ifdef QT_XIM_DEBUG
qDebug("compose start: no qic");
#endif // QT_XIM_DEBUG
return 0;
}
qic->resetClientState();
qic->sendIMEvent( TQEvent::IMStart );
#ifdef QT_XIM_DEBUG
qDebug("compose start");
#endif // QT_XIM_DEBUG
return 0;
}
static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) {
TQXIMInputContext *qic = (TQXIMInputContext *) client_data;
if (! qic) {
#ifdef QT_XIM_DEBUG
qDebug("compose event: invalid compose event %p", qic);
#endif // QT_XIM_DEBUG
return 0;
}
bool send_imstart = FALSE;
if( ! qic->isComposing() && qic->hasFocus() ) {
qic->resetClientState();
send_imstart = TRUE;
} else if ( ! qic->isComposing() || ! qic->hasFocus() ) {
#ifdef QT_XIM_DEBUG
qDebug( "compose event: invalid compose event composing=%d hasFocus=%d",
qic->isComposing(), qic->hasFocus() );
#endif // QT_XIM_DEBUG
return 0;
}
if ( send_imstart )
qic->sendIMEvent( TQEvent::IMStart );
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 ) {
if( qic->composingText.isEmpty() ) {
#ifdef QT_XIM_DEBUG
qDebug( "compose emptied" );
#endif // QT_XIM_DEBUG
// if the composition string has been emptied, we need
// to send an IMEnd event
qic->sendIMEvent( TQEvent::IMEnd );
qic->resetClientState();
// if the commit string has coming after here, IMStart
// 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;
TQString s = TQString::fromLocal8Bit(str);
if (text->encoding_is_wchar)
delete [] str;
if (drawstruct->chg_length < 0)
qic->composingText.replace(drawstruct->chg_first, UINT_MAX, s);
else
qic->composingText.replace(drawstruct->chg_first, drawstruct->chg_length, s);
if ( qic->selectedChars.size() < qic->composingText.length() ) {
// expand the selectedChars array if the compose string is longer
uint from = qic->selectedChars.size();
qic->selectedChars.resize( qic->composingText.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->composingText.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->composingText.remove(drawstruct->chg_first, drawstruct->chg_length);
bool qt_compose_emptied = qic->composingText.isEmpty();
if ( qt_compose_emptied ) {
#ifdef QT_XIM_DEBUG
qDebug( "compose emptied" );
#endif // QT_XIM_DEBUG
// if the composition string has been emptied, we need
// to send an IMEnd event
qic->sendIMEvent( TQEvent::IMEnd );
qic->resetClientState();
// if the commit string has coming after here, IMStart
// will be sent dynamically
return 0;
}
}
qic->sendIMEvent( TQEvent::IMCompose,
qic->composingText, cursor, sellen );
return 0;
}
static int xic_done_callback(XIC, XPointer client_data, XPointer) {
TQXIMInputContext *qic = (TQXIMInputContext *) client_data;
if (! qic)
return 0;
// Don't send IMEnd here. TQXIMInputContext::x11FilterEvent()
// handles IMEnd with commit string.
#if 0
if ( qic->isComposing() )
qic->sendIMEvent( TQEvent::IMEnd );
qic->resetClientState();
#endif
return 0;
}
#ifdef Q_C_CALLBACKS
}
#endif // Q_C_CALLBACKS
#endif // !QT_NO_XIM
TQXIMInputContext::TQXIMInputContext()
: TQInputContext(), ic(0), fontset(0)
{
if(!isInitXIM)
TQXIMInputContext::init_xim();
}
void TQXIMInputContext::setHolderWidget( TQWidget *widget )
{
if ( ! widget )
return;
TQInputContext::setHolderWidget( widget );
#if !defined(QT_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);
if( ! ximContextList )
ximContextList = new TQPtrList<TQXIMInputContext>;
ximContextList->append( this );
#endif // !QT_NO_XIM
}
TQXIMInputContext::~TQXIMInputContext()
{
#if !defined(QT_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;
}
}
}
if( ximContextList ) {
ximContextList->remove( this );
if(ximContextList->isEmpty()) {
// Calling XCloseIM gives a Purify FMR error
// XCloseIM( qt_xim );
// We prefer a less serious memory leak
if( qt_xim ) {
qt_xim = 0;
isInitXIM = FALSE;
}
delete ximContextList;
ximContextList = 0;
}
}
#endif // !QT_NO_XIM
ic = 0;
}
void TQXIMInputContext::init_xim()
{
#ifndef QT_NO_XIM
if(!isInitXIM)
isInitXIM = TRUE;
qt_xim = 0;
TQString ximServerName(qt_ximServer);
if (qt_ximServer)
ximServerName.prepend("@im=");
else
ximServerName = "";
if ( !XSupportsLocale() )
qWarning("TQt: Locales not supported on X server");
#ifdef USE_X11R6_XIM
else if ( XSetLocaleModifiers (ximServerName.ascii()) == 0 )
qWarning( "TQt: Cannot set locale modifiers: %s",
ximServerName.ascii());
else {
Display *dpy = TQPaintDevice::x11AppDisplay();
XWindowAttributes attr; // XIM unselects all events on the root window
XGetWindowAttributes( dpy, TQPaintDevice::x11AppRootWindow(),&attr );
XRegisterIMInstantiateCallback(dpy, 0, 0, 0,
(XIMProc) xim_create_callback, 0);
XSelectInput( dpy, TQPaintDevice::x11AppRootWindow(), attr.your_event_mask );
}
#else // !USE_X11R6_XIM
else if ( XSetLocaleModifiers ("") == 0 )
qWarning("TQt: Cannot set locale modifiers");
else
TQXIMInputContext::create_xim();
#endif // USE_X11R6_XIM
#endif // QT_NO_XIM
}
/*! \internal
Creates the application input method.
*/
void TQXIMInputContext::create_xim()
{
#ifndef QT_NO_XIM
Display *appDpy = TQPaintDevice::x11AppDisplay();
qt_xim = XOpenIM( appDpy, 0, 0, 0 );
if ( qt_xim ) {
#ifdef USE_X11R6_XIM
XIMCallback destroy;
destroy.callback = (XIMProc) xim_destroy_callback;
destroy.client_data = 0;
if ( XSetIMValues( qt_xim, XNDestroyCallback, &destroy, (char *) 0 ) != 0 )
qWarning( "Xlib doesn't support destroy callback");
#endif // USE_X11R6_XIM
XIMStyles *styles = 0;
XGetIMValues(qt_xim, XNQueryInputStyle, &styles, (char *) 0, (char *) 0);
if ( styles ) {
int i;
for ( i = 0; !qt_xim_style && i < styles->count_styles; i++ ) {
if ( styles->supported_styles[i] == qt_xim_preferred_style ) {
qt_xim_style = qt_xim_preferred_style;
break;
}
}
// if the preferred input style couldn't be found, look for
// Nothing
for ( i = 0; !qt_xim_style && i < styles->count_styles; i++ ) {
if ( styles->supported_styles[i] == (XIMPreeditNothing |
XIMStatusNothing) ) {
qt_xim_style = XIMPreeditNothing | XIMStatusNothing;
break;
}
}
// ... and failing that, None.
for ( i = 0; !qt_xim_style && i < styles->count_styles; i++ ) {
if ( styles->supported_styles[i] == (XIMPreeditNone |
XIMStatusNone) ) {
qt_xim_style = XIMPreeditNone | XIMStatusNone;
break;
}
}
// qDebug("TQApplication: using im style %lx", qt_xim_style);
XFree( (char *)styles );
}
if ( qt_xim_style ) {
#ifdef USE_X11R6_XIM
XUnregisterIMInstantiateCallback(appDpy, 0, 0, 0,
(XIMProc) xim_create_callback, 0);
#endif // USE_X11R6_XIM
} else {
// Give up
qWarning( "No supported input style found."
" See InputMethod documentation.");
TQXIMInputContext::close_xim();
}
}
#endif // QT_NO_XIM
}
/*! \internal
Closes the application input method.
*/
void TQXIMInputContext::close_xim()
{
#ifndef QT_NO_XIM
TQString errMsg( "TQXIMInputContext::close_xim() has been called" );
// Calling XCloseIM gives a Purify FMR error
// XCloseIM( qt_xim );
// We prefer a less serious memory leak
qt_xim = 0;
if( ximContextList ) {
TQPtrList<TQXIMInputContext> contexts( *ximContextList );
TQPtrList<TQXIMInputContext>::Iterator it = contexts.begin();
while( it != contexts.end() ) {
(*it)->close( errMsg );
++it;
}
// ximContextList will be deleted in ~TQXIMInputContext
}
#endif // QT_NO_XIM
}
bool TQXIMInputContext::x11FilterEvent( TQWidget *keywidget, XEvent *event )
{
#ifndef QT_NO_XIM
int xkey_keycode = event->xkey.keycode;
if ( XFilterEvent( event, keywidget->topLevelWidget()->winId() ) ) {
qt_ximComposingKeycode = xkey_keycode; // ### not documented in xlib
// Cancel of the composition is realizable even if
// follwing codes don't exist
#if 0
if ( event->type != XKeyPress || ! (qt_xim_style & XIMPreeditCallbacks) )
return TRUE;
/*
* The Solaris htt input method will transform a ClientMessage
* event into a filtered KeyPress event, in which case our
* keywidget is still zero.
*/
TQETWidget *widget = (TQETWidget*)TQWidget::find( (WId)event->xany.window );
if ( ! keywidget ) {
keywidget = (TQETWidget*)TQWidget::keyboardGrabber();
if ( keywidget ) {
grabbed = TRUE;
} else {
if ( focus_widget )
keywidget = (TQETWidget*)focus_widget;
if ( !keywidget ) {
if ( tqApp->inPopupMode() ) // no focus widget, see if we have a popup
keywidget = (TQETWidget*) tqApp->activePopupWidget();
else if ( widget )
keywidget = (TQETWidget*)widget->topLevelWidget();
}
}
}
/*
if the composition string has been emptied, we need to send
an IMEnd event. however, we have no way to tell if the user
has cancelled input, or if the user has accepted the
composition.
so, we have to look for the next keypress and see if it is
the 'commit' key press (keycode == 0). if it is, we deliver
an IMEnd event with the final text, otherwise we deliver an
IMEnd with empty text (meaning the user has cancelled the
input).
*/
if ( composing && focusWidget && qt_compose_emptied ) {
XEvent event2;
bool found = FALSE;
if ( XCheckTypedEvent( TQPaintDevice::x11AppDisplay(),
XKeyPress, &event2 ) ) {
if ( event2.xkey.keycode == 0 ) {
// found a key event with the 'commit' string
found = TRUE;
XPutBackEvent( TQPaintDevice::x11AppDisplay(), &event2 );
}
}
if ( !found ) {
// no key event, so the user must have cancelled the composition
TQIMEvent endevent( TQEvent::IMEnd, TQString::null, -1 );
TQApplication::sendEvent( focusWidget, &endevent );
focusWidget = 0;
}
qt_compose_emptied = FALSE;
}
#endif
return TRUE;
} else if ( focusWidget() ) {
if ( event->type == XKeyPress && event->xkey.keycode == 0 ) {
// input method has sent us a commit string
TQCString data(513);
KeySym sym; // unused
Status status; // unused
TQString inputText;
int count = lookupString( &(event->xkey), data, &sym, &status );
if ( count > 0 )
inputText = qt_input_mapper->toUnicode( data, count );
if ( ! ( qt_xim_style & XIMPreeditCallbacks ) || ! isComposing() ) {
// there is no composing state
sendIMEvent( TQEvent::IMStart );
}
sendIMEvent( TQEvent::IMEnd, inputText );
resetClientState();
return TRUE;
}
}
#endif // !QT_NO_XIM
return FALSE;
}
void TQXIMInputContext::sendIMEvent( TQEvent::Type type, const TQString &text,
int cursorPosition, int selLength )
{
TQInputContext::sendIMEvent( type, text, cursorPosition, selLength );
if ( type == TQEvent::IMCompose )
composingText = text;
}
void TQXIMInputContext::reset()
{
#if !defined(QT_NO_XIM)
if ( focusWidget() && isComposing() && ! composingText.isNull() ) {
#ifdef QT_XIM_DEBUG
qDebug("TQXIMInputContext::reset: composing - sending IMEnd (empty) to %p",
focusWidget() );
#endif // QT_XIM_DEBUG
TQInputContext::reset();
resetClientState();
char *mb = XmbResetIC((XIC) ic);
if (mb)
XFree(mb);
}
#endif // !QT_NO_XIM
}
void TQXIMInputContext::resetClientState()
{
#if !defined(QT_NO_XIM)
composingText = TQString::null;
if ( selectedChars.size() < 128 )
selectedChars.resize( 128 );
selectedChars.fill( 0 );
#endif // !QT_NO_XIM
}
void TQXIMInputContext::close( const TQString &errMsg )
{
qDebug( errMsg );
emit deletionRequested();
}
bool TQXIMInputContext::hasFocus() const
{
return ( focusWidget() != 0 );
}
void TQXIMInputContext::setMicroFocus(int x, int y, int, int h, TQFont *f)
{
TQWidget *widget = focusWidget();
if ( qt_xim && widget ) {
TQPoint p( x, y );
TQPoint p2 = widget->mapTo( widget->topLevelWidget(), TQPoint( 0, 0 ) );
p = widget->topLevelWidget()->mapFromGlobal( p );
setXFontSet( f ? *f : widget->font() );
setComposePosition(p.x(), p.y() + h);
setComposeArea(p2.x(), p2.y(), widget->width(), widget->height());
}
}
void TQXIMInputContext::mouseHandler( int , TQEvent::Type type,
TQt::ButtonState button,
TQt::ButtonState)
{
if ( type == TQEvent::MouseButtonPress ||
type == TQEvent::MouseButtonDblClick ) {
// Don't reset Japanese input context here. Japanese input
// context sometimes contains a whole paragraph and has
// minutes of lifetime different to ephemeral one in other
// languages. The input context should be survived until
// focused again.
if ( ! isPreeditPreservationEnabled() )
reset();
}
}
void TQXIMInputContext::setComposePosition(int x, int y)
{
#if !defined(QT_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 // !QT_NO_XIM
}
void TQXIMInputContext::setComposeArea(int x, int y, int w, int h)
{
#if !defined(QT_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
}
void TQXIMInputContext::setXFontSet(const TQFont &f)
{
#if !defined(QT_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
Q_UNUSED( f );
#endif
}
int TQXIMInputContext::lookupString(XKeyEvent *event, TQCString &chars,
KeySym *key, Status *status) const
{
int count = 0;
#if !defined(QT_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 // QT_NO_XIM
return count;
}
void TQXIMInputContext::setFocus()
{
#if !defined(QT_NO_XIM)
if ( qt_xim && ic )
XSetICFocus((XIC) ic);
#endif // !QT_NO_XIM
}
void TQXIMInputContext::unsetFocus()
{
#if !defined(QT_NO_XIM)
if (qt_xim && ic)
XUnsetICFocus((XIC) ic);
#endif // !QT_NO_XIM
// Don't reset Japanese input context here. Japanese input context
// sometimes contains a whole paragraph and has minutes of
// lifetime different to ephemeral one in other languages. The
// input context should be survived until focused again.
if ( ! isPreeditPreservationEnabled() )
reset();
}
bool TQXIMInputContext::isPreeditRelocationEnabled()
{
return ( language() == "ja" );
}
bool TQXIMInputContext::isPreeditPreservationEnabled()
{
return ( language() == "ja" );
}
TQString TQXIMInputContext::identifierName()
{
// the name should be "xim" rather than "XIM" to be consistent
// with corresponding immodule of GTK+
return "xim";
}
TQString TQXIMInputContext::language()
{
#if !defined(QT_NO_XIM)
if ( qt_xim ) {
TQString locale( XLocaleOfIM( qt_xim ) );
if ( locale.startsWith( "zh" ) ) {
// Chinese language should be formed as "zh_CN", "zh_TW", "zh_HK"
_language = locale.left( 5 );
} else {
// other languages should be two-letter ISO 639 language code
_language = locale.left( 2 );
}
}
#endif
return _language;
}
#endif //QT_NO_IM