~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/inputmethod/qximinputcontext_x11.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the input methods of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
/****************************************************************************
 
30
**
 
31
** Implementation of QXIMInputContext class
 
32
**
 
33
** Copyright (C) 2003-2004 immodule for Qt Project.  All rights reserved.
 
34
**
 
35
** This file is written to contribute to Trolltech AS under their own
 
36
** licence. You may use this file under your Qt license. Following
 
37
** description is copied from their original file headers. Contact
 
38
** immodule-qt@freedesktop.org if any conditions of this licensing are
 
39
** not clear to you.
 
40
**
 
41
****************************************************************************/
 
42
 
 
43
#include "qximinputcontext_p.h"
 
44
 
 
45
#if !defined(QT_NO_IM)
 
46
 
 
47
#if !defined(QT_NO_XIM)
 
48
 
 
49
#include "qplatformdefs.h"
 
50
 
 
51
#include "qapplication.h"
 
52
#include "qwidget.h"
 
53
#include "qstring.h"
 
54
#include "qlist.h"
 
55
#include "qtextcodec.h"
 
56
#include "qevent.h"
 
57
#include "qtextformat.h"
 
58
 
 
59
#include "qx11info_x11.h"
 
60
#include <qdebug.h>
 
61
 
 
62
#include <stdlib.h>
 
63
#include <limits.h>
 
64
 
 
65
// #define QT_XIM_DEBUG
 
66
#ifdef QT_XIM_DEBUG
 
67
#define XIM_DEBUG qDebug
 
68
#else
 
69
#define XIM_DEBUG if (0) qDebug
 
70
#endif
 
71
 
 
72
// from qapplication_x11.cpp
 
73
// #### move to X11 struct
 
74
extern XIMStyle qt_xim_preferred_style;
 
75
extern char    *qt_ximServer;
 
76
extern int qt_ximComposingKeycode;
 
77
extern QTextCodec * qt_input_mapper;
 
78
 
 
79
XIMStyle QXIMInputContext::xim_style = 0;
 
80
// moved from qapplication_x11.cpp
 
81
static const XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing;
 
