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