summaryrefslogtreecommitdiffstats
path: root/experimental/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'experimental/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp')
-rw-r--r--experimental/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp535
1 files changed, 535 insertions, 0 deletions
diff --git a/experimental/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp b/experimental/tqtinterface/qt4/src/kernel/tqinputcontext_x11.cpp
new file mode 100644
index 000000000..758b56d48
--- /dev/null
+++ b/experimental/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
+}