82
 
 
83
 
 
84
extern "C" {
 
85
#ifdef USE_X11R6_XIM
 
86
    static void xim_create_callback(XIM /*im*/,
 
87
                                    XPointer client_data,
 
88
                                    XPointer /*call_data*/)
 
89
    {
 
90
        QXIMInputContext *qic = reinterpret_cast<QXIMInputContext *>(client_data);
 
91
        // qDebug("xim_create_callback");
 
92
        qic->create_xim();
 
93
    }
 
94
 
 
95
    static void xim_destroy_callback(XIM /*im*/,
 
96
                                     XPointer client_data,
 
97
                                     XPointer /*call_data*/)
 
98
    {
 
99
        QXIMInputContext *qic = reinterpret_cast<QXIMInputContext *>(client_data);
 
100
        // qDebug("xim_destroy_callback");
 
101
        qic->close_xim();
 
102
        XRegisterIMInstantiateCallback(X11->display, 0, 0, 0,
 
103
                                       (XIMProc) xim_create_callback, reinterpret_cast<char *>(qic));
 
104
    }
 
105
#endif // USE_X11R6_XIM
 
106
 
 
107
    static int xic_start_callback(XIC, XPointer client_data, XPointer) {
 
108
        QXIMInputContext *qic = (QXIMInputContext *) client_data;
 
109
        if (!qic) {
 
110
            XIM_DEBUG("xic_start_callback: no qic");
 
111
            return 0;
 
112
        }
 
113
        QXIMInputContext::ICData *data = qic->icData();
 
114
        if (!data) {
 
115
            XIM_DEBUG("xic_start_callback: no ic data");
 
116
            return 0;
 
117
        }
 
118
        XIM_DEBUG("xic_start_callback");
 
119
 
 
120
        data->clear();
 
121
        data->composing = true;
 
122
 
 
123
        return 0;
 
124
    }
 
125
 
 
126
    static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) {
 
127
        QXIMInputContext *qic = (QXIMInputContext *) client_data;
 
128
        if (!qic) {
 
129
            XIM_DEBUG("xic_draw_callback: no qic");
 
130
            return 0;
 
131
        }
 
132
        QXIMInputContext::ICData *data = qic->icData();
 
133
        if (!data) {
 
134
            XIM_DEBUG("xic_draw_callback: no ic data");
 
135
            return 0;
 
136
        }
 
137
        XIM_DEBUG("xic_draw_callback");
 
138
 
 
139
 
 
140
        if(!data->composing) {
 
141
            data->clear();
 
142
            data->composing = true;
 
143
        }
 
144
 
 
145
        XIMPreeditDrawCallbackStruct *drawstruct = (XIMPreeditDrawCallbackStruct *) call_data;
 
146
        XIMText *text = (XIMText *) drawstruct->text;
 
147
        int cursor = drawstruct->caret, sellen = 0;
 
148
 
 
149
        if (!drawstruct->caret && !drawstruct->chg_first && !drawstruct->chg_length && !text) {
 
150
            if(data->text.isEmpty()) {
 
151
                XIM_DEBUG("compose emptied");
 
152
                // if the composition string has been emptied, we need
 
153
                // to send an InputMethodEnd event
 
154
                QInputMethodEvent e;
 
155
                qic->sendEvent(e);
 
156
                data->clear();
 
157
 
 
158
                // if the commit string has coming after here, InputMethodStart
 
159
                // will be sent dynamically
 
160
            }
 
161
            return 0;
 
162
        }
 
163
 
 
164
        if (text) {
 
165
            char *str = 0;
 
166
            if (text->encoding_is_wchar) {
 
167
                int l = wcstombs(NULL, text->string.wide_char, text->length);
 
168
                if (l != -1) {
 
169
                    str = new char[l + 1];
 
170
                    wcstombs(str, text->string.wide_char, l);
 
171
                    str[l] = 0;
 
172
                }
 
173
            } else
 
174
                str = text->string.multi_byte;
 
175
 
 
176
            if (!str)
 
177
                return 0;
 
178
 
 
179
            QString s = QString::fromLocal8Bit(str);
 
180
 
 
181
            if (text->encoding_is_wchar)
 
182
                delete [] str;
 
183
 
 
184
            if (drawstruct->chg_length < 0)
 
185
                data->text.replace(drawstruct->chg_first, UINT_MAX, s);
 
186
            else
 
187
                data->text.replace(drawstruct->chg_first, drawstruct->chg_length, s);
 
188
 
 
189
            if (data->selectedChars.size() < data->text.length()) {
 
190
                // expand the selectedChars array if the compose string is longer
 
191
                int from = data->selectedChars.size();
 
192
                data->selectedChars.resize(data->text.length());
 
193
                for (int x = from; x < data->selectedChars.size(); ++x)
 
194
                    data->selectedChars.clearBit(x);
 
195
            }
 
196
 
 
197
            // determine if the changed chars are selected based on text->feedback
 
198
            for (int x = 0; x < text->length; ++x)
 
199
                data->selectedChars.setBit(x + drawstruct->chg_first,
 
200
                                           (text->feedback ? (text->feedback[x] & XIMReverse) : 0));
 
201
 
 
202
            // figure out where the selection starts, and how long it is
 
203
            bool started = false;
 
204
            for (int x = 0; x < qMin(data->selectedChars.size(), data->text.length()); ++x) {
 
205
                if (started) {
 
206
                    if (data->selectedChars.testBit(x)) ++sellen;
 
207
                    else break;
 
208
                } else {
 
209
                    if (data->selectedChars.testBit(x)) {
 
210
                        cursor = x;
 
211
                        started = true;
 
212
                        sellen = 1;
 
213
                    }
 
214
                }
 
215
            }
 
216
        } else {
 
217
            if (drawstruct->chg_length == 0)
 
218
                drawstruct->chg_length = -1;
 
219
 
 
220
            data->text.remove(drawstruct->chg_first, drawstruct->chg_length);
 
221
            bool qt_compose_emptied = data->text.isEmpty();
 
222
            if (qt_compose_emptied) {
 
223
                XIM_DEBUG("compose emptied 2 text=%s", data->text.toUtf8().constData());
 
224
                // if the composition string has been emptied, we need
 
225
                // to send an InputMethodEnd event
 
226
                QInputMethodEvent e;
 
227
                qic->sendEvent(e);
 
228
                data->clear();
 
229
                // if the commit string has coming after here, InputMethodStart
 
230
                // will be sent dynamically
 
231
                return 0;
 
232
            }
 
233
        }
 
234
 
 
235
        if (!sellen)
 
236
            cursor = data->text.length();
 
237
        XIM_DEBUG("sending compose: '%s', cursor=%d, sellen=%d",
 
238
                  data->text.toUtf8().constData(), cursor, sellen);
 
239
        QList<QInputMethodEvent::Attribute> attrs;
 
240
        if (cursor > 0)
 
241
            attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, cursor,
 
242
                               qic->standardFormat(QInputContext::PreeditFormat));
 
