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 *
207 wcstombsdmp(wchar_t *wcs, int len)
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 }
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 */
333 setX11InputMethodData(env, imInstance, NULL);
334 freeX11InputMethodData(env, pX11IMData);
335 pX11IMData = NULL;
336 }
337
338 return pX11IMData;
339 }
340
341 static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) {
342 JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData);
343 }
344
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
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);
1157 } else {
1158 tmpstyle = (jint *)malloc(sizeof(jint)*(text->length));
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
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
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 }
|
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 #if defined(AIX)
37 #include <X11/Intrinsic.h>
38
39 #include <wchar.h>
40 #include <wctype.h>
41 #include <langinfo.h>
42 #endif
43
44 #include "awt.h"
45 #include "awt_p.h"
46
47 #include <sun_awt_X11InputMethod.h>
48 #include <sun_awt_X11_XInputMethod.h>
49
50 #define THROW_OUT_OF_MEMORY_ERROR() \
51 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)
52
53 #if !defined(AIX)
54 #define RESUME_ENABLE 1
55 #endif
56
57 struct X11InputMethodIDs {
58 jfieldID pData;
59 } x11InputMethodIDs;
60
61 #if !defined(AIX)
62 static void PreeditStartCallback(XIC, XPointer, XPointer);
63 #else
64 static int PreeditStartCallback(XIC, XPointer, XPointer);
65 #endif
66 static void PreeditDoneCallback(XIC, XPointer, XPointer);
67 static void PreeditDrawCallback(XIC, XPointer,
68 XIMPreeditDrawCallbackStruct *);
69 static void PreeditCaretCallback(XIC, XPointer,
70 XIMPreeditCaretCallbackStruct *);
71 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
72 static void StatusStartCallback(XIC, XPointer, XPointer);
73 static void StatusDoneCallback(XIC, XPointer, XPointer);
74 static void StatusDrawCallback(XIC, XPointer,
75 XIMStatusDrawCallbackStruct *);
76 #endif
77
78 #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing)
79 #define NO_STYLES (XIMPreeditNone | XIMStatusNone)
80 #if defined(AIX)
81 /* added style to allow for in-place composition, such as "dead" keys for accents */
82 #define IN_PLACE_STYLES (XIMPreeditNothing | XIMStatusNone)
83 #endif
84
85 #define PreeditStartIndex 0
86 #define PreeditDoneIndex 1
87 #define PreeditDrawIndex 2
88 #define PreeditCaretIndex 3
89 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
90 #define StatusStartIndex 4
91 #define StatusDoneIndex 5
92 #define StatusDrawIndex 6
93 #define NCALLBACKS 7
94 #else
95 #define NCALLBACKS 4
96 #endif
97
98 #if defined(AIX)
99 #define STATUS_BORDER 2 /* Status Border width */
100 #define CARET_OFFSET 1 /* Offset of caret position (pixel) */
101 #define BORDER_MARGIN 3 /* BORDER MARGIN width */
102 #define STATUS_MARGIN 7 /* Margin between the status window and its parent window */
103 #define PREEDIT_ATTR_MASK (XIMReverse|XIMUnderline)
104 /* Preedit attribute which host adapter can handle */
105 #endif
106
107 /*
108 * Callback function pointers: the order has to match the *Index
109 * values above.
110 */
111 static XIMProc callback_funcs[NCALLBACKS] = {
112 (XIMProc)PreeditStartCallback,
113 (XIMProc)PreeditDoneCallback,
114 (XIMProc)PreeditDrawCallback,
115 (XIMProc)PreeditCaretCallback,
116 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
117 (XIMProc)StatusStartCallback,
118 (XIMProc)StatusDoneCallback,
119 (XIMProc)StatusDrawCallback,
120 #endif
121 };
122
123 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
124 #define MAX_STATUS_LEN 100
125 typedef struct {
126 Window w; /*status window id */
127 Window root; /*the root window id */
128 Window parent; /*parent shell window */
129 #if defined(AIX)
130 Window grandParent; /*window has WM frame */
131 #endif
132 int x, y; /*parent's upperleft position */
133 int width, height; /*parent's width, height */
134 GC lightGC; /*gc for light border */
135 GC dimGC; /*gc for dim border */
136 GC bgGC; /*normal painting */
137 GC fgGC; /*normal painting */
138 int statusW, statusH; /*status window's w, h */
139 int rootW, rootH; /*root window's w, h */
140 int bWidth; /*border width */
141 #if !defined(AIX)
142 char status[MAX_STATUS_LEN]; /*status text */
143 #else
144 wchar_t status[MAX_STATUS_LEN+1]; /*status text */
145 #endif
146 XFontSet fontset; /*fontset for drawing */
147 int off_x, off_y;
148 Bool on; /*if the status window on*/
149 #if defined(AIX)
150 int fOff; /* font base line(in pixel) from top */
151 int fBot; /* font bottom line(in pixel) from top */
152 int peTextW; /* Composition text width in pixel */
153 wchar_t* peText; /* Composed string (wide char.) */
154 XIMFeedback* peAttr; /* Composed text attribute */
155 int peCaret; /* Caret position in number of character */
156 Bool status_ready; /* Not draw Status at XCreateIC */
157 #endif
158 } StatusWindow;
159 #endif
160
161 /*
162 * X11InputMethodData keeps per X11InputMethod instance information. A pointer
163 * to this data structure is kept in an X11InputMethod object (pData).
164 */
165 typedef struct _X11InputMethodData {
166 XIC current_ic; /* current X Input Context */
167 XIC ic_active; /* X Input Context for active clients */
168 XIC ic_passive; /* X Input Context for passive clients */
169 XIMCallback *callbacks; /* callback parameters */
170 jobject x11inputmethod; /* global ref to X11InputMethod instance */
171 /* associated with the XIC */
172 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
173 StatusWindow *statusWindow; /* our own status window */
174 #endif
175 #if !defined(AIX)
176 char *lookup_buf; /* buffer used for XmbLookupString */
177 int lookup_buf_len; /* lookup buffer size in bytes */
178 #else
179 Bool passiveStatusWindow;/* Passive Client uses StatusWindow */
180 Bool isActiveClient; /* True:clinet is active */
181 Bool forceReset; /* True: call resetXIC before UnsetICFocus */
182 #endif
183 } X11InputMethodData;
184
185 #if defined(RESUME_ENABLE)
186 /*
187 * When XIC is created, a global reference is created for
188 * sun.awt.X11InputMethod object so that it could be used by the XIM callback
189 * functions. This could be a dangerous thing to do when the original
190 * X11InputMethod object is garbage collected and as a result,
191 * destroyX11InputMethodData is called to delete the global reference.
192 * If any XIM callback function still holds and uses the "already deleted"
193 * global reference, disaster is going to happen. So we have to maintain
194 * a list for these global references which is consulted first when the
195 * callback functions or any function tries to use "currentX11InputMethodObject"
196 * which always refers to the global reference try to use it.
197 *
198 */
199 typedef struct _X11InputMethodGRefNode {
200 jobject inputMethodGRef;
201 struct _X11InputMethodGRefNode* next;
202 } X11InputMethodGRefNode;
203
204 X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL;
205 #endif
206
207 /* reference to the current X11InputMethod instance, it is always
208 point to the global reference to the X11InputMethodObject since
209 it could be referenced by different threads. */
210 jobject currentX11InputMethodInstance = NULL;
211
212 Window currentFocusWindow = 0; /* current window that has focus for input
213 method. (the best place to put this
214 information should be
215 currentX11InputMethodInstance's pData) */
216 static XIM X11im = NULL;
217 Display * dpy = NULL;
218
219 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)
220
221 #if defined(RESUME_ENABLE)
222 static void DestroyXIMCallback(XIM, XPointer, XPointer);
223 static void OpenXIMCallback(Display *, XPointer, XPointer);
224 #endif
225
226 #if !defined(AIX)
227 /* Solaris XIM Extention */
228 #define XNCommitStringCallback "commitStringCallback"
229 static void CommitStringCallback(XIC, XPointer, XPointer);
230 #endif
231
232 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject);
233 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *);
234 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *);
235 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *);
236
237 #if defined(__solaris__) || defined(AIX)
238 /* Prototype for this function is missing in Solaris X11R6 Xlib.h */
239 extern char *XSetIMValues(
240 #if NeedVarargsPrototypes
241 XIM /* im */, ...
242 #endif
243 );
244 #endif
245
246 #if defined(AIX)
247 static int st_wcslen(wchar_t *string);
248 static Bool isPreeditStateActive(XIC ic);
249 static void * buf_insert(void * src, void * insert, int size,
250 int src_len, int ins_len, int offset);
251 static void * handle_buffer(void * source, void * insert,
252 int size, int src_len, int ins_len,
253 int del_len, int offset);
254 static void preedit_draw_passive(X11InputMethodData *pX11IMData,
255 XIMPreeditDrawCallbackStruct *pre_draw);
256 static void resetPassivePreeditText(StatusWindow *statusWindow);
257 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos);
258 static int get_next_attr(int len, unsigned long *attr);
259 static void draw_preedit(StatusWindow *statusWindow);
260 static void align_status(StatusWindow *statusWindow);
261 static void shrink_status(StatusWindow *statusWindow);
262 static GC create_gc(Window win, Bool isReverse);
263 static XFontSet create_fontset(void);
264 static Bool is_text_available(XIMText * text);
265 static Bool isNativeIm();
266 static Window getGrandParent(Window parent);
267 static void moveStatusWindow(StatusWindow *statusWindow);
268 static void arrange_window_stack(StatusWindow* statusWindow);
269 static Window get_current_focus(XIC ic);
270 #endif
271
272 /*
273 * This function is stolen from /src/solaris/hpi/src/system_md.c
274 * It is used in setting the time in Java-level InputEvents
275 */
276 jlong
277 awt_util_nowMillisUTC()
278 {
279 struct timeval t;
280 gettimeofday(&t, NULL);
281 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
282 }
283
284 /*
285 * Converts the wchar_t string to a multi-byte string calling wcstombs(). A
286 * buffer is allocated by malloc() to store the multi-byte string. NULL is
287 * returned if the given wchar_t string pointer is NULL or buffer allocation is
288 * failed.
289 */
290 static char *
291 wcstombsdmp(wchar_t *wcs, int len)
296 if (wcs == NULL)
297 return NULL;
298
299 n = len*MB_CUR_MAX + 1;
300
301 mbs = (char *) malloc(n * sizeof(char));
302 if (mbs == NULL) {
303 THROW_OUT_OF_MEMORY_ERROR();
304 return NULL;
305 }
306
307 /* TODO: check return values... Handle invalid characters properly... */
308 if (wcstombs(mbs, wcs, n) == (size_t)-1) {
309 free(mbs);
310 return NULL;
311 }
312
313 return mbs;
314 }
315
316 #if defined(RESUME_ENABLE)
317 /*
318 * Returns True if the global reference is still in the list,
319 * otherwise False.
320 */
321 static Bool isX11InputMethodGRefInList(jobject imGRef) {
322 X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead;
323
324 if (imGRef == NULL) {
325 return False;
326 }
327
328 while (pX11InputMethodGRef != NULL) {
329 if (pX11InputMethodGRef->inputMethodGRef == imGRef) {
330 return True;
331 }
332 pX11InputMethodGRef = pX11InputMethodGRef->next;
333 }
334
335 return False;
336 }
376 if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) {
377 break;
378 }
379 pX11InputMethodGRef = cX11InputMethodGRef;
380 cX11InputMethodGRef = cX11InputMethodGRef->next;
381 }
382
383 if (cX11InputMethodGRef == NULL) {
384 return; /* Not found. */
385 }
386
387 if (cX11InputMethodGRef == x11InputMethodGRefListHead) {
388 x11InputMethodGRefListHead = x11InputMethodGRefListHead->next;
389 } else {
390 pX11InputMethodGRef->next = cX11InputMethodGRef->next;
391 }
392 free(cX11InputMethodGRef);
393
394 return;
395 }
396 #endif /* RESUME_ENABLE */
397
398
399 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {
400 X11InputMethodData *pX11IMData =
401 (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);
402
403 /*
404 * In case the XIM server was killed somehow, reset X11InputMethodData.
405 */
406 if (X11im == NULL && pX11IMData != NULL) {
407 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
408 "flushText",
409 "()V");
410 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
411 #if defined(AIX)
412 if ((*env)->ExceptionOccurred(env)) {
413 (*env)->ExceptionDescribe(env);
414 (*env)->ExceptionClear(env);
415 }
416 #endif
417 /* IMPORTANT:
418 The order of the following calls is critical since "imInstance" may
419 point to the global reference itself, if "freeX11InputMethodData" is called
420 first, the global reference will be destroyed and "setX11InputMethodData"
421 will in fact fail silently. So pX11IMData will not be set to NULL.
422 This could make the original java object refers to a deleted pX11IMData
423 object.
424 */
425 setX11InputMethodData(env, imInstance, NULL);
426 freeX11InputMethodData(env, pX11IMData);
427 pX11IMData = NULL;
428 }
429
430 return pX11IMData;
431 }
432
433 static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) {
434 JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData);
435 }
436
447
448 if (pX11IMData->ic_active != (XIC)0) {
449 XUnsetICFocus(pX11IMData->ic_active);
450 XDestroyIC(pX11IMData->ic_active);
451 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
452 if (pX11IMData->ic_passive != (XIC)0) {
453 XUnsetICFocus(pX11IMData->ic_passive);
454 XDestroyIC(pX11IMData->ic_passive);
455 }
456 pX11IMData->ic_passive = (XIC)0;
457 pX11IMData->current_ic = (XIC)0;
458 }
459 }
460
461 freeX11InputMethodData(env, pX11IMData);
462 }
463
464 static void
465 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
466 {
467 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
468 if (pX11IMData->statusWindow != NULL){
469 StatusWindow *sw = pX11IMData->statusWindow;
470 XFreeGC(awt_display, sw->lightGC);
471 XFreeGC(awt_display, sw->dimGC);
472 XFreeGC(awt_display, sw->bgGC);
473 XFreeGC(awt_display, sw->fgGC);
474 if (sw->fontset != NULL) {
475 XFreeFontSet(awt_display, sw->fontset);
476 }
477 XDestroyWindow(awt_display, sw->w);
478 #if defined(AIX)
479 if (pX11IMData->statusWindow->peText){
480 free((void *)pX11IMData->statusWindow->peText);
481 pX11IMData->statusWindow->peText = NULL;
482 }
483 if (pX11IMData->statusWindow->peAttr){
484 free((void *)pX11IMData->statusWindow->peAttr);
485 pX11IMData->statusWindow->peAttr = NULL;
486 }
487 #endif
488 free((void*)sw);
489 }
490 #endif
491
492 if (pX11IMData->callbacks)
493 free((void *)pX11IMData->callbacks);
494
495 if (env) {
496 #if defined(RESUME_ENABLE)
497 /* Remove the global reference from the list, so that
498 the callback function or whoever refers to it could know.
499 */
500 removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod);
501 #endif
502 (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);
503 }
504
505 #if !defined(AIX)
506 if (pX11IMData->lookup_buf) {
507 free((void *)pX11IMData->lookup_buf);
508 }
509 #endif
510
511 free((void *)pX11IMData);
512 }
513
514 /*
515 * Sets or unsets the focus to the given XIC.
516 */
517 static void
518 setXICFocus(XIC ic, unsigned short req)
519 {
520 if (ic == NULL) {
521 (void)fprintf(stderr, "Couldn't find X Input Context\n");
522 return;
523 }
524 if (req == 1)
525 XSetICFocus(ic);
526 else
527 XUnsetICFocus(ic);
528 }
529
544 * Invokes XmbLookupString() to get something from the XIM. It invokes
545 * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns
546 * committed text. This function is called from handleKeyEvent in canvas.c and
547 * it's under the Motif event loop thread context.
548 *
549 * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,
550 * where it never returns XBufferOverflow. We need to allocate the initial lookup buffer
551 * big enough, so that the possibility that user encounters this problem is relatively
552 * small. When this bug gets fixed, we can make the initial buffer size smaller.
553 * Note that XmbLookupString() sometimes produces a non-null-terminated string.
554 *
555 * Returns True when there is a keysym value to be handled.
556 */
557 #define INITIAL_LOOKUP_BUF_SIZE 512
558
559 Boolean
560 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)
561 {
562 JNIEnv *env = GetJNIEnv();
563 X11InputMethodData *pX11IMData = NULL;
564 #if defined(AIX)
565 int buf_len = INITIAL_LOOKUP_BUF_SIZE;
566 char mbbuf[INITIAL_LOOKUP_BUF_SIZE];
567 char *buf;
568 #endif
569 KeySym keysym = NoSymbol;
570 Status status;
571 int mblen;
572 jstring javastr;
573 XIC ic;
574 Boolean result = True;
575 static Boolean composing = False;
576
577 /*
578 printf("lookupString: entering...\n");
579 */
580
581 #if defined(RESUME_ENABLE)
582 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
583 currentX11InputMethodInstance = NULL;
584 return False;
585 }
586 #endif
587
588 pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
589
590 if (pX11IMData == NULL) {
591 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
592 return False;
593 #else
594 return result;
595 #endif
596 }
597
598 if ((ic = pX11IMData->current_ic) == (XIC)0){
599 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
600 return False;
601 #else
602 return result;
603 #endif
604 }
605
606 #if !defined(AIX)
607 /* allocate the lookup buffer at the first invocation */
608 if (pX11IMData->lookup_buf_len == 0) {
609 pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE);
610 if (pX11IMData->lookup_buf == NULL) {
611 THROW_OUT_OF_MEMORY_ERROR();
612 return result;
613 }
614 pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE;
615 }
616
617 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
618 pX11IMData->lookup_buf_len - 1, &keysym, &status);
619 #else
620 buf = mbbuf;
621 mblen = XmbLookupString(ic, event, buf,
622 buf_len - 1, &keysym, &status);
623 #endif
624
625 /*
626 * In case of overflow, a buffer is allocated and it retries
627 * XmbLookupString().
628 */
629 if (status == XBufferOverflow) {
630 #if !defined(AIX)
631 free((void *)pX11IMData->lookup_buf);
632 pX11IMData->lookup_buf_len = 0;
633 pX11IMData->lookup_buf = (char *)malloc(mblen + 1);
634 if (pX11IMData->lookup_buf == NULL) {
635 THROW_OUT_OF_MEMORY_ERROR();
636 return result;
637 }
638 pX11IMData->lookup_buf_len = mblen + 1;
639 mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
640 pX11IMData->lookup_buf_len - 1, &keysym, &status);
641 #else
642 buf_len = mblen + 1;
643 buf = (char *)malloc(buf_len);
644 if (buf == NULL) {
645 THROW_OUT_OF_MEMORY_ERROR();
646 return result;
647 }
648 mblen = XmbLookupString(ic, event, buf, buf_len, &keysym, &status);
649 #endif
650 }
651 #if !defined(AIX)
652 pX11IMData->lookup_buf[mblen] = 0;
653 #else
654 buf[mblen] = 0;
655 #endif
656
657 /* Get keysym without taking modifiers into account first to map
658 * to AWT keyCode table.
659 */
660 switch (status) {
661 case XLookupBoth:
662 if (!composing) {
663 if (event->keycode != 0) {
664 *keysymp = keysym;
665 result = False;
666 break;
667 }
668 }
669 composing = False;
670 /*FALLTHRU*/
671 case XLookupChars:
672 /*
673 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
674 event->type, event->state, event->keycode, keysym);
675 */
676 #if !defined(AIX)
677 javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
678 #else
679 javastr = JNU_NewStringPlatform(env, (const char *)buf);
680 #endif
681 if (javastr != NULL) {
682 JNU_CallMethodByName(env, NULL,
683 currentX11InputMethodInstance,
684 "dispatchCommittedText",
685 "(Ljava/lang/String;J)V",
686 javastr,
687 event->time);
688 #if defined(AIX)
689 if ((*env)->ExceptionOccurred(env)) {
690 (*env)->ExceptionDescribe(env);
691 (*env)->ExceptionClear(env);
692 }
693 #endif
694 }
695 break;
696
697 case XLookupKeySym:
698 /*
699 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
700 event->type, event->state, event->keycode, keysym);
701 */
702 if (keysym == XK_Multi_key)
703 composing = True;
704 if (! composing) {
705 *keysymp = keysym;
706 result = False;
707 }
708 break;
709
710 case XLookupNone:
711 /*
712 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
713 event->type, event->state, event->keycode, keysym);
714 */
715 break;
716 }
717
718 #if defined(AIX)
719 if (buf != mbbuf) free(buf);
720 #endif
721 return result;
722 }
723
724 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
725 static StatusWindow *createStatusWindow(
726 Window parent) {
727 StatusWindow *statusWindow;
728 XSetWindowAttributes attrib;
729 unsigned long attribmask;
730 Window containerWindow;
731 Window status;
732 Window child;
733 XWindowAttributes xwa;
734 XWindowAttributes xxwa;
735 /* Variable for XCreateFontSet()*/
736 char **mclr;
737 int mccr = 0;
738 char *dsr;
739 unsigned long bg, fg, light, dim;
740 int x, y, off_x, off_y, xx, yy;
741 unsigned int w, h, bw, depth;
742 XGCValues values;
743 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/
744 int screen = 0;
745 int i;
746 AwtGraphicsConfigDataPtr adata;
747 extern int awt_numScreens;
748 /*hardcode the size right now, should get the size base on font*/
749 int width=80, height=22;
750 Window rootWindow;
751 Window *ignoreWindowPtr;
752 unsigned int ignoreUnit;
753 #if defined(AIX)
754 Window grandParent;
755 Window target;
756 XFontSet fontset;
757
758 fontset = create_fontset();
759 if (NULL == fontset) return NULL;
760 #endif
761
762 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
763
764 attrib.override_redirect = True;
765 attribmask = CWOverrideRedirect;
766 for (i = 0; i < awt_numScreens; i++) {
767 if (RootWindow(dpy, i) == rootWindow) {
768 screen = i;
769 break;
770 }
771 }
772 adata = getDefaultConfig(screen);
773 bg = adata->AwtColorMatch(255, 255, 255, adata);
774 fg = adata->AwtColorMatch(0, 0, 0, adata);
775 light = adata->AwtColorMatch(195, 195, 195, adata);
776 dim = adata->AwtColorMatch(128, 128, 128, adata);
777
778 #if !defined(AIX)
779 XGetWindowAttributes(dpy, parent, &xwa);
780 #else
781 grandParent=getGrandParent(parent);
782 if (grandParent == 0){
783 target = parent;
784 }else{
785 target = grandParent;
786 }
787 XGetWindowAttributes(dpy, target, &xwa);
788 #endif
789 bw = 2; /*xwa.border_width does not have the correct value*/
790
791 /*compare the size difference between parent container
792 and shell widget, the diff should be the border frame
793 and title bar height (?)*/
794
795 XQueryTree( dpy,
796 #if !defined(AIX)
797 parent,
798 #else
799 target,
800 #endif
801 &rootWindow,
802 &containerWindow,
803 &ignoreWindowPtr,
804 &ignoreUnit);
805 XGetWindowAttributes(dpy, containerWindow, &xxwa);
806
807 #if !defined(AIX)
808 off_x = (xxwa.width - xwa.width) / 2;
809 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
810 #else
811 XTranslateCoordinates(dpy,
812 target, xwa.root,
813 0, 0,
814 &x, &y, &child);
815
816 if (containerWindow == rootWindow){
817 off_x = 0; off_y = STATUS_MARGIN;
818 }else{
819 XGetWindowAttributes(dpy, containerWindow, &xxwa);
820 off_x = (xxwa.width - xwa.width) / 2;
821 /* off_y = xxwa.height - xwa.height - off_x;*/ /*it's magic:-) */
822 {
823 int cx, cy;
824 XTranslateCoordinates(dpy,
825 containerWindow, xxwa.root,
826 0, 0,
827 &cx, &cy,
828 &child);
829 off_y = (xxwa.height + cy) - (xwa.height + y) ;
830 }
831 }
832 #endif
833
834 /*get the size of root window*/
835 XGetWindowAttributes(dpy, rootWindow, &xxwa);
836
837 XTranslateCoordinates(dpy,
838 #if !defined(AIX)
839 parent, xwa.root,
840 #else
841 target, xwa.root,
842 #endif
843 xwa.x, xwa.y,
844 &x, &y,
845 &child);
846 xx = x - off_x;
847 yy = y + xwa.height - off_y;
848 if (xx < 0 ){
849 xx = 0;
850 }
851 if (xx + width > xxwa.width){
852 xx = xxwa.width - width;
853 }
854 if (yy + height > xxwa.height){
855 yy = xxwa.height - height;
856 }
857
858 #if defined(AIX)
859 if ((DefaultVisual(dpy,screen))->class != adata->awt_visInfo.visual->class &&
860 adata->awt_visInfo.visual->class == TrueColor) {
861 attrib.colormap = XCreateColormap(dpy, xwa.root,
862 adata->awt_visInfo.visual, AllocNone );
863 attrib.border_pixel = BlackPixel(dpy, screen) ;
864 attribmask |= CWColormap | CWBorderPixel;
865 }
866 #endif
867
868 status = XCreateWindow(dpy,
869 xwa.root,
870 xx, yy,
871 width, height,
872 0,
873 xwa.depth,
874 InputOutput,
875 adata->awt_visInfo.visual,
876 attribmask, &attrib);
877 XSelectInput(dpy, status,
878 ExposureMask | StructureNotifyMask | EnterWindowMask |
879 LeaveWindowMask | VisibilityChangeMask);
880 #if defined(AIX)
881 if (grandParent != 0){
882 long mask;
883 XGetWindowAttributes(dpy, grandParent, &xwa);
884 mask = xwa.your_event_mask | StructureNotifyMask |
885 VisibilityChangeMask | PropertyChangeMask;
886 XSelectInput(dpy, grandParent,mask);
887 }
888 #endif
889
890 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
891 if (statusWindow == NULL){
892 THROW_OUT_OF_MEMORY_ERROR();
893 return NULL;
894 }
895 statusWindow->w = status;
896 #if !defined(AIX)
897 //12-point font
898 statusWindow->fontset = XCreateFontSet(dpy,
899 "-*-*-medium-r-normal-*-*-120-*-*-*-*",
900 &mclr, &mccr, &dsr);
901 /* In case we didn't find the font set, release the list of missing characters */
902 if (mccr > 0) {
903 XFreeStringList(mclr);
904 }
905 #else
906 statusWindow->fontset = fontset;
907 #endif
908 statusWindow->parent = parent;
909 #if defined(AIX)
910 statusWindow->grandParent = grandParent;
911 #endif
912 statusWindow->on = False;
913 statusWindow->x = x;
914 statusWindow->y = y;
915 statusWindow->width = xwa.width;
916 statusWindow->height = xwa.height;
917 statusWindow->off_x = off_x;
918 statusWindow->off_y = off_y;
919 statusWindow->bWidth = bw;
920 statusWindow->statusH = height;
921 statusWindow->statusW = width;
922 #if defined(AIX)
923 statusWindow->peTextW = 0;
924 #endif
925 statusWindow->rootH = xxwa.height;
926 statusWindow->rootW = xxwa.width;
927 statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
928 XSetForeground(dpy, statusWindow->lightGC, light);
929 statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
930 XSetForeground(dpy, statusWindow->dimGC, dim);
931 #if !defined(AIX)
932 statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);
933 #else
934 statusWindow->fgGC = create_gc(status, FALSE);
935 #endif
936 XSetForeground(dpy, statusWindow->fgGC, fg);
937 #if !defined(AIX)
938 statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
939 #else
940 statusWindow->bgGC = create_gc(status, TRUE);
941 #endif
942 XSetForeground(dpy, statusWindow->bgGC, bg);
943 #if defined(AIX)
944 statusWindow->status_ready = False;
945 wcscpy(statusWindow->status, L"");
946 #endif
947 return statusWindow;
948 }
949
950 /* This method is to turn off or turn on the status window. */
951 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
952 Window parent,
953 Bool ON){
954 XWindowAttributes xwa;
955 Window child;
956 int x, y;
957 StatusWindow *statusWindow = NULL;
958
959 #if !defined(AIX)
960 if (NULL == currentX11InputMethodInstance ||
961 NULL == pX11IMData ||
962 #else
963 if (NULL == pX11IMData ||
964 #endif
965 NULL == (statusWindow = pX11IMData->statusWindow)){
966 return;
967 }
968
969 if (ON == False){
970 XUnmapWindow(dpy, statusWindow->w);
971 #if !defined(AIX)
972 statusWindow->on = False;
973 #endif
974 return;
975 }
976 #if !defined(AIX)
977 parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
978 #else
979 if (NULL == currentX11InputMethodInstance){
980 return;
981 }
982 {
983 JNIEnv *env = GetJNIEnv();
984 parent = JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
985 #endif
986 "getCurrentParentWindow",
987 "()J").j;
988 #if defined(AIX)
989 if ((*env)->ExceptionOccurred(env)) {
990 (*env)->ExceptionDescribe(env);
991 (*env)->ExceptionClear(env);
992 }
993 }
994 #endif
995 if (statusWindow->parent != parent){
996 statusWindow->parent = parent;
997 }
998 #if !defined(AIX)
999 XGetWindowAttributes(dpy, parent, &xwa);
1000 XTranslateCoordinates(dpy,
1001 parent, xwa.root,
1002 xwa.x, xwa.y,
1003 &x, &y,
1004 &child);
1005 if (statusWindow->x != x
1006 || statusWindow->y != y
1007 || statusWindow->height != xwa.height){
1008 statusWindow->x = x;
1009 statusWindow->y = y;
1010 statusWindow->height = xwa.height;
1011 x = statusWindow->x - statusWindow->off_x;
1012 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
1013 if (x < 0 ){
1014 x = 0;
1015 }
1016 if (x + statusWindow->statusW > statusWindow->rootW){
1017 x = statusWindow->rootW - statusWindow->statusW;
1018 }
1019 if (y + statusWindow->statusH > statusWindow->rootH){
1020 y = statusWindow->rootH - statusWindow->statusH;
1021 }
1022 XMoveWindow(dpy, statusWindow->w, x, y);
1023 }
1024 statusWindow->on = True;
1025 XMapWindow(dpy, statusWindow->w);
1026 #else
1027 if (st_wcslen(statusWindow->status) > 0
1028 || (statusWindow->peText != NULL && st_wcslen(statusWindow->peText) > 0 )){
1029 moveStatusWindow(statusWindow);
1030 XMapRaised(dpy, statusWindow->w);
1031 }
1032 #endif
1033 }
1034
1035 void paintStatusWindow(StatusWindow *statusWindow){
1036 Window win = statusWindow->w;
1037 GC lightgc = statusWindow->lightGC;
1038 GC dimgc = statusWindow->dimGC;
1039 GC bggc = statusWindow->bgGC;
1040 GC fggc = statusWindow->fgGC;
1041
1042 int width = statusWindow->statusW;
1043 int height = statusWindow->statusH;
1044 int bwidth = statusWindow->bWidth;
1045 #if defined(AIX)
1046 int len;
1047 XRectangle logical, ink;
1048
1049 if (NULL == statusWindow) return;
1050 if ((len = st_wcslen(statusWindow->status)) == 0)
1051 return;
1052 XwcTextExtents(statusWindow->fontset, statusWindow->status,
1053 len, &ink, &logical);
1054 width = logical.width;
1055 height = logical.height;
1056
1057 XFillRectangle(dpy, win, bggc, 0, 0, width+2, height+2);
1058 #endif
1059
1060 #if !defined(AIX)
1061 XFillRectangle(dpy, win, bggc, 0, 0, width, height);
1062 /* draw border */
1063 XDrawLine(dpy, win, fggc, 0, 0, width, 0);
1064 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
1065 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
1066 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
1067
1068 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
1069 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
1070 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
1071 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
1072
1073 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
1074 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
1075 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
1076 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
1077 #else
1078 XDrawLine(dpy, win, fggc, 0, 0, width+2, 0);
1079 XDrawLine(dpy, win, fggc, 0, height+2, width+2, height+2);
1080 XDrawLine(dpy, win, fggc, 0, 0, 0, height+2);
1081 XDrawLine(dpy, win, fggc, width+2, 0, width+2, height+2);
1082 #endif
1083
1084 if (statusWindow->fontset){
1085 #if !defined(AIX)
1086 XmbDrawString(dpy, win, statusWindow->fontset, fggc,
1087 bwidth + 2, height - bwidth - 4,
1088 #else
1089 XwcDrawString(dpy, win, statusWindow->fontset, fggc,
1090 -logical.x + 1, -logical.y + 1,
1091 #endif
1092 statusWindow->status,
1093 #if !defined(AIX)
1094 strlen(statusWindow->status));
1095 #else
1096 st_wcslen(statusWindow->status));
1097 #endif
1098 }
1099 else{
1100 /*too bad we failed to create a fontset for this locale*/
1101 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
1102 "[InputMethod ON]", strlen("[InputMethod ON]"));
1103 }
1104 }
1105
1106 #if !defined(AIX)
1107 void statusWindowEventHandler(XEvent event){
1108 #else
1109 Bool statusWindowEventHandler(XEvent event){
1110 #endif
1111 JNIEnv *env = GetJNIEnv();
1112 X11InputMethodData *pX11IMData = NULL;
1113 StatusWindow *statusWindow;
1114
1115 #if defined(RESUME_ENABLE)
1116 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
1117 currentX11InputMethodInstance = NULL;
1118 #if !defined(AIX)
1119 return;
1120 #else
1121 return False;
1122 #endif
1123 }
1124 #endif
1125
1126 if (NULL == currentX11InputMethodInstance
1127 || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance))
1128 #if !defined(AIX)
1129 || NULL == (statusWindow = pX11IMData->statusWindow)
1130 || statusWindow->w != event.xany.window){
1131 return;
1132 #else
1133 || NULL == (statusWindow = pX11IMData->statusWindow)){
1134 return False;
1135 #endif
1136 }
1137
1138 #if defined(AIX)
1139 if (statusWindow->w == event.xany.window){
1140 #endif
1141 switch (event.type){
1142 case Expose:
1143 paintStatusWindow(statusWindow);
1144 #if defined(AIX)
1145 if (statusWindow->peText)
1146 draw_preedit(statusWindow);
1147 arrange_window_stack(statusWindow);
1148 #endif
1149 break;
1150 #if !defined(AIX)
1151 case MapNotify:
1152 #endif
1153 case ConfigureNotify:
1154 #if defined(AIX)
1155 case VisibilityNotify:
1156 arrange_window_stack(statusWindow);
1157 #endif
1158 #if !defined(AIX)
1159 {
1160 /*need to reset the stackMode...*/
1161 XWindowChanges xwc;
1162 int value_make = CWStackMode;
1163 xwc.stack_mode = TopIf;
1164 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
1165 }
1166 #endif
1167 break;
1168 /*
1169 case UnmapNotify:
1170 case VisibilityNotify:
1171 break;
1172 */
1173 default:
1174 break;
1175 }
1176 #if defined(AIX)
1177 return True;
1178 }else if ((statusWindow->parent == event.xany.window)
1179 ||(statusWindow->grandParent
1180 && statusWindow->grandParent == event.xany.window)){
1181 switch (event.type){
1182 case MapNotify:
1183 if (statusWindow->on){
1184 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1185 }
1186 break;
1187 case UnmapNotify:
1188 onoffStatusWindow(pX11IMData, 0, False);
1189 break;
1190 case VisibilityNotify:
1191 if (statusWindow->on){
1192 arrange_window_stack(statusWindow);
1193 }
1194 break;
1195 case ConfigureNotify:
1196 if (statusWindow->grandParent && statusWindow->on){
1197 moveStatusWindow(statusWindow);
1198 }
1199 case PropertyNotify:
1200 if (statusWindow->on){
1201 arrange_window_stack(statusWindow);
1202 }
1203 break;
1204 default:
1205 break;
1206 }
1207 }
1208 return False;
1209 #endif
1210 }
1211
1212 static void adjustStatusWindow(Window shell){
1213 JNIEnv *env = GetJNIEnv();
1214 X11InputMethodData *pX11IMData = NULL;
1215 StatusWindow *statusWindow;
1216
1217 if (NULL == currentX11InputMethodInstance
1218 #if defined(RESUME_ENABLE)
1219 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1220 #endif
1221 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1222 || NULL == (statusWindow = pX11IMData->statusWindow)
1223 || !statusWindow->on) {
1224 return;
1225 }
1226 #if defined(AIX)
1227 moveStatusWindow(statusWindow);
1228 #endif
1229 #if !defined(AIX)
1230 {
1231 XWindowAttributes xwa;
1232 int x, y;
1233 Window child;
1234 XGetWindowAttributes(dpy, shell, &xwa);
1235 XTranslateCoordinates(dpy,
1236 shell, xwa.root,
1237 xwa.x, xwa.y,
1238 &x, &y,
1239 &child);
1240 if (statusWindow->x != x
1241 || statusWindow->y != y
1242 || statusWindow->height != xwa.height){
1243 statusWindow->x = x;
1244 statusWindow->y = y;
1245 statusWindow->height = xwa.height;
1246
1247 x = statusWindow->x - statusWindow->off_x;
1248 y = statusWindow->y + statusWindow->height - statusWindow->off_y;
1249 if (x < 0 ){
1250 x = 0;
1251 }
1252 if (x + statusWindow->statusW > statusWindow->rootW){
1253 x = statusWindow->rootW - statusWindow->statusW;
1254 }
1255 if (y + statusWindow->statusH > statusWindow->rootH){
1256 y = statusWindow->rootH - statusWindow->statusH;
1257 }
1258 XMoveWindow(dpy, statusWindow->w, x, y);
1259 }
1260 }
1261 #endif
1262 }
1263 #endif /* __linux__ || MACOSX || AIX */
1264 /*
1265 * Creates two XICs, one for active clients and the other for passive
1266 * clients. All information on those XICs are stored in the
1267 * X11InputMethodData given by the pX11IMData parameter.
1268 *
1269 * For active clients: Try to use preedit callback to support
1270 * on-the-spot. If tc is not null, the XIC to be created will
1271 * share the Status Area with Motif widgets (TextComponents). If the
1272 * preferable styles can't be used, fallback to root-window styles. If
1273 * root-window styles failed, fallback to None styles.
1274 *
1275 * For passive clients: Try to use root-window styles. If failed,
1276 * fallback to None styles.
1277 */
1278 static Bool
1279 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
1280 {
1281 XVaNestedList preedit = NULL;
1282 XVaNestedList status = NULL;
1283 XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
1284 #if defined(AIX)
1285 in_place_styles = 0,
1286 #endif
1287 active_styles = 0,
1288 passive_styles = 0,
1289 no_styles = 0;
1290 XIMCallback *callbacks;
1291 unsigned short i;
1292 XIMStyles *im_styles;
1293 char *ret = NULL;
1294 #if defined(AIX)
1295 Bool passiveStatusWindow = False;
1296
1297 pX11IMData->statusWindow = NULL;
1298 #endif
1299
1300 if (X11im == NULL) {
1301 return False;
1302 }
1303 if (!w) {
1304 return False;
1305 }
1306
1307 #if defined(AIX)
1308 if (getenv("IBMJAVA_PASSIVE") == NULL) {
1309 passiveStatusWindow = False;
1310 } else {
1311 passiveStatusWindow = True;
1312 }
1313
1314 if (isNativeIm()) { passiveStatusWindow = True; }
1315 #endif
1316
1317 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
1318
1319 if (ret != NULL) {
1320 jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
1321 return FALSE ;
1322 }
1323
1324 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
1325 on_the_spot_styles |= XIMStatusNothing;
1326
1327 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
1328 at the same time, so use StatusCallback to draw the status
1329 ourself
1330 */
1331 for (i = 0; i < im_styles->count_styles; i++) {
1332 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
1333 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
1334 break;
1335 }
1336 }
1337 #else /*! __linux__ && !MACOSX && !AIX */
1338 on_the_spot_styles |= XIMStatusNothing;
1339 #endif /* __linux__ || MACOSX || AIX */
1340
1341 #if !defined(AIX)
1342 for (i = 0; i < im_styles->count_styles; i++) {
1343 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
1344 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
1345 no_styles |= im_styles->supported_styles[i] & NO_STYLES;
1346 }
1347 #else
1348 for (i = 0; i < im_styles->count_styles; i++) {
1349 if (im_styles->supported_styles[i] == on_the_spot_styles)
1350 active_styles = im_styles->supported_styles[i];
1351 if (im_styles->supported_styles[i] == ROOT_WINDOW_STYLES)
1352 passive_styles = im_styles->supported_styles[i];
1353 if (im_styles->supported_styles[i] == IN_PLACE_STYLES) {
1354 in_place_styles = im_styles->supported_styles[i];
1355 }
1356 if (im_styles->supported_styles[i] == NO_STYLES)
1357 no_styles = im_styles->supported_styles[i];
1358 }
1359 #endif
1360
1361 XFree(im_styles);
1362
1363 if (active_styles != on_the_spot_styles) {
1364 if (passive_styles == ROOT_WINDOW_STYLES)
1365 active_styles = passive_styles;
1366 else {
1367 #if defined(AIX)
1368 if (in_place_styles == IN_PLACE_STYLES){
1369 active_styles = passive_styles = IN_PLACE_STYLES;
1370 } else {
1371 #endif
1372 if (no_styles == NO_STYLES)
1373 active_styles = passive_styles = NO_STYLES;
1374 else
1375 active_styles = passive_styles = 0;
1376 #if defined(AIX)
1377 }
1378 #endif
1379 }
1380 } else {
1381 #if defined(AIX)
1382 if (!passiveStatusWindow) {
1383 #endif
1384 if (passive_styles != ROOT_WINDOW_STYLES) {
1385 if (no_styles == NO_STYLES)
1386 active_styles = passive_styles = NO_STYLES;
1387 else
1388 active_styles = passive_styles = 0;
1389 }
1390 #if defined(AIX)
1391 } else
1392 passive_styles = active_styles;
1393 #endif
1394 }
1395
1396 if (active_styles == on_the_spot_styles) {
1397 #if !defined(AIX)
1398 pX11IMData->ic_passive = XCreateIC(X11im,
1399 XNClientWindow, w,
1400 XNFocusWindow, w,
1401 XNInputStyle, passive_styles,
1402 NULL);
1403
1404 #endif
1405 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
1406 if (callbacks == (XIMCallback *)NULL)
1407 return False;
1408 pX11IMData->callbacks = callbacks;
1409
1410 for (i = 0; i < NCALLBACKS; i++, callbacks++) {
1411 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
1412 callbacks->callback = callback_funcs[i];
1413 }
1414
1415 callbacks = pX11IMData->callbacks;
1416 preedit = (XVaNestedList)XVaCreateNestedList(0,
1417 XNPreeditStartCallback, &callbacks[PreeditStartIndex],
1418 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex],
1419 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex],
1420 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
1421 NULL);
1422 if (preedit == (XVaNestedList)NULL)
1423 goto err;
1424 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
1425 /*always try XIMStatusCallbacks for active client...*/
1426 {
1427 #if defined(AIX)
1428 if (on_the_spot_styles & XIMStatusCallbacks) {
1429 #endif
1430 status = (XVaNestedList)XVaCreateNestedList(0,
1431 XNStatusStartCallback, &callbacks[StatusStartIndex],
1432 XNStatusDoneCallback, &callbacks[StatusDoneIndex],
1433 XNStatusDrawCallback, &callbacks[StatusDrawIndex],
1434 NULL);
1435
1436 if (status == NULL)
1437 goto err;
1438 #if defined(AIX)
1439 }
1440 #endif
1441 pX11IMData->statusWindow = createStatusWindow(w);
1442 pX11IMData->ic_active = XCreateIC(X11im,
1443 XNClientWindow, w,
1444 XNFocusWindow, w,
1445 XNInputStyle, active_styles,
1446 XNPreeditAttributes, preedit,
1447 XNStatusAttributes, status,
1448 NULL);
1449 #if defined(AIX)
1450 if (NULL != pX11IMData->statusWindow) {
1451 pX11IMData->statusWindow->status_ready = True;
1452 }
1453 #endif
1454 XFree((void *)status);
1455 XFree((void *)preedit);
1456 }
1457 #else /* !__linux__ && !MACOSX && !AIX */
1458 pX11IMData->ic_active = XCreateIC(X11im,
1459 XNClientWindow, w,
1460 XNFocusWindow, w,
1461 XNInputStyle, active_styles,
1462 XNPreeditAttributes, preedit,
1463 NULL);
1464 XFree((void *)preedit);
1465 #endif /* __linux__ || MACOSX || AIX */
1466 #if defined(AIX)
1467 if (passiveStatusWindow) {
1468 pX11IMData->ic_passive = pX11IMData->ic_active;
1469 } else {
1470 pX11IMData->ic_passive = XCreateIC(X11im,
1471 XNClientWindow, w,
1472 XNFocusWindow, w,
1473 XNInputStyle, passive_styles,
1474 NULL);
1475 }
1476 #endif
1477 } else {
1478 pX11IMData->ic_active = XCreateIC(X11im,
1479 XNClientWindow, w,
1480 XNFocusWindow, w,
1481 XNInputStyle, active_styles,
1482 NULL);
1483 pX11IMData->ic_passive = pX11IMData->ic_active;
1484 }
1485
1486 #if defined(AIX)
1487 // The code set the IC mode that the preedit state is not initialied
1488 // at XmbResetIC. This attribute can be set at XCreateIC. I separately
1489 // set the attribute to avoid the failure of XCreateIC at some platform
1490 // which does not support the attribute.
1491 if (pX11IMData->ic_active != 0)
1492 XSetICValues(pX11IMData->ic_active,
1493 XNResetState, XIMPreserveState, NULL);
1494 if (pX11IMData->ic_passive != 0 &&
1495 pX11IMData->ic_active != pX11IMData->ic_passive)
1496 XSetICValues(pX11IMData->ic_passive,
1497 XNResetState, XIMInitialState, NULL);
1498
1499 pX11IMData->passiveStatusWindow = passiveStatusWindow;
1500 #endif
1501
1502 if (pX11IMData->ic_active == (XIC)0
1503 || pX11IMData->ic_passive == (XIC)0) {
1504 return False;
1505 }
1506 #if !defined(AIX)
1507 /*
1508 * Use commit string call back if possible.
1509 * This will ensure the correct order of preedit text and commit text
1510 */
1511 {
1512 XIMCallback cb;
1513 cb.client_data = (XPointer) pX11IMData->x11inputmethod;
1514 cb.callback = (XIMProc) CommitStringCallback;
1515 XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL);
1516 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1517 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1518 }
1519 }
1520 #endif
1521
1522 #if defined(RESUME_ENABLE)
1523 /* Add the global reference object to X11InputMethod to the list. */
1524 addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1525 #endif
1526
1527 #if defined(AIX)
1528 /* Unset focus to avoid unexpected IM on */
1529 setXICFocus(pX11IMData->ic_active, False);
1530 if (pX11IMData->ic_active != pX11IMData->ic_passive)
1531 setXICFocus(pX11IMData->ic_passive, False);
1532 #endif
1533
1534 return True;
1535
1536 err:
1537 if (preedit)
1538 XFree((void *)preedit);
1539 THROW_OUT_OF_MEMORY_ERROR();
1540 return False;
1541 }
1542
1543 #if !defined(AIX)
1544 static void
1545 #else
1546 static int
1547 #endif
1548 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1549 {
1550 #if defined(AIX)
1551 JNIEnv *env = GetJNIEnv();
1552 X11InputMethodData *pX11IMData;
1553 #endif
1554
1555 /*ARGSUSED*/
1556 #if !defined(AIX)
1557 /* printf("Native: PreeditCaretCallback\n"); */
1558 #else
1559 /* printf("Native: PreeditStartCallback\n"); */
1560
1561 pX11IMData = getX11InputMethodData(env, (jobject)client_data);
1562 if (pX11IMData == NULL || pX11IMData->statusWindow == NULL) {
1563 return 0;
1564 }
1565 resetPassivePreeditText(pX11IMData->statusWindow);
1566
1567 return -1; /* unlimited length for preedit text */
1568 #endif
1569 }
1570
1571 static void
1572 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1573 {
1574 #if defined(AIX)
1575 JNIEnv *env = GetJNIEnv();
1576 X11InputMethodData *pX11IMData;
1577 #endif
1578
1579 /*ARGSUSED*/
1580 #if !defined(AIX)
1581 /* printf("Native: StatusStartCallback\n"); */
1582 #else
1583 /* printf("Native: PreeditDoneCallback\n"); */
1584 pX11IMData = getX11InputMethodData(env, (jobject)client_data);
1585 if (pX11IMData == NULL) {
1586 return;
1587 }
1588
1589 if (!pX11IMData->isActiveClient) {
1590 resetPassivePreeditText(pX11IMData->statusWindow);
1591 shrink_status(pX11IMData->statusWindow);
1592 }
1593 else{
1594 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1595 "clearComposedText",
1596 "(J)V",
1597 awt_util_nowMillisUTC());
1598 if ((*env)->ExceptionOccurred(env)) {
1599 (*env)->ExceptionDescribe(env);
1600 (*env)->ExceptionClear(env);
1601 }
1602 }
1603 #endif
1604 }
1605
1606 /*
1607 * Translate the preedit draw callback items to Java values and invoke
1608 * X11InputMethod.dispatchComposedText().
1609 *
1610 * client_data: X11InputMethod object
1611 */
1612 static void
1613 PreeditDrawCallback(XIC ic, XPointer client_data,
1614 XIMPreeditDrawCallbackStruct *pre_draw)
1615 {
1616 JNIEnv *env = GetJNIEnv();
1617 X11InputMethodData *pX11IMData = NULL;
1618 jmethodID x11imMethodID;
1619
1620 XIMText *text;
1621 jstring javastr = NULL;
1622 jintArray style = NULL;
1623
1624 /* printf("Native: PreeditDrawCallback() \n"); */
1625 if (pre_draw == NULL) {
1626 return;
1627 }
1628 AWT_LOCK();
1629 #if defined(RESUME_ENABLE)
1630 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1631 if ((jobject)client_data == currentX11InputMethodInstance) {
1632 currentX11InputMethodInstance = NULL;
1633 }
1634 goto finally;
1635 }
1636 #endif
1637 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1638 goto finally;
1639 }
1640
1641 #if defined(AIX)
1642 if (!pX11IMData->isActiveClient){
1643 if (ic == pX11IMData->ic_passive) {
1644 preedit_draw_passive(pX11IMData, pre_draw);
1645 }
1646 goto finally;
1647 }
1648 #endif
1649
1650 if ((text = pre_draw->text) != NULL) {
1651 #if defined(AIX)
1652 if (is_text_available(text)) {
1653 #endif
1654 if (text->string.multi_byte != NULL) {
1655 if (pre_draw->text->encoding_is_wchar == False) {
1656 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1657 if (javastr == NULL) {
1658 goto finally;
1659 }
1660 } else {
1661 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1662 if (mbstr == NULL) {
1663 goto finally;
1664 }
1665 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1666 free(mbstr);
1667 if (javastr == NULL) {
1668 goto finally;
1669 }
1670 }
1671 }
1672 #if defined(AIX)
1673 }
1674 #endif
1675 if (text->feedback != NULL) {
1676 int cnt;
1677 jint *tmpstyle;
1678
1679 style = (*env)->NewIntArray(env, text->length);
1680 if (JNU_IsNull(env, style)) {
1681 (*env)->ExceptionClear(env);
1682 THROW_OUT_OF_MEMORY_ERROR();
1683 goto finally;
1684 }
1685
1686 if (sizeof(XIMFeedback) == sizeof(jint)) {
1687 /*
1688 * Optimization to avoid copying the array
1689 */
1690 (*env)->SetIntArrayRegion(env, style, 0,
1691 text->length, (jint *)text->feedback);
1692 } else {
1693 tmpstyle = (jint *)malloc(sizeof(jint)*(text->length));
1694 if (tmpstyle == (jint *) NULL) {
1695 THROW_OUT_OF_MEMORY_ERROR();
1696 goto finally;
1697 }
1698 for (cnt = 0; cnt < (int)text->length; cnt++)
1699 tmpstyle[cnt] = text->feedback[cnt];
1700 (*env)->SetIntArrayRegion(env, style, 0,
1701 text->length, (jint *)tmpstyle);
1702 }
1703 }
1704 }
1705 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1706 "dispatchComposedText",
1707 "(Ljava/lang/String;[IIIIJ)V",
1708 javastr,
1709 style,
1710 (jint)pre_draw->chg_first,
1711 (jint)pre_draw->chg_length,
1712 (jint)pre_draw->caret,
1713 awt_util_nowMillisUTC());
1714 #if defined(AIX)
1715 if ((*env)->ExceptionOccurred(env)) {
1716 (*env)->ExceptionDescribe(env);
1717 (*env)->ExceptionClear(env);
1718 }
1719 #endif
1720 finally:
1721 AWT_UNLOCK();
1722 return;
1723 }
1724
1725 static void
1726 PreeditCaretCallback(XIC ic, XPointer client_data,
1727 XIMPreeditCaretCallbackStruct *pre_caret)
1728 {
1729 #if defined(AIX)
1730 XIMPreeditDrawCallbackStruct pre_draw;
1731 #endif
1732
1733 /*ARGSUSED*/
1734 /* printf("Native: PreeditCaretCallback\n"); */
1735
1736 #if defined(AIX)
1737 if (pre_caret != NULL && pre_caret->direction == XIMAbsolutePosition) {
1738 pre_draw.caret = pre_caret->position;
1739 pre_draw.chg_first = 0;
1740 pre_draw.chg_length = 0;
1741 pre_draw.text = NULL;
1742 PreeditDrawCallback(ic, client_data, &pre_draw);
1743 }
1744 #endif
1745 }
1746
1747 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
1748 static void
1749 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1750 {
1751 /*ARGSUSED*/
1752 /*printf("StatusStartCallback:\n"); */
1753
1754 }
1755
1756 static void
1757 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1758 {
1759 /*ARGSUSED*/
1760 /*printf("StatusDoneCallback:\n"); */
1761
1762 }
1763
1764 static void
1765 StatusDrawCallback(XIC ic, XPointer client_data,
1766 XIMStatusDrawCallbackStruct *status_draw)
1767 {
1768 /*ARGSUSED*/
1769 /*printf("StatusDrawCallback:\n"); */
1770 JNIEnv *env = GetJNIEnv();
1771 X11InputMethodData *pX11IMData = NULL;
1772 StatusWindow *statusWindow;
1773 #if defined(AIX)
1774 int value_make = CWX|CWWidth|CWHeight;
1775 XRectangle logical, ink;
1776 XWindowChanges xwc;
1777 int len;
1778 #endif
1779
1780 AWT_LOCK();
1781
1782 #if defined(RESUME_ENABLE)
1783 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1784 if ((jobject)client_data == currentX11InputMethodInstance) {
1785 currentX11InputMethodInstance = NULL;
1786 }
1787 goto finally;
1788 }
1789 #endif
1790
1791 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1792 || NULL == (statusWindow = pX11IMData->statusWindow)){
1793 goto finally;
1794 }
1795 #if !defined(AIX)
1796 currentX11InputMethodInstance = (jobject)client_data;
1797 #endif
1798
1799 if (status_draw->type == XIMTextType){
1800 XIMText *text = (status_draw->data).text;
1801 if (text != NULL){
1802 if (text->string.multi_byte != NULL) {
1803 #if !defined(AIX)
1804 strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN);
1805 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1806 #else
1807 if(!strcmp(text->string.multi_byte," ")){
1808 wcscpy(statusWindow->status, L"");
1809 onoffStatusWindow(pX11IMData, 0, False);
1810 goto finally;
1811 }
1812 mbstowcs(statusWindow->status,
1813 (const char *)text->string.multi_byte,
1814 (size_t)MAX_STATUS_LEN);
1815 #endif
1816 }
1817 else {
1818 #if !defined(AIX)
1819 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1820 strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN);
1821 statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1822 #else
1823 if (0 == st_wcslen(text->string.wide_char)){
1824 wcscpy(statusWindow->status, L"");
1825 onoffStatusWindow(pX11IMData, 0, False);
1826 goto finally;
1827 }
1828 wcsncpy(statusWindow->status,
1829 text->string.wide_char,
1830 MAX_STATUS_LEN);
1831 #endif
1832 }
1833 #if !defined(AIX)
1834 statusWindow->on = True;
1835 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1836 paintStatusWindow(statusWindow);
1837 #else
1838 XwcTextExtents(statusWindow->fontset, statusWindow->status,
1839 st_wcslen(statusWindow->status), &ink, &logical);
1840 statusWindow->statusW = logical.width + BORDER_MARGIN;
1841 statusWindow->statusH = logical.height + BORDER_MARGIN;
1842 xwc.x = statusWindow->x - statusWindow->off_x;
1843 if (xwc.x < 0 ) xwc.x = 0;
1844 xwc.width = statusWindow->statusW;
1845 xwc.height = statusWindow->statusH;
1846 if (xwc.x + xwc.width > statusWindow->rootW){
1847 xwc.x = statusWindow->rootW - xwc.width;
1848 }
1849 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
1850 if (statusWindow->status_ready && statusWindow->on == True){
1851 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1852 }
1853 paintStatusWindow(statusWindow);
1854 if (statusWindow->peText)
1855 draw_preedit(statusWindow);
1856 #endif
1857 }
1858 else {
1859 #if !defined(AIX)
1860 statusWindow->on = False;
1861 #else
1862 wcscpy(statusWindow->status, L"");
1863 #endif
1864 /*just turnoff the status window
1865 paintStatusWindow(statusWindow);
1866 */
1867 onoffStatusWindow(pX11IMData, 0, False);
1868 }
1869 }
1870
1871 finally:
1872 AWT_UNLOCK();
1873 }
1874 #endif /* __linux__ || MACOSX */
1875
1876 #if !defined(AIX)
1877 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1878 JNIEnv *env = GetJNIEnv();
1879 XIMText * text = (XIMText *)call_data;
1880 X11InputMethodData *pX11IMData = NULL;
1881 jstring javastr;
1882
1883 AWT_LOCK();
1884
1885 if (!isX11InputMethodGRefInList((jobject)client_data)) {
1886 if ((jobject)client_data == currentX11InputMethodInstance) {
1887 currentX11InputMethodInstance = NULL;
1888 }
1889 goto finally;
1890 }
1891
1892 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1893 goto finally;
1894 }
1895 currentX11InputMethodInstance = (jobject)client_data;
1896
1899 } else {
1900 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1901 if (mbstr == NULL) {
1902 goto finally;
1903 }
1904 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1905 free(mbstr);
1906 }
1907
1908 if (javastr != NULL) {
1909 JNU_CallMethodByName(env, NULL,
1910 pX11IMData->x11inputmethod,
1911 "dispatchCommittedText",
1912 "(Ljava/lang/String;J)V",
1913 javastr,
1914 awt_util_nowMillisUTC());
1915 }
1916 finally:
1917 AWT_UNLOCK();
1918 }
1919 #endif
1920
1921 #if defined(RESUME_ENABLE)
1922 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) {
1923 XIMCallback ximCallback;
1924
1925 X11im = XOpenIM(display, NULL, NULL, NULL);
1926 if (X11im == NULL) {
1927 return;
1928 }
1929
1930 ximCallback.callback = (XIMProc)DestroyXIMCallback;
1931 ximCallback.client_data = NULL;
1932 XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1933 }
1934
1935 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1936 /* mark that XIM server was destroyed */
1937 X11im = NULL;
1938 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1939 /* free the old pX11IMData and set it to null. this also avoids crashing
1940 * the jvm if the XIM server reappears */
1941 X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1942 }
1943 #endif /* RESUME_ENABLE */
1944
1945 /*
1946 * Class: sun_awt_X11InputMethod
1947 * Method: initIDs
1948 * Signature: ()V
1949 */
1950
1951 /* This function gets called from the static initializer for
1952 X11InputMethod.java
1953 to initialize the fieldIDs for fields that may be accessed from C */
1954 JNIEXPORT void JNICALL
1955 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1956 {
1957 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1958 }
1959
1960
1961 JNIEXPORT jboolean JNICALL
1962 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1963 jobject this,
1964 jlong display)
1965 {
1966 Bool registered;
1967
1968 AWT_LOCK();
1969
1970 dpy = (Display *)jlong_to_ptr(display);
1971
1972 #ifndef RESUME_ENABLE
1973 if (X11im == NULL) {
1974 X11im = XOpenIM(dpy, NULL, NULL, NULL);
1975 }
1976 #else /* !RESUME_ENABLE */
1977 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1978 (4768335)
1979 */
1980 #if defined(__linux__) || defined(MACOSX)
1981 registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1982 NULL, (XIDProc)OpenXIMCallback, NULL);
1983 if (!registered) {
1984 /* directly call openXIM callback */
1985 #endif
1986 OpenXIMCallback(dpy, NULL, NULL);
1987 #if defined(__linux__) || defined(MACOSX)
1988 }
1989 #endif
1990 #endif /* RESUME_ENABLE */
1991
1992 AWT_UNLOCK();
1993
1994 return JNI_TRUE;
1995 }
1996
1997 JNIEXPORT jboolean JNICALL
1998 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1999 jobject this,
2000 jlong window)
2001 {
2002 X11InputMethodData *pX11IMData;
2003 jobject globalRef;
2004 XIC ic;
2005
2006 AWT_LOCK();
2007
2008 if (!window) {
2009 JNU_ThrowNullPointerException(env, "NullPointerException");
2010 AWT_UNLOCK();
2011 return JNI_FALSE;
2012 }
2013
2014 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
2015 if (pX11IMData == NULL) {
2016 THROW_OUT_OF_MEMORY_ERROR();
2017 AWT_UNLOCK();
2018 return JNI_FALSE;
2019 }
2020
2021 globalRef = (*env)->NewGlobalRef(env, this);
2022 pX11IMData->x11inputmethod = globalRef;
2023 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
2024 pX11IMData->statusWindow = NULL;
2025 #endif /* __linux__ || MACOSX || AIX */
2026
2027 #if !defined(AIX)
2028 pX11IMData->lookup_buf = 0;
2029 pX11IMData->lookup_buf_len = 0;
2030
2031 #else
2032 setX11InputMethodData(env, this, pX11IMData);
2033
2034 #endif
2035
2036 if (createXIC(env, pX11IMData, (Window)window) == False) {
2037 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
2038 pX11IMData = (X11InputMethodData *) NULL;
2039 #if defined(AIX)
2040 setX11InputMethodData(env, this, pX11IMData);
2041 #endif
2042 if ((*env)->ExceptionCheck(env)) {
2043 goto finally;
2044 }
2045 }
2046
2047 #if !defined(AIX)
2048 setX11InputMethodData(env, this, pX11IMData);
2049 #endif
2050
2051 finally:
2052 AWT_UNLOCK();
2053 return (pX11IMData != NULL);
2054 }
2055
2056 JNIEXPORT void JNICALL
2057 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
2058 jobject this,
2059 jlong w,
2060 jboolean req,
2061 jboolean active)
2062 {
2063 X11InputMethodData *pX11IMData;
2064 AWT_LOCK();
2065 pX11IMData = getX11InputMethodData(env, this);
2066 if (pX11IMData == NULL) {
2067 AWT_UNLOCK();
2068 return;
2069 }
2070
2071 if (req) {
2072 if (!w) {
2073 AWT_UNLOCK();
2074 return;
2075 }
2076 #if defined(AIX)
2077 pX11IMData->isActiveClient = active;
2078 #endif
2079 pX11IMData->current_ic = active ?
2080 pX11IMData->ic_active : pX11IMData->ic_passive;
2081 /*
2082 * On Solaris2.6, setXICWindowFocus() has to be invoked
2083 * before setting focus.
2084 */
2085 #if defined(AIX)
2086 get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */
2087 if (currentFocusWindow != w) {
2088 #endif
2089 setXICWindowFocus(pX11IMData->current_ic, w);
2090 setXICFocus(pX11IMData->current_ic, req);
2091 currentX11InputMethodInstance = pX11IMData->x11inputmethod;
2092 currentFocusWindow = w;
2093 #if defined(AIX)
2094 } else {
2095 #endif
2096 #if defined(__linux__) || defined(MACOSX)
2097 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
2098 #endif
2099 #if defined(AIX)
2100 setXICFocus(pX11IMData->current_ic, req);
2101 }
2102 if ((active || pX11IMData->passiveStatusWindow)
2103 && (pX11IMData->statusWindow && pX11IMData->statusWindow->on))
2104 #endif
2105 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
2106 onoffStatusWindow(pX11IMData, w, True);
2107 #endif
2108 } else {
2109 currentX11InputMethodInstance = NULL;
2110 currentFocusWindow = 0;
2111 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
2112 onoffStatusWindow(pX11IMData, 0, False);
2113 if (pX11IMData->current_ic != NULL)
2114 #endif
2115 setXICFocus(pX11IMData->current_ic, req);
2116
2117 pX11IMData->current_ic = (XIC)0;
2118 }
2119
2120 XFlush(dpy);
2121 AWT_UNLOCK();
2122 }
2123
2124 JNIEXPORT void JNICALL
2125 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
2126 jobject this)
2127 {
2128 #if defined(__linux__) || defined(MACOSX) || defined(AIX)
2129 X11InputMethodData *pX11IMData;
2130 StatusWindow *statusWindow;
2131
2132 AWT_LOCK();
2133
2134 if (NULL == currentX11InputMethodInstance
2135 #if defined(RESUME_ENABLE)
2136 || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
2137 #endif
2138 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
2139 || NULL == (statusWindow = pX11IMData->statusWindow)
2140 || !statusWindow->on ){
2141 AWT_UNLOCK();
2142 return;
2143 }
2144 onoffStatusWindow(pX11IMData, 0, False);
2145 #if defined(AIX)
2146 statusWindow->on = False;
2147 #endif
2148
2149 AWT_UNLOCK();
2150 #endif
2151 }
2152
2153 JNIEXPORT void JNICALL
2154 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
2155 jobject this)
2156 {
2157 X11InputMethodData *pX11IMData = NULL;
2158
2159 AWT_LOCK();
2160 pX11IMData = getX11InputMethodData(env, this);
2161 if (pX11IMData == NULL) {
2162 AWT_UNLOCK();
2163 return;
2164 }
2165
2166 setX11InputMethodData(env, this, NULL);
2167
2172 destroyX11InputMethodData(env, pX11IMData);
2173 AWT_UNLOCK();
2174 }
2175
2176 JNIEXPORT jstring JNICALL
2177 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
2178 jobject this)
2179 {
2180 X11InputMethodData *pX11IMData;
2181 char *xText = NULL;
2182 jstring jText = (jstring)0;
2183
2184 AWT_LOCK();
2185 pX11IMData = getX11InputMethodData(env, this);
2186 if (pX11IMData == NULL) {
2187 AWT_UNLOCK();
2188 return jText;
2189 }
2190
2191 if (pX11IMData->current_ic)
2192 #if defined(AIX)
2193 {
2194 if (!isPreeditStateActive(pX11IMData->current_ic)) {
2195 xText = NULL;
2196 } else {
2197 if (!(pX11IMData->forceReset))
2198 setXICFocus(pX11IMData->current_ic, FALSE);
2199 #endif
2200 xText = XmbResetIC(pX11IMData->current_ic);
2201 #if defined(AIX)
2202 if (!(pX11IMData->forceReset))
2203 setXICFocus(pX11IMData->current_ic, TRUE);
2204 }
2205 }
2206 #endif
2207 else {
2208 /*
2209 * If there is no reference to the current XIC, try to reset both XICs.
2210 */
2211 #if defined(AIX)
2212 if (!isPreeditStateActive(pX11IMData->ic_active))
2213 xText = NULL;
2214 else
2215 #endif
2216 xText = XmbResetIC(pX11IMData->ic_active);
2217 /*it may also means that the real client component does
2218 not have focus -- has been deactivated... its xic should
2219 not have the focus, bug#4284651 showes reset XIC for htt
2220 may bring the focus back, so de-focus it again.
2221 */
2222 setXICFocus(pX11IMData->ic_active, FALSE);
2223 if (pX11IMData->ic_active != pX11IMData->ic_passive) {
2224 #if !defined(AIX)
2225 char *tmpText = XmbResetIC(pX11IMData->ic_passive);
2226 #else
2227 char *tmpText;
2228 if (!isPreeditStateActive(pX11IMData->ic_passive))
2229 tmpText = NULL;
2230 else
2231 tmpText = XmbResetIC(pX11IMData->ic_passive);
2232 #endif
2233 setXICFocus(pX11IMData->ic_passive, FALSE);
2234 if (xText == (char *)NULL && tmpText)
2235 xText = tmpText;
2236 }
2237
2238 }
2239 if (xText != NULL) {
2240 jText = JNU_NewStringPlatform(env, (const char *)xText);
2241 XFree((void *)xText);
2242 }
2243
2244 #if defined(AIX)
2245 /* workaround
2246 * Some IME do not call PreeditDoneCallback routine even
2247 * when XmbResetIC is called. I force to reset the preedit string.
2248 */
2249 if (!pX11IMData->isActiveClient) {
2250 resetPassivePreeditText(pX11IMData->statusWindow);
2251 shrink_status(pX11IMData->statusWindow);
2252 } else {
2253 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
2254 "clearComposedText",
2255 "()V");
2256 if ((*env)->ExceptionOccurred(env)) {
2257 (*env)->ExceptionDescribe(env);
2258 (*env)->ExceptionClear(env);
2259 }
2260 }
2261 #endif
2262
2263 AWT_UNLOCK();
2264 return jText;
2265 }
2266
2267 /*
2268 * Class: sun_awt_X11InputMethod
2269 * Method: setCompositionEnabledNative
2270 * Signature: (ZJ)V
2271 *
2272 * This method tries to set the XNPreeditState attribute associated with the current
2273 * XIC to the passed in 'enable' state.
2274 *
2275 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
2276 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
2277 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
2278 * method fails due to other reasons.
2279 *
2280 */
2281 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
2282 (JNIEnv *env, jobject this, jboolean enable)
2283 {
2284 X11InputMethodData *pX11IMData;
2285 char * ret = NULL;
2286 #if defined(AIX)
2287 XVaNestedList pr_atrb;
2288 #endif
2289
2290 AWT_LOCK();
2291 pX11IMData = getX11InputMethodData(env, this);
2292
2293 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
2294 AWT_UNLOCK();
2295 return JNI_FALSE;
2296 }
2297
2298 #if !defined(AIX)
2299 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
2300 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
2301 AWT_UNLOCK();
2302
2303 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
2304 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
2305 }
2306 #else
2307 pr_atrb = XVaCreateNestedList(0, XNPreeditState,
2308 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
2309 ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);
2310 XFree((void *)pr_atrb);
2311 AWT_UNLOCK();
2312
2313 if ((ret != 0) &&
2314 ((strcmp(ret, XNPreeditAttributes) == 0)
2315 || (strcmp(ret, XNPreeditState) == 0))) {
2316 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
2317 }
2318 #endif
2319
2320 return (jboolean)(ret == 0);
2321 }
2322
2323 /*
2324 * Class: sun_awt_X11InputMethod
2325 * Method: isCompositionEnabledNative
2326 * Signature: (J)Z
2327 *
2328 * This method tries to get the XNPreeditState attribute associated with the current XIC.
2329 *
2330 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
2331 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
2332 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
2333 *
2334 */
2335 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
2336 (JNIEnv *env, jobject this)
2337 {
2338 X11InputMethodData *pX11IMData = NULL;
2339 char * ret = NULL;
2340 #if !defined(AIX)
2341 XIMPreeditState state;
2342 #else
2343 XIMPreeditState state = XIMPreeditUnKnown;
2344 XVaNestedList pr_atrb;
2345 #endif
2346
2347 AWT_LOCK();
2348 pX11IMData = getX11InputMethodData(env, this);
2349
2350 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
2351 AWT_UNLOCK();
2352 return JNI_FALSE;
2353 }
2354
2355 #if !defined(AIX)
2356 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
2357 AWT_UNLOCK();
2358
2359 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
2360 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
2361 return JNI_FALSE;
2362 }
2363 #else
2364 pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL);
2365 ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL);
2366 XFree((void *)pr_atrb);
2367 AWT_UNLOCK();
2368
2369 if ((ret != 0) &&
2370 ((strcmp(ret, XNPreeditAttributes) == 0)
2371 || (strcmp(ret, XNPreeditState) == 0))) {
2372 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
2373 return JNI_FALSE;
2374 }
2375 #endif
2376
2377 return (jboolean)(state == XIMPreeditEnable);
2378 }
2379
2380 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
2381 (JNIEnv *env, jobject this, jlong window)
2382 {
2383 #if defined(__linux__) || defined(MACOSX)
2384 AWT_LOCK();
2385 adjustStatusWindow(window);
2386 AWT_UNLOCK();
2387 #endif
2388 }
2389 #if defined(AIX)
2390 /*
2391 * The following functions are IBM's enhancement.
2392 */
2393
2394 JNIEXPORT void JNICALL
2395 Java_sun_awt_X11InputMethod_setStatusAreaVisible(JNIEnv *env,
2396 jobject this,
2397 jboolean value,
2398 jlong data)
2399 {
2400 X11InputMethodData *pX11IMData;
2401
2402 pX11IMData = getX11InputMethodData(env, this);
2403 if (NULL == pX11IMData) return;
2404 if (NULL == pX11IMData->statusWindow) return;
2405
2406 if ((int)value){
2407 pX11IMData->statusWindow->on = True;
2408 }else{
2409 pX11IMData->statusWindow->on = False;
2410 }
2411 return;
2412 }
2413
2414 /* return the string length without trailing spaces */
2415 /* work around code for Japanese AIXIM is implemented. */
2416 static int st_wcslen(wchar_t *string)
2417 {
2418 int len = (int32_t)wcslen(string);
2419 if (len == 0)
2420 return 0;
2421 for (len--;len >= 0; len--) {
2422 if (!iswspace((wint_t) string[len])) break;
2423 }
2424 return len+1;
2425 }
2426
2427 /*
2428 * Checks whether given XIMText contains a string data.
2429 */
2430 static Bool is_text_available(XIMText * text)
2431 {
2432 if (text == NULL || text->length==0)
2433 return False;
2434 if (text->encoding_is_wchar) {
2435 if(text->string.wide_char[0] == L'\0')
2436 return False;
2437 } else {
2438 if (text->string.multi_byte[0] == '\0')
2439 return False;
2440 }
2441 return True;
2442 }
2443
2444 /*
2445 * check if preedit status is active
2446 */
2447 static Bool isPreeditStateActive(XIC ic)
2448 {
2449 XIMPreeditState state = XIMPreeditUnKnown;
2450 XVaNestedList pr_atrb;
2451 char* nosupportAttr;
2452
2453 if (ic == NULL) return False;
2454
2455 pr_atrb = XVaCreateNestedList(0,XNPreeditState,&state,NULL);
2456 nosupportAttr=XGetICValues(ic,XNPreeditAttributes,pr_atrb,NULL);
2457 XFree(pr_atrb);
2458 if (nosupportAttr==NULL && state & XIMPreeditDisable)
2459 return False;
2460 else
2461 return True;
2462 }
2463
2464 static void * buf_insert(void * src, void * insert, int size,
2465 int src_len, int ins_len, int offset)
2466 {
2467 char *temp;
2468
2469 temp = realloc(src, size*(src_len+ins_len+1));
2470 if (temp == NULL) {
2471 THROW_OUT_OF_MEMORY_ERROR();
2472 return src;
2473 }
2474 if (offset != src_len) {
2475 memmove(&temp[size*(offset+ins_len)],
2476 &((char *)temp)[size*offset],
2477 size*(src_len-offset));
2478 }
2479 memcpy(&temp[size*offset], insert, size*ins_len);
2480
2481 return (void *)temp;
2482 }
2483
2484 static void * handle_buffer(void * source, void * insert,
2485 int size,int src_len, int ins_len,
2486 int del_len, int offset)
2487 {
2488 void * temp = source;
2489
2490 if(del_len > 0) {
2491 if (del_len == ins_len) {
2492 memcpy(&((char *)source)[size*offset], insert, size*ins_len);
2493 return source;
2494 }
2495 else if (src_len > offset+del_len) {
2496 memmove(&((char *)source)[size*offset],
2497 &((char *)source)[size*(offset+del_len)],
2498 size*(src_len-offset-del_len));
2499 }
2500 }
2501 if(ins_len > 0) {
2502 temp = buf_insert(source, insert, size, src_len,
2503 ins_len, offset);
2504 }
2505 return temp;
2506 }
2507 /*
2508 * Display the given preedit text to the root window which is ownd by
2509 * myself. All of the character is converted to wide char.
2510 * this function is used for the passive client.
2511 */
2512 static void preedit_draw_passive(X11InputMethodData *pX11IMData,
2513 XIMPreeditDrawCallbackStruct *pre_draw)
2514 {
2515 XIMText *text;
2516 wchar_t *tempbuf = NULL;
2517 StatusWindow *statusWindow;
2518 wchar_t *cur_text;
2519 unsigned long *cur_attr;
2520 int cur_len = 0;
2521 int chg_len = pre_draw->chg_length;
2522 int chg_1st = pre_draw->chg_first;
2523
2524 if (NULL == (statusWindow = pX11IMData->statusWindow))
2525 return;
2526 cur_text = statusWindow->peText;
2527 cur_attr = statusWindow->peAttr;
2528 if (cur_text == NULL && pre_draw->text == NULL)
2529 return;
2530
2531 if (cur_text != NULL)
2532 cur_len = (int32_t)wcslen(cur_text);
2533 text = pre_draw->text;
2534 if (text == NULL) {
2535 /* delete only */
2536 if (cur_len > chg_1st+chg_len) {
2537 memmove(&cur_text[chg_1st],
2538 &cur_text[chg_1st+chg_len],
2539 sizeof(wchar_t)*(cur_len-chg_1st-chg_len));
2540 memmove(&cur_attr[chg_1st],
2541 &cur_attr[chg_1st+chg_len],
2542 sizeof(long)*(cur_len-chg_1st-chg_len));
2543 }
2544 if ((pre_draw->chg_length <= cur_len ) && (pre_draw->chg_length >0))
2545 cur_text[cur_len-pre_draw->chg_length] =L'\0';
2546 }
2547 else {
2548 /* insert or replace */
2549 int ins_len = 0;
2550 void * ins_text = NULL;
2551
2552 /* if invalid offset is specified, do nothing. */
2553 /* this fix is for aixim for eucTW */
2554 if (cur_len < chg_1st)
2555 return;
2556 if(is_text_available(text)) {
2557 /* insert or replace the text */
2558 if (text->encoding_is_wchar == False) {
2559 /* convert the text to wide chars.
2560 allocate enough size buffer
2561 */
2562 tempbuf = (wchar_t *)malloc(sizeof(wchar_t)*(text->length+1));
2563 if (tempbuf == NULL) {
2564 THROW_OUT_OF_MEMORY_ERROR();
2565 return;
2566 }
2567 ins_len = (int32_t)mbstowcs(tempbuf, text->string.multi_byte,
2568 text->length);
2569 if (ins_len == -1) {
2570 free(tempbuf);
2571 return;
2572 }
2573 ins_text = (void *)tempbuf;
2574 }
2575 else {
2576 ins_len = text->length;
2577 ins_text = text->string.wide_char;
2578 }
2579 /* finish prepare the data to be inserted */
2580
2581 statusWindow->peText =
2582 handle_buffer(cur_text, ins_text, sizeof(wchar_t),
2583 cur_len, ins_len, chg_len, chg_1st);
2584 statusWindow->peAttr =
2585 handle_buffer(cur_attr, text->feedback, sizeof(long),
2586 cur_len, ins_len, chg_len, chg_1st);
2587 statusWindow->peText[cur_len-chg_len+ins_len] =L'\0';
2588
2589 if (tempbuf != NULL)
2590 free(tempbuf);
2591 } /* endof insert or replace text */
2592 else {
2593 /* change attribute only */
2594 memcpy(&cur_attr[chg_1st], text->feedback,
2595 sizeof(long)*text->length);
2596 }
2597 }
2598 statusWindow->peCaret= pre_draw->caret;
2599 draw_preedit(statusWindow);
2600 if (statusWindow->on && wcslen(statusWindow->peText) > 0)
2601 onoffStatusWindow(pX11IMData, statusWindow->parent, True);
2602 else if (wcslen(statusWindow->status) == 0)
2603 onoffStatusWindow(pX11IMData, 0, False);
2604 }
2605
2606 /*
2607 * reset predit test of passive mode
2608 */
2609 static void
2610 resetPassivePreeditText(StatusWindow *statusWindow)
2611 {
2612 if (NULL == statusWindow) return;
2613 if(statusWindow->peText != NULL) {
2614 free(statusWindow->peText);
2615 statusWindow->peText = NULL;
2616 }
2617 if(statusWindow->peAttr != NULL) {
2618 free(statusWindow->peAttr);
2619 statusWindow->peAttr = NULL;
2620 }
2621 statusWindow->peCaret= 0;
2622 }
2623
2624 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos)
2625 {
2626 if (NULL == statusWindow) return;
2627 XSetFunction(dpy, gc, GXinvert);
2628 XDrawLine(dpy, statusWindow->w,
2629 gc, pos, STATUS_BORDER/2,
2630 pos, STATUS_BORDER/2+statusWindow->fOff);
2631 XSetFunction(dpy, gc, GXcopy);
2632 }
2633
2634 static int get_next_attr(int len, unsigned long *attr)
2635 {
2636 int count;
2637
2638 for (count = 1; count < len; count++) {
2639 if ((attr[count-1] & PREEDIT_ATTR_MASK)
2640 != (attr[count] & PREEDIT_ATTR_MASK))
2641 break;
2642 }
2643 return count;
2644 }
2645
2646 static void draw_preedit(StatusWindow *statusWindow)
2647 {
2648 unsigned long *attr;
2649 int x_pos,x_caret;
2650 unsigned int len;
2651 int len_disp, pos;
2652 wchar_t *str;
2653 GC gc;
2654 XRectangle ink, rect, rect_c;
2655 Bool caret_done = False;
2656
2657 if (NULL == statusWindow) return;
2658 align_status(statusWindow);
2659 XFillRectangle(dpy, statusWindow->w,
2660 statusWindow->bgGC,
2661 statusWindow->statusW,0,
2662 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,
2663 statusWindow->fBot+2);
2664
2665
2666 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
2667 statusWindow->statusW, 0,
2668 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0);
2669 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
2670 statusWindow->statusW, statusWindow->fBot+2,
2671 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,
2672 statusWindow->fBot+2);
2673 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
2674 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0,
2675 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN,
2676 statusWindow->fBot+2);
2677 if (0 == statusWindow->statusW)
2678 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC,
2679 0, 0, 0, statusWindow->fBot+2);
2680
2681 str = statusWindow->peText;
2682
2683 if (str != NULL && (len = (int32_t)wcslen(str)) != 0) {
2684 pos = 0;
2685 attr = statusWindow->peAttr;
2686 x_pos = x_caret = statusWindow->statusW + STATUS_BORDER;
2687 while((int)len-1 >= pos) {
2688 len_disp = get_next_attr(len - pos, &attr[pos]);
2689 if (attr[pos] & XIMReverse) {
2690 gc = statusWindow->bgGC;
2691 }
2692 else {
2693 gc = statusWindow->fgGC;
2694 }
2695 XwcTextExtents(statusWindow->fontset,
2696 &str[pos],
2697 len_disp, &ink, &rect);
2698 XwcDrawImageString(dpy, statusWindow->w,
2699 statusWindow->fontset, gc,
2700 x_pos, statusWindow->fOff+1, &str[pos], len_disp);
2701 if (attr[pos] & XIMUnderline) {
2702 XDrawLine(dpy, statusWindow->w,
2703 gc, x_pos, statusWindow->fBot,
2704 x_pos+rect.width, statusWindow->fBot);
2705 }
2706 if (!caret_done) {
2707 if( statusWindow->peCaret >= pos &&
2708 statusWindow->peCaret <= pos+len_disp) {
2709 if (statusWindow->peCaret == 0)
2710 x_caret = x_pos;
2711 else if (statusWindow->peCaret == pos+len_disp)
2712 x_caret = x_pos+rect.width;
2713 else {
2714 XwcTextExtents(statusWindow->fontset,
2715 &str[pos],
2716 statusWindow->peCaret-pos,
2717 &ink, &rect_c);
2718 x_caret = x_pos+ rect_c.width;
2719 }
2720 x_caret-=CARET_OFFSET;
2721 caret_done = True;
2722 }
2723 }
2724 pos += len_disp;
2725 x_pos += rect.width;
2726 }
2727 if (caret_done)
2728 draw_caret(statusWindow, statusWindow->fgGC, x_caret);
2729 }
2730 }
2731 /* calc requied status window size and resize the window */
2732 static void align_status(StatusWindow *statusWindow)
2733 {
2734 int len_st, len_pe = 0;
2735 XRectangle rect_st, rect_pe, ink;
2736 Dimension cur_w;
2737 int value_make = CWX|CWWidth|CWHeight;
2738 XWindowChanges xwc;
2739
2740 if (NULL == statusWindow) return;
2741 if ((len_st = st_wcslen(statusWindow->status)) == 0
2742 && (statusWindow->peText == NULL || st_wcslen(statusWindow->peText) == 0 ))
2743 return;
2744
2745 rect_pe.x = rect_pe.y = rect_pe.width = rect_pe.height = 0;
2746
2747 XwcTextExtents(statusWindow->fontset,
2748 statusWindow->status,
2749 len_st, &ink, &rect_st);
2750 if (statusWindow->peText != NULL
2751 && (len_pe = (int32_t)wcslen(statusWindow->peText)) > 0) {
2752 XwcTextExtents(statusWindow->fontset,
2753 statusWindow->peText,
2754 len_pe, &ink, &rect_pe);
2755 }
2756 statusWindow->fOff = max(-rect_st.y, -rect_pe.y);
2757 statusWindow->fBot = max(rect_st.height, rect_pe.height);
2758 statusWindow->statusW =rect_st.width;
2759 if (rect_st.width > 0) statusWindow->statusW += BORDER_MARGIN;
2760 statusWindow->peTextW = rect_pe.width;
2761
2762 xwc.x = statusWindow->x - statusWindow->off_x;
2763 if (xwc.x < 0 ) xwc.x = 0;
2764
2765 if (len_pe > 0) {
2766 xwc.width = statusWindow->statusW
2767 + statusWindow->peTextW + BORDER_MARGIN + 1;
2768 xwc.height = statusWindow->fBot + BORDER_MARGIN;
2769 } else {
2770 xwc.width = statusWindow->statusW;
2771 xwc.height = statusWindow->fBot + BORDER_MARGIN;
2772 }
2773 if (xwc.x + xwc.width > statusWindow->rootW){
2774 xwc.x = statusWindow->rootW - xwc.width;
2775 }
2776 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
2777 }
2778
2779 static void shrink_status(StatusWindow *statusWindow)
2780 {
2781 int value_make = CWX|CWWidth|CWHeight;
2782 XWindowChanges xwc;
2783
2784 if (NULL == statusWindow) return;
2785 xwc.width = statusWindow->statusW;
2786 xwc.height = statusWindow->statusH;
2787 statusWindow->peTextW = 0;
2788 xwc.x = statusWindow->x - statusWindow->off_x;
2789 if (xwc.x < 0 ) xwc.x = 0;
2790 if (xwc.x + xwc.width > statusWindow->rootW){
2791 xwc.x = statusWindow->rootW - xwc.width;
2792 }
2793 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
2794 }
2795
2796 static GC create_gc(Window win, Bool isReverse)
2797 {
2798 XGCValues xgcv;
2799 unsigned long mask;
2800 AwtScreenDataPtr defaultScreen;
2801
2802 defaultScreen = getScreenData(DefaultScreen(dpy));
2803
2804 mask = (GCForeground | GCBackground );
2805 if (isReverse) {
2806 xgcv.foreground = defaultScreen->whitepixel;
2807 xgcv.background = defaultScreen->blackpixel;
2808 }
2809 else {
2810 xgcv.foreground = defaultScreen->blackpixel;
2811 xgcv.background = defaultScreen->whitepixel;
2812 }
2813 return XCreateGC(dpy, win, mask, &xgcv);
2814 }
2815
2816 static Bool isNativeIm()
2817 {
2818 #define XIMMODIFIER "@im="
2819 #define XIM_SERVER_CATEGORY "@server="
2820 char *immodifiers;
2821 char *imserver, *imserverPtr;
2822 Atom imserverAtom;
2823
2824 if (!(immodifiers = getenv("XMODIFIERS"))) return True;
2825 if (!(imserver = calloc(1,strlen(immodifiers)+strlen(XIM_SERVER_CATEGORY)+1))) return True;
2826 if (!(immodifiers = strstr(immodifiers,XIMMODIFIER))) return True;
2827 immodifiers += strlen(XIMMODIFIER);
2828 strcpy(imserver,XIM_SERVER_CATEGORY);
2829 imserverPtr = imserver + strlen(imserver);
2830 while(*immodifiers != '@' && *immodifiers != '\0') {
2831 *imserverPtr = *immodifiers;
2832 imserverPtr++;
2833 immodifiers++;
2834 }
2835 imserverAtom = XInternAtom(awt_display, imserver, True);
2836 free(imserver);
2837 if (imserverAtom > 0)
2838 return False;
2839 else
2840 return True;
2841 }
2842
2843 static Window getGrandParent(Window parent)
2844 {
2845 Window containerWindow,rootWindow,tmp;
2846 Window *ignoreWindowPtr;
2847 unsigned int ignoreUnit;
2848 Window grandParent=0;
2849 XWindowAttributes xwa;
2850 Atom WM_STATE;
2851 Atom type = None;
2852 int32_t format;
2853 unsigned long nitems, after;
2854 unsigned char * data;
2855
2856 if (parent == 0) return grandParent;
2857 WM_STATE = XInternAtom(dpy, "WM_STATE", True);
2858 if (WM_STATE == None) return grandParent;
2859
2860 tmp=parent;
2861 while(XQueryTree(dpy, tmp,
2862 &rootWindow, &containerWindow,
2863 &ignoreWindowPtr, &ignoreUnit)){
2864 XFree(ignoreWindowPtr);
2865 if (containerWindow == rootWindow) break;
2866 if (XGetWindowProperty(dpy, containerWindow, WM_STATE,
2867 0, 0, False, AnyPropertyType,
2868 &type, &format, &nitems, &after, &data) == Success) {
2869 XFree(data);
2870 if (type) {
2871 XGetWindowAttributes(dpy, containerWindow, &xwa);
2872 if (FALSE == xwa.override_redirect){
2873 grandParent=containerWindow;
2874 }
2875 }
2876 }
2877 tmp=containerWindow;
2878 }
2879 return grandParent;
2880 }
2881
2882 static void moveStatusWindow(StatusWindow *statusWindow)
2883 {
2884 XWindowAttributes xwa;
2885 Window child;
2886 int x, y, width;
2887 Window target;
2888
2889 if (NULL == statusWindow) return;
2890 if (statusWindow->grandParent){
2891 target = statusWindow->grandParent;
2892 }else{
2893 target = statusWindow->parent;
2894 }
2895 XGetWindowAttributes(dpy, target, &xwa);
2896 XTranslateCoordinates(dpy,
2897 target, xwa.root,
2898 0, 0,
2899 &x, &y,
2900 &child);
2901 if (statusWindow->x != x
2902 || statusWindow->y != y
2903 || statusWindow->width != xwa.width
2904 || statusWindow->height != xwa.height){
2905 statusWindow->x = x;
2906 statusWindow->y = y;
2907 statusWindow->height = xwa.height;
2908 statusWindow->width = xwa.width;
2909 x = statusWindow->x - statusWindow->off_x;
2910 y = statusWindow->y + statusWindow->height + statusWindow->off_y;
2911 if (x < 0 ){
2912 x = 0;
2913 }
2914 if (statusWindow->peTextW > 0) {
2915 width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1;
2916 if (x + width > statusWindow->rootW){
2917 x = statusWindow->rootW - width;
2918 }
2919 } else {
2920 if (x + statusWindow->statusW > statusWindow->rootW){
2921 x = statusWindow->rootW - statusWindow->statusW;
2922 }
2923 }
2924 if (y + statusWindow->statusH > statusWindow->rootH){
2925 y = statusWindow->rootH - statusWindow->statusH;
2926 }
2927 XMoveWindow(dpy, statusWindow->w, x, y);
2928 }
2929 }
2930
2931 static void arrange_window_stack(StatusWindow* statusWindow)
2932 {
2933 XWindowChanges xwc;
2934 int value_make = CWSibling|CWStackMode;
2935 Window root, parent, *children;
2936 unsigned int nchildren;
2937
2938 if (NULL == statusWindow) return;
2939 if (XQueryTree(dpy, statusWindow->parent,
2940 &root, &parent, &children, &nchildren)){
2941 XFree(children);
2942 xwc.sibling = parent;
2943 while(XQueryTree(dpy, xwc.sibling, &root, &parent, &children, &nchildren)) {
2944 XFree(children);
2945 if (root != parent) {
2946 xwc.sibling = parent;
2947 } else {
2948 break;
2949 }
2950 }
2951 xwc.stack_mode = Above;
2952 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
2953 }
2954 }
2955
2956 static int count_missing_fonts(char **charset_list, int charset_count)
2957 {
2958 int i,j;
2959 if (charset_count > 0) {
2960 j=charset_count;
2961 for(i=0; i < charset_count; i++) {
2962 if ((strstr(charset_list[i], "IBM-udc")) ||
2963 (strstr(charset_list[i], "IBM-sbd")) ||
2964 (strstr(charset_list[i], "IBM-ucdTW")))
2965 j--;
2966 }
2967 return j;
2968 }
2969 else
2970 return 0;
2971 }
2972
2973 static XFontSet create_fontset_name(char * font_name, Bool force)
2974 {
2975 XFontSet fontset = NULL;
2976 char **charset_list;
2977 int charset_count;
2978 char *def_string;
2979 int missing_fonts;
2980
2981 fontset = XCreateFontSet(dpy, font_name,
2982 &charset_list, &charset_count, &def_string);
2983 if (charset_count > 0) {
2984 missing_fonts = count_missing_fonts(charset_list,
2985 charset_count);
2986 XFreeStringList(charset_list);
2987 if (fontset && (missing_fonts > 0)) {
2988 if (!force) {
2989 XFreeFontSet(dpy, fontset);
2990 fontset = NULL;
2991 }
2992 }
2993 }
2994 return fontset;
2995 }
2996
2997 static XFontSet create_fontset()
2998 {
2999 XFontSet fontset = NULL;
3000 int i;
3001 static char * fontlist[] = {
3002 "-dt-interface user-medium-r-normal-S*-*-*-*-*-*-*-*-*",
3003 "-*-*-medium-r-normal-*-14-*-*-*-c-*-*-*",
3004 "-*-*-medium-r-normal-*-14-*-*-*-m-*-*-*",
3005 "-*-*-medium-r-normal--14-0-0-0-m-*-*-*",
3006 "-monotype-sansmonowt-medium-r-normal--14-*-*-*-m-*-*-*",
3007 "-*--14-*",
3008 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*",
3009 "-*--16-*",
3010 "-*--17-*",
3011 "-*--18-*",
3012 "-*--19-*",
3013 "-*--20-*",
3014 "-*--24-*",
3015 NULL};
3016
3017 for (i=0; fontlist[i] != NULL && fontset==NULL; i++)
3018 fontset = create_fontset_name(fontlist[i], False);
3019
3020 if (!fontset)
3021 fprintf(stdout, "Cannot load fonts for IMF.\n");
3022 return fontset;
3023 }
3024
3025 static Window get_current_focus(XIC ic)
3026 {
3027 Window w = 0;
3028 if (ic != NULL)
3029 XGetICValues(ic, XNFocusWindow, &w, NULL);
3030 return w;
3031 }
3032 #endif
|