Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c
41155 views
1
/*
2
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#ifdef HEADLESS
27
#error This file should not be included in headless library
28
#endif
29
30
#include "awt.h"
31
#include "awt_p.h"
32
33
#include <sun_awt_X11InputMethodBase.h>
34
#include <sun_awt_X11_XInputMethod.h>
35
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <sys/time.h>
39
#include <X11/keysym.h>
40
#include <X11/Xlib.h>
41
42
#define THROW_OUT_OF_MEMORY_ERROR() \
43
JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)
44
45
struct X11InputMethodIDs {
46
jfieldID pData;
47
} x11InputMethodIDs;
48
49
static int PreeditStartCallback(XIC, XPointer, XPointer);
50
static void PreeditDoneCallback(XIC, XPointer, XPointer);
51
static void PreeditDrawCallback(XIC, XPointer,
52
XIMPreeditDrawCallbackStruct *);
53
static void PreeditCaretCallback(XIC, XPointer,
54
XIMPreeditCaretCallbackStruct *);
55
#if defined(__linux__)
56
static void StatusStartCallback(XIC, XPointer, XPointer);
57
static void StatusDoneCallback(XIC, XPointer, XPointer);
58
static void StatusDrawCallback(XIC, XPointer,
59
XIMStatusDrawCallbackStruct *);
60
#endif
61
62
#define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing)
63
#define NO_STYLES (XIMPreeditNone | XIMStatusNone)
64
65
#define PreeditStartIndex 0
66
#define PreeditDoneIndex 1
67
#define PreeditDrawIndex 2
68
#define PreeditCaretIndex 3
69
#if defined(__linux__)
70
#define StatusStartIndex 4
71
#define StatusDoneIndex 5
72
#define StatusDrawIndex 6
73
#define NCALLBACKS 7
74
#else
75
#define NCALLBACKS 4
76
#endif
77
78
/*
79
* Callback function pointers: the order has to match the *Index
80
* values above.
81
*/
82
static XIMProc callback_funcs[NCALLBACKS] = {
83
(XIMProc)(void *)&PreeditStartCallback,
84
(XIMProc)PreeditDoneCallback,
85
(XIMProc)PreeditDrawCallback,
86
(XIMProc)PreeditCaretCallback,
87
#if defined(__linux__)
88
(XIMProc)StatusStartCallback,
89
(XIMProc)StatusDoneCallback,
90
(XIMProc)StatusDrawCallback,
91
#endif
92
};
93
94
#if defined(__linux__)
95
#define MAX_STATUS_LEN 100
96
typedef struct {
97
Window w; /*status window id */
98
Window root; /*the root window id */
99
Window parent; /*parent shell window */
100
int x, y; /*parent's upperleft position */
101
int width, height; /*parent's width, height */
102
GC lightGC; /*gc for light border */
103
GC dimGC; /*gc for dim border */
104
GC bgGC; /*normal painting */
105
GC fgGC; /*normal painting */
106
int statusW, statusH; /*status window's w, h */
107
int rootW, rootH; /*root window's w, h */
108
int bWidth; /*border width */
109
char status[MAX_STATUS_LEN]; /*status text */
110
XFontSet fontset; /*fontset for drawing */
111
int off_x, off_y;
112
Bool on; /*if the status window on*/
113
} StatusWindow;
114
#endif
115
116
/*
117
* X11InputMethodData keeps per X11InputMethod instance information. A pointer
118
* to this data structure is kept in an X11InputMethod object (pData).
119
*/
120
typedef struct _X11InputMethodData {
121
XIC current_ic; /* current X Input Context */
122
XIC ic_active; /* X Input Context for active clients */
123
XIC ic_passive; /* X Input Context for passive clients */
124
XIMCallback *callbacks; /* callback parameters */
125
jobject x11inputmethod; /* global ref to X11InputMethod instance */
126
/* associated with the XIC */
127
#if defined(__linux__)
128
StatusWindow *statusWindow; /* our own status window */
129
#endif
130
char *lookup_buf; /* buffer used for XmbLookupString */
131
int lookup_buf_len; /* lookup buffer size in bytes */
132
} X11InputMethodData;
133
134
/*
135
* When XIC is created, a global reference is created for
136
* sun.awt.X11InputMethod object so that it could be used by the XIM callback
137
* functions. This could be a dangerous thing to do when the original
138
* X11InputMethod object is garbage collected and as a result,
139
* destroyX11InputMethodData is called to delete the global reference.
140
* If any XIM callback function still holds and uses the "already deleted"
141
* global reference, disaster is going to happen. So we have to maintain
142
* a list for these global references which is consulted first when the
143
* callback functions or any function tries to use "currentX11InputMethodObject"
144
* which always refers to the global reference try to use it.
145
*
146
*/
147
typedef struct _X11InputMethodGRefNode {
148
jobject inputMethodGRef;
149
struct _X11InputMethodGRefNode* next;
150
} X11InputMethodGRefNode;
151
152
X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL;
153
154
/* reference to the current X11InputMethod instance, it is always
155
point to the global reference to the X11InputMethodObject since
156
it could be referenced by different threads. */
157
jobject currentX11InputMethodInstance = NULL;
158
159
Window currentFocusWindow = 0; /* current window that has focus for input
160
method. (the best place to put this
161
information should be
162
currentX11InputMethodInstance's pData) */
163
static XIM X11im = NULL;
164
Display * dpy = NULL;
165
166
#define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)
167
168
static void DestroyXIMCallback(XIM, XPointer, XPointer);
169
static void OpenXIMCallback(Display *, XPointer, XPointer);
170
/* Solaris XIM Extention */
171
#define XNCommitStringCallback "commitStringCallback"
172
static void CommitStringCallback(XIC, XPointer, XPointer);
173
174
static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject);
175
static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *);
176
static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *);
177
static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *);
178
#if defined(__linux__)
179
static Window getParentWindow(Window);
180
#endif
181
182
/*
183
* This function is stolen from /src/solaris/hpi/src/system_md.c
184
* It is used in setting the time in Java-level InputEvents
185
*/
186
jlong
187
awt_util_nowMillisUTC()
188
{
189
struct timeval t;
190
gettimeofday(&t, NULL);
191
return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
192
}
193
194
/*
195
* Converts the wchar_t string to a multi-byte string calling wcstombs(). A
196
* buffer is allocated by malloc() to store the multi-byte string. NULL is
197
* returned if the given wchar_t string pointer is NULL or buffer allocation is
198
* failed.
199
*/
200
static char *
201
wcstombsdmp(wchar_t *wcs, int len)
202
{
203
size_t n;
204
char *mbs;
205
206
if (wcs == NULL)
207
return NULL;
208
209
n = len*MB_CUR_MAX + 1;
210
211
mbs = (char *) malloc(n * sizeof(char));
212
if (mbs == NULL) {
213
THROW_OUT_OF_MEMORY_ERROR();
214
return NULL;
215
}
216
217
/* TODO: check return values... Handle invalid characters properly... */
218
if (wcstombs(mbs, wcs, n) == (size_t)-1) {
219
free(mbs);
220
return NULL;
221
}
222
223
return mbs;
224
}
225
226
/*
227
* Returns True if the global reference is still in the list,
228
* otherwise False.
229
*/
230
static Bool isX11InputMethodGRefInList(jobject imGRef) {
231
X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead;
232
233
if (imGRef == NULL) {
234
return False;
235
}
236
237
while (pX11InputMethodGRef != NULL) {
238
if (pX11InputMethodGRef->inputMethodGRef == imGRef) {
239
return True;
240
}
241
pX11InputMethodGRef = pX11InputMethodGRef->next;
242
}
243
244
return False;
245
}
246
247
/*
248
* Add the new created global reference to the list.
249
*/
250
static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) {
251
X11InputMethodGRefNode *newNode = NULL;
252
253
if (newX11InputMethodGRef == NULL ||
254
isX11InputMethodGRefInList(newX11InputMethodGRef)) {
255
return;
256
}
257
258
newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode));
259
260
if (newNode == NULL) {
261
return;
262
} else {
263
newNode->inputMethodGRef = newX11InputMethodGRef;
264
newNode->next = x11InputMethodGRefListHead;
265
x11InputMethodGRefListHead = newNode;
266
}
267
}
268
269
/*
270
* Remove the global reference from the list.
271
*/
272
static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) {
273
X11InputMethodGRefNode *pX11InputMethodGRef = NULL;
274
X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead;
275
276
if (x11InputMethodGRefListHead == NULL ||
277
x11InputMethodGRef == NULL) {
278
return;
279
}
280
281
/* cX11InputMethodGRef always refers to the current node while
282
pX11InputMethodGRef refers to the previous node.
283
*/
284
while (cX11InputMethodGRef != NULL) {
285
if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) {
286
break;
287
}
288
pX11InputMethodGRef = cX11InputMethodGRef;
289
cX11InputMethodGRef = cX11InputMethodGRef->next;
290
}
291
292
if (cX11InputMethodGRef == NULL) {
293
return; /* Not found. */
294
}
295
296
if (cX11InputMethodGRef == x11InputMethodGRefListHead) {
297
x11InputMethodGRefListHead = x11InputMethodGRefListHead->next;
298
} else {
299
pX11InputMethodGRef->next = cX11InputMethodGRef->next;
300
}
301
free(cX11InputMethodGRef);
302
303
return;
304
}
305
306
307
static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {
308
X11InputMethodData *pX11IMData =
309
(X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);
310
311
/*
312
* In case the XIM server was killed somehow, reset X11InputMethodData.
313
*/
314
if (X11im == NULL && pX11IMData != NULL) {
315
JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
316
"flushText",
317
"()V");
318
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
319
/* IMPORTANT:
320
The order of the following calls is critical since "imInstance" may
321
point to the global reference itself, if "freeX11InputMethodData" is called
322
first, the global reference will be destroyed and "setX11InputMethodData"
323
will in fact fail silently. So pX11IMData will not be set to NULL.
324
This could make the original java object refers to a deleted pX11IMData
325
object.
326
*/
327
setX11InputMethodData(env, imInstance, NULL);
328
freeX11InputMethodData(env, pX11IMData);
329
pX11IMData = NULL;
330
}
331
332
return pX11IMData;
333
}
334
335
static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) {
336
JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData);
337
}
338
339
/* this function should be called within AWT_LOCK() */
340
static void
341
destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
342
{
343
/*
344
* Destroy XICs
345
*/
346
if (pX11IMData == NULL) {
347
return;
348
}
349
350
if (pX11IMData->ic_active != (XIC)0) {
351
XUnsetICFocus(pX11IMData->ic_active);
352
XDestroyIC(pX11IMData->ic_active);
353
if (pX11IMData->ic_active != pX11IMData->ic_passive) {
354
if (pX11IMData->ic_passive != (XIC)0) {
355
XUnsetICFocus(pX11IMData->ic_passive);
356
XDestroyIC(pX11IMData->ic_passive);
357
}
358
pX11IMData->ic_passive = (XIC)0;
359
pX11IMData->current_ic = (XIC)0;
360
}
361
}
362
363
freeX11InputMethodData(env, pX11IMData);
364
}
365
366
static void
367
freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
368
{
369
#if defined(__linux__)
370
if (pX11IMData->statusWindow != NULL){
371
StatusWindow *sw = pX11IMData->statusWindow;
372
XFreeGC(awt_display, sw->lightGC);
373
XFreeGC(awt_display, sw->dimGC);
374
XFreeGC(awt_display, sw->bgGC);
375
XFreeGC(awt_display, sw->fgGC);
376
if (sw->fontset != NULL) {
377
XFreeFontSet(awt_display, sw->fontset);
378
}
379
XDestroyWindow(awt_display, sw->w);
380
free((void*)sw);
381
}
382
#endif
383
384
if (pX11IMData->callbacks)
385
free((void *)pX11IMData->callbacks);
386
387
if (env) {
388
/* Remove the global reference from the list, so that
389
the callback function or whoever refers to it could know.
390
*/
391
removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod);
392
(*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);
393
}
394
395
if (pX11IMData->lookup_buf) {
396
free((void *)pX11IMData->lookup_buf);
397
}
398
399
free((void *)pX11IMData);
400
}
401
402
/*
403
* Sets or unsets the focus to the given XIC.
404
*/
405
static void
406
setXICFocus(XIC ic, unsigned short req)
407
{
408
if (ic == NULL) {
409
(void)fprintf(stderr, "Couldn't find X Input Context\n");
410
return;
411
}
412
if (req == 1)
413
XSetICFocus(ic);
414
else
415
XUnsetICFocus(ic);
416
}
417
418
/*
419
* Sets the focus window to the given XIC.
420
*/
421
static void
422
setXICWindowFocus(XIC ic, Window w)
423
{
424
if (ic == NULL) {
425
(void)fprintf(stderr, "Couldn't find X Input Context\n");
426
return;
427
}
428
(void) XSetICValues(ic, XNFocusWindow, w, NULL);
429
}
430
431
/*
432
* Invokes XmbLookupString() to get something from the XIM. It invokes
433
* X11InputMethod.dispatchCommittedText() if XmbLookupString() returns
434
* committed text. This function is called from handleKeyEvent in canvas.c and
435
* it's under the Motif event loop thread context.
436
*
437
* Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,
438
* where it never returns XBufferOverflow. We need to allocate the initial lookup buffer
439
* big enough, so that the possibility that user encounters this problem is relatively
440
* small. When this bug gets fixed, we can make the initial buffer size smaller.
441
* Note that XmbLookupString() sometimes produces a non-null-terminated string.
442
*
443
* Returns True when there is a keysym value to be handled.
444
*/
445
#define INITIAL_LOOKUP_BUF_SIZE 512
446
447
Boolean
448
awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)
449
{
450
JNIEnv *env = GetJNIEnv();
451
X11InputMethodData *pX11IMData = NULL;
452
KeySym keysym = NoSymbol;
453
Status status;
454
int mblen;
455
jstring javastr;
456
XIC ic;
457
Boolean result = True;
458
static Boolean composing = False;
459
460
/*
461
printf("lookupString: entering...\n");
462
*/
463
464
if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
465
currentX11InputMethodInstance = NULL;
466
return False;
467
}
468
469
pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
470
471
if (pX11IMData == NULL) {
472
#if defined(__linux__)
473
return False;
474
#else
475
return result;
476
#endif
477
}
478
479
if ((ic = pX11IMData->current_ic) == (XIC)0){
480
#if defined(__linux__)
481
return False;
482
#else
483
return result;
484
#endif
485
}
486
487
/* allocate the lookup buffer at the first invocation */
488
if (pX11IMData->lookup_buf_len == 0) {
489
pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE);
490
if (pX11IMData->lookup_buf == NULL) {
491
THROW_OUT_OF_MEMORY_ERROR();
492
return result;
493
}
494
pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE;
495
}
496
497
mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
498
pX11IMData->lookup_buf_len - 1, &keysym, &status);
499
500
/*
501
* In case of overflow, a buffer is allocated and it retries
502
* XmbLookupString().
503
*/
504
if (status == XBufferOverflow) {
505
free((void *)pX11IMData->lookup_buf);
506
pX11IMData->lookup_buf_len = 0;
507
pX11IMData->lookup_buf = (char *)malloc(mblen + 1);
508
if (pX11IMData->lookup_buf == NULL) {
509
THROW_OUT_OF_MEMORY_ERROR();
510
return result;
511
}
512
pX11IMData->lookup_buf_len = mblen + 1;
513
mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
514
pX11IMData->lookup_buf_len - 1, &keysym, &status);
515
}
516
pX11IMData->lookup_buf[mblen] = 0;
517
518
/* Get keysym without taking modifiers into account first to map
519
* to AWT keyCode table.
520
*/
521
switch (status) {
522
case XLookupBoth:
523
if (!composing) {
524
if (event->keycode != 0) {
525
*keysymp = keysym;
526
result = False;
527
break;
528
}
529
}
530
composing = False;
531
/*FALLTHRU*/
532
case XLookupChars:
533
/*
534
printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
535
event->type, event->state, event->keycode, keysym);
536
*/
537
javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
538
if (javastr != NULL) {
539
JNU_CallMethodByName(env, NULL,
540
currentX11InputMethodInstance,
541
"dispatchCommittedText",
542
"(Ljava/lang/String;J)V",
543
javastr,
544
event->time);
545
}
546
break;
547
548
case XLookupKeySym:
549
/*
550
printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
551
event->type, event->state, event->keycode, keysym);
552
*/
553
if (keysym == XK_Multi_key)
554
composing = True;
555
if (! composing) {
556
*keysymp = keysym;
557
result = False;
558
}
559
break;
560
561
case XLookupNone:
562
/*
563
printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
564
event->type, event->state, event->keycode, keysym);
565
*/
566
break;
567
}
568
569
return result;
570
}
571
572
#if defined(__linux__)
573
static StatusWindow *createStatusWindow(Window parent) {
574
StatusWindow *statusWindow;
575
XSetWindowAttributes attrib;
576
unsigned long attribmask;
577
Window containerWindow;
578
Window status;
579
Window child;
580
XWindowAttributes xwa;
581
XWindowAttributes xxwa;
582
/* Variable for XCreateFontSet()*/
583
char **mclr;
584
int mccr = 0;
585
char *dsr;
586
unsigned long bg, fg, light, dim;
587
int x, y, off_x, off_y, xx, yy;
588
unsigned int w, h, bw, depth;
589
XGCValues values;
590
unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/
591
int screen = 0;
592
int i;
593
AwtGraphicsConfigDataPtr adata;
594
extern int awt_numScreens;
595
/*hardcode the size right now, should get the size base on font*/
596
int width=80, height=22;
597
Window rootWindow;
598
Window *ignoreWindowPtr;
599
unsigned int ignoreUnit;
600
601
XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
602
603
attrib.override_redirect = True;
604
attribmask = CWOverrideRedirect;
605
for (i = 0; i < awt_numScreens; i++) {
606
if (RootWindow(dpy, i) == rootWindow) {
607
screen = i;
608
break;
609
}
610
}
611
adata = getDefaultConfig(screen);
612
bg = adata->AwtColorMatch(255, 255, 255, adata);
613
fg = adata->AwtColorMatch(0, 0, 0, adata);
614
light = adata->AwtColorMatch(195, 195, 195, adata);
615
dim = adata->AwtColorMatch(128, 128, 128, adata);
616
617
XGetWindowAttributes(dpy, parent, &xwa);
618
bw = 2; /*xwa.border_width does not have the correct value*/
619
620
/*compare the size difference between parent container
621
and shell widget, the diff should be the border frame
622
and title bar height (?)*/
623
624
XQueryTree( dpy,
625
parent,
626
&rootWindow,
627
&containerWindow,
628
&ignoreWindowPtr,
629
&ignoreUnit);
630
XGetWindowAttributes(dpy, containerWindow, &xxwa);
631
632
off_x = (xxwa.width - xwa.width) / 2;
633
off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
634
635
/*get the size of root window*/
636
XGetWindowAttributes(dpy, rootWindow, &xxwa);
637
638
XTranslateCoordinates(dpy,
639
parent, xwa.root,
640
xwa.x, xwa.y,
641
&x, &y,
642
&child);
643
xx = x - off_x;
644
yy = y + xwa.height - off_y;
645
if (xx < 0 ){
646
xx = 0;
647
}
648
if (xx + width > xxwa.width) {
649
xx = xxwa.width - width;
650
}
651
if (yy + height > xxwa.height) {
652
yy = xxwa.height - height;
653
}
654
655
status = XCreateWindow(dpy,
656
xwa.root,
657
xx, yy,
658
width, height,
659
0,
660
xwa.depth,
661
InputOutput,
662
adata->awt_visInfo.visual,
663
attribmask, &attrib);
664
XSelectInput(dpy, status,
665
ExposureMask | StructureNotifyMask | EnterWindowMask |
666
LeaveWindowMask | VisibilityChangeMask);
667
statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
668
if (statusWindow == NULL){
669
THROW_OUT_OF_MEMORY_ERROR();
670
return NULL;
671
}
672
statusWindow->w = status;
673
//12, 13-point fonts
674
statusWindow->fontset = XCreateFontSet(dpy,
675
"-*-*-medium-r-normal-*-*-120-*-*-*-*," \
676
"-*-*-medium-r-normal-*-*-130-*-*-*-*",
677
&mclr, &mccr, &dsr);
678
/* In case we didn't find the font set, release the list of missing characters */
679
if (mccr > 0) {
680
XFreeStringList(mclr);
681
}
682
statusWindow->parent = parent;
683
statusWindow->on = False;
684
statusWindow->x = x;
685
statusWindow->y = y;
686
statusWindow->width = xwa.width;
687
statusWindow->height = xwa.height;
688
statusWindow->off_x = off_x;
689
statusWindow->off_y = off_y;
690
statusWindow->bWidth = bw;
691
statusWindow->statusH = height;
692
statusWindow->statusW = width;
693
statusWindow->rootH = xxwa.height;
694
statusWindow->rootW = xxwa.width;
695
statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
696
XSetForeground(dpy, statusWindow->lightGC, light);
697
statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
698
XSetForeground(dpy, statusWindow->dimGC, dim);
699
statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);
700
XSetForeground(dpy, statusWindow->fgGC, fg);
701
statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
702
XSetForeground(dpy, statusWindow->bgGC, bg);
703
return statusWindow;
704
}
705
706
/* This method is to turn off or turn on the status window. */
707
static void onoffStatusWindow(X11InputMethodData* pX11IMData,
708
Window parent,
709
Bool ON){
710
XWindowAttributes xwa;
711
Window child;
712
int x, y;
713
StatusWindow *statusWindow = NULL;
714
715
if (NULL == currentX11InputMethodInstance ||
716
NULL == pX11IMData ||
717
NULL == (statusWindow = pX11IMData->statusWindow)){
718
return;
719
}
720
721
if (ON == False) {
722
XUnmapWindow(dpy, statusWindow->w);
723
statusWindow->on = False;
724
return;
725
}
726
parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
727
"getCurrentParentWindow",
728
"()J").j;
729
if (statusWindow->parent != parent) {
730
statusWindow->parent = parent;
731
}
732
XGetWindowAttributes(dpy, parent, &xwa);
733
XTranslateCoordinates(dpy,
734
parent, xwa.root,
735
xwa.x, xwa.y,
736
&x, &y,
737
&child);
738
if (statusWindow->x != x ||
739
statusWindow->y != y ||
740
statusWindow->height != xwa.height)
741
{
742
statusWindow->x = x;
743
statusWindow->y = y;
744
statusWindow->height = xwa.height;
745
x = statusWindow->x - statusWindow->off_x;
746
y = statusWindow->y + statusWindow->height - statusWindow->off_y;
747
if (x < 0 ) {
748
x = 0;
749
}
750
if (x + statusWindow->statusW > statusWindow->rootW) {
751
x = statusWindow->rootW - statusWindow->statusW;
752
}
753
if (y + statusWindow->statusH > statusWindow->rootH) {
754
y = statusWindow->rootH - statusWindow->statusH;
755
}
756
XMoveWindow(dpy, statusWindow->w, x, y);
757
}
758
statusWindow->on = True;
759
XMapWindow(dpy, statusWindow->w);
760
}
761
762
void paintStatusWindow(StatusWindow *statusWindow){
763
Window win = statusWindow->w;
764
GC lightgc = statusWindow->lightGC;
765
GC dimgc = statusWindow->dimGC;
766
GC bggc = statusWindow->bgGC;
767
GC fggc = statusWindow->fgGC;
768
769
int width = statusWindow->statusW;
770
int height = statusWindow->statusH;
771
int bwidth = statusWindow->bWidth;
772
XFillRectangle(dpy, win, bggc, 0, 0, width, height);
773
/* draw border */
774
XDrawLine(dpy, win, fggc, 0, 0, width, 0);
775
XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
776
XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
777
XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
778
779
XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
780
XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
781
XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
782
XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
783
784
XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
785
XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
786
XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
787
XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
788
if (statusWindow->fontset) {
789
XmbDrawString(dpy, win, statusWindow->fontset, fggc,
790
bwidth + 2, height - bwidth - 4,
791
statusWindow->status,
792
strlen(statusWindow->status));
793
} else {
794
/*too bad we failed to create a fontset for this locale*/
795
XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
796
"[InputMethod ON]", strlen("[InputMethod ON]"));
797
}
798
}
799
800
static void adjustStatusWindow(Window shell) {
801
JNIEnv *env = GetJNIEnv();
802
X11InputMethodData *pX11IMData = NULL;
803
StatusWindow *statusWindow;
804
805
if (NULL == currentX11InputMethodInstance
806
|| !isX11InputMethodGRefInList(currentX11InputMethodInstance)
807
|| NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
808
|| NULL == (statusWindow = pX11IMData->statusWindow)
809
|| !statusWindow->on)
810
{
811
return;
812
}
813
814
{
815
XWindowAttributes xwa;
816
int x, y;
817
Window child;
818
XGetWindowAttributes(dpy, shell, &xwa);
819
XTranslateCoordinates(dpy,
820
shell, xwa.root,
821
xwa.x, xwa.y,
822
&x, &y,
823
&child);
824
if (statusWindow->x != x
825
|| statusWindow->y != y
826
|| statusWindow->height != xwa.height){
827
statusWindow->x = x;
828
statusWindow->y = y;
829
statusWindow->height = xwa.height;
830
831
x = statusWindow->x - statusWindow->off_x;
832
y = statusWindow->y + statusWindow->height - statusWindow->off_y;
833
if (x < 0 ) {
834
x = 0;
835
}
836
if (x + statusWindow->statusW > statusWindow->rootW){
837
x = statusWindow->rootW - statusWindow->statusW;
838
}
839
if (y + statusWindow->statusH > statusWindow->rootH){
840
y = statusWindow->rootH - statusWindow->statusH;
841
}
842
XMoveWindow(dpy, statusWindow->w, x, y);
843
}
844
}
845
}
846
#endif /* __linux__ */
847
848
/*
849
* Creates two XICs, one for active clients and the other for passive
850
* clients. All information on those XICs are stored in the
851
* X11InputMethodData given by the pX11IMData parameter.
852
*
853
* For active clients: Try to use preedit callback to support
854
* on-the-spot. If tc is not null, the XIC to be created will
855
* share the Status Area with Motif widgets (TextComponents). If the
856
* preferable styles can't be used, fallback to root-window styles. If
857
* root-window styles failed, fallback to None styles.
858
*
859
* For passive clients: Try to use root-window styles. If failed,
860
* fallback to None styles.
861
*/
862
static Bool
863
createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
864
{
865
XVaNestedList preedit = NULL;
866
XVaNestedList status = NULL;
867
XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
868
active_styles = 0,
869
passive_styles = 0,
870
no_styles = 0;
871
XIMCallback *callbacks;
872
unsigned short i;
873
XIMStyles *im_styles;
874
char *ret = NULL;
875
876
if (X11im == NULL) {
877
return False;
878
}
879
if (!w) {
880
return False;
881
}
882
883
ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
884
885
if (ret != NULL) {
886
jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
887
return FALSE ;
888
}
889
890
on_the_spot_styles |= XIMStatusNothing;
891
892
#if defined(__linux__)
893
/*kinput does not support XIMPreeditCallbacks and XIMStatusArea
894
at the same time, so use StatusCallback to draw the status
895
ourself
896
*/
897
for (i = 0; i < im_styles->count_styles; i++) {
898
if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
899
on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
900
break;
901
}
902
}
903
#endif /* __linux__ */
904
905
for (i = 0; i < im_styles->count_styles; i++) {
906
active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
907
passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
908
no_styles |= im_styles->supported_styles[i] & NO_STYLES;
909
}
910
911
XFree(im_styles);
912
913
if (active_styles != on_the_spot_styles) {
914
if (passive_styles == ROOT_WINDOW_STYLES)
915
active_styles = passive_styles;
916
else {
917
if (no_styles == NO_STYLES)
918
active_styles = passive_styles = NO_STYLES;
919
else
920
active_styles = passive_styles = 0;
921
}
922
} else {
923
if (passive_styles != ROOT_WINDOW_STYLES) {
924
if (no_styles == NO_STYLES)
925
active_styles = passive_styles = NO_STYLES;
926
else
927
active_styles = passive_styles = 0;
928
}
929
}
930
931
if (active_styles == on_the_spot_styles) {
932
pX11IMData->ic_passive = XCreateIC(X11im,
933
XNClientWindow, w,
934
XNFocusWindow, w,
935
XNInputStyle, passive_styles,
936
NULL);
937
938
callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
939
if (callbacks == (XIMCallback *)NULL)
940
return False;
941
pX11IMData->callbacks = callbacks;
942
943
for (i = 0; i < NCALLBACKS; i++, callbacks++) {
944
callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
945
callbacks->callback = callback_funcs[i];
946
}
947
948
callbacks = pX11IMData->callbacks;
949
preedit = (XVaNestedList)XVaCreateNestedList(0,
950
XNPreeditStartCallback, &callbacks[PreeditStartIndex],
951
XNPreeditDoneCallback, &callbacks[PreeditDoneIndex],
952
XNPreeditDrawCallback, &callbacks[PreeditDrawIndex],
953
XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
954
NULL);
955
if (preedit == (XVaNestedList)NULL)
956
goto err;
957
#if defined(__linux__)
958
/*always try XIMStatusCallbacks for active client...*/
959
{
960
status = (XVaNestedList)XVaCreateNestedList(0,
961
XNStatusStartCallback, &callbacks[StatusStartIndex],
962
XNStatusDoneCallback, &callbacks[StatusDoneIndex],
963
XNStatusDrawCallback, &callbacks[StatusDrawIndex],
964
NULL);
965
966
if (status == NULL)
967
goto err;
968
pX11IMData->statusWindow = createStatusWindow(w);
969
pX11IMData->ic_active = XCreateIC(X11im,
970
XNClientWindow, w,
971
XNFocusWindow, w,
972
XNInputStyle, active_styles,
973
XNPreeditAttributes, preedit,
974
XNStatusAttributes, status,
975
NULL);
976
XFree((void *)status);
977
XFree((void *)preedit);
978
}
979
#else /* !__linux__ */
980
pX11IMData->ic_active = XCreateIC(X11im,
981
XNClientWindow, w,
982
XNFocusWindow, w,
983
XNInputStyle, active_styles,
984
XNPreeditAttributes, preedit,
985
NULL);
986
XFree((void *)preedit);
987
#endif /* __linux__ */
988
} else {
989
pX11IMData->ic_active = XCreateIC(X11im,
990
XNClientWindow, w,
991
XNFocusWindow, w,
992
XNInputStyle, active_styles,
993
NULL);
994
pX11IMData->ic_passive = pX11IMData->ic_active;
995
}
996
997
if (pX11IMData->ic_active == (XIC)0
998
|| pX11IMData->ic_passive == (XIC)0) {
999
return False;
1000
}
1001
1002
/*
1003
* Use commit string call back if possible.
1004
* This will ensure the correct order of preedit text and commit text
1005
*/
1006
{
1007
XIMCallback cb;
1008
cb.client_data = (XPointer) pX11IMData->x11inputmethod;
1009
cb.callback = (XIMProc) CommitStringCallback;
1010
XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL);
1011
if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1012
XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1013
}
1014
}
1015
1016
// The code set the IC mode that the preedit state is not initialied
1017
// at XmbResetIC. This attribute can be set at XCreateIC. I separately
1018
// set the attribute to avoid the failure of XCreateIC at some platform
1019
// which does not support the attribute.
1020
if (pX11IMData->ic_active != 0)
1021
XSetICValues(pX11IMData->ic_active,
1022
XNResetState, XIMInitialState,
1023
NULL);
1024
if (pX11IMData->ic_passive != 0
1025
&& pX11IMData->ic_active != pX11IMData->ic_passive)
1026
XSetICValues(pX11IMData->ic_passive,
1027
XNResetState, XIMInitialState,
1028
NULL);
1029
1030
/* Add the global reference object to X11InputMethod to the list. */
1031
addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1032
1033
/* Unset focus to avoid unexpected IM on */
1034
setXICFocus(pX11IMData->ic_active, False);
1035
if (pX11IMData->ic_active != pX11IMData->ic_passive)
1036
setXICFocus(pX11IMData->ic_passive, False);
1037
1038
return True;
1039
1040
err:
1041
if (preedit)
1042
XFree((void *)preedit);
1043
THROW_OUT_OF_MEMORY_ERROR();
1044
return False;
1045
}
1046
1047
static int
1048
PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1049
{
1050
/*ARGSUSED*/
1051
/* printf("Native: PreeditStartCallback\n"); */
1052
return -1;
1053
}
1054
1055
static void
1056
PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1057
{
1058
/*ARGSUSED*/
1059
/* printf("Native: PreeditDoneCallback\n"); */
1060
}
1061
1062
/*
1063
* Translate the preedit draw callback items to Java values and invoke
1064
* X11InputMethod.dispatchComposedText().
1065
*
1066
* client_data: X11InputMethod object
1067
*/
1068
static void
1069
PreeditDrawCallback(XIC ic, XPointer client_data,
1070
XIMPreeditDrawCallbackStruct *pre_draw)
1071
{
1072
JNIEnv *env = GetJNIEnv();
1073
X11InputMethodData *pX11IMData = NULL;
1074
jmethodID x11imMethodID;
1075
1076
XIMText *text;
1077
jstring javastr = NULL;
1078
jintArray style = NULL;
1079
1080
/* printf("Native: PreeditDrawCallback() \n"); */
1081
if (pre_draw == NULL) {
1082
return;
1083
}
1084
AWT_LOCK();
1085
if (!isX11InputMethodGRefInList((jobject)client_data)) {
1086
if ((jobject)client_data == currentX11InputMethodInstance) {
1087
currentX11InputMethodInstance = NULL;
1088
}
1089
goto finally;
1090
}
1091
if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1092
goto finally;
1093
}
1094
1095
if ((text = pre_draw->text) != NULL) {
1096
if (text->string.multi_byte != NULL) {
1097
if (pre_draw->text->encoding_is_wchar == False) {
1098
javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1099
if (javastr == NULL) {
1100
goto finally;
1101
}
1102
} else {
1103
char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1104
if (mbstr == NULL) {
1105
goto finally;
1106
}
1107
javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1108
free(mbstr);
1109
if (javastr == NULL) {
1110
goto finally;
1111
}
1112
}
1113
}
1114
if (text->feedback != NULL) {
1115
int cnt;
1116
jint *tmpstyle;
1117
1118
style = (*env)->NewIntArray(env, text->length);
1119
if (JNU_IsNull(env, style)) {
1120
(*env)->ExceptionClear(env);
1121
THROW_OUT_OF_MEMORY_ERROR();
1122
goto finally;
1123
}
1124
1125
if (sizeof(XIMFeedback) == sizeof(jint)) {
1126
/*
1127
* Optimization to avoid copying the array
1128
*/
1129
(*env)->SetIntArrayRegion(env, style, 0,
1130
text->length, (jint *)text->feedback);
1131
} else {
1132
tmpstyle = (jint *)malloc(sizeof(jint)*(text->length));
1133
if (tmpstyle == (jint *) NULL) {
1134
THROW_OUT_OF_MEMORY_ERROR();
1135
goto finally;
1136
}
1137
for (cnt = 0; cnt < (int)text->length; cnt++)
1138
tmpstyle[cnt] = text->feedback[cnt];
1139
(*env)->SetIntArrayRegion(env, style, 0,
1140
text->length, (jint *)tmpstyle);
1141
free(tmpstyle);
1142
}
1143
}
1144
}
1145
JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1146
"dispatchComposedText",
1147
"(Ljava/lang/String;[IIIIJ)V",
1148
javastr,
1149
style,
1150
(jint)pre_draw->chg_first,
1151
(jint)pre_draw->chg_length,
1152
(jint)pre_draw->caret,
1153
awt_util_nowMillisUTC());
1154
finally:
1155
AWT_UNLOCK();
1156
return;
1157
}
1158
1159
static void
1160
PreeditCaretCallback(XIC ic, XPointer client_data,
1161
XIMPreeditCaretCallbackStruct *pre_caret)
1162
{
1163
/*ARGSUSED*/
1164
/* printf("Native: PreeditCaretCallback\n"); */
1165
}
1166
1167
#if defined(__linux__)
1168
static void
1169
StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1170
{
1171
/*ARGSUSED*/
1172
/*printf("StatusStartCallback:\n"); */
1173
}
1174
1175
static void
1176
StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1177
{
1178
/*ARGSUSED*/
1179
/*printf("StatusDoneCallback:\n"); */
1180
JNIEnv *env = GetJNIEnv();
1181
X11InputMethodData *pX11IMData = NULL;
1182
StatusWindow *statusWindow;
1183
1184
AWT_LOCK();
1185
1186
if (!isX11InputMethodGRefInList((jobject)client_data)) {
1187
if ((jobject)client_data == currentX11InputMethodInstance) {
1188
currentX11InputMethodInstance = NULL;
1189
}
1190
goto finally;
1191
}
1192
1193
if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1194
|| NULL == (statusWindow = pX11IMData->statusWindow)){
1195
goto finally;
1196
}
1197
currentX11InputMethodInstance = (jobject)client_data;
1198
1199
onoffStatusWindow(pX11IMData, 0, False);
1200
1201
finally:
1202
AWT_UNLOCK();
1203
}
1204
1205
static void
1206
StatusDrawCallback(XIC ic, XPointer client_data,
1207
XIMStatusDrawCallbackStruct *status_draw)
1208
{
1209
/*ARGSUSED*/
1210
/*printf("StatusDrawCallback:\n"); */
1211
JNIEnv *env = GetJNIEnv();
1212
X11InputMethodData *pX11IMData = NULL;
1213
StatusWindow *statusWindow;
1214
1215
AWT_LOCK();
1216
1217
if (!isX11InputMethodGRefInList((jobject)client_data)) {
1218
if ((jobject)client_data == currentX11InputMethodInstance) {
1219
currentX11InputMethodInstance = NULL;
1220
}
1221
goto finally;
1222
}
1223
1224
if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1225
|| NULL == (statusWindow = pX11IMData->statusWindow)){
1226
goto finally;
1227
}
1228
currentX11InputMethodInstance = (jobject)client_data;
1229
1230
if (status_draw->type == XIMTextType) {
1231
XIMText *text = (status_draw->data).text;
1232
if (text != NULL) {
1233
if (text->string.multi_byte != NULL) {
1234
strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN);
1235
statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1236
} else {
1237
char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1238
if (mbstr == NULL) {
1239
goto finally;
1240
}
1241
strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN);
1242
statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1243
free(mbstr);
1244
}
1245
statusWindow->on = True;
1246
onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1247
paintStatusWindow(statusWindow);
1248
} else {
1249
statusWindow->on = False;
1250
/*just turnoff the status window
1251
paintStatusWindow(statusWindow);
1252
*/
1253
onoffStatusWindow(pX11IMData, 0, False);
1254
}
1255
}
1256
1257
finally:
1258
AWT_UNLOCK();
1259
}
1260
#endif /* __linux__ */
1261
1262
static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1263
JNIEnv *env = GetJNIEnv();
1264
XIMText * text = (XIMText *)call_data;
1265
X11InputMethodData *pX11IMData = NULL;
1266
jstring javastr;
1267
1268
AWT_LOCK();
1269
1270
if (!isX11InputMethodGRefInList((jobject)client_data)) {
1271
if ((jobject)client_data == currentX11InputMethodInstance) {
1272
currentX11InputMethodInstance = NULL;
1273
}
1274
goto finally;
1275
}
1276
1277
if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1278
goto finally;
1279
}
1280
currentX11InputMethodInstance = (jobject)client_data;
1281
1282
if (text->encoding_is_wchar == False) {
1283
javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1284
} else {
1285
char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1286
if (mbstr == NULL) {
1287
goto finally;
1288
}
1289
javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1290
free(mbstr);
1291
}
1292
1293
if (javastr != NULL) {
1294
JNU_CallMethodByName(env, NULL,
1295
pX11IMData->x11inputmethod,
1296
"dispatchCommittedText",
1297
"(Ljava/lang/String;J)V",
1298
javastr,
1299
awt_util_nowMillisUTC());
1300
}
1301
finally:
1302
AWT_UNLOCK();
1303
}
1304
1305
static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) {
1306
XIMCallback ximCallback;
1307
1308
X11im = XOpenIM(display, NULL, NULL, NULL);
1309
if (X11im == NULL) {
1310
return;
1311
}
1312
1313
ximCallback.callback = (XIMProc)DestroyXIMCallback;
1314
ximCallback.client_data = NULL;
1315
XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1316
}
1317
1318
static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1319
/* mark that XIM server was destroyed */
1320
X11im = NULL;
1321
JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1322
1323
AWT_LOCK();
1324
/* free the old pX11IMData and set it to null. this also avoids crashing
1325
* the jvm if the XIM server reappears */
1326
while (x11InputMethodGRefListHead != NULL) {
1327
if (getX11InputMethodData(env,
1328
x11InputMethodGRefListHead->inputMethodGRef) == NULL) {
1329
/* Clear possible exceptions
1330
*/
1331
if ((*env)->ExceptionOccurred(env)) {
1332
(*env)->ExceptionDescribe(env);
1333
(*env)->ExceptionClear(env);
1334
}
1335
}
1336
}
1337
AWT_UNLOCK();
1338
}
1339
1340
JNIEXPORT jboolean JNICALL
1341
Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1342
jobject this,
1343
jlong display)
1344
{
1345
Bool registered;
1346
1347
AWT_LOCK();
1348
1349
dpy = (Display *)jlong_to_ptr(display);
1350
1351
/* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1352
(4768335)
1353
*/
1354
#if defined(__linux__)
1355
registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1356
NULL, (XIDProc)OpenXIMCallback, NULL);
1357
if (!registered) {
1358
/* directly call openXIM callback */
1359
#endif
1360
OpenXIMCallback(dpy, NULL, NULL);
1361
#if defined(__linux__)
1362
}
1363
#endif
1364
1365
AWT_UNLOCK();
1366
1367
return JNI_TRUE;
1368
}
1369
1370
JNIEXPORT jboolean JNICALL
1371
Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1372
jobject this,
1373
jlong window)
1374
{
1375
X11InputMethodData *pX11IMData;
1376
jobject globalRef;
1377
XIC ic;
1378
1379
AWT_LOCK();
1380
1381
if (!window) {
1382
JNU_ThrowNullPointerException(env, "NullPointerException");
1383
AWT_UNLOCK();
1384
return JNI_FALSE;
1385
}
1386
1387
pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1388
if (pX11IMData == NULL) {
1389
THROW_OUT_OF_MEMORY_ERROR();
1390
AWT_UNLOCK();
1391
return JNI_FALSE;
1392
}
1393
1394
globalRef = (*env)->NewGlobalRef(env, this);
1395
pX11IMData->x11inputmethod = globalRef;
1396
#if defined(__linux__)
1397
pX11IMData->statusWindow = NULL;
1398
#endif /* __linux__ */
1399
1400
pX11IMData->lookup_buf = 0;
1401
pX11IMData->lookup_buf_len = 0;
1402
1403
if (createXIC(env, pX11IMData, (Window)window) == False) {
1404
destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1405
pX11IMData = (X11InputMethodData *) NULL;
1406
if ((*env)->ExceptionCheck(env)) {
1407
goto finally;
1408
}
1409
}
1410
1411
setX11InputMethodData(env, this, pX11IMData);
1412
1413
finally:
1414
AWT_UNLOCK();
1415
return (pX11IMData != NULL);
1416
}
1417
1418
JNIEXPORT void JNICALL
1419
Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1420
jobject this,
1421
jlong w,
1422
jboolean req,
1423
jboolean active)
1424
{
1425
X11InputMethodData *pX11IMData;
1426
AWT_LOCK();
1427
pX11IMData = getX11InputMethodData(env, this);
1428
if (pX11IMData == NULL) {
1429
AWT_UNLOCK();
1430
return;
1431
}
1432
1433
if (req) {
1434
if (!w) {
1435
AWT_UNLOCK();
1436
return;
1437
}
1438
pX11IMData->current_ic = active ?
1439
pX11IMData->ic_active : pX11IMData->ic_passive;
1440
/*
1441
* On Solaris2.6, setXICWindowFocus() has to be invoked
1442
* before setting focus.
1443
*/
1444
setXICWindowFocus(pX11IMData->current_ic, w);
1445
setXICFocus(pX11IMData->current_ic, req);
1446
currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1447
currentFocusWindow = w;
1448
#if defined(__linux__)
1449
if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1450
onoffStatusWindow(pX11IMData, w, True);
1451
#endif
1452
} else {
1453
currentX11InputMethodInstance = NULL;
1454
currentFocusWindow = 0;
1455
#if defined(__linux__)
1456
onoffStatusWindow(pX11IMData, 0, False);
1457
if (pX11IMData->current_ic != NULL)
1458
#endif
1459
setXICFocus(pX11IMData->current_ic, req);
1460
1461
pX11IMData->current_ic = (XIC)0;
1462
}
1463
1464
XFlush(dpy);
1465
AWT_UNLOCK();
1466
}
1467
1468
/*
1469
* Class: sun_awt_X11InputMethodBase
1470
* Method: initIDs
1471
* Signature: ()V
1472
* This function gets called from the static initializer for
1473
* X11InputMethod.java to initialize the fieldIDs for fields
1474
* that may be accessed from C
1475
*/
1476
JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_initIDs
1477
(JNIEnv *env, jclass cls)
1478
{
1479
x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1480
}
1481
1482
/*
1483
* Class: sun_awt_X11InputMethodBase
1484
* Method: turnoffStatusWindow
1485
* Signature: ()V
1486
*/
1487
JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow
1488
(JNIEnv *env, jobject this)
1489
{
1490
#if defined(__linux__)
1491
X11InputMethodData *pX11IMData;
1492
StatusWindow *statusWindow;
1493
1494
AWT_LOCK();
1495
1496
if (NULL == currentX11InputMethodInstance
1497
|| !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1498
|| NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1499
|| NULL == (statusWindow = pX11IMData->statusWindow)
1500
|| !statusWindow->on ){
1501
AWT_UNLOCK();
1502
return;
1503
}
1504
onoffStatusWindow(pX11IMData, 0, False);
1505
1506
AWT_UNLOCK();
1507
#endif
1508
}
1509
1510
/*
1511
* Class: sun_awt_X11InputMethodBase
1512
* Method: disposeXIC
1513
* Signature: ()V
1514
*/
1515
JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_disposeXIC
1516
(JNIEnv *env, jobject this)
1517
{
1518
X11InputMethodData *pX11IMData = NULL;
1519
1520
AWT_LOCK();
1521
pX11IMData = getX11InputMethodData(env, this);
1522
if (pX11IMData == NULL) {
1523
AWT_UNLOCK();
1524
return;
1525
}
1526
1527
setX11InputMethodData(env, this, NULL);
1528
1529
if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1530
currentX11InputMethodInstance = NULL;
1531
currentFocusWindow = 0;
1532
}
1533
destroyX11InputMethodData(env, pX11IMData);
1534
AWT_UNLOCK();
1535
}
1536
1537
/*
1538
* Class: sun_awt_X11InputMethodBase
1539
* Method: resetXIC
1540
* Signature: ()Ljava/lang/String;
1541
*/
1542
JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_resetXIC
1543
(JNIEnv *env, jobject this)
1544
{
1545
X11InputMethodData *pX11IMData;
1546
char *xText = NULL;
1547
jstring jText = (jstring)0;
1548
1549
AWT_LOCK();
1550
pX11IMData = getX11InputMethodData(env, this);
1551
if (pX11IMData == NULL) {
1552
AWT_UNLOCK();
1553
return jText;
1554
}
1555
1556
if (pX11IMData->current_ic)
1557
xText = XmbResetIC(pX11IMData->current_ic);
1558
else {
1559
/*
1560
* If there is no reference to the current XIC, try to reset both XICs.
1561
*/
1562
xText = XmbResetIC(pX11IMData->ic_active);
1563
/*it may also means that the real client component does
1564
not have focus -- has been deactivated... its xic should
1565
not have the focus, bug#4284651 showes reset XIC for htt
1566
may bring the focus back, so de-focus it again.
1567
*/
1568
setXICFocus(pX11IMData->ic_active, FALSE);
1569
if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1570
char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1571
setXICFocus(pX11IMData->ic_passive, FALSE);
1572
if (xText == (char *)NULL && tmpText)
1573
xText = tmpText;
1574
}
1575
1576
}
1577
if (xText != NULL) {
1578
jText = JNU_NewStringPlatform(env, (const char *)xText);
1579
XFree((void *)xText);
1580
}
1581
1582
AWT_UNLOCK();
1583
return jText;
1584
}
1585
1586
/*
1587
* Class: sun_awt_X11InputMethodBase
1588
* Method: setCompositionEnabledNative
1589
* Signature: (Z)Z
1590
*
1591
* This method tries to set the XNPreeditState attribute associated with the current
1592
* XIC to the passed in 'enable' state.
1593
*
1594
* Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1595
* 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1596
* java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1597
* method fails due to other reasons.
1598
*/
1599
JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_setCompositionEnabledNative
1600
(JNIEnv *env, jobject this, jboolean enable)
1601
{
1602
X11InputMethodData *pX11IMData;
1603
char * ret = NULL;
1604
XVaNestedList pr_atrb;
1605
#if defined(__linux__)
1606
Boolean calledXSetICFocus = False;
1607
#endif
1608
1609
AWT_LOCK();
1610
pX11IMData = getX11InputMethodData(env, this);
1611
1612
if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1613
AWT_UNLOCK();
1614
return JNI_FALSE;
1615
}
1616
1617
#if defined(__linux__)
1618
if (NULL != pX11IMData->statusWindow) {
1619
Window focus = 0;
1620
int revert_to;
1621
#if defined(_LP64) && !defined(_LITTLE_ENDIAN)
1622
// The Window value which is used for XGetICValues must be 32bit on BigEndian XOrg's xlib
1623
unsigned int w = 0;
1624
#else
1625
Window w = 0;
1626
#endif
1627
XGetInputFocus(awt_display, &focus, &revert_to);
1628
XGetICValues(pX11IMData->current_ic, XNFocusWindow, &w, NULL);
1629
if (RevertToPointerRoot == revert_to
1630
&& pX11IMData->ic_active != pX11IMData->ic_passive) {
1631
if (pX11IMData->current_ic == pX11IMData->ic_active) {
1632
if (getParentWindow(focus) == getParentWindow(w)) {
1633
XUnsetICFocus(pX11IMData->ic_active);
1634
calledXSetICFocus = True;
1635
}
1636
}
1637
}
1638
}
1639
#endif
1640
pr_atrb = XVaCreateNestedList(0,
1641
XNPreeditState, (enable ? XIMPreeditEnable : XIMPreeditDisable),
1642
NULL);
1643
ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);
1644
XFree((void *)pr_atrb);
1645
#if defined(__linux__)
1646
if (calledXSetICFocus) {
1647
XSetICFocus(pX11IMData->ic_active);
1648
}
1649
#endif
1650
AWT_UNLOCK();
1651
1652
if ((ret != 0)
1653
&& ((strcmp(ret, XNPreeditAttributes) == 0)
1654
|| (strcmp(ret, XNPreeditState) == 0))) {
1655
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1656
}
1657
1658
return (jboolean)(ret == 0);
1659
}
1660
1661
/*
1662
* Class: sun_awt_X11InputMethodBase
1663
* Method: isCompositionEnabledNative
1664
* Signature: ()Z
1665
*
1666
* This method tries to get the XNPreeditState attribute associated with the current XIC.
1667
*
1668
* Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1669
* XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1670
* will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1671
*/
1672
JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_isCompositionEnabledNative
1673
(JNIEnv *env, jobject this)
1674
{
1675
X11InputMethodData *pX11IMData = NULL;
1676
char * ret = NULL;
1677
#if defined(__linux__) && defined(_LP64) && !defined(_LITTLE_ENDIAN)
1678
// XIMPreeditState value which is used for XGetICValues must be 32bit on BigEndian XOrg's xlib
1679
unsigned int state = XIMPreeditUnKnown;
1680
#else
1681
XIMPreeditState state = XIMPreeditUnKnown;
1682
#endif
1683
1684
XVaNestedList pr_atrb;
1685
1686
AWT_LOCK();
1687
pX11IMData = getX11InputMethodData(env, this);
1688
1689
if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1690
AWT_UNLOCK();
1691
return JNI_FALSE;
1692
}
1693
1694
pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL);
1695
ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);
1696
XFree((void *)pr_atrb);
1697
AWT_UNLOCK();
1698
1699
if ((ret != 0)
1700
&& ((strcmp(ret, XNPreeditAttributes) == 0)
1701
|| (strcmp(ret, XNPreeditState) == 0))) {
1702
JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1703
return JNI_FALSE;
1704
}
1705
1706
return (jboolean)(state == XIMPreeditEnable);
1707
}
1708
1709
JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
1710
(JNIEnv *env, jobject this, jlong window)
1711
{
1712
#if defined(__linux__)
1713
AWT_LOCK();
1714
adjustStatusWindow(window);
1715
AWT_UNLOCK();
1716
#endif
1717
}
1718
1719
#if defined(__linux__)
1720
static Window getParentWindow(Window w)
1721
{
1722
Window root=None, parent=None, *ignore_children=NULL;
1723
unsigned int ignore_uint=0;
1724
Status status = 0;
1725
1726
if (w == None)
1727
return None;
1728
status = XQueryTree(dpy, w, &root, &parent, &ignore_children, &ignore_uint);
1729
XFree(ignore_children);
1730
if (status == 0)
1731
return None;
1732
return parent;
1733
}
1734
#endif
1735
1736