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