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