243
        if (sellen)
 
244
            attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, cursor, sellen,
 
245
                               qic->standardFormat(QInputContext::SelectionFormat));
 
246
        if (cursor + sellen < data->text.length())
 
247
            attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
 
248
                                     cursor + sellen, data->text.length() - cursor - sellen,
 
249
                                     qic->standardFormat(QInputContext::PreeditFormat));
 
250
        QInputMethodEvent e(data->text, attrs);
 
251
        qic->sendEvent(e);
 
252
 
 
253
        return 0;
 
254
    }
 
255
 
 
256
    static int xic_done_callback(XIC, XPointer client_data, XPointer) {
 
257
        QXIMInputContext *qic = (QXIMInputContext *) client_data;
 
258
        if (!qic)
 
259
            return 0;
 
260
 
 
261
        XIM_DEBUG("xic_done_callback");
 
262
        // Don't send InputMethodEnd here. QXIMInputContext::x11FilterEvent()
 
263
        // handles InputMethodEnd with commit string.
 
264
        return 0;
 
265
    }
 
266
}
 
267
 
 
268
void QXIMInputContext::ICData::clear()
 
269
{
 
270
    text = QString();
 
271
    selectedChars.clear();
 
272
    composing = false;
 
273
}
 
274
 
 
275
QXIMInputContext::ICData *QXIMInputContext::icData() const
 
276
{
 
277
    return ximData.value(focusWidget());
 
278
}
 
279
/* The cache here is needed, as X11 leaks a few kb for every
 
280
   XFreeFontSet call, so we avoid creating and deletion of fontsets as
 
281
   much as possible
 
282
*/
 
