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