1 /*
2 * Copyright (c) 1997, 2016, 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 <stdio.h>
31 #include <stdlib.h>
32 #include <X11/Xlib.h>
33 #include <X11/keysym.h>
34 #include <sys/time.h>
35
36 #include "awt.h"
37 #include "awt_p.h"
38
39 #include <sun_awt_X11InputMethod.h>
40 #include <sun_awt_X11_XInputMethod.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 void 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)
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)
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)PreeditStartCallback,
84 (XIMProc)PreeditDoneCallback,
85 (XIMProc)PreeditDrawCallback,
86 (XIMProc)PreeditCaretCallback,
87 #if defined(__linux__) || defined(MACOSX)
88 (XIMProc)StatusStartCallback,
89 (XIMProc)StatusDoneCallback,
90 (XIMProc)StatusDrawCallback,
91 #endif
92 };
93
94 #if defined(__linux__) || defined(MACOSX)
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)
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
179 #ifdef __solaris__
180 /* Prototype for this function is missing in Solaris X11R6 Xlib.h */
181 extern char *XSetIMValues(
182 #if NeedVarargsPrototypes
183 XIM /* im */, ...
184 #endif
185 );
186 #endif
187
188 /*
189 * This function is stolen from /src/solaris/hpi/src/system_md.c
190 * It is used in setting the time in Java-level InputEvents
191 */
192 jlong
193 awt_util_nowMillisUTC()
194 {
195 struct timeval t;
196 gettimeofday(&t, NULL);
197 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
198 }
199
200 /*
201 * Converts the wchar_t string to a multi-byte string calling wcstombs(). A
202 * buffer is allocated by malloc() to store the multi-byte string. NULL is
203 * returned if the given wchar_t string pointer is NULL or buffer allocation is
204 * failed.
205 */
206 static char *
212 if (wcs == NULL)
213 return NULL;
214
215 n = len*MB_CUR_MAX + 1;
216
217 mbs = (char *) malloc(n * sizeof(char));
218 if (mbs == NULL) {
219 THROW_OUT_OF_MEMORY_ERROR();
220 return NULL;
221 }
222
223 /* TODO: check return values... Handle invalid characters properly... */
224 if (wcstombs(mbs, wcs, n) == (size_t)-1) {
225 free(mbs);
226 return NULL;
227 }
228
229 return mbs;
230 }
231
232 /*
233 * Returns True if the global reference is still in the list,
234 * otherwise False.
235 */
236 static Bool isX11InputMethodGRefInList(jobject imGRef) {
237 X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead;
238
239 if (imGRef == NULL) {
240 return False;
241 }
242
243 while (pX11InputMethodGRef != NULL) {
244 if (pX11InputMethodGRef->inputMethodGRef == imGRef) {
245 return True;
246 }
247 pX11InputMethodGRef = pX11InputMethodGRef->next;
248 }
249
250 return False;
251 }
252
253 /*
254 * Add the new created global reference to the list.
255 */
256 static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) {
257 X11InputMethodGRefNode *newNode = NULL;
258
259 if (newX11InputMethodGRef == NULL ||
260 isX11InputMethodGRefInList(newX11InputMethodGRef)) {
261 return;
262 }
263
264 newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode));
265
266 if (newNode == NULL) {
267 return;
268 } else {
269 newNode->inputMethodGRef = newX11InputMethodGRef;
270 newNode->next = x11InputMethodGRefListHead;
271 x11InputMethodGRefListHead = newNode;
272 }
273 }
274
275 /*
276 * Remove the global reference from the list.
277 */
278 static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) {
279 X11InputMethodGRefNode *pX11InputMethodGRef = NULL;
280 X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead;
281
282 if (x11InputMethodGRefListHead == NULL ||
283 x11InputMethodGRef == NULL) {
284 return;
285 }
286
287 /* cX11InputMethodGRef always refers to the current node while
288 pX11InputMethodGRef refers to the previous node.
289 */
290 while (cX11InputMethodGRef != NULL) {
291 if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) {
292 break;
293 }
294 pX11InputMethodGRef = cX11InputMethodGRef;
295 cX11InputMethodGRef = cX11InputMethodGRef->next;
296 }
297
298 if (cX11InputMethodGRef == NULL) {
299 return; /* Not found. */
300 }
301
302 if (cX11InputMethodGRef == x11InputMethodGRefListHead) {
303 x11InputMethodGRefListHead = x11InputMethodGRefListHead->next;
304 } else {
305 pX11InputMethodGRef->next = cX11InputMethodGRef->next;
306 }
307 free(cX11InputMethodGRef);
308
309 return;
310 }
311
312
313 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {
314 X11InputMethodData *pX11IMData =
315 (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);
316
317 /*
318 * In case the XIM server was killed somehow, reset X11InputMethodData.
319 */
320 if (X11im == NULL && pX11IMData != NULL) {
321 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
322 "flushText",
323 "()V");
324 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
325 /* IMPORTANT:
326 The order of the following calls is critical since "imInstance" may
327 point to the global reference itself, if "freeX11InputMethodData" is called
328 first, the global reference will be destroyed and "setX11InputMethodData"
329 will in fact fail silently. So pX11IMData will not be set to NULL.
330 This could make the original java object refers to a deleted pX11IMData
331 object.
332 */
355
356 if (pX11IMData->ic_active != (XIC)0) {
357 XUnsetICFocus(pX11IMData->ic_active);
358 XDestroyIC(pX11IMData->ic_active);
359 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
360 if (pX11IMData->ic_passive != (XIC)0) {
361 XUnsetICFocus(pX11IMData->ic_passive);
362 XDestroyIC(pX11IMData->ic_passive);
363 }
364 pX11IMData->ic_passive = (XIC)0;
365 pX11IMData->current_ic = (XIC)0;
366 }
367 }
368
369 freeX11InputMethodData(env, pX11IMData);
370 }
371
372 static void
373 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
374 {
375 #if defined(__linux__) || defined(MACOSX)
376 if (pX11IMData->statusWindow != NULL){
377 StatusWindow *sw = pX11IMData->statusWindow;
378 XFreeGC(awt_display, sw->lightGC);
379 XFreeGC(awt_display, sw->dimGC);
380 XFreeGC(awt_display, sw->bgGC);
381 XFreeGC(awt_display, sw->fgGC);
382 if (sw->fontset != NULL) {
383 XFreeFontSet(awt_display, sw->fontset);
384 }
385 XDestroyWindow(awt_display, sw->w);
386 free((void*)sw);
387 }
388 #endif
389
390 if (pX11IMData->callbacks)
391 free((void *)pX11IMData->callbacks);
392
393 if (env) {
394 /* Remove the global reference from the list, so that
395 the callback function or whoever refers to it could know.
396 */
397 removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod);
398 (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);
399 }
400
401 if (pX11IMData->lookup_buf) {
402 free((void *)pX11IMData->lookup_buf);
403 }
404
405 free((void *)pX11IMData);
406 }
407
408 /*
409 * Sets or unsets the focus to the given XIC.
410 */
411 static void
412 setXICFocus(XIC ic, unsigned short req)
413 {
414 if (ic == NULL) {
415 (void)fprintf(stderr, "Couldn't find X Input Context\n");
416 return;
417 }
418 if (req == 1)
419 XSetICFocus(ic);
420 else
421 XUnsetICFocus(ic);
422 }
423
424 /*
438 * Invokes XmbLookupString() to get something from the XIM. It invokes
439 * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns
440 * committed text. This function is called from handleKeyEvent in canvas.c and
441 * it's under the Motif event loop thread context.
442 *
443 * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,
444 * where it never returns XBufferOverflow. We need to allocate the initial lookup buffer
445 * big enough, so that the possibility that user encounters this problem is relatively
446 * small. When this bug gets fixed, we can make the initial buffer size smaller.
447 * Note that XmbLookupString() sometimes produces a non-null-terminated string.
448 *
449 * Returns True when there is a keysym value to be handled.
450 */
451 #define INITIAL_LOOKUP_BUF_SIZE 512
452
453 Boolean
454 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)
455 {
456 JNIEnv *env = GetJNIEnv();
457 X11InputMethodData *pX11IMData = NULL;
458 KeySym keysym = NoSymbol;
459 Status status;
460 int mblen;
461 jstring javastr;
462 XIC ic;
463 Boolean result = True;
464 static Boolean composing = False;
465
466 /*
467 printf("lookupString: entering...\n");
468 */
469
470 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
471 currentX11InputMethodInstance = NULL;
472 return False;
473 }
474
475 pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
476
477 if (pX11IMData == NULL) {
478 #if defined(__linux__) || defined(MACOSX)
479 return False;
480 #else
481 return result;
482 #endif
483 }
484
485 if ((ic = pX11IMData->current_ic) == (XIC)0){
486 #if defined(__linux__) || defined(MACOSX)
487 return False;
488 #else
489 return result;
490 #endif
491 }
492
493 /* allocate the lookup buffer at the first invocation */
494 if (pX11IMData->lookup_buf_len == 0) {
495 pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE);
496 if (pX11IMData->lookup_buf == NULL) {
497 THROW_OUT_OF_MEMORY_ERROR();
498 return result;
499 }
500 pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE;
501 }
502
503 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
504 pX11IMData->lookup_buf_len - 1, &keysym, &status);
505
506 /*
507 * In case of overflow, a buffer is allocated and it retries
508 * XmbLookupString().
509 */
510 if (status == XBufferOverflow) {
511 free((void *)pX11IMData->lookup_buf);
512 pX11IMData->lookup_buf_len = 0;
513 pX11IMData->lookup_buf = (char *)malloc(mblen + 1);
514 if (pX11IMData->lookup_buf == NULL) {
515 THROW_OUT_OF_MEMORY_ERROR();
516 return result;
517 }
518 pX11IMData->lookup_buf_len = mblen + 1;
519 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
520 pX11IMData->lookup_buf_len - 1, &keysym, &status);
521 }
522 pX11IMData->lookup_buf[mblen] = 0;
523
524 /* Get keysym without taking modifiers into account first to map
525 * to AWT keyCode table.
526 */
527 switch (status) {
528 case XLookupBoth:
529 if (!composing) {
530 if (event->keycode != 0) {
531 *keysymp = keysym;
532 result = False;
533 break;
534 }
535 }
536 composing = False;
537 /*FALLTHRU*/
538 case XLookupChars:
539 /*
540 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
541 event->type, event->state, event->keycode, keysym);
542 */
543 javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
544 if (javastr != NULL) {
545 JNU_CallMethodByName(env, NULL,
546 currentX11InputMethodInstance,
547 "dispatchCommittedText",
548 "(Ljava/lang/String;J)V",
549 javastr,
550 event->time);
551 }
552 break;
553
554 case XLookupKeySym:
555 /*
556 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
557 event->type, event->state, event->keycode, keysym);
558 */
559 if (keysym == XK_Multi_key)
560 composing = True;
561 if (! composing) {
562 *keysymp = keysym;
563 result = False;
564 }
565 break;
566
567 case XLookupNone:
568 /*
569 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
570 event->type, event->state, event->keycode, keysym);
571 */
572 break;
573 }
574
575 return result;
576 }
577
578 #if defined(__linux__) || defined(MACOSX)
579 static StatusWindow *createStatusWindow(
580 Window parent) {
581 StatusWindow *statusWindow;
582 XSetWindowAttributes attrib;
583 unsigned long attribmask;
584 Window containerWindow;
585 Window status;
586 Window child;
587 XWindowAttributes xwa;
588 XWindowAttributes xxwa;
589 /* Variable for XCreateFontSet()*/
590 char **mclr;
591 int mccr = 0;
592 char *dsr;
593 unsigned long bg, fg, light, dim;
594 int x, y, off_x, off_y, xx, yy;
595 unsigned int w, h, bw, depth;
596 XGCValues values;
597 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/
598 int screen = 0;
599 int i;
600 AwtGraphicsConfigDataPtr adata;
601 extern int awt_numScreens;
602 /*hardcode the size right now, should get the size base on font*/
603 int width=80, height=22;
604 Window rootWindow;
605 Window *ignoreWindowPtr;
606 unsigned int ignoreUnit;
607
608 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
609
610 attrib.override_redirect = True;
611 attribmask = CWOverrideRedirect;
612 for (i = 0; i < awt_numScreens; i++) {
613 if (RootWindow(dpy, i) == rootWindow) {
614 screen = i;
615 break;
616 }
617 }
618 adata = getDefaultConfig(screen);
619 bg = adata->AwtColorMatch(255, 255, 255, adata);
620 fg = adata->AwtColorMatch(0, 0, 0, adata);
621 light = adata->AwtColorMatch(195, 195, 195, adata);
622 dim = adata->AwtColorMatch(128, 128, 128, adata);
623
624 XGetWindowAttributes(dpy, parent, &xwa);
625 bw = 2; /*xwa.border_width does not have the correct value*/
626
627 /*compare the size difference between parent container
628 and shell widget, the diff should be the border frame
629 and title bar height (?)*/
630
631 XQueryTree( dpy,
632 parent,
633 &rootWindow,
634 &containerWindow,
635 &ignoreWindowPtr,
636 &ignoreUnit);
637 XGetWindowAttributes(dpy, containerWindow, &xxwa);
638
639 off_x = (xxwa.width - xwa.width) / 2;
640 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
641
642 /*get the size of root window*/
643 XGetWindowAttributes(dpy, rootWindow, &xxwa);
644
645 XTranslateCoordinates(dpy,
646 parent, xwa.root,
647 xwa.x, xwa.y,
648 &x, &y,
649 &child);
650 xx = x - off_x;
651 yy = y + xwa.height - off_y;
652 if (xx < 0 ){
653 xx = 0;
654 }
655 if (xx + width > xxwa.width){
656 xx = xxwa.width - width;
657 }
658 if (yy + height > xxwa.height){
659 yy = xxwa.height - height;
660 }
661
662 status = XCreateWindow(dpy,
663 xwa.root,
664 xx, yy,
665 width, height,
666 0,
667 xwa.depth,
668 InputOutput,
669 adata->awt_visInfo.visual,
670 attribmask, &attrib);
671 XSelectInput(dpy, status,
672 ExposureMask | StructureNotifyMask | EnterWindowMask |
673 LeaveWindowMask | VisibilityChangeMask);
674 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
675 if (statusWindow == NULL){
676 THROW_OUT_OF_MEMORY_ERROR();
677 return NULL;
678 }
679 statusWindow->w = status;
680 //12-point font
681 statusWindow->fontset = XCreateFontSet(dpy,
682 "-*-*-medium-r-normal-*-*-120-*-*-*-*",
683 &mclr, &mccr, &dsr);
684 /* In case we didn't find the font set, release the list of missing characters */
685 if (mccr > 0) {
686 XFreeStringList(mclr);
687 }
688 statusWindow->parent = parent;
689 statusWindow->on = False;
690 statusWindow->x = x;
691 statusWindow->y = y;
692 statusWindow->width = xwa.width;
693 statusWindow->height = xwa.height;
694 statusWindow->off_x = off_x;
695 statusWindow->off_y = off_y;
696 statusWindow->bWidth = bw;
697 statusWindow->statusH = height;
698 statusWindow->statusW = width;
699 statusWindow->rootH = xxwa.height;
700 statusWindow->rootW = xxwa.width;
701 statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
702 XSetForeground(dpy, statusWindow->lightGC, light);
703 statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
704 XSetForeground(dpy, statusWindow->dimGC, dim);
705 statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);
706 XSetForeground(dpy, statusWindow->fgGC, fg);
707 statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
708 XSetForeground(dpy, statusWindow->bgGC, bg);
709 return statusWindow;
710 }
711
712 /* This method is to turn off or turn on the status window. */
713 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
714 Window parent,
715 Bool ON){
716 XWindowAttributes xwa;
717 Window child;
718 int x, y;
719 StatusWindow *statusWindow = NULL;
720
721 if (NULL == currentX11InputMethodInstance ||
722 NULL == pX11IMData ||
723 NULL == (statusWindow = pX11IMData->statusWindow)){
724 return;
725 }
726
727 if (ON == False){
728 XUnmapWindow(dpy, statusWindow->w);
729 statusWindow->on = False;
730 return;
731 }
732 parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
733 "getCurrentParentWindow",
734 "()J").j;
735 if (statusWindow->parent != parent){
736 statusWindow->parent = parent;
737 }
738 XGetWindowAttributes(dpy, parent, &xwa);
739 XTranslateCoordinates(dpy,
740 parent, xwa.root,
741 xwa.x, xwa.y,
742 &x, &y,
743 &child);
744 if (statusWindow->x != x
745 || statusWindow->y != y
746 || statusWindow->height != xwa.height){
747 statusWindow->x = x;
748 statusWindow->y = y;
749 statusWindow->height = xwa.height;
750 x = statusWindow->x - statusWindow->off_x;
751 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
752 if (x < 0 ){
753 x = 0;
754 }
755 if (x + statusWindow->statusW > statusWindow->rootW){
756 x = statusWindow->rootW - statusWindow->statusW;
757 }
758 if (y + statusWindow->statusH > statusWindow->rootH){
759 y = statusWindow->rootH - statusWindow->statusH;
760 }
761 XMoveWindow(dpy, statusWindow->w, x, y);
762 }
763 statusWindow->on = True;
764 XMapWindow(dpy, statusWindow->w);
765 }
766
767 void paintStatusWindow(StatusWindow *statusWindow){
768 Window win = statusWindow->w;
769 GC lightgc = statusWindow->lightGC;
770 GC dimgc = statusWindow->dimGC;
771 GC bggc = statusWindow->bgGC;
772 GC fggc = statusWindow->fgGC;
773
774 int width = statusWindow->statusW;
775 int height = statusWindow->statusH;
776 int bwidth = statusWindow->bWidth;
777 XFillRectangle(dpy, win, bggc, 0, 0, width, height);
778 /* draw border */
779 XDrawLine(dpy, win, fggc, 0, 0, width, 0);
780 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
781 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
782 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
783
784 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
785 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
786 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
787 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
788
789 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
790 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
791 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
792 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
793 if (statusWindow->fontset){
794 XmbDrawString(dpy, win, statusWindow->fontset, fggc,
795 bwidth + 2, height - bwidth - 4,
796 statusWindow->status,
797 strlen(statusWindow->status));
798 }
799 else{
800 /*too bad we failed to create a fontset for this locale*/
801 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
802 "[InputMethod ON]", strlen("[InputMethod ON]"));
803 }
804 }
805
806 void statusWindowEventHandler(XEvent event){
807 JNIEnv *env = GetJNIEnv();
808 X11InputMethodData *pX11IMData = NULL;
809 StatusWindow *statusWindow;
810
811 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
812 currentX11InputMethodInstance = NULL;
813 return;
814 }
815
816 if (NULL == currentX11InputMethodInstance
817 || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance))
818 || NULL == (statusWindow = pX11IMData->statusWindow)
819 || statusWindow->w != event.xany.window){
820 return;
821 }
822
823 switch (event.type){
824 case Expose:
825 paintStatusWindow(statusWindow);
826 break;
827 case MapNotify:
828 case ConfigureNotify:
829 {
830 /*need to reset the stackMode...*/
831 XWindowChanges xwc;
832 int value_make = CWStackMode;
833 xwc.stack_mode = TopIf;
834 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
835 }
836 break;
837 /*
838 case UnmapNotify:
839 case VisibilityNotify:
840 break;
841 */
842 default:
843 break;
844 }
845 }
846
847 static void adjustStatusWindow(Window shell){
848 JNIEnv *env = GetJNIEnv();
849 X11InputMethodData *pX11IMData = NULL;
850 StatusWindow *statusWindow;
851
852 if (NULL == currentX11InputMethodInstance
853 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
854 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
855 || NULL == (statusWindow = pX11IMData->statusWindow)
856 || !statusWindow->on) {
857 return;
858 }
859 {
860 XWindowAttributes xwa;
861 int x, y;
862 Window child;
863 XGetWindowAttributes(dpy, shell, &xwa);
864 XTranslateCoordinates(dpy,
865 shell, xwa.root,
866 xwa.x, xwa.y,
867 &x, &y,
868 &child);
869 if (statusWindow->x != x
870 || statusWindow->y != y
871 || statusWindow->height != xwa.height){
872 statusWindow->x = x;
873 statusWindow->y = y;
874 statusWindow->height = xwa.height;
875
876 x = statusWindow->x - statusWindow->off_x;
877 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
878 if (x < 0 ){
879 x = 0;
880 }
881 if (x + statusWindow->statusW > statusWindow->rootW){
882 x = statusWindow->rootW - statusWindow->statusW;
883 }
884 if (y + statusWindow->statusH > statusWindow->rootH){
885 y = statusWindow->rootH - statusWindow->statusH;
886 }
887 XMoveWindow(dpy, statusWindow->w, x, y);
888 }
889 }
890 }
891 #endif /* __linux__ || MACOSX */
892 /*
893 * Creates two XICs, one for active clients and the other for passive
894 * clients. All information on those XICs are stored in the
895 * X11InputMethodData given by the pX11IMData parameter.
896 *
897 * For active clients: Try to use preedit callback to support
898 * on-the-spot. If tc is not null, the XIC to be created will
899 * share the Status Area with Motif widgets (TextComponents). If the
900 * preferable styles can't be used, fallback to root-window styles. If
901 * root-window styles failed, fallback to None styles.
902 *
903 * For passive clients: Try to use root-window styles. If failed,
904 * fallback to None styles.
905 */
906 static Bool
907 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
908 {
909 XVaNestedList preedit = NULL;
910 XVaNestedList status = NULL;
911 XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
912 active_styles = 0,
913 passive_styles = 0,
914 no_styles = 0;
915 XIMCallback *callbacks;
916 unsigned short i;
917 XIMStyles *im_styles;
918 char *ret = NULL;
919
920 if (X11im == NULL) {
921 return False;
922 }
923 if (!w) {
924 return False;
925 }
926
927 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
928
929 if (ret != NULL) {
930 jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
931 return FALSE ;
932 }
933
934 #if defined(__linux__) || defined(MACOSX)
935 on_the_spot_styles |= XIMStatusNothing;
936
937 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
938 at the same time, so use StatusCallback to draw the status
939 ourself
940 */
941 for (i = 0; i < im_styles->count_styles; i++) {
942 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
943 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
944 break;
945 }
946 }
947 #else /*! __linux__ && !MACOSX */
948 on_the_spot_styles |= XIMStatusNothing;
949 #endif /* __linux__ || MACOSX */
950
951 for (i = 0; i < im_styles->count_styles; i++) {
952 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
953 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
954 no_styles |= im_styles->supported_styles[i] & NO_STYLES;
955 }
956
957 XFree(im_styles);
958
959 if (active_styles != on_the_spot_styles) {
960 if (passive_styles == ROOT_WINDOW_STYLES)
961 active_styles = passive_styles;
962 else {
963 if (no_styles == NO_STYLES)
964 active_styles = passive_styles = NO_STYLES;
965 else
966 active_styles = passive_styles = 0;
967 }
968 } else {
969 if (passive_styles != ROOT_WINDOW_STYLES) {
970 if (no_styles == NO_STYLES)
971 active_styles = passive_styles = NO_STYLES;
972 else
973 active_styles = passive_styles = 0;
974 }
975 }
976
977 if (active_styles == on_the_spot_styles) {
978 pX11IMData->ic_passive = XCreateIC(X11im,
979 XNClientWindow, w,
980 XNFocusWindow, w,
981 XNInputStyle, passive_styles,
982 NULL);
983
984 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
985 if (callbacks == (XIMCallback *)NULL)
986 return False;
987 pX11IMData->callbacks = callbacks;
988
989 for (i = 0; i < NCALLBACKS; i++, callbacks++) {
990 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
991 callbacks->callback = callback_funcs[i];
992 }
993
994 callbacks = pX11IMData->callbacks;
995 preedit = (XVaNestedList)XVaCreateNestedList(0,
996 XNPreeditStartCallback, &callbacks[PreeditStartIndex],
997 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex],
998 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex],
999 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
1000 NULL);
1001 if (preedit == (XVaNestedList)NULL)
1002 goto err;
1003 #if defined(__linux__) || defined(MACOSX)
1004 /*always try XIMStatusCallbacks for active client...*/
1005 {
1006 status = (XVaNestedList)XVaCreateNestedList(0,
1007 XNStatusStartCallback, &callbacks[StatusStartIndex],
1008 XNStatusDoneCallback, &callbacks[StatusDoneIndex],
1009 XNStatusDrawCallback, &callbacks[StatusDrawIndex],
1010 NULL);
1011
1012 if (status == NULL)
1013 goto err;
1014 pX11IMData->statusWindow = createStatusWindow(w);
1015 pX11IMData->ic_active = XCreateIC(X11im,
1016 XNClientWindow, w,
1017 XNFocusWindow, w,
1018 XNInputStyle, active_styles,
1019 XNPreeditAttributes, preedit,
1020 XNStatusAttributes, status,
1021 NULL);
1022 XFree((void *)status);
1023 XFree((void *)preedit);
1024 }
1025 #else /* !__linux__ && !MACOSX */
1026 pX11IMData->ic_active = XCreateIC(X11im,
1027 XNClientWindow, w,
1028 XNFocusWindow, w,
1029 XNInputStyle, active_styles,
1030 XNPreeditAttributes, preedit,
1031 NULL);
1032 XFree((void *)preedit);
1033 #endif /* __linux__ || MACOSX */
1034 } else {
1035 pX11IMData->ic_active = XCreateIC(X11im,
1036 XNClientWindow, w,
1037 XNFocusWindow, w,
1038 XNInputStyle, active_styles,
1039 NULL);
1040 pX11IMData->ic_passive = pX11IMData->ic_active;
1041 }
1042
1043 if (pX11IMData->ic_active == (XIC)0
1044 || pX11IMData->ic_passive == (XIC)0) {
1045 return False;
1046 }
1047
1048 /*
1049 * Use commit string call back if possible.
1050 * This will ensure the correct order of preedit text and commit text
1051 */
1052 {
1053 XIMCallback cb;
1054 cb.client_data = (XPointer) pX11IMData->x11inputmethod;
1055 cb.callback = (XIMProc) CommitStringCallback;
1056 XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL);
1057 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1058 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1059 }
1060 }
1061
1062 /* Add the global reference object to X11InputMethod to the list. */
1063 addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1064
1065 return True;
1066
1067 err:
1068 if (preedit)
1069 XFree((void *)preedit);
1070 THROW_OUT_OF_MEMORY_ERROR();
1071 return False;
1072 }
1073
1074 static void
1075 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1076 {
1077 /*ARGSUSED*/
1078 /* printf("Native: PreeditCaretCallback\n"); */
1079 }
1080
1081 static void
1082 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1083 {
1084 /*ARGSUSED*/
1085 /* printf("Native: StatusStartCallback\n"); */
1086 }
1087
1088 /*
1089 * Translate the preedit draw callback items to Java values and invoke
1090 * X11InputMethod.dispatchComposedText().
1091 *
1092 * client_data: X11InputMethod object
1093 */
1094 static void
1095 PreeditDrawCallback(XIC ic, XPointer client_data,
1096 XIMPreeditDrawCallbackStruct *pre_draw)
1097 {
1098 JNIEnv *env = GetJNIEnv();
1099 X11InputMethodData *pX11IMData = NULL;
1100 jmethodID x11imMethodID;
1101
1102 XIMText *text;
1103 jstring javastr = NULL;
1104 jintArray style = NULL;
1105
1106 /* printf("Native: PreeditDrawCallback() \n"); */
1107 if (pre_draw == NULL) {
1108 return;
1109 }
1110 AWT_LOCK();
1111 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1112 if ((jobject)client_data == currentX11InputMethodInstance) {
1113 currentX11InputMethodInstance = NULL;
1114 }
1115 goto finally;
1116 }
1117 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1118 goto finally;
1119 }
1120
1121 if ((text = pre_draw->text) != NULL) {
1122 if (text->string.multi_byte != NULL) {
1123 if (pre_draw->text->encoding_is_wchar == False) {
1124 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1125 if (javastr == NULL) {
1126 goto finally;
1127 }
1128 } else {
1129 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1130 if (mbstr == NULL) {
1131 goto finally;
1132 }
1133 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1134 free(mbstr);
1135 if (javastr == NULL) {
1136 goto finally;
1137 }
1138 }
1139 }
1140 if (text->feedback != NULL) {
1141 int cnt;
1142 jint *tmpstyle;
1143
1144 style = (*env)->NewIntArray(env, text->length);
1145 if (JNU_IsNull(env, style)) {
1146 (*env)->ExceptionClear(env);
1147 THROW_OUT_OF_MEMORY_ERROR();
1148 goto finally;
1149 }
1150
1151 if (sizeof(XIMFeedback) == sizeof(jint)) {
1152 /*
1153 * Optimization to avoid copying the array
1154 */
1155 (*env)->SetIntArrayRegion(env, style, 0,
1156 text->length, (jint *)text->feedback);
1159 if (tmpstyle == (jint *) NULL) {
1160 THROW_OUT_OF_MEMORY_ERROR();
1161 goto finally;
1162 }
1163 for (cnt = 0; cnt < (int)text->length; cnt++)
1164 tmpstyle[cnt] = text->feedback[cnt];
1165 (*env)->SetIntArrayRegion(env, style, 0,
1166 text->length, (jint *)tmpstyle);
1167 }
1168 }
1169 }
1170 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1171 "dispatchComposedText",
1172 "(Ljava/lang/String;[IIIIJ)V",
1173 javastr,
1174 style,
1175 (jint)pre_draw->chg_first,
1176 (jint)pre_draw->chg_length,
1177 (jint)pre_draw->caret,
1178 awt_util_nowMillisUTC());
1179 finally:
1180 AWT_UNLOCK();
1181 return;
1182 }
1183
1184 static void
1185 PreeditCaretCallback(XIC ic, XPointer client_data,
1186 XIMPreeditCaretCallbackStruct *pre_caret)
1187 {
1188 /*ARGSUSED*/
1189 /* printf("Native: PreeditCaretCallback\n"); */
1190
1191 }
1192
1193 #if defined(__linux__) || defined(MACOSX)
1194 static void
1195 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1196 {
1197 /*ARGSUSED*/
1198 /*printf("StatusStartCallback:\n"); */
1199
1200 }
1201
1202 static void
1203 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1204 {
1205 /*ARGSUSED*/
1206 /*printf("StatusDoneCallback:\n"); */
1207
1208 }
1209
1210 static void
1211 StatusDrawCallback(XIC ic, XPointer client_data,
1212 XIMStatusDrawCallbackStruct *status_draw)
1213 {
1214 /*ARGSUSED*/
1215 /*printf("StatusDrawCallback:\n"); */
1216 JNIEnv *env = GetJNIEnv();
1217 X11InputMethodData *pX11IMData = NULL;
1218 StatusWindow *statusWindow;
1219
1220 AWT_LOCK();
1221
1222 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1223 if ((jobject)client_data == currentX11InputMethodInstance) {
1224 currentX11InputMethodInstance = NULL;
1225 }
1226 goto finally;
1227 }
1228
1229 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1230 || NULL == (statusWindow = pX11IMData->statusWindow)){
1231 goto finally;
1232 }
1233 currentX11InputMethodInstance = (jobject)client_data;
1234
1235 if (status_draw->type == XIMTextType){
1236 XIMText *text = (status_draw->data).text;
1237 if (text != NULL){
1238 if (text->string.multi_byte != NULL) {
1239 strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN);
1240 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1241 }
1242 else {
1243 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1244 strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN);
1245 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1246 }
1247 statusWindow->on = True;
1248 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1249 paintStatusWindow(statusWindow);
1250 }
1251 else {
1252 statusWindow->on = False;
1253 /*just turnoff the status window
1254 paintStatusWindow(statusWindow);
1255 */
1256 onoffStatusWindow(pX11IMData, 0, False);
1257 }
1258 }
1259
1260 finally:
1261 AWT_UNLOCK();
1262 }
1263 #endif /* __linux__ || MACOSX */
1264
1265 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1266 JNIEnv *env = GetJNIEnv();
1267 XIMText * text = (XIMText *)call_data;
1268 X11InputMethodData *pX11IMData = NULL;
1269 jstring javastr;
1270
1271 AWT_LOCK();
1272
1273 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1274 if ((jobject)client_data == currentX11InputMethodInstance) {
1275 currentX11InputMethodInstance = NULL;
1276 }
1277 goto finally;
1278 }
1279
1280 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1281 goto finally;
1282 }
1283 currentX11InputMethodInstance = (jobject)client_data;
1284
1285 if (text->encoding_is_wchar == False) {
1286 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1287 } else {
1288 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1289 if (mbstr == NULL) {
1290 goto finally;
1291 }
1292 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1293 free(mbstr);
1294 }
1295
1296 if (javastr != NULL) {
1297 JNU_CallMethodByName(env, NULL,
1298 pX11IMData->x11inputmethod,
1299 "dispatchCommittedText",
1300 "(Ljava/lang/String;J)V",
1301 javastr,
1302 awt_util_nowMillisUTC());
1303 }
1304 finally:
1305 AWT_UNLOCK();
1306 }
1307
1308 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) {
1309 XIMCallback ximCallback;
1310
1311 X11im = XOpenIM(display, NULL, NULL, NULL);
1312 if (X11im == NULL) {
1313 return;
1314 }
1315
1316 ximCallback.callback = (XIMProc)DestroyXIMCallback;
1317 ximCallback.client_data = NULL;
1318 XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1319 }
1320
1321 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1322 /* mark that XIM server was destroyed */
1323 X11im = NULL;
1324 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1325 /* free the old pX11IMData and set it to null. this also avoids crashing
1326 * the jvm if the XIM server reappears */
1327 X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1328 }
1329
1330 /*
1331 * Class: sun_awt_X11InputMethod
1332 * Method: initIDs
1333 * Signature: ()V
1334 */
1335
1336 /* This function gets called from the static initializer for
1337 X11InputMethod.java
1338 to initialize the fieldIDs for fields that may be accessed from C */
1339 JNIEXPORT void JNICALL
1340 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1341 {
1342 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1343 }
1344
1345
1346 JNIEXPORT jboolean JNICALL
1347 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1348 jobject this,
1349 jlong display)
1350 {
1351 Bool registered;
1352
1353 AWT_LOCK();
1354
1355 dpy = (Display *)jlong_to_ptr(display);
1356
1357 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1358 (4768335)
1359 */
1360 #if defined(__linux__) || defined(MACOSX)
1361 registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1362 NULL, (XIDProc)OpenXIMCallback, NULL);
1363 if (!registered) {
1364 /* directly call openXIM callback */
1365 #endif
1366 OpenXIMCallback(dpy, NULL, NULL);
1367 #if defined(__linux__) || defined(MACOSX)
1368 }
1369 #endif
1370
1371 AWT_UNLOCK();
1372
1373 return JNI_TRUE;
1374 }
1375
1376 JNIEXPORT jboolean JNICALL
1377 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1378 jobject this,
1379 jlong window)
1380 {
1381 X11InputMethodData *pX11IMData;
1382 jobject globalRef;
1383 XIC ic;
1384
1385 AWT_LOCK();
1386
1387 if (!window) {
1388 JNU_ThrowNullPointerException(env, "NullPointerException");
1389 AWT_UNLOCK();
1390 return JNI_FALSE;
1391 }
1392
1393 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1394 if (pX11IMData == NULL) {
1395 THROW_OUT_OF_MEMORY_ERROR();
1396 AWT_UNLOCK();
1397 return JNI_FALSE;
1398 }
1399
1400 globalRef = (*env)->NewGlobalRef(env, this);
1401 pX11IMData->x11inputmethod = globalRef;
1402 #if defined(__linux__) || defined(MACOSX)
1403 pX11IMData->statusWindow = NULL;
1404 #endif /* __linux__ || MACOSX */
1405
1406 pX11IMData->lookup_buf = 0;
1407 pX11IMData->lookup_buf_len = 0;
1408
1409 if (createXIC(env, pX11IMData, (Window)window) == False) {
1410 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1411 pX11IMData = (X11InputMethodData *) NULL;
1412 if ((*env)->ExceptionCheck(env)) {
1413 goto finally;
1414 }
1415 }
1416
1417 setX11InputMethodData(env, this, pX11IMData);
1418
1419 finally:
1420 AWT_UNLOCK();
1421 return (pX11IMData != NULL);
1422 }
1423
1424 JNIEXPORT void JNICALL
1425 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1426 jobject this,
1427 jlong w,
1428 jboolean req,
1429 jboolean active)
1430 {
1431 X11InputMethodData *pX11IMData;
1432 AWT_LOCK();
1433 pX11IMData = getX11InputMethodData(env, this);
1434 if (pX11IMData == NULL) {
1435 AWT_UNLOCK();
1436 return;
1437 }
1438
1439 if (req) {
1440 if (!w) {
1441 AWT_UNLOCK();
1442 return;
1443 }
1444 pX11IMData->current_ic = active ?
1445 pX11IMData->ic_active : pX11IMData->ic_passive;
1446 /*
1447 * On Solaris2.6, setXICWindowFocus() has to be invoked
1448 * before setting focus.
1449 */
1450 setXICWindowFocus(pX11IMData->current_ic, w);
1451 setXICFocus(pX11IMData->current_ic, req);
1452 currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1453 currentFocusWindow = w;
1454 #if defined(__linux__) || defined(MACOSX)
1455 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1456 onoffStatusWindow(pX11IMData, w, True);
1457 #endif
1458 } else {
1459 currentX11InputMethodInstance = NULL;
1460 currentFocusWindow = 0;
1461 #if defined(__linux__) || defined(MACOSX)
1462 onoffStatusWindow(pX11IMData, 0, False);
1463 if (pX11IMData->current_ic != NULL)
1464 #endif
1465 setXICFocus(pX11IMData->current_ic, req);
1466
1467 pX11IMData->current_ic = (XIC)0;
1468 }
1469
1470 XFlush(dpy);
1471 AWT_UNLOCK();
1472 }
1473
1474 JNIEXPORT void JNICALL
1475 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
1476 jobject this)
1477 {
1478 #if defined(__linux__) || defined(MACOSX)
1479 X11InputMethodData *pX11IMData;
1480 StatusWindow *statusWindow;
1481
1482 AWT_LOCK();
1483
1484 if (NULL == currentX11InputMethodInstance
1485 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1486 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1487 || NULL == (statusWindow = pX11IMData->statusWindow)
1488 || !statusWindow->on ){
1489 AWT_UNLOCK();
1490 return;
1491 }
1492 onoffStatusWindow(pX11IMData, 0, False);
1493
1494 AWT_UNLOCK();
1495 #endif
1496 }
1497
1498 JNIEXPORT void JNICALL
1499 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
1500 jobject this)
1501 {
1502 X11InputMethodData *pX11IMData = NULL;
1503
1504 AWT_LOCK();
1505 pX11IMData = getX11InputMethodData(env, this);
1506 if (pX11IMData == NULL) {
1507 AWT_UNLOCK();
1508 return;
1509 }
1510
1511 setX11InputMethodData(env, this, NULL);
1512
1513 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1514 currentX11InputMethodInstance = NULL;
1515 currentFocusWindow = 0;
1516 }
1517 destroyX11InputMethodData(env, pX11IMData);
1518 AWT_UNLOCK();
1519 }
1520
1521 JNIEXPORT jstring JNICALL
1522 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
1523 jobject this)
1524 {
1525 X11InputMethodData *pX11IMData;
1526 char *xText = NULL;
1527 jstring jText = (jstring)0;
1528
1529 AWT_LOCK();
1530 pX11IMData = getX11InputMethodData(env, this);
1531 if (pX11IMData == NULL) {
1532 AWT_UNLOCK();
1533 return jText;
1534 }
1535
1536 if (pX11IMData->current_ic)
1537 xText = XmbResetIC(pX11IMData->current_ic);
1538 else {
1539 /*
1540 * If there is no reference to the current XIC, try to reset both XICs.
1541 */
1542 xText = XmbResetIC(pX11IMData->ic_active);
1543 /*it may also means that the real client component does
1544 not have focus -- has been deactivated... its xic should
1545 not have the focus, bug#4284651 showes reset XIC for htt
1546 may bring the focus back, so de-focus it again.
1547 */
1548 setXICFocus(pX11IMData->ic_active, FALSE);
1549 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1550 char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1551 setXICFocus(pX11IMData->ic_passive, FALSE);
1552 if (xText == (char *)NULL && tmpText)
1553 xText = tmpText;
1554 }
1555
1556 }
1557 if (xText != NULL) {
1558 jText = JNU_NewStringPlatform(env, (const char *)xText);
1559 XFree((void *)xText);
1560 }
1561
1562 AWT_UNLOCK();
1563 return jText;
1564 }
1565
1566 /*
1567 * Class: sun_awt_X11InputMethod
1568 * Method: setCompositionEnabledNative
1569 * Signature: (ZJ)V
1570 *
1571 * This method tries to set the XNPreeditState attribute associated with the current
1572 * XIC to the passed in 'enable' state.
1573 *
1574 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1575 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1576 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1577 * method fails due to other reasons.
1578 *
1579 */
1580 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
1581 (JNIEnv *env, jobject this, jboolean enable)
1582 {
1583 X11InputMethodData *pX11IMData;
1584 char * ret = NULL;
1585
1586 AWT_LOCK();
1587 pX11IMData = getX11InputMethodData(env, this);
1588
1589 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1590 AWT_UNLOCK();
1591 return JNI_FALSE;
1592 }
1593
1594 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1595 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1596 AWT_UNLOCK();
1597
1598 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1599 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1600 }
1601
1602 return (jboolean)(ret == 0);
1603 }
1604
1605 /*
1606 * Class: sun_awt_X11InputMethod
1607 * Method: isCompositionEnabledNative
1608 * Signature: (J)Z
1609 *
1610 * This method tries to get the XNPreeditState attribute associated with the current XIC.
1611 *
1612 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1613 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1614 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1615 *
1616 */
1617 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
1618 (JNIEnv *env, jobject this)
1619 {
1620 X11InputMethodData *pX11IMData = NULL;
1621 char * ret = NULL;
1622 XIMPreeditState state;
1623
1624 AWT_LOCK();
1625 pX11IMData = getX11InputMethodData(env, this);
1626
1627 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1628 AWT_UNLOCK();
1629 return JNI_FALSE;
1630 }
1631
1632 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1633 AWT_UNLOCK();
1634
1635 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1636 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1637 return JNI_FALSE;
1638 }
1639
1640 return (jboolean)(state == XIMPreeditEnable);
1641 }
1642
1643 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
1644 (JNIEnv *env, jobject this, jlong window)
1645 {
1646 #if defined(__linux__) || defined(MACOSX)
1647 AWT_LOCK();
1648 adjustStatusWindow(window);
1649 AWT_UNLOCK();
1650 #endif
1651 }
|
1 /*
2 * Copyright (c) 1997, 2018, 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 #include "awt.h"
27 #include "awt_p.h"
28
29 #include <sun_awt_X11InputMethodBase.h>
30 #include <sun_awt_X11InputMethod.h>
31 #include <sun_awt_X11_XInputMethod.h>
32
33 #include <langinfo.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/time.h>
37 #include <wchar.h>
38 #include <wctype.h>
39 #include <X11/Intrinsic.h>
40 #include <X11/keysym.h>
41 #include <X11/Xlib.h>
42
43 #ifdef HEADLESS
44 #error This file should not be included in headless library
45 #endif
46
47 #define THROW_OUT_OF_MEMORY_ERROR() \
48 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)
49
50 struct X11InputMethodIDs {
51 jfieldID pData;
52 } x11InputMethodIDs;
53
54 static int PreeditStartCallback(XIC, XPointer, XPointer);
55 static void PreeditDoneCallback(XIC, XPointer, XPointer);
56 static void PreeditDrawCallback(XIC, XPointer,
57 XIMPreeditDrawCallbackStruct *);
58 static void PreeditCaretCallback(XIC, XPointer,
59 XIMPreeditCaretCallbackStruct *);
60 static void StatusStartCallback(XIC, XPointer, XPointer);
61 static void StatusDoneCallback(XIC, XPointer, XPointer);
62 static void StatusDrawCallback(XIC, XPointer,
63 XIMStatusDrawCallbackStruct *);
64
65 #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing)
66 #define NO_STYLES (XIMPreeditNone | XIMStatusNone)
67 /* added style to allow for in-place composition, such as "dead" keys for accents */
68 #define IN_PLACE_STYLES (XIMPreeditNothing | XIMStatusNone)
69
70 #define PreeditStartIndex 0
71 #define PreeditDoneIndex 1
72 #define PreeditDrawIndex 2
73 #define PreeditCaretIndex 3
74 #define StatusStartIndex 4
75 #define StatusDoneIndex 5
76 #define StatusDrawIndex 6
77 #define NCALLBACKS 7
78
79 #define STATUS_BORDER 2 /* Status Border width */
80 #define CARET_OFFSET 1 /* Offset of caret position (pixel) */
81 #define BORDER_MARGIN 3 /* BORDER MARGIN width */
82 #define STATUS_MARGIN 7 /* Margin between the status window and its parent window */
83 #define PREEDIT_ATTR_MASK (XIMReverse|XIMUnderline)
84 /* Preedit attribute which host adapter can handle */
85
86 /*
87 * Callback function pointers: the order has to match the *Index
88 * values above.
89 */
90 static XIMProc callback_funcs[NCALLBACKS] = {
91 (XIMProc)PreeditStartCallback,
92 (XIMProc)PreeditDoneCallback,
93 (XIMProc)PreeditDrawCallback,
94 (XIMProc)PreeditCaretCallback,
95 (XIMProc)StatusStartCallback,
96 (XIMProc)StatusDoneCallback,
97 (XIMProc)StatusDrawCallback,
98 };
99
100 #define MAX_STATUS_LEN 100
101 typedef struct {
102 Window w; /*status window id */
103 Window root; /*the root window id */
104 Window parent; /*parent shell window */
105 Window grandParent; /*window has WM frame */
106 int x, y; /*parent's upperleft position */
107 int width, height; /*parent's width, height */
108 GC lightGC; /*gc for light border */
109 GC dimGC; /*gc for dim border */
110 GC bgGC; /*normal painting */
111 GC fgGC; /*normal painting */
112 int statusW, statusH; /*status window's w, h */
113 int rootW, rootH; /*root window's w, h */
114 int bWidth; /*border width */
115 wchar_t status[MAX_STATUS_LEN + 1]; /*status text */
116 XFontSet fontset; /*fontset for drawing */
117 int off_x, off_y;
118 Bool on; /*if the status window on*/
119 int fOff; /* font base line(in pixel) from top */
120 int fBot; /* font bottom line(in pixel) from top */
121 int peTextW; /* Composition text width in pixel */
122 wchar_t* peText; /* Composed string (wide char.) */
123 XIMFeedback* peAttr; /* Composed text attribute */
124 int peCaret; /* Caret position in number of character */
125 Bool status_ready; /* Not draw Status at XCreateIC */
126 } StatusWindow;
127
128 /*
129 * X11InputMethodData keeps per X11InputMethod instance information. A pointer
130 * to this data structure is kept in an X11InputMethod object (pData).
131 */
132 typedef struct _X11InputMethodData {
133 XIC current_ic; /* current X Input Context */
134 XIC ic_active; /* X Input Context for active clients */
135 XIC ic_passive; /* X Input Context for passive clients */
136 XIMCallback *callbacks; /* callback parameters */
137 jobject x11inputmethod; /* global ref to X11InputMethod instance */
138 /* associated with the XIC */
139 StatusWindow *statusWindow; /* our own status window */
140 Bool passiveStatusWindow;/* Passive Client uses StatusWindow */
141 Bool isActiveClient; /* True:clinet is active */
142 Bool forceReset; /* True: call resetXIC before UnsetICFocus */
143 } X11InputMethodData;
144
145 /* reference to the current X11InputMethod instance, it is always
146 point to the global reference to the X11InputMethodObject since
147 it could be referenced by different threads. */
148 jobject currentX11InputMethodInstance = NULL;
149
150 Window currentFocusWindow = 0; /* current window that has focus for input
151 method. (the best place to put this
152 information should be
153 currentX11InputMethodInstance's pData) */
154 static XIM X11im = NULL;
155 Display * dpy = NULL;
156
157 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)
158
159 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject);
160 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *);
161 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *);
162 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *);
163
164 /* Prototype for this function is missing in AIX Xlib.h */
165 extern char *XSetIMValues(
166 #if NeedVarargsPrototypes
167 XIM /* im */, ...
168 #endif
169 );
170
171 static int st_wcslen(wchar_t *string);
172 static Bool isPreeditStateActive(XIC ic);
173 static void * buf_insert(void * src, void * insert, int size,
174 int src_len, int ins_len, int offset);
175 static void * handle_buffer(void * source, void * insert,
176 int size, int src_len, int ins_len,
177 int del_len, int offset);
178 static void preedit_draw_passive(X11InputMethodData *pX11IMData,
179 XIMPreeditDrawCallbackStruct *pre_draw);
180 static void resetPassivePreeditText(StatusWindow *statusWindow);
181 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos);
182 static int get_next_attr(int len, unsigned long *attr);
183 static void draw_preedit(StatusWindow *statusWindow);
184 static void align_status(StatusWindow *statusWindow);
185 static void shrink_status(StatusWindow *statusWindow);
186 static GC create_gc(Window win, Bool isReverse);
187 static XFontSet create_fontset(void);
188 static Bool is_text_available(XIMText * text);
189 static Bool isNativeIm();
190 static Window getGrandParent(Window parent);
191 static void moveStatusWindow(StatusWindow *statusWindow);
192 static void arrange_window_stack(StatusWindow* statusWindow);
193 static Window get_current_focus(XIC ic);
194
195 /*
196 * This function is stolen from /src/solaris/hpi/src/system_md.c
197 * It is used in setting the time in Java-level InputEvents
198 */
199 jlong
200 awt_util_nowMillisUTC()
201 {
202 struct timeval t;
203 gettimeofday(&t, NULL);
204 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
205 }
206
207 /*
208 * Converts the wchar_t string to a multi-byte string calling wcstombs(). A
209 * buffer is allocated by malloc() to store the multi-byte string. NULL is
210 * returned if the given wchar_t string pointer is NULL or buffer allocation is
211 * failed.
212 */
213 static char *
219 if (wcs == NULL)
220 return NULL;
221
222 n = len*MB_CUR_MAX + 1;
223
224 mbs = (char *) malloc(n * sizeof(char));
225 if (mbs == NULL) {
226 THROW_OUT_OF_MEMORY_ERROR();
227 return NULL;
228 }
229
230 /* TODO: check return values... Handle invalid characters properly... */
231 if (wcstombs(mbs, wcs, n) == (size_t)-1) {
232 free(mbs);
233 return NULL;
234 }
235
236 return mbs;
237 }
238
239 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {
240 X11InputMethodData *pX11IMData =
241 (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);
242
243 /*
244 * In case the XIM server was killed somehow, reset X11InputMethodData.
245 */
246 if (X11im == NULL && pX11IMData != NULL) {
247 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
248 "flushText",
249 "()V");
250 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
251 /* IMPORTANT:
252 The order of the following calls is critical since "imInstance" may
253 point to the global reference itself, if "freeX11InputMethodData" is called
254 first, the global reference will be destroyed and "setX11InputMethodData"
255 will in fact fail silently. So pX11IMData will not be set to NULL.
256 This could make the original java object refers to a deleted pX11IMData
257 object.
258 */
281
282 if (pX11IMData->ic_active != (XIC)0) {
283 XUnsetICFocus(pX11IMData->ic_active);
284 XDestroyIC(pX11IMData->ic_active);
285 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
286 if (pX11IMData->ic_passive != (XIC)0) {
287 XUnsetICFocus(pX11IMData->ic_passive);
288 XDestroyIC(pX11IMData->ic_passive);
289 }
290 pX11IMData->ic_passive = (XIC)0;
291 pX11IMData->current_ic = (XIC)0;
292 }
293 }
294
295 freeX11InputMethodData(env, pX11IMData);
296 }
297
298 static void
299 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
300 {
301 if (pX11IMData->statusWindow != NULL){
302 StatusWindow *sw = pX11IMData->statusWindow;
303 XFreeGC(awt_display, sw->lightGC);
304 XFreeGC(awt_display, sw->dimGC);
305 XFreeGC(awt_display, sw->bgGC);
306 XFreeGC(awt_display, sw->fgGC);
307 if (sw->fontset != NULL) {
308 XFreeFontSet(awt_display, sw->fontset);
309 }
310 XDestroyWindow(awt_display, sw->w);
311 if (pX11IMData->statusWindow->peText){
312 free((void *)pX11IMData->statusWindow->peText);
313 pX11IMData->statusWindow->peText = NULL;
314 }
315 if (pX11IMData->statusWindow->peAttr){
316 free((void *)pX11IMData->statusWindow->peAttr);
317 pX11IMData->statusWindow->peAttr = NULL;
318 }
319 free((void*)sw);
320 }
321
322 if (pX11IMData->callbacks)
323 free((void *)pX11IMData->callbacks);
324
325 if (env) {
326 (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);
327 }
328
329 free((void *)pX11IMData);
330 }
331
332 /*
333 * Sets or unsets the focus to the given XIC.
334 */
335 static void
336 setXICFocus(XIC ic, unsigned short req)
337 {
338 if (ic == NULL) {
339 (void)fprintf(stderr, "Couldn't find X Input Context\n");
340 return;
341 }
342 if (req == 1)
343 XSetICFocus(ic);
344 else
345 XUnsetICFocus(ic);
346 }
347
348 /*
362 * Invokes XmbLookupString() to get something from the XIM. It invokes
363 * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns
364 * committed text. This function is called from handleKeyEvent in canvas.c and
365 * it's under the Motif event loop thread context.
366 *
367 * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,
368 * where it never returns XBufferOverflow. We need to allocate the initial lookup buffer
369 * big enough, so that the possibility that user encounters this problem is relatively
370 * small. When this bug gets fixed, we can make the initial buffer size smaller.
371 * Note that XmbLookupString() sometimes produces a non-null-terminated string.
372 *
373 * Returns True when there is a keysym value to be handled.
374 */
375 #define INITIAL_LOOKUP_BUF_SIZE 512
376
377 Boolean
378 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)
379 {
380 JNIEnv *env = GetJNIEnv();
381 X11InputMethodData *pX11IMData = NULL;
382 int buf_len = INITIAL_LOOKUP_BUF_SIZE;
383 char mbbuf[INITIAL_LOOKUP_BUF_SIZE];
384 char *buf;
385 KeySym keysym = NoSymbol;
386 Status status;
387 int mblen;
388 jstring javastr;
389 XIC ic;
390 Boolean result = True;
391 static Boolean composing = False;
392
393 /*
394 printf("lookupString: entering...\n");
395 */
396
397 pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
398
399 if (pX11IMData == NULL) {
400 return False;
401 }
402
403 if ((ic = pX11IMData->current_ic) == (XIC)0){
404 return False;
405 }
406
407 buf = mbbuf;
408 mblen = XmbLookupString(ic, event, buf,
409 buf_len - 1, &keysym, &status);
410
411 /*
412 * In case of overflow, a buffer is allocated and it retries
413 * XmbLookupString().
414 */
415 if (status == XBufferOverflow) {
416 buf_len = mblen + 1;
417 buf = (char *)malloc(buf_len);
418 if (buf == NULL) {
419 THROW_OUT_OF_MEMORY_ERROR();
420 return result;
421 }
422 mblen = XmbLookupString(ic, event, buf, buf_len, &keysym, &status);
423 }
424 buf[mblen] = 0;
425
426 /* Get keysym without taking modifiers into account first to map
427 * to AWT keyCode table.
428 */
429 switch (status) {
430 case XLookupBoth:
431 if (!composing) {
432 if (event->keycode != 0) {
433 *keysymp = keysym;
434 result = False;
435 break;
436 }
437 }
438 composing = False;
439 /*FALLTHRU*/
440 case XLookupChars:
441 /*
442 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
443 event->type, event->state, event->keycode, keysym);
444 */
445 javastr = JNU_NewStringPlatform(env, (const char *)buf);
446 if (javastr != NULL) {
447 JNU_CallMethodByName(env, NULL,
448 currentX11InputMethodInstance,
449 "dispatchCommittedText",
450 "(Ljava/lang/String;J)V",
451 javastr,
452 event->time);
453 if ((*env)->ExceptionOccurred(env)) {
454 (*env)->ExceptionDescribe(env);
455 (*env)->ExceptionClear(env);
456 }
457 }
458 break;
459
460 case XLookupKeySym:
461 /*
462 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
463 event->type, event->state, event->keycode, keysym);
464 */
465 if (keysym == XK_Multi_key)
466 composing = True;
467 if (! composing) {
468 *keysymp = keysym;
469 result = False;
470 }
471 break;
472
473 case XLookupNone:
474 /*
475 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
476 event->type, event->state, event->keycode, keysym);
477 */
478 break;
479 }
480
481 if (buf != mbbuf) {
482 free(buf);
483 }
484 return result;
485 }
486
487 static StatusWindow *createStatusWindow(Window parent) {
488 StatusWindow *statusWindow;
489 XSetWindowAttributes attrib;
490 unsigned long attribmask;
491 Window containerWindow;
492 Window status;
493 Window child;
494 XWindowAttributes xwa;
495 XWindowAttributes xxwa;
496 /* Variable for XCreateFontSet()*/
497 char **mclr;
498 int mccr = 0;
499 char *dsr;
500 unsigned long bg, fg, light, dim;
501 int x, y, off_x, off_y, xx, yy;
502 unsigned int w, h, bw, depth;
503 XGCValues values;
504 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/
505 int screen = 0;
506 int i;
507 AwtGraphicsConfigDataPtr adata;
508 extern int awt_numScreens;
509 /*hardcode the size right now, should get the size base on font*/
510 int width=80, height=22;
511 Window rootWindow;
512 Window *ignoreWindowPtr;
513 unsigned int ignoreUnit;
514 Window grandParent;
515 Window target;
516 XFontSet fontset;
517
518 fontset = create_fontset();
519 if (NULL == fontset) {
520 return NULL;
521 }
522
523 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
524
525 attrib.override_redirect = True;
526 attribmask = CWOverrideRedirect;
527 for (i = 0; i < awt_numScreens; i++) {
528 if (RootWindow(dpy, i) == rootWindow) {
529 screen = i;
530 break;
531 }
532 }
533 adata = getDefaultConfig(screen);
534 bg = adata->AwtColorMatch(255, 255, 255, adata);
535 fg = adata->AwtColorMatch(0, 0, 0, adata);
536 light = adata->AwtColorMatch(195, 195, 195, adata);
537 dim = adata->AwtColorMatch(128, 128, 128, adata);
538
539 grandParent = getGrandParent(parent);
540 target = (grandParent == 0) ? parent : grandParent;
541 XGetWindowAttributes(dpy, target, &xwa);
542 bw = 2; /*xwa.border_width does not have the correct value*/
543
544 /*compare the size difference between parent container
545 and shell widget, the diff should be the border frame
546 and title bar height (?)*/
547
548 XQueryTree( dpy,
549 target,
550 &rootWindow,
551 &containerWindow,
552 &ignoreWindowPtr,
553 &ignoreUnit);
554 XGetWindowAttributes(dpy, containerWindow, &xxwa);
555
556 XTranslateCoordinates(dpy,
557 target, xwa.root,
558 0, 0,
559 &x, &y, &child);
560
561 if (containerWindow == rootWindow) {
562 off_x = 0; off_y = STATUS_MARGIN;
563 } else {
564 XGetWindowAttributes(dpy, containerWindow, &xxwa);
565 off_x = (xxwa.width - xwa.width) / 2;
566 /* off_y = xxwa.height - xwa.height - off_x;*/ /*it's magic:-) */
567 {
568 int cx, cy;
569 XTranslateCoordinates(dpy,
570 containerWindow, xxwa.root,
571 0, 0,
572 &cx, &cy,
573 &child);
574 off_y = (xxwa.height + cy) - (xwa.height + y);
575 }
576 }
577
578 /*get the size of root window*/
579 XGetWindowAttributes(dpy, rootWindow, &xxwa);
580
581 XTranslateCoordinates(dpy,
582 target, xwa.root,
583 xwa.x, xwa.y,
584 &x, &y,
585 &child);
586 xx = x - off_x;
587 yy = y + xwa.height - off_y;
588 if (xx < 0 ){
589 xx = 0;
590 }
591 if (xx + width > xxwa.width) {
592 xx = xxwa.width - width;
593 }
594 if (yy + height > xxwa.height) {
595 yy = xxwa.height - height;
596 }
597
598 if ((DefaultVisual(dpy,screen))->class != adata->awt_visInfo.visual->class &&
599 adata->awt_visInfo.visual->class == TrueColor) {
600 attrib.colormap = XCreateColormap(dpy, xwa.root,
601 adata->awt_visInfo.visual, AllocNone );
602 attrib.border_pixel = BlackPixel(dpy, screen) ;
603 attribmask |= CWColormap | CWBorderPixel;
604 }
605
606 status = XCreateWindow(dpy,
607 xwa.root,
608 xx, yy,
609 width, height,
610 0,
611 xwa.depth,
612 InputOutput,
613 adata->awt_visInfo.visual,
614 attribmask, &attrib);
615 XSelectInput(dpy, status,
616 ExposureMask | StructureNotifyMask | EnterWindowMask |
617 LeaveWindowMask | VisibilityChangeMask);
618 if (grandParent != 0){
619 long mask;
620 XGetWindowAttributes(dpy, grandParent, &xwa);
621 mask = xwa.your_event_mask | StructureNotifyMask |
622 VisibilityChangeMask | PropertyChangeMask;
623 XSelectInput(dpy, grandParent,mask);
624 }
625
626 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
627 if (statusWindow == NULL){
628 THROW_OUT_OF_MEMORY_ERROR();
629 return NULL;
630 }
631 statusWindow->w = status;
632 statusWindow->fontset = fontset;
633 statusWindow->parent = parent;
634 statusWindow->grandParent = grandParent;
635 statusWindow->on = False;
636 statusWindow->x = x;
637 statusWindow->y = y;
638 statusWindow->width = xwa.width;
639 statusWindow->height = xwa.height;
640 statusWindow->off_x = off_x;
641 statusWindow->off_y = off_y;
642 statusWindow->bWidth = bw;
643 statusWindow->statusH = height;
644 statusWindow->statusW = width;
645 statusWindow->peTextW = 0;
646 statusWindow->rootH = xxwa.height;
647 statusWindow->rootW = xxwa.width;
648 statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
649 XSetForeground(dpy, statusWindow->lightGC, light);
650 statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
651 XSetForeground(dpy, statusWindow->dimGC, dim);
652 statusWindow->fgGC = create_gc(status, FALSE);
653 XSetForeground(dpy, statusWindow->fgGC, fg);
654 statusWindow->bgGC = create_gc(status, TRUE);
655 XSetForeground(dpy, statusWindow->bgGC, bg);
656 statusWindow->status_ready = False;
657 wcscpy(statusWindow->status, L"");
658 return statusWindow;
659 }
660
661 /* This method is to turn off or turn on the status window. */
662 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
663 Window parent,
664 Bool ON){
665 XWindowAttributes xwa;
666 Window child;
667 int x, y;
668 StatusWindow *statusWindow = NULL;
669
670 if (NULL == pX11IMData ||
671 NULL == (statusWindow = pX11IMData->statusWindow)){
672 return;
673 }
674
675 if (ON == False) {
676 XUnmapWindow(dpy, statusWindow->w);
677 return;
678 }
679 if (NULL == currentX11InputMethodInstance){
680 return;
681 }
682 {
683 JNIEnv *env = GetJNIEnv();
684 parent = JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
685 "getCurrentParentWindow",
686 "()J").j;
687 if ((*env)->ExceptionOccurred(env)) {
688 (*env)->ExceptionDescribe(env);
689 (*env)->ExceptionClear(env);
690 }
691 }
692 if (statusWindow->parent != parent) {
693 statusWindow->parent = parent;
694 }
695 if (st_wcslen(statusWindow->status) > 0 ||
696 (statusWindow->peText != NULL && st_wcslen(statusWindow->peText) > 0 )) {
697 moveStatusWindow(statusWindow);
698 XMapRaised(dpy, statusWindow->w);
699 }
700 }
701
702 void paintStatusWindow(StatusWindow *statusWindow){
703 Window win = statusWindow->w;
704 GC lightgc = statusWindow->lightGC;
705 GC dimgc = statusWindow->dimGC;
706 GC bggc = statusWindow->bgGC;
707 GC fggc = statusWindow->fgGC;
708
709 int width = statusWindow->statusW;
710 int height = statusWindow->statusH;
711 int bwidth = statusWindow->bWidth;
712 int len;
713 XRectangle logical, ink;
714
715 if (NULL == statusWindow) return;
716 if ((len = st_wcslen(statusWindow->status)) == 0) {
717 return;
718 }
719 XwcTextExtents(statusWindow->fontset, statusWindow->status,
720 len, &ink, &logical);
721 width = logical.width;
722 height = logical.height;
723
724 XFillRectangle(dpy, win, bggc, 0, 0, width+2, height+2);
725
726 XDrawLine(dpy, win, fggc, 0, 0, width+2, 0);
727 XDrawLine(dpy, win, fggc, 0, height+2, width+2, height+2);
728 XDrawLine(dpy, win, fggc, 0, 0, 0, height+2);
729 XDrawLine(dpy, win, fggc, width+2, 0, width+2, height+2);
730
731 if (statusWindow->fontset) {
732 XwcDrawString(dpy, win, statusWindow->fontset, fggc,
733 -logical.x + 1, -logical.y + 1,
734 statusWindow->status,
735 st_wcslen(statusWindow->status));
736 } else {
737 /*too bad we failed to create a fontset for this locale*/
738 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
739 "[InputMethod ON]", strlen("[InputMethod ON]"));
740 }
741 }
742
743 Bool statusWindowEventHandler(XEvent event) {
744 JNIEnv *env = GetJNIEnv();
745 X11InputMethodData *pX11IMData = NULL;
746 StatusWindow *statusWindow;
747
748 if (NULL == currentX11InputMethodInstance ||
749 NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) ||
750 NULL == (statusWindow = pX11IMData->statusWindow))
751 {
752 return False;
753 }
754
755 if (statusWindow->w == event.xany.window) {
756 switch (event.type) {
757 case Expose:
758 paintStatusWindow(statusWindow);
759 if (statusWindow->peText)
760 draw_preedit(statusWindow);
761 arrange_window_stack(statusWindow);
762 break;
763 case ConfigureNotify:
764 case VisibilityNotify:
765 arrange_window_stack(statusWindow);
766 break;
767 /*
768 case UnmapNotify:
769 case VisibilityNotify:
770 break;
771 */
772 default:
773 break;
774 }
775 return True;
776 } else if ((statusWindow->parent == event.xany.window) ||
777 (statusWindow->grandParent && statusWindow->grandParent == event.xany.window)) {
778 switch (event.type) {
779 case MapNotify:
780 if (statusWindow->on) {
781 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
782 }
783 break;
784 case UnmapNotify:
785 onoffStatusWindow(pX11IMData, 0, False);
786 break;
787 case VisibilityNotify:
788 if (statusWindow->on) {
789 arrange_window_stack(statusWindow);
790 }
791 break;
792 case ConfigureNotify:
793 if (statusWindow->grandParent && statusWindow->on) {
794 moveStatusWindow(statusWindow);
795 }
796 case PropertyNotify:
797 if (statusWindow->on) {
798 arrange_window_stack(statusWindow);
799 }
800 break;
801 default:
802 break;
803 }
804 }
805 return False;
806 }
807
808 static void adjustStatusWindow(Window shell) {
809 JNIEnv *env = GetJNIEnv();
810 X11InputMethodData *pX11IMData = NULL;
811 StatusWindow *statusWindow;
812
813 if (NULL == currentX11InputMethodInstance
814 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
815 || NULL == (statusWindow = pX11IMData->statusWindow)
816 || !statusWindow->on)
817 {
818 return;
819 }
820
821 moveStatusWindow(statusWindow);
822 }
823
824 /*
825 * Creates two XICs, one for active clients and the other for passive
826 * clients. All information on those XICs are stored in the
827 * X11InputMethodData given by the pX11IMData parameter.
828 *
829 * For active clients: Try to use preedit callback to support
830 * on-the-spot. If tc is not null, the XIC to be created will
831 * share the Status Area with Motif widgets (TextComponents). If the
832 * preferable styles can't be used, fallback to root-window styles. If
833 * root-window styles failed, fallback to None styles.
834 *
835 * For passive clients: Try to use root-window styles. If failed,
836 * fallback to None styles.
837 */
838 static Bool
839 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
840 {
841 XVaNestedList preedit = NULL;
842 XVaNestedList status = NULL;
843 XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
844 in_place_styles = 0,
845 active_styles = 0,
846 passive_styles = 0,
847 no_styles = 0;
848 XIMCallback *callbacks;
849 unsigned short i;
850 XIMStyles *im_styles;
851 char *ret = NULL;
852 Bool passiveStatusWindow = False;
853 pX11IMData->statusWindow = NULL;
854
855 if (X11im == NULL) {
856 return False;
857 }
858 if (!w) {
859 return False;
860 }
861
862 if (getenv("IBMJAVA_PASSIVE") == NULL) {
863 passiveStatusWindow = False;
864 } else {
865 passiveStatusWindow = True;
866 }
867
868 if (isNativeIm()) { passiveStatusWindow = True; }
869
870 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
871
872 if (ret != NULL) {
873 jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
874 return FALSE ;
875 }
876
877 on_the_spot_styles |= XIMStatusNothing;
878
879 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
880 at the same time, so use StatusCallback to draw the status
881 ourself
882 */
883 for (i = 0; i < im_styles->count_styles; i++) {
884 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
885 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
886 break;
887 }
888 }
889
890 for (i = 0; i < im_styles->count_styles; i++) {
891 if (im_styles->supported_styles[i] == on_the_spot_styles)
892 active_styles = im_styles->supported_styles[i];
893 if (im_styles->supported_styles[i] == ROOT_WINDOW_STYLES)
894 passive_styles = im_styles->supported_styles[i];
895 if (im_styles->supported_styles[i] == IN_PLACE_STYLES) {
896 in_place_styles = im_styles->supported_styles[i];
897 }
898 if (im_styles->supported_styles[i] == NO_STYLES) {
899 no_styles = im_styles->supported_styles[i];
900 }
901 }
902
903 XFree(im_styles);
904
905 if (active_styles != on_the_spot_styles) {
906 if (passive_styles == ROOT_WINDOW_STYLES)
907 active_styles = passive_styles;
908 else {
909 if (in_place_styles == IN_PLACE_STYLES){
910 active_styles = passive_styles = IN_PLACE_STYLES;
911 } else {
912 if (no_styles == NO_STYLES)
913 active_styles = passive_styles = NO_STYLES;
914 else
915 active_styles = passive_styles = 0;
916 }
917 }
918 } else {
919 if (!passiveStatusWindow) {
920 if (passive_styles != ROOT_WINDOW_STYLES) {
921 if (no_styles == NO_STYLES)
922 active_styles = passive_styles = NO_STYLES;
923 else
924 active_styles = passive_styles = 0;
925 }
926 } else
927 passive_styles = active_styles;
928 }
929
930 if (active_styles == on_the_spot_styles) {
931 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
932 if (callbacks == (XIMCallback *)NULL)
933 return False;
934 pX11IMData->callbacks = callbacks;
935
936 for (i = 0; i < NCALLBACKS; i++, callbacks++) {
937 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
938 callbacks->callback = callback_funcs[i];
939 }
940
941 callbacks = pX11IMData->callbacks;
942 preedit = (XVaNestedList)XVaCreateNestedList(0,
943 XNPreeditStartCallback, &callbacks[PreeditStartIndex],
944 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex],
945 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex],
946 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
947 NULL);
948 if (preedit == (XVaNestedList)NULL)
949 goto err;
950 /*always try XIMStatusCallbacks for active client...*/
951 {
952 if (on_the_spot_styles & XIMStatusCallbacks) {
953 status = (XVaNestedList)XVaCreateNestedList(0,
954 XNStatusStartCallback, &callbacks[StatusStartIndex],
955 XNStatusDoneCallback, &callbacks[StatusDoneIndex],
956 XNStatusDrawCallback, &callbacks[StatusDrawIndex],
957 NULL);
958
959 if (status == NULL)
960 goto err;
961 }
962 pX11IMData->statusWindow = createStatusWindow(w);
963 pX11IMData->ic_active = XCreateIC(X11im,
964 XNClientWindow, w,
965 XNFocusWindow, w,
966 XNInputStyle, active_styles,
967 XNPreeditAttributes, preedit,
968 XNStatusAttributes, status,
969 NULL);
970 if (NULL != pX11IMData->statusWindow) {
971 pX11IMData->statusWindow->status_ready = True;
972 }
973 XFree((void *)status);
974 XFree((void *)preedit);
975 }
976 if (passiveStatusWindow) {
977 pX11IMData->ic_passive = pX11IMData->ic_active;
978 } else {
979 pX11IMData->ic_passive = XCreateIC(X11im,
980 XNClientWindow, w,
981 XNFocusWindow, w,
982 XNInputStyle, passive_styles,
983 NULL);
984 }
985 } else {
986 pX11IMData->ic_active = XCreateIC(X11im,
987 XNClientWindow, w,
988 XNFocusWindow, w,
989 XNInputStyle, active_styles,
990 NULL);
991 pX11IMData->ic_passive = pX11IMData->ic_active;
992 }
993
994 // The code set the IC mode that the preedit state is not initialied
995 // at XmbResetIC. This attribute can be set at XCreateIC. I separately
996 // set the attribute to avoid the failure of XCreateIC at some platform
997 // which does not support the attribute.
998 if (pX11IMData->ic_active != 0)
999 XSetICValues(pX11IMData->ic_active,
1000 XNResetState, XIMPreserveState, NULL);
1001 if (pX11IMData->ic_passive != 0 &&
1002 pX11IMData->ic_active != pX11IMData->ic_passive)
1003 XSetICValues(pX11IMData->ic_passive,
1004 XNResetState, XIMInitialState, NULL);
1005
1006 pX11IMData->passiveStatusWindow = passiveStatusWindow;
1007
1008 if (pX11IMData->ic_active == (XIC)0
1009 || pX11IMData->ic_passive == (XIC)0) {
1010 return False;
1011 }
1012
1013 /* Unset focus to avoid unexpected IM on */
1014 setXICFocus(pX11IMData->ic_active, False);
1015 if (pX11IMData->ic_active != pX11IMData->ic_passive)
1016 setXICFocus(pX11IMData->ic_passive, False);
1017
1018 return True;
1019
1020 err:
1021 if (preedit)
1022 XFree((void *)preedit);
1023 THROW_OUT_OF_MEMORY_ERROR();
1024 return False;
1025 }
1026
1027 static int
1028 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1029 {
1030 JNIEnv *env = GetJNIEnv();
1031 X11InputMethodData *pX11IMData;
1032
1033 pX11IMData = getX11InputMethodData(env, (jobject)client_data);
1034 if (pX11IMData == NULL || pX11IMData->statusWindow == NULL) {
1035 return 0;
1036 }
1037 resetPassivePreeditText(pX11IMData->statusWindow);
1038
1039 return -1; /* unlimited length for preedit text */
1040 }
1041
1042 static void
1043 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1044 {
1045 JNIEnv *env = GetJNIEnv();
1046 X11InputMethodData *pX11IMData;
1047
1048 pX11IMData = getX11InputMethodData(env, (jobject)client_data);
1049 if (pX11IMData == NULL) {
1050 return;
1051 }
1052
1053 if (!pX11IMData->isActiveClient) {
1054 resetPassivePreeditText(pX11IMData->statusWindow);
1055 shrink_status(pX11IMData->statusWindow);
1056 }
1057 else{
1058 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1059 "clearComposedText",
1060 "(J)V",
1061 awt_util_nowMillisUTC());
1062 if ((*env)->ExceptionOccurred(env)) {
1063 (*env)->ExceptionDescribe(env);
1064 (*env)->ExceptionClear(env);
1065 }
1066 }
1067 }
1068
1069 /*
1070 * Translate the preedit draw callback items to Java values and invoke
1071 * X11InputMethod.dispatchComposedText().
1072 *
1073 * client_data: X11InputMethod object
1074 */
1075 static void
1076 PreeditDrawCallback(XIC ic, XPointer client_data,
1077 XIMPreeditDrawCallbackStruct *pre_draw)
1078 {
1079 JNIEnv *env = GetJNIEnv();
1080 X11InputMethodData *pX11IMData = NULL;
1081 jmethodID x11imMethodID;
1082
1083 XIMText *text;
1084 jstring javastr = NULL;
1085 jintArray style = NULL;
1086
1087 /* printf("Native: PreeditDrawCallback() \n"); */
1088 if (pre_draw == NULL) {
1089 return;
1090 }
1091 AWT_LOCK();
1092 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1093 goto finally;
1094 }
1095
1096 if (!pX11IMData->isActiveClient){
1097 if (ic == pX11IMData->ic_passive) {
1098 preedit_draw_passive(pX11IMData, pre_draw);
1099 }
1100 goto finally;
1101 }
1102
1103 if ((text = pre_draw->text) != NULL) {
1104 if (is_text_available(text)) {
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 }
1124 if (text->feedback != NULL) {
1125 int cnt;
1126 jint *tmpstyle;
1127
1128 style = (*env)->NewIntArray(env, text->length);
1129 if (JNU_IsNull(env, style)) {
1130 (*env)->ExceptionClear(env);
1131 THROW_OUT_OF_MEMORY_ERROR();
1132 goto finally;
1133 }
1134
1135 if (sizeof(XIMFeedback) == sizeof(jint)) {
1136 /*
1137 * Optimization to avoid copying the array
1138 */
1139 (*env)->SetIntArrayRegion(env, style, 0,
1140 text->length, (jint *)text->feedback);
1143 if (tmpstyle == (jint *) NULL) {
1144 THROW_OUT_OF_MEMORY_ERROR();
1145 goto finally;
1146 }
1147 for (cnt = 0; cnt < (int)text->length; cnt++)
1148 tmpstyle[cnt] = text->feedback[cnt];
1149 (*env)->SetIntArrayRegion(env, style, 0,
1150 text->length, (jint *)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
1164 if ((*env)->ExceptionOccurred(env)) {
1165 (*env)->ExceptionDescribe(env);
1166 (*env)->ExceptionClear(env);
1167 }
1168
1169 finally:
1170 AWT_UNLOCK();
1171 return;
1172 }
1173
1174 static void
1175 PreeditCaretCallback(XIC ic, XPointer client_data,
1176 XIMPreeditCaretCallbackStruct *pre_caret)
1177 {
1178 XIMPreeditDrawCallbackStruct pre_draw;
1179
1180 if (pre_caret != NULL && pre_caret->direction == XIMAbsolutePosition) {
1181 pre_draw.caret = pre_caret->position;
1182 pre_draw.chg_first = 0;
1183 pre_draw.chg_length = 0;
1184 pre_draw.text = NULL;
1185 PreeditDrawCallback(ic, client_data, &pre_draw);
1186 }
1187 }
1188
1189 static void
1190 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1191 {
1192 /*ARGSUSED*/
1193 /*printf("StatusStartCallback:\n"); */
1194 }
1195
1196 static void
1197 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1198 {
1199 /*ARGSUSED*/
1200 /*printf("StatusDoneCallback:\n"); */
1201 }
1202
1203 static void StatusDrawCallback
1204 (XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *status_draw)
1205 {
1206 /*ARGSUSED*/
1207 /*printf("StatusDrawCallback:\n"); */
1208 JNIEnv *env = GetJNIEnv();
1209 X11InputMethodData *pX11IMData = NULL;
1210 StatusWindow *statusWindow;
1211 int value_make = CWX|CWWidth|CWHeight;
1212 XRectangle logical, ink;
1213 XWindowChanges xwc;
1214 int len;
1215
1216 AWT_LOCK();
1217
1218 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1219 || NULL == (statusWindow = pX11IMData->statusWindow)){
1220 goto finally;
1221 }
1222
1223 if (status_draw->type == XIMTextType) {
1224 XIMText *text = (status_draw->data).text;
1225 if (text != NULL) {
1226 if (text->string.multi_byte != NULL) {
1227 if(!strcmp(text->string.multi_byte," ")){
1228 wcscpy(statusWindow->status, L"");
1229 onoffStatusWindow(pX11IMData, 0, False);
1230 goto finally;
1231 }
1232 mbstowcs(statusWindow->status,
1233 (const char *)text->string.multi_byte,
1234 (size_t)MAX_STATUS_LEN);
1235 } else {
1236 if (0 == st_wcslen(text->string.wide_char)){
1237 wcscpy(statusWindow->status, L"");
1238 onoffStatusWindow(pX11IMData, 0, False);
1239 goto finally;
1240 }
1241 wcsncpy(statusWindow->status,
1242 text->string.wide_char,
1243 MAX_STATUS_LEN);
1244 }
1245 XwcTextExtents(statusWindow->fontset, statusWindow->status,
1246 st_wcslen(statusWindow->status), &ink, &logical);
1247 statusWindow->statusW = logical.width + BORDER_MARGIN;
1248 statusWindow->statusH = logical.height + BORDER_MARGIN;
1249 xwc.x = statusWindow->x - statusWindow->off_x;
1250 if (xwc.x < 0 ) xwc.x = 0;
1251 xwc.width = statusWindow->statusW;
1252 xwc.height = statusWindow->statusH;
1253 if (xwc.x + xwc.width > statusWindow->rootW){
1254 xwc.x = statusWindow->rootW - xwc.width;
1255 }
1256 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
1257 if (statusWindow->status_ready && statusWindow->on == True){
1258 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1259 }
1260 paintStatusWindow(statusWindow);
1261 if (statusWindow->peText)
1262 draw_preedit(statusWindow);
1263 }
1264 else {
1265 wcscpy(statusWindow->status, L"");
1266 /*just turnoff the status window
1267 paintStatusWindow(statusWindow);
1268 */
1269 onoffStatusWindow(pX11IMData, 0, False);
1270 }
1271 }
1272
1273 finally:
1274 AWT_UNLOCK();
1275 }
1276
1277 /* return the string length without trailing spaces */
1278 /* work around code for Japanese AIXIM is implemented. */
1279 static int st_wcslen(wchar_t *string)
1280 {
1281 int len = (int32_t)wcslen(string);
1282 if (len == 0)
1283 return 0;
1284 for (len--;len >= 0; len--) {
1285 if (!iswspace((wint_t) string[len])) break;
1286 }
1287 return len+1;
1288 }
1289
1290 /*
1291 * Checks whether given XIMText contains a string data.
1292 */
1293 static Bool is_text_available(XIMText * text)
1294 {
1295 if (text == NULL || text->length==0)
1296 return False;
1297 if (text->encoding_is_wchar) {
1298 if(text->string.wide_char[0] == L'\0')
1299 return False;
1300 } else {
1301 if (text->string.multi_byte[0] == '\0')
1302 return False;
1303 }
1304 return True;
1305 }
1306
1307 /*
1308 * check if preedit status is active
1309 */
1310 static Bool isPreeditStateActive(XIC ic)
1311 {
1312 XIMPreeditState state = XIMPreeditUnKnown;
1313 XVaNestedList pr_atrb;
1314 char* nosupportAttr;
1315
1316 if (ic == NULL) return False;
1317
1318 pr_atrb = XVaCreateNestedList(0,XNPreeditState,&state,NULL);
1319 nosupportAttr=XGetICValues(ic,XNPreeditAttributes,pr_atrb,NULL);
1320 XFree(pr_atrb);
1321 if (nosupportAttr==NULL && state & XIMPreeditDisable)
1322 return False;
1323 else
1324 return True;
1325 }
1326
1327 static void * buf_insert(void * src, void * insert, int size,
1328 int src_len, int ins_len, int offset)
1329 {
1330 char *temp;
1331
1332 temp = realloc(src, size*(src_len+ins_len+1));
1333 if (temp == NULL) {
1334 THROW_OUT_OF_MEMORY_ERROR();
1335 return src;
1336 }
1337 if (offset != src_len) {
1338 memmove(&temp[size*(offset+ins_len)],
1339 &((char *)temp)[size*offset],
1340 size*(src_len-offset));
1341 }
1342 memcpy(&temp[size*offset], insert, size*ins_len);
1343
1344 return (void *)temp;
1345 }
1346
1347 static void * handle_buffer(void * source, void * insert,
1348 int size,int src_len, int ins_len,
1349 int del_len, int offset)
1350 {
1351 void * temp = source;
1352
1353 if (del_len > 0) {
1354 if (del_len == ins_len) {
1355 memcpy(&((char *)source)[size*offset], insert, size*ins_len);
1356 return source;
1357 }
1358 else if (src_len > offset+del_len) {
1359 memmove(&((char *)source)[size*offset],
1360 &((char *)source)[size*(offset+del_len)],
1361 size*(src_len-offset-del_len));
1362 }
1363 }
1364 if (ins_len > 0) {
1365 temp = buf_insert(source, insert, size, src_len,
1366 ins_len, offset);
1367 }
1368 return temp;
1369 }
1370 /*
1371 * Display the given preedit text to the root window which is ownd by
1372 * myself. All of the character is converted to wide char.
1373 * this function is used for the passive client.
1374 */
1375 static void preedit_draw_passive(X11InputMethodData *pX11IMData,
1376 XIMPreeditDrawCallbackStruct *pre_draw)
1377 {
1378 XIMText *text;
1379 wchar_t *tempbuf = NULL;
1380 StatusWindow *statusWindow;
1381 wchar_t *cur_text;
1382 unsigned long *cur_attr;
1383 int cur_len = 0;
1384 int chg_len = pre_draw->chg_length;
1385 int chg_1st = pre_draw->chg_first;
1386
1387 if (NULL == (statusWindow = pX11IMData->statusWindow))
1388 return;
1389 cur_text = statusWindow->peText;
1390 cur_attr = statusWindow->peAttr;
1391 if (cur_text == NULL && pre_draw->text == NULL)
1392 return;
1393
1394 if (cur_text != NULL)
1395 cur_len = (int32_t)wcslen(cur_text);
1396 text = pre_draw->text;
1397 if (text == NULL) {
1398 /* delete only */
1399 if (cur_len > chg_1st+chg_len) {
1400 memmove(&cur_text[chg_1st],
1401 &cur_text[chg_1st+chg_len],
1402 sizeof(wchar_t)*(cur_len-chg_1st-chg_len));
1403 memmove(&cur_attr[chg_1st],
1404 &cur_attr[chg_1st+chg_len],
1405 sizeof(long)*(cur_len-chg_1st-chg_len));
1406 }
1407 if ((pre_draw->chg_length <= cur_len ) && (pre_draw->chg_length >0))
1408 cur_text[cur_len-pre_draw->chg_length] =L'\0';
1409 } else {
1410 /* insert or replace */
1411 int ins_len = 0;
1412 void * ins_text = NULL;
1413
1414 /* if invalid offset is specified, do nothing. */
1415 /* this fix is for aixim for eucTW */
1416 if (cur_len < chg_1st)
1417 return;
1418 if(is_text_available(text)) {
1419 /* insert or replace the text */
1420 if (text->encoding_is_wchar == False) {
1421 /* convert the text to wide chars.
1422 allocate enough size buffer
1423 */
1424 tempbuf = (wchar_t *)malloc(sizeof(wchar_t)*(text->length+1));
1425 if (tempbuf == NULL) {
1426 THROW_OUT_OF_MEMORY_ERROR();
1427 return;
1428 }
1429 ins_len = (int32_t)mbstowcs(tempbuf, text->string.multi_byte,
1430 text->length);
1431 if (ins_len == -1) {
1432 free(tempbuf);
1433 return;
1434 }
1435 ins_text = (void *)tempbuf;
1436 }
1437 else {
1438 ins_len = text->length;
1439 ins_text = text->string.wide_char;
1440 }
1441 /* finish prepare the data to be inserted */
1442
1443 statusWindow->peText =
1444 handle_buffer(cur_text, ins_text, sizeof(wchar_t),
1445 cur_len, ins_len, chg_len, chg_1st);
1446 statusWindow->peAttr =
1447 handle_buffer(cur_attr, text->feedback, sizeof(long),
1448 cur_len, ins_len, chg_len, chg_1st);
1449 statusWindow->peText[cur_len-chg_len+ins_len] =L'\0';
1450
1451 if (tempbuf != NULL)
1452 free(tempbuf);
1453 } /* endof insert or replace text */
1454 else {
1455 /* change attribute only */
1456 memcpy(&cur_attr[chg_1st], text->feedback,
1457 sizeof(long)*text->length);
1458 }
1459 }
1460 statusWindow->peCaret= pre_draw->caret;
1461 draw_preedit(statusWindow);
1462 if (statusWindow->on && wcslen(statusWindow->peText) > 0)
1463 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1464 else if (wcslen(statusWindow->status) == 0)
1465 onoffStatusWindow(pX11IMData, 0, False);
1466 }
1467
1468 /*
1469 * reset predit test of passive mode
1470 */
1471 static void
1472 resetPassivePreeditText(StatusWindow *statusWindow)
1473 {
1474 if (NULL == statusWindow) return;
1475 if(statusWindow->peText != NULL) {
1476 free(statusWindow->peText);
1477 statusWindow->peText = NULL;
1478 }
1479 if(statusWindow->peAttr != NULL) {
1480 free(statusWindow->peAttr);
1481 statusWindow->peAttr = NULL;
1482 }
1483 statusWindow->peCaret= 0;
1484 }
1485
1486 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos)
1487 {
1488 if (NULL == statusWindow) return;
1489 XSetFunction(dpy, gc, GXinvert);
1490 XDrawLine(dpy, statusWindow->w,
1491 gc, pos, STATUS_BORDER/2,
1492 pos, STATUS_BORDER/2+statusWindow->fOff);
1493 XSetFunction(dpy, gc, GXcopy);
1494 }
1495
1496 static int get_next_attr(int len, unsigned long *attr)
1497 {
1498 int count;
1499
1500 for (count = 1; count < len; count++) {
1501 if ((attr[count-1] & PREEDIT_ATTR_MASK)
1502 != (attr[count] & PREEDIT_ATTR_MASK))
1503 break;
1504 }
1505 return count;
1506 }
1507
1508 static void draw_preedit(StatusWindow *statusWindow)
1509 {
1510 unsigned long *attr;
1511 int x_pos,x_caret;
1512 unsigned int len;
1513 int len_disp, pos;
1514 wchar_t *str;
1515 GC gc;
1516 XRectangle ink, rect, rect_c;
1517 Bool caret_done = False;
1518
1519 if (NULL == statusWindow) return;
1520 align_status(statusWindow);
1521 XFillRectangle(dpy, statusWindow->w,
1522 statusWindow->bgGC,
1523 statusWindow->statusW,0,
1524 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,
1525 statusWindow->fBot+2);
1526
1527
1528 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
1529 statusWindow->statusW, 0,
1530 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0);
1531 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
1532 statusWindow->statusW, statusWindow->fBot+2,
1533 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,
1534 statusWindow->fBot+2);
1535 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
1536 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0,
1537 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,
1538 statusWindow->fBot+2);
1539 if (0 == statusWindow->statusW)
1540 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
1541 0, 0, 0, statusWindow->fBot+2);
1542
1543 str = statusWindow->peText;
1544
1545 if (str != NULL && (len = (int32_t)wcslen(str)) != 0) {
1546 pos = 0;
1547 attr = statusWindow->peAttr;
1548 x_pos = x_caret = statusWindow->statusW + STATUS_BORDER;
1549 while((int)len-1 >= pos) {
1550 len_disp = get_next_attr(len - pos, &attr[pos]);
1551 if (attr[pos] & XIMReverse) {
1552 gc = statusWindow->bgGC;
1553 }
1554 else {
1555 gc = statusWindow->fgGC;
1556 }
1557 XwcTextExtents(statusWindow->fontset,
1558 &str[pos],
1559 len_disp, &ink, &rect);
1560 XwcDrawImageString(dpy, statusWindow->w,
1561 statusWindow->fontset, gc,
1562 x_pos, statusWindow->fOff+1, &str[pos], len_disp);
1563 if (attr[pos] & XIMUnderline) {
1564 XDrawLine(dpy, statusWindow->w,
1565 gc, x_pos, statusWindow->fBot,
1566 x_pos+rect.width, statusWindow->fBot);
1567 }
1568 if (!caret_done) {
1569 if( statusWindow->peCaret >= pos &&
1570 statusWindow->peCaret <= pos+len_disp) {
1571 if (statusWindow->peCaret == 0)
1572 x_caret = x_pos;
1573 else if (statusWindow->peCaret == pos+len_disp)
1574 x_caret = x_pos+rect.width;
1575 else {
1576 XwcTextExtents(statusWindow->fontset,
1577 &str[pos],
1578 statusWindow->peCaret-pos,
1579 &ink, &rect_c);
1580 x_caret = x_pos+ rect_c.width;
1581 }
1582 x_caret-=CARET_OFFSET;
1583 caret_done = True;
1584 }
1585 }
1586 pos += len_disp;
1587 x_pos += rect.width;
1588 }
1589 if (caret_done)
1590 draw_caret(statusWindow, statusWindow->fgGC, x_caret);
1591 }
1592 }
1593
1594 /* calc required status window size and resize the window */
1595 static void align_status(StatusWindow *statusWindow)
1596 {
1597 int len_st, len_pe = 0;
1598 XRectangle rect_st, rect_pe, ink;
1599 Dimension cur_w;
1600 int value_make = CWX|CWWidth|CWHeight;
1601 XWindowChanges xwc;
1602
1603 if (NULL == statusWindow) return;
1604 if ((len_st = st_wcslen(statusWindow->status)) == 0
1605 && (statusWindow->peText == NULL || st_wcslen(statusWindow->peText) == 0 ))
1606 return;
1607
1608 rect_pe.x = rect_pe.y = rect_pe.width = rect_pe.height = 0;
1609
1610 XwcTextExtents(statusWindow->fontset,
1611 statusWindow->status,
1612 len_st, &ink, &rect_st);
1613 if (statusWindow->peText != NULL
1614 && (len_pe = (int32_t)wcslen(statusWindow->peText)) > 0) {
1615 XwcTextExtents(statusWindow->fontset,
1616 statusWindow->peText,
1617 len_pe, &ink, &rect_pe);
1618 }
1619 statusWindow->fOff = max(-rect_st.y, -rect_pe.y);
1620 statusWindow->fBot = max(rect_st.height, rect_pe.height);
1621 statusWindow->statusW =rect_st.width;
1622 if (rect_st.width > 0) statusWindow->statusW += BORDER_MARGIN;
1623 statusWindow->peTextW = rect_pe.width;
1624
1625 xwc.x = statusWindow->x - statusWindow->off_x;
1626 if (xwc.x < 0 ) xwc.x = 0;
1627
1628 if (len_pe > 0) {
1629 xwc.width = statusWindow->statusW
1630 + statusWindow->peTextW + BORDER_MARGIN + 1;
1631 xwc.height = statusWindow->fBot + BORDER_MARGIN;
1632 } else {
1633 xwc.width = statusWindow->statusW;
1634 xwc.height = statusWindow->fBot + BORDER_MARGIN;
1635 }
1636 if (xwc.x + xwc.width > statusWindow->rootW){
1637 xwc.x = statusWindow->rootW - xwc.width;
1638 }
1639 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
1640 }
1641
1642 static void shrink_status(StatusWindow *statusWindow)
1643 {
1644 int value_make = CWX|CWWidth|CWHeight;
1645 XWindowChanges xwc;
1646
1647 if (NULL == statusWindow) return;
1648 xwc.width = statusWindow->statusW;
1649 xwc.height = statusWindow->statusH;
1650 statusWindow->peTextW = 0;
1651 xwc.x = statusWindow->x - statusWindow->off_x;
1652 if (xwc.x < 0 ) xwc.x = 0;
1653 if (xwc.x + xwc.width > statusWindow->rootW){
1654 xwc.x = statusWindow->rootW - xwc.width;
1655 }
1656 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
1657 }
1658
1659 static GC create_gc(Window win, Bool isReverse)
1660 {
1661 XGCValues xgcv;
1662 unsigned long mask;
1663 AwtScreenDataPtr defaultScreen;
1664
1665 defaultScreen = getScreenData(DefaultScreen(dpy));
1666
1667 mask = (GCForeground | GCBackground );
1668 if (isReverse) {
1669 xgcv.foreground = defaultScreen->whitepixel;
1670 xgcv.background = defaultScreen->blackpixel;
1671 } else {
1672 xgcv.foreground = defaultScreen->blackpixel;
1673 xgcv.background = defaultScreen->whitepixel;
1674 }
1675 return XCreateGC(dpy, win, mask, &xgcv);
1676 }
1677
1678 static Bool isNativeIm()
1679 {
1680 #define XIMMODIFIER "@im="
1681 #define XIM_SERVER_CATEGORY "@server="
1682 char *immodifiers;
1683 char *imserver, *imserverPtr;
1684 Atom imserverAtom;
1685
1686 if (!(immodifiers = getenv("XMODIFIERS"))) return True;
1687 if (!(imserver = calloc(1,strlen(immodifiers)+strlen(XIM_SERVER_CATEGORY)+1))) return True;
1688 if (!(immodifiers = strstr(immodifiers,XIMMODIFIER))) return True;
1689 immodifiers += strlen(XIMMODIFIER);
1690 strcpy(imserver,XIM_SERVER_CATEGORY);
1691 imserverPtr = imserver + strlen(imserver);
1692 while(*immodifiers != '@' && *immodifiers != '\0') {
1693 *imserverPtr = *immodifiers;
1694 imserverPtr++;
1695 immodifiers++;
1696 }
1697 imserverAtom = XInternAtom(awt_display, imserver, True);
1698 free(imserver);
1699 if (imserverAtom > 0)
1700 return False;
1701 else
1702 return True;
1703 }
1704
1705 static Window getGrandParent(Window parent)
1706 {
1707 Window containerWindow,rootWindow,tmp;
1708 Window *ignoreWindowPtr;
1709 unsigned int ignoreUnit;
1710 Window grandParent=0;
1711 XWindowAttributes xwa;
1712 Atom WM_STATE;
1713 Atom type = None;
1714 int32_t format;
1715 unsigned long nitems, after;
1716 unsigned char * data;
1717
1718 if (parent == 0) return grandParent;
1719 WM_STATE = XInternAtom(dpy, "WM_STATE", True);
1720 if (WM_STATE == None) return grandParent;
1721
1722 tmp=parent;
1723 while(XQueryTree(dpy, tmp,
1724 &rootWindow, &containerWindow,
1725 &ignoreWindowPtr, &ignoreUnit)){
1726 XFree(ignoreWindowPtr);
1727 if (containerWindow == rootWindow) break;
1728 if (XGetWindowProperty(dpy, containerWindow, WM_STATE,
1729 0, 0, False, AnyPropertyType,
1730 &type, &format, &nitems, &after, &data) == Success) {
1731 XFree(data);
1732 if (type) {
1733 XGetWindowAttributes(dpy, containerWindow, &xwa);
1734 if (FALSE == xwa.override_redirect){
1735 grandParent=containerWindow;
1736 }
1737 }
1738 }
1739 tmp=containerWindow;
1740 }
1741 return grandParent;
1742 }
1743
1744 static void moveStatusWindow(StatusWindow *statusWindow)
1745 {
1746 XWindowAttributes xwa;
1747 Window child;
1748 int x, y, width;
1749 Window target;
1750
1751 if (NULL == statusWindow) return;
1752 if (statusWindow->grandParent) {
1753 target = statusWindow->grandParent;
1754 } else {
1755 target = statusWindow->parent;
1756 }
1757 XGetWindowAttributes(dpy, target, &xwa);
1758 XTranslateCoordinates(dpy,
1759 target, xwa.root,
1760 0, 0,
1761 &x, &y,
1762 &child);
1763 if (statusWindow->x != x
1764 || statusWindow->y != y
1765 || statusWindow->width != xwa.width
1766 || statusWindow->height != xwa.height){
1767 statusWindow->x = x;
1768 statusWindow->y = y;
1769 statusWindow->height = xwa.height;
1770 statusWindow->width = xwa.width;
1771 x = statusWindow->x - statusWindow->off_x;
1772 y = statusWindow->y + statusWindow->height + statusWindow->off_y;
1773 if (x < 0 ){
1774 x = 0;
1775 }
1776 if (statusWindow->peTextW > 0) {
1777 width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1;
1778 if (x + width > statusWindow->rootW){
1779 x = statusWindow->rootW - width;
1780 }
1781 } else {
1782 if (x + statusWindow->statusW > statusWindow->rootW){
1783 x = statusWindow->rootW - statusWindow->statusW;
1784 }
1785 }
1786 if (y + statusWindow->statusH > statusWindow->rootH){
1787 y = statusWindow->rootH - statusWindow->statusH;
1788 }
1789 XMoveWindow(dpy, statusWindow->w, x, y);
1790 }
1791 }
1792
1793 static void arrange_window_stack(StatusWindow* statusWindow)
1794 {
1795 XWindowChanges xwc;
1796 int value_make = CWSibling|CWStackMode;
1797 Window root, parent, *children;
1798 unsigned int nchildren;
1799
1800 if (NULL == statusWindow) return;
1801 if (XQueryTree(dpy, statusWindow->parent,
1802 &root, &parent, &children, &nchildren)){
1803 XFree(children);
1804 xwc.sibling = parent;
1805 while(XQueryTree(dpy, xwc.sibling, &root, &parent, &children, &nchildren)) {
1806 XFree(children);
1807 if (root != parent) {
1808 xwc.sibling = parent;
1809 } else {
1810 break;
1811 }
1812 }
1813 xwc.stack_mode = Above;
1814 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
1815 }
1816 }
1817
1818 static int count_missing_fonts(char **charset_list, int charset_count)
1819 {
1820 int i,j;
1821 if (charset_count > 0) {
1822 j=charset_count;
1823 for(i=0; i < charset_count; i++) {
1824 if ((strstr(charset_list[i], "IBM-udc")) ||
1825 (strstr(charset_list[i], "IBM-sbd")) ||
1826 (strstr(charset_list[i], "IBM-ucdTW")))
1827 j--;
1828 }
1829 return j;
1830 }
1831 else
1832 return 0;
1833 }
1834
1835 static XFontSet create_fontset_name(char * font_name, Bool force)
1836 {
1837 XFontSet fontset = NULL;
1838 char **charset_list;
1839 int charset_count;
1840 char *def_string;
1841 int missing_fonts;
1842
1843 fontset = XCreateFontSet(dpy, font_name,
1844 &charset_list, &charset_count, &def_string);
1845 if (charset_count > 0) {
1846 missing_fonts = count_missing_fonts(charset_list,
1847 charset_count);
1848 XFreeStringList(charset_list);
1849 if (fontset && (missing_fonts > 0)) {
1850 if (!force) {
1851 XFreeFontSet(dpy, fontset);
1852 fontset = NULL;
1853 }
1854 }
1855 }
1856 return fontset;
1857 }
1858
1859 static XFontSet create_fontset()
1860 {
1861 XFontSet fontset = NULL;
1862 int i;
1863 static char * fontlist[] = {
1864 "-dt-interface user-medium-r-normal-S*-*-*-*-*-*-*-*-*",
1865 "-*-*-medium-r-normal-*-14-*-*-*-c-*-*-*",
1866 "-*-*-medium-r-normal-*-14-*-*-*-m-*-*-*",
1867 "-*-*-medium-r-normal--14-0-0-0-m-*-*-*",
1868 "-monotype-sansmonowt-medium-r-normal--14-*-*-*-m-*-*-*",
1869 "-*--14-*",
1870 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*",
1871 "-*--16-*",
1872 "-*--17-*",
1873 "-*--18-*",
1874 "-*--19-*",
1875 "-*--20-*",
1876 "-*--24-*",
1877 NULL};
1878
1879 for (i=0; fontlist[i] != NULL && fontset==NULL; i++)
1880 fontset = create_fontset_name(fontlist[i], False);
1881
1882 if (!fontset)
1883 fprintf(stdout, "Cannot load fonts for IMF.\n");
1884 return fontset;
1885 }
1886
1887 static Window get_current_focus(XIC ic) {
1888 Window w = 0;
1889 if (ic != NULL)
1890 XGetICValues(ic, XNFocusWindow, &w, NULL);
1891 return w;
1892 }
1893
1894 JNIEXPORT jboolean JNICALL
1895 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1896 jobject this,
1897 jlong display)
1898 {
1899 Bool registered;
1900
1901 AWT_LOCK();
1902
1903 dpy = (Display *)jlong_to_ptr(display);
1904
1905 if (X11im == NULL) {
1906 X11im = XOpenIM(dpy, NULL, NULL, NULL);
1907 }
1908
1909 AWT_UNLOCK();
1910
1911 return JNI_TRUE;
1912 }
1913
1914 JNIEXPORT jboolean JNICALL
1915 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1916 jobject this,
1917 jlong window)
1918 {
1919 X11InputMethodData *pX11IMData;
1920 jobject globalRef;
1921 XIC ic;
1922
1923 AWT_LOCK();
1924
1925 if (!window) {
1926 JNU_ThrowNullPointerException(env, "NullPointerException");
1927 AWT_UNLOCK();
1928 return JNI_FALSE;
1929 }
1930
1931 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1932 if (pX11IMData == NULL) {
1933 THROW_OUT_OF_MEMORY_ERROR();
1934 AWT_UNLOCK();
1935 return JNI_FALSE;
1936 }
1937
1938 globalRef = (*env)->NewGlobalRef(env, this);
1939 pX11IMData->x11inputmethod = globalRef;
1940 pX11IMData->statusWindow = NULL;
1941
1942 setX11InputMethodData(env, this, pX11IMData);
1943
1944 if (createXIC(env, pX11IMData, (Window)window) == False) {
1945 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1946 pX11IMData = (X11InputMethodData *) NULL;
1947 setX11InputMethodData(env, this, pX11IMData);
1948 if ((*env)->ExceptionCheck(env)) {
1949 goto finally;
1950 }
1951 }
1952
1953 finally:
1954 AWT_UNLOCK();
1955 return (pX11IMData != NULL);
1956 }
1957
1958 JNIEXPORT void JNICALL
1959 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1960 jobject this,
1961 jlong w,
1962 jboolean req,
1963 jboolean active)
1964 {
1965 X11InputMethodData *pX11IMData;
1966 AWT_LOCK();
1967 pX11IMData = getX11InputMethodData(env, this);
1968 if (pX11IMData == NULL) {
1969 AWT_UNLOCK();
1970 return;
1971 }
1972
1973 if (req) {
1974 if (!w) {
1975 AWT_UNLOCK();
1976 return;
1977 }
1978 pX11IMData->isActiveClient = active;
1979 pX11IMData->current_ic = active ?
1980 pX11IMData->ic_active : pX11IMData->ic_passive;
1981 /*
1982 * On Solaris2.6, setXICWindowFocus() has to be invoked
1983 * before setting focus.
1984 */
1985 get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */
1986 if (currentFocusWindow != w) {
1987 setXICWindowFocus(pX11IMData->current_ic, w);
1988 setXICFocus(pX11IMData->current_ic, req);
1989 currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1990 currentFocusWindow = w;
1991 } else {
1992 setXICFocus(pX11IMData->current_ic, req);
1993 }
1994 if ((active || pX11IMData->passiveStatusWindow)
1995 && (pX11IMData->statusWindow && pX11IMData->statusWindow->on))
1996 onoffStatusWindow(pX11IMData, w, True);
1997 } else {
1998 currentX11InputMethodInstance = NULL;
1999 currentFocusWindow = 0;
2000 onoffStatusWindow(pX11IMData, 0, False);
2001 if (pX11IMData->current_ic != NULL)
2002 setXICFocus(pX11IMData->current_ic, req);
2003
2004 pX11IMData->current_ic = (XIC)0;
2005 }
2006
2007 XFlush(dpy);
2008 AWT_UNLOCK();
2009 }
2010
2011 /*
2012 * Class: sun_awt_X11InputMethodBase
2013 * Method: initIDs
2014 * Signature: ()V
2015 * This function gets called from the static initializer for
2016 * X11InputMethod.java to initialize the fieldIDs for fields
2017 * that may be accessed from C
2018 */
2019 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_initIDs
2020 (JNIEnv *env, jclass cls)
2021 {
2022 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
2023 }
2024
2025 /*
2026 * Class: sun_awt_X11InputMethodBase
2027 * Method: turnoffStatusWindow
2028 * Signature: ()V
2029 */
2030 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow
2031 (JNIEnv *env, jobject this)
2032 {
2033 X11InputMethodData *pX11IMData;
2034 StatusWindow *statusWindow;
2035
2036 AWT_LOCK();
2037
2038 if (NULL == currentX11InputMethodInstance
2039 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
2040 || NULL == (statusWindow = pX11IMData->statusWindow)
2041 || !statusWindow->on ){
2042 AWT_UNLOCK();
2043 return;
2044 }
2045 onoffStatusWindow(pX11IMData, 0, False);
2046 statusWindow->on = False;
2047
2048 AWT_UNLOCK();
2049 }
2050
2051 /*
2052 * Class: sun_awt_X11InputMethodBase
2053 * Method: disposeXIC
2054 * Signature: ()V
2055 */
2056 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_disposeXIC
2057 (JNIEnv *env, jobject this)
2058 {
2059 X11InputMethodData *pX11IMData = NULL;
2060
2061 AWT_LOCK();
2062 pX11IMData = getX11InputMethodData(env, this);
2063 if (pX11IMData == NULL) {
2064 AWT_UNLOCK();
2065 return;
2066 }
2067
2068 setX11InputMethodData(env, this, NULL);
2069
2070 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
2071 currentX11InputMethodInstance = NULL;
2072 currentFocusWindow = 0;
2073 }
2074 destroyX11InputMethodData(env, pX11IMData);
2075 AWT_UNLOCK();
2076 }
2077
2078 /*
2079 * Class: sun_awt_X11InputMethodBase
2080 * Method: resetXIC
2081 * Signature: ()Ljava/lang/String;
2082 */
2083 JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_resetXIC
2084 (JNIEnv *env, jobject this)
2085 {
2086 X11InputMethodData *pX11IMData;
2087 char *xText = NULL;
2088 jstring jText = (jstring)0;
2089
2090 AWT_LOCK();
2091 pX11IMData = getX11InputMethodData(env, this);
2092 if (pX11IMData == NULL) {
2093 AWT_UNLOCK();
2094 return jText;
2095 }
2096
2097 if (pX11IMData->current_ic) {
2098 if (!isPreeditStateActive(pX11IMData->current_ic)) {
2099 xText = NULL;
2100 } else {
2101 if (!(pX11IMData->forceReset))
2102 setXICFocus(pX11IMData->current_ic, FALSE);
2103 xText = XmbResetIC(pX11IMData->current_ic);
2104 if (!(pX11IMData->forceReset))
2105 setXICFocus(pX11IMData->current_ic, TRUE);
2106 }
2107 } else {
2108 /*
2109 * If there is no reference to the current XIC, try to reset both XICs.
2110 */
2111 if (!isPreeditStateActive(pX11IMData->ic_active))
2112 xText = NULL;
2113 else
2114 xText = XmbResetIC(pX11IMData->ic_active);
2115 /*it may also means that the real client component does
2116 not have focus -- has been deactivated... its xic should
2117 not have the focus, bug#4284651 showes reset XIC for htt
2118 may bring the focus back, so de-focus it again.
2119 */
2120 setXICFocus(pX11IMData->ic_active, FALSE);
2121 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
2122 char *tmpText;
2123 if (!isPreeditStateActive(pX11IMData->ic_passive))
2124 tmpText = NULL;
2125 else
2126 tmpText = XmbResetIC(pX11IMData->ic_passive);
2127 setXICFocus(pX11IMData->ic_passive, FALSE);
2128 if (xText == (char *)NULL && tmpText)
2129 xText = tmpText;
2130 }
2131 }
2132 if (xText != NULL) {
2133 jText = JNU_NewStringPlatform(env, (const char *)xText);
2134 XFree((void *)xText);
2135 }
2136
2137 /* workaround
2138 * Some IME do not call PreeditDoneCallback routine even
2139 * when XmbResetIC is called. I force to reset the preedit string.
2140 */
2141 if (!pX11IMData->isActiveClient) {
2142 resetPassivePreeditText(pX11IMData->statusWindow);
2143 shrink_status(pX11IMData->statusWindow);
2144 } else {
2145 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
2146 "clearComposedText",
2147 "()V");
2148 if ((*env)->ExceptionOccurred(env)) {
2149 (*env)->ExceptionDescribe(env);
2150 (*env)->ExceptionClear(env);
2151 }
2152 }
2153
2154 AWT_UNLOCK();
2155 return jText;
2156 }
2157
2158 /*
2159 * Class: sun_awt_X11InputMethodBase
2160 * Method: setCompositionEnabledNative
2161 * Signature: (Z)Z
2162 *
2163 * This method tries to set the XNPreeditState attribute associated with the current
2164 * XIC to the passed in 'enable' state.
2165 *
2166 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
2167 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
2168 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
2169 * method fails due to other reasons.
2170 */
2171 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_setCompositionEnabledNative
2172 (JNIEnv *env, jobject this, jboolean enable)
2173 {
2174 X11InputMethodData *pX11IMData;
2175 char * ret = NULL;
2176 XVaNestedList pr_atrb;
2177
2178 AWT_LOCK();
2179 pX11IMData = getX11InputMethodData(env, this);
2180
2181 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
2182 AWT_UNLOCK();
2183 return JNI_FALSE;
2184 }
2185
2186 pr_atrb = XVaCreateNestedList(0, XNPreeditState,
2187 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
2188 ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);
2189 XFree((void *)pr_atrb);
2190 AWT_UNLOCK();
2191
2192 if ((ret != 0) &&
2193 ((strcmp(ret, XNPreeditAttributes) == 0)
2194 || (strcmp(ret, XNPreeditState) == 0))) {
2195 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
2196 }
2197
2198 return (jboolean)(ret == 0);
2199 }
2200
2201 /*
2202 * Class: sun_awt_X11InputMethodBase
2203 * Method: isCompositionEnabledNative
2204 * Signature: ()Z
2205 *
2206 * This method tries to get the XNPreeditState attribute associated with the current XIC.
2207 *
2208 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
2209 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
2210 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
2211 */
2212 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_isCompositionEnabledNative
2213 (JNIEnv *env, jobject this)
2214 {
2215 X11InputMethodData *pX11IMData = NULL;
2216 char * ret = NULL;
2217 XIMPreeditState state = XIMPreeditUnKnown;
2218 XVaNestedList pr_atrb;
2219
2220 AWT_LOCK();
2221 pX11IMData = getX11InputMethodData(env, this);
2222
2223 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
2224 AWT_UNLOCK();
2225 return JNI_FALSE;
2226 }
2227
2228 pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL);
2229 ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);
2230 XFree((void *)pr_atrb);
2231 AWT_UNLOCK();
2232
2233 if ((ret != 0) &&
2234 ((strcmp(ret, XNPreeditAttributes) == 0)
2235 || (strcmp(ret, XNPreeditState) == 0))) {
2236 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
2237 return JNI_FALSE;
2238 }
2239
2240 return (jboolean)(state == XIMPreeditEnable);
2241 }
2242
2243 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
2244 (JNIEnv *env, jobject this, jlong window)
2245 {
2246
2247 }
2248
2249 /*
2250 * Class: sun_awt_X11InputMethod
2251 * Method: setStatusAreaVisible
2252 * Signature: (ZJ)V
2253 */
2254 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_setStatusAreaVisible
2255 (JNIEnv *env, jobject this, jboolean value, jlong data)
2256 {
2257 X11InputMethodData *pX11IMData;
2258
2259 pX11IMData = getX11InputMethodData(env, this);
2260 if (NULL == pX11IMData) return;
2261 if (NULL == pX11IMData->statusWindow) return;
2262
2263 if ((int)value){
2264 pX11IMData->statusWindow->on = True;
2265 }else{
2266 pX11IMData->statusWindow->on = False;
2267 }
2268 return;
2269 }
|