283
static XFontSet fontsetCache[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
284
static int fontsetRefCount = 0;
 
285
 
 
286
static const char * const fontsetnames[] = {
 
287
    "-*-fixed-medium-r-*-*-16-*,-*-*-medium-r-*-*-16-*",
 
288
    "-*-fixed-medium-i-*-*-16-*,-*-*-medium-i-*-*-16-*",
 
289
    "-*-fixed-bold-r-*-*-16-*,-*-*-bold-r-*-*-16-*",
 
290
    "-*-fixed-bold-i-*-*-16-*,-*-*-bold-i-*-*-16-*",
 
291
    "-*-fixed-medium-r-*-*-24-*,-*-*-medium-r-*-*-24-*",
 
292
    "-*-fixed-medium-i-*-*-24-*,-*-*-medium-i-*-*-24-*",
 
293
    "-*-fixed-bold-r-*-*-24-*,-*-*-bold-r-*-*-24-*",
 
294
    "-*-fixed-bold-i-*-*-24-*,-*-*-bold-i-*-*-24-*"
 
295
};
 
296
 
 
297
static XFontSet getFontSet(const QFont &f)
 
298
{
 
299
    int i = 0;
 
300
    if (f.italic())
 
301
        i |= 1;
 
302
    if (f.bold())
 
303
        i |= 2;
 
304
 
 
305
    if (f.pointSize() > 20)
 
306
        i += 4;
 
307
 
 
308
    if (!fontsetCache[i]) {
 
309
        Display* dpy = X11->display;
 
310
        int missCount;
 
311
        char** missList;
 
312
        fontsetCache[i] = XCreateFontSet(dpy, fontsetnames[i], &missList, &missCount, 0);
 
313
        if(missCount > 0)
 
314
            XFreeStringList(missList);
 
315
        if (!fontsetCache[i]) {
 
316
            fontsetCache[i] = XCreateFontSet(dpy, "-*-fixed-*-*-*-*-16-*", &missList, &missCount, 0);
 
317
            if(missCount > 0)
 
318
                XFreeStringList(missList);
 
319
            if (!fontsetCache[i])
 
320
                fontsetCache[i] = (XFontSet)-1;
 
321
        }
 
322
    }
 
323
    return (fontsetCache[i] == (XFontSet)-1) ? 0 : fontsetCache[i];
 
324
}
 
325
 
 
326
 
 
327
 
 
328
QXIMInputContext::QXIMInputContext()
 
329
{
 
330
    if (!qt_xim_preferred_style) // no configured input style, use the default
 
331
        qt_xim_preferred_style = xim_default_style;
 
332
 
 
333
    xim = 0;
 
334
    QByteArray ximServerName(qt_ximServer);
 
335
    if (qt_ximServer)
 
336
        ximServerName.prepend("@im=");
 
337
    else
 
338
        ximServerName = "";
 
339
 
 
340
    if (!XSupportsLocale())
 
341
        qWarning("Qt: Locales not supported on X server");
 
342
 
 
343
#ifdef USE_X11R6_XIM
 
344
    else if (XSetLocaleModifiers (ximServerName.constData()) == 0)
 
345
        qWarning("Qt: Cannot set locale modifiers: %s", ximServerName.constData());
 
346
    else /* if (!noxim) */
 
347
        XRegisterIMInstantiateCallback(X11->display, 0, 0, 0,
 
348
                                       (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));
 
349
#else // !USE_X11R6_XIM
 
350
    else if (XSetLocaleModifiers ("") == 0)
 
351
        qWarning("Qt: Cannot set locale modifiers");
 
352
    else /* if (!noxim) */
 
353
        QXIMInputContext::create_xim();
 
354
#endif // USE_X11R6_XIM
 
355
}
 
356
 
 
357
 
 
358
/*!\internal
 
359
  Creates the application input method.
 
360
*/
 
361
void QXIMInputContext::create_xim()
 
362
{
 
363
    ++fontsetRefCount;
 
364
#ifndef QT_NO_XIM
 
365
    xim = XOpenIM(X11->display, 0, 0, 0);
 
366
    if (xim) {
 
367
 
 
368
#ifdef USE_X11R6_XIM
 
369
        XIMCallback destroy;
 
370
        destroy.callback = (XIMProc) xim_destroy_callback;
 
371
        destroy.client_data = 0;
 
372
        if (XSetIMValues(xim, XNDestroyCallback, &destroy, (char *) 0) != 0)
 
373
            qWarning("Xlib dosn't support destroy callback");
 
374
#endif // USE_X11R6_XIM
 
375
 
 
376
        XIMStyles *styles = 0;
 
377
        XGetIMValues(xim, XNQueryInputStyle, &styles, (char *) 0, (char *) 0);
 
378
        if (styles) {
 
379
            int i;
 
380
            for (i = 0; !xim_style && i < styles->count_styles; i++) {
 
381
                if (styles->supported_styles[i] == qt_xim_preferred_style) {
 
382
                    xim_style = qt_xim_preferred_style;
 
383
                    break;
 
384
                }
 
385
            }
 
386
            // if the preferred input style couldn't be found, look for
 
387
            // Nothing
 
388
            for (i = 0; !xim_style && i < styles->count_styles; i++) {
 
389
                if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) {
 
390
                    xim_style = XIMPreeditNothing | XIMStatusNothing;
 
391
                    break;
 
392
                }
 
393
            }
 
394
            // ... and failing that, None.
 
395
            for (i = 0; !xim_style && i < styles->count_styles; i++) {
 
396
                if (styles->supported_styles[i] == (XIMPreeditNone |
 
397
                                                    XIMStatusNone)) {
 
398
                    xim_style = XIMPreeditNone | XIMStatusNone;
 
399
                    break;
 
400
                }
 
401
            }
 
402
 
 
403
            // qDebug("QApplication: using im style %lx", xim_style);
 
404
            XFree((char *)styles);
 
405
        }
 
406
 
 
407
        if (xim_style) {
 
408
 
 
409
#ifdef USE_X11R6_XIM
 
410
            XUnregisterIMInstantiateCallback(X11->display, 0, 0, 0,
 
411
                                             (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));
 
412
#endif // USE_X11R6_XIM
 
413
 
 
414
            // following code fragment is not required for immodule
 
415
            // version of XIM
 
416
#if 0
 
417
            QWidgetList list = qApp->topLevelWidgets();
 
418
            for (int i = 0; i < list.size(); ++i) {
 
419
                QWidget *w = list.at(i);
 
420
                w->d->createTLSysExtra();
 
421
            }
 
422
#endif
 
423
        } else {
 
424
            // Give up
 
425
            qWarning("No supported input style found."
 
426
                     "  See InputMethod documentation.");
 
427
            close_xim();
 
428
        }
 
429
    }
 
430
#endif // QT_NO_XIM
 
431
}
 
432
 
 
433
/*!\internal
 
434
  Closes the application input method.
 
435
*/
 
436
void QXIMInputContext::close_xim()
 
437
{
 
438
    QString errMsg("QXIMInputContext::close_xim() has been called");
 
439
 
 
440
    // ###clean up ximData!
 
441
    ximData.clear();
 
442
 
 
443
    // ############## check this!
 
444
    // Calling XCloseIM gives a Purify FMR error
 
445
    // XCloseIM(xim);
 
446
    // We prefer a less serious memory leak
 
447
    xim = 0;
 
448
 
 
449
    if ( --fontsetRefCount == 0 ) {
 
450
        Display *dpy = X11->display;
 
451
        for ( int i = 0; i < 8; i++ ) {
 
452
            if ( fontsetCache[i] && fontsetCache[i] != (XFontSet)-1 ) {
 
453
                XFreeFontSet(dpy, fontsetCache[i]);
 
454
                fontsetCache[i] = 0;
 
455
            }
 
456
        }
 
457
    }
 
458
}
 
459
 
 
460
 
 
461
 
 
462
QXIMInputContext::~QXIMInputContext()
 
463
{
 
464
    close_xim();
 
465
}
 
466
 
 
467
 
 
468
QString QXIMInputContext::identifierName()
 
469
{
 
470
    // the name should be "xim" rather than "XIM" to be consistent
 
471
    // with corresponding immodule of GTK+
 
472
    return "xim";
 
473
}
 
474
 
 
475
 
 
476
QString QXIMInputContext::language()
 
477
{
 
478
    QString language;
 
479
    if (xim) {
 
480
        QByteArray locale(XLocaleOfIM(xim));
 
481
 
 
482
        if (locale.startsWith("zh")) {
 
483
            // Chinese language should be formed as "zh_CN", "zh_TW", "zh_HK"
 
484
            language = locale.left(5);
 
485
        } else {
 
486
            // other languages should be two-letter ISO 639 language code
 
487
            language = locale.left(2);
 
488
        }
 
489
    }
 
490
    return language;
 
491
}
 
492
 
 
493
void QXIMInputContext::reset()
 
494
{
 
495
    QWidget *w = focusWidget();
 
496
    if (!w)
 
497
        return;
 
498
 
 
499
    ICData *data = ximData.value(w);
 
500
    if (!data)
 
501
        return;
 
502
 
 
503
    if (data->ic) {
 
504
        char *mb = XmbResetIC(data->ic);
 
505
        if (mb) {
 
506
            QInputMethodEvent e;
 
507
            e.setCommitString(QString::fromLocal8Bit(mb));
 
508
            sendEvent(e);
 
509
            XFree(mb);
 
510
        }
 
511
    }
 
512
    data->clear();
 
513
}
 
514
 
 
515
void QXIMInputContext::widgetDestroyed(QWidget *w)
 
516
{
 
517
    QInputContext::widgetDestroyed(w);
 
518
    ICData *data = ximData.take(w);
 
519
    if (!data)
 
520
        return;
 
521
 
 
522
    data->clear();
 
523
    if (data->ic)
 
524
        XDestroyIC(data->ic);
 
525
    delete data;
 
526
}
 
527
 
 
528
void QXIMInputContext::mouseHandler(int pos, QMouseEvent *)
 
529
{
 
530
    XIM_DEBUG("QXIMInputContext::mouseHandler pos=%d", pos);
 
531
    ICData *data = ximData.value(focusWidget());
 
532
    if (!data)
 
533
        return;
 
534
    if (pos < 0 || pos > data->text.length())
 
535
        reset();
 
536
    // ##### handle mouse position
 
537
}
 
538
 
 
539
bool QXIMInputContext::isComposing() const
 
540
{
 
541
    QWidget *w = focusWidget();
 
542
    if (!w)
 
543
        return false;
 
544
 
 
545
    ICData *data = ximData.value(w);
 
546
    if (!data)
 
547
        return false;
 
548
    return data->composing;
 
549
}
 
550
 
 
551
void QXIMInputContext::setFocusWidget(QWidget *w)
 
552
{
 
553
    QWidget *oldFocus = focusWidget();
 
554
    if (oldFocus == w)
 
555
        return;
 
556
 
 
557
    if (language() != QLatin1String("ja"))
 
558
        reset();
 
559
 
 
560
    if (oldFocus) {
 
561
        ICData *data = ximData.value(oldFocus);
 
562
        if (data && data->ic)
 
563
            XUnsetICFocus(data->ic);
 
564
    }
 
565
 
 
566
    QInputContext::setFocusWidget(w);
 
567
 
 
568
    if (!w)
 
569
        return;
 
570
 
 
571
    ICData *data = ximData.value(w);
 
572
    if (!data)
 
573
        data = createICData(w);
 
574
 
 
575
    if (data->ic)
 
576
        XSetICFocus(data->ic);
 
577
 
 
578
    update();
 
579
}
 
580
 
 
581
 
 
582
bool QXIMInputContext::x11FilterEvent(QWidget *keywidget, XEvent *event)
 
583
{
 
584
    int xkey_keycode = event->xkey.keycode;
 
585
    if (XFilterEvent(event, keywidget->winId())) {
 
586
        qt_ximComposingKeycode = xkey_keycode; // ### not documented in xlib
 
587
 
 
588
        return true;
 
589
    }
 
590
    if (event->type != XKeyPress || event->xkey.keycode != 0)
 
591
        return false;
 
592
 
 
593
    QWidget *w = focusWidget();
 
594
    if (keywidget != w)
 
595
        return false;
 
596
    ICData *data = ximData.value(w);
 
597
    if (!data)
 
598
        return false;
 
599
 
 
600
    // input method has sent us a commit string
 
601
    QByteArray string;
 
602
    string.resize(513);
 
603
    KeySym key;    // unused
 
604
    Status status; // unused
 
605
    QString text;
 
606
    int count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(),
 
607
                                &key, &status);
 
608
 
 
609
    if (status == XBufferOverflow) {
 
610
        string.resize(count + 1);
 
611
        count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(),
 
612
                                &key, &status);
 
613
    }
 
614
    if (count > 0)
 
615
        text = qt_input_mapper->toUnicode(string.constData() , count);
 
616
 
 
617
#if 0
 
618
    if (!(xim_style & XIMPreeditCallbacks) || !isComposing()) {
 
619
        // ############### send a regular key event here!
 
620
        ;
 
621
    }
 
622
#endif
 
623
 
 
624
    QInputMethodEvent e;
 
625
    e.setCommitString(text);
 
626
    sendEvent(e);
 
627
    data->clear();
 
628
    return true;
 
629
}
 
630
 
 
631
 
 
632
QXIMInputContext::ICData *QXIMInputContext::createICData(QWidget *w)
 
633
{
 
634
    ICData *data = new ICData;
 
635
    data->widget = w;
 
636
 
 
637
    XVaNestedList preedit_attr = 0;
 
638
    XIMCallback startcallback, drawcallback, donecallback;
 
639
 
 
640
    QFont font = w->font();
 
641
    data->fontset = getFontSet(font);
 
642
 
 
643
    if (xim_style & XIMPreeditArea) {
 
644
        XRectangle rect;
 
645
        rect.x = 0;
 
646
        rect.y = 0;
 
647
        rect.width = w->width();
 
648
        rect.height = w->height();
 
649
 
 
650
        preedit_attr = XVaCreateNestedList(0,
 
651
                                           XNArea, &rect,
 
652
                                           XNFontSet, data->fontset,
 
653
                                           (char *) 0);
 
654
    } else if (xim_style & XIMPreeditPosition) {
 
655
        XPoint spot;
 
656
        spot.x = 1;
 
657
        spot.y = 1;
 
658
 
 
659
        preedit_attr = XVaCreateNestedList(0,
 
660
                                           XNSpotLocation, &spot,
 
661
                                           XNFontSet, data->fontset,
 
662
                                           (char *) 0);
 
663
    } else if (xim_style & XIMPreeditCallbacks) {
 
664
        startcallback.client_data = (XPointer) this;
 
665
        startcallback.callback = (XIMProc) xic_start_callback;
 
666
        drawcallback.client_data = (XPointer) this;
 
667
        drawcallback.callback = (XIMProc)xic_draw_callback;
 
668
        donecallback.client_data = (XPointer) this;
 
669
        donecallback.callback = (XIMProc) xic_done_callback;
 
670
 
 
671
        preedit_attr = XVaCreateNestedList(0,
 
672
                                           XNPreeditStartCallback, &startcallback,
 
673
                                           XNPreeditDrawCallback, &drawcallback,
 
674
                                           XNPreeditDoneCallback, &donecallback,
 
675
                                           (char *) 0);
 
676
    }
 
677
 
 
678
    if (preedit_attr) {
 
679
        data->ic = XCreateIC(xim,
 
680
                             XNInputStyle, xim_style,
 
681
                             XNClientWindow, w->winId(),
 
682
                             XNPreeditAttributes, preedit_attr,
 
683
                             (char *) 0);
 
684
        XFree(preedit_attr);
 
685
    } else {
 
686
        data->ic = XCreateIC(xim,
 
687
                             XNInputStyle, xim_style,
 
688
                             XNClientWindow, w->winId(),
 
689
                             (char *) 0);
 
690
    }
 
691
 
 
692
    if (data->ic) {
 
693
        // when resetting the input context, preserve the input state
 
694
        (void) XSetICValues(data->ic, XNResetState, XIMPreserveState, (char *) 0);
 
695
    } else {
 
696
        qWarning("Failed to create XIC");
 
697
    }
 
698
 
 
699
    ximData[w] = data;
 
700
    return data;
 
701
}
 
702
 
 
703
void QXIMInputContext::update()
 
704
{
 
705
    QWidget *w = focusWidget();
 
706
    if (!w)
 
707
        return;
 
708
 
 
709
    ICData *data = ximData.value(w);
 
710
    if (!data || !data->ic)
 
711
        return;
 
712
 
 
713
    QRect r = w->inputMethodQuery(Qt::ImMicroFocus).toRect();
 
714
    QPoint p = r.bottomLeft();
 
715
    XPoint spot;
 
716
    spot.x = p.x();
 
717
    spot.y = p.y();
 
718
 
 
719
    r = w->rect();
 
720
    XRectangle area;
 
721
    area.x = r.x();
 
722
    area.y = r.y();
 
723
    area.width = r.width();
 
724
    area.height = r.height();
 
725
 
 
726
    XFontSet fontset = getFontSet(qvariant_cast<QFont>(w->inputMethodQuery(Qt::ImFont)));
 
727
    if (data->fontset == fontset)
 
728
        fontset = 0;
 
729
    else
 
730
        data->fontset = fontset;
 
731
 
 
732
    XVaNestedList preedit_attr;
 
733
    if (fontset)
 
734
        preedit_attr = XVaCreateNestedList(0,
 
735
                                           XNSpotLocation, &spot,
 
736
                                           XNArea, &area,
 
737
                                           XNFontSet, fontset,
 
738
                                           (char *) 0);
 
739
    else
 
740
        preedit_attr = XVaCreateNestedList(0,
 
741
                                           XNSpotLocation, &spot,
 
742
                                           XNArea, &area,
 
743
                                           (char *) 0);
 
744
 
 
745
    XSetICValues(data->ic, XNPreeditAttributes, preedit_attr, (char *) 0);
 
746
    XFree(preedit_attr);
 
747
}
 
748
 
 
749
 
 
750
#else
 
751
/*
 
752
    When QT_NO_XIM is defined, we provide a dummy implementation for
 
753
    this class. The reason for this is that the header file is moc'ed
 
754
    regardless of QT_NO_XIM. The best would be to remove the file
 
755
    completely from the pri file is QT_NO_XIM was defined, or for moc
 
756
    to understand this preprocessor directive. Since the header does
 
757
    not declare this class when QT_NO_XIM is defined, this is dead
 
758
    code.
 
759
*/
 
760
bool QXIMInputContext::isComposing() const { return false; }
 
761
QString QXIMInputContext::identifierName() { return QString(); }
 
762
void QXIMInputContext::mouseHandler(int, QMouseEvent *) {}
 
763
void QXIMInputContext::setFocusWidget(QWidget *) {}
 
764
void QXIMInputContext::reset() {}
 
765
void QXIMInputContext::update() {}
 
766
QXIMInputContext::~QXIMInputContext() {}
 
767
void QXIMInputContext::widgetDestroyed(QWidget *) {}
 
768
QString QXIMInputContext::language() { return QString(); }
 
769
bool QXIMInputContext::x11FilterEvent(QWidget *, XEvent *) { return true; }
 
770
#endif //QT_NO_XIM
 
771
 
 
772
#endif //QT_NO_IM