1 /*
   2  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #ifdef HEADLESS
  27     #error This file should not be included in headless library
  28 #endif
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <X11/Xlib.h>
  33 #include <sys/time.h>
  34 
  35 #include "awt.h"
  36 #include "awt_p.h"
  37 
  38 #include <sun_awt_X11InputMethod.h>
  39 #include <sun_awt_X11_XComponentPeer.h>
  40 #include <sun_awt_X11_XInputMethod.h>
  41 
  42 #define THROW_OUT_OF_MEMORY_ERROR() \
  43         JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL)
  44 #define SETARG(name, value)     XtSetArg(args[argc], name, value); argc++
  45 
  46 struct X11InputMethodIDs {
  47   jfieldID pData;
  48 } x11InputMethodIDs;
  49 
  50 static void PreeditStartCallback(XIC, XPointer, XPointer);
  51 static void PreeditDoneCallback(XIC, XPointer, XPointer);
  52 static void PreeditDrawCallback(XIC, XPointer,
  53                                 XIMPreeditDrawCallbackStruct *);
  54 static void PreeditCaretCallback(XIC, XPointer,
  55                                  XIMPreeditCaretCallbackStruct *);
  56 #if defined(__linux__) || defined(MACOSX)
  57 static void StatusStartCallback(XIC, XPointer, XPointer);
  58 static void StatusDoneCallback(XIC, XPointer, XPointer);
  59 static void StatusDrawCallback(XIC, XPointer,
  60                                XIMStatusDrawCallbackStruct *);
  61 #endif
  62 
  63 #define ROOT_WINDOW_STYLES      (XIMPreeditNothing | XIMStatusNothing)
  64 #define NO_STYLES               (XIMPreeditNone | XIMStatusNone)
  65 
  66 #define PreeditStartIndex       0
  67 #define PreeditDoneIndex        1
  68 #define PreeditDrawIndex        2
  69 #define PreeditCaretIndex       3
  70 #if defined(__linux__) || defined(MACOSX)
  71 #define StatusStartIndex        4
  72 #define StatusDoneIndex         5
  73 #define StatusDrawIndex         6
  74 #define NCALLBACKS              7
  75 #else
  76 #define NCALLBACKS              4
  77 #endif
  78 
  79 /*
  80  * Callback function pointers: the order has to match the *Index
  81  * values above.
  82  */
  83 static XIMProc callback_funcs[NCALLBACKS] = {
  84     (XIMProc)PreeditStartCallback,
  85     (XIMProc)PreeditDoneCallback,
  86     (XIMProc)PreeditDrawCallback,
  87     (XIMProc)PreeditCaretCallback,
  88 #if defined(__linux__) || defined(MACOSX)
  89     (XIMProc)StatusStartCallback,
  90     (XIMProc)StatusDoneCallback,
  91     (XIMProc)StatusDrawCallback,
  92 #endif
  93 };
  94 
  95 #if defined(__linux__) || defined(MACOSX)
  96 #define MAX_STATUS_LEN  100
  97 typedef struct {
  98     Window   w;                /*status window id        */
  99     Window   root;             /*the root window id      */
 100     Window   parent;           /*parent shell window     */
 101     int      x, y;             /*parent's upperleft position */
 102     int      width, height;    /*parent's width, height  */
 103     GC       lightGC;          /*gc for light border     */
 104     GC       dimGC;            /*gc for dim border       */
 105     GC       bgGC;             /*normal painting         */
 106     GC       fgGC;             /*normal painting         */
 107     int      statusW, statusH; /*status window's w, h    */
 108     int      rootW, rootH;     /*root window's w, h    */
 109     int      bWidth;           /*border width            */
 110     char     status[MAX_STATUS_LEN]; /*status text       */
 111     XFontSet fontset;           /*fontset for drawing    */
 112     int      off_x, off_y;
 113     Bool     on;                /*if the status window on*/
 114 } StatusWindow;
 115 #endif
 116 
 117 /*
 118  * X11InputMethodData keeps per X11InputMethod instance information. A pointer
 119  * to this data structure is kept in an X11InputMethod object (pData).
 120  */
 121 typedef struct _X11InputMethodData {
 122     XIC         current_ic;     /* current X Input Context */
 123     XIC         ic_active;      /* X Input Context for active clients */
 124     XIC         ic_passive;     /* X Input Context for passive clients */
 125     XIMCallback *callbacks;     /* callback parameters */
 126     jobject     x11inputmethod; /* global ref to X11InputMethod instance */
 127                                 /* associated with the XIC */
 128 #if defined(__linux__) || defined(MACOSX)
 129     StatusWindow *statusWindow; /* our own status window  */
 130 #endif
 131     char        *lookup_buf;    /* buffer used for XmbLookupString */
 132     int         lookup_buf_len; /* lookup buffer size in bytes */
 133 } X11InputMethodData;
 134 
 135 /*
 136  * When XIC is created, a global reference is created for
 137  * sun.awt.X11InputMethod object so that it could be used by the XIM callback
 138  * functions. This could be a dangerous thing to do when the original
 139  * X11InputMethod object is garbage collected and as a result,
 140  * destroyX11InputMethodData is called to delete the global reference.
 141  * If any XIM callback function still holds and uses the "already deleted"
 142  * global reference, disaster is going to happen. So we have to maintain
 143  * a list for these global references which is consulted first when the
 144  * callback functions or any function tries to use "currentX11InputMethodObject"
 145  * which always refers to the global reference try to use it.
 146  *
 147  */
 148 typedef struct _X11InputMethodGRefNode {
 149     jobject inputMethodGRef;
 150     struct _X11InputMethodGRefNode* next;
 151 } X11InputMethodGRefNode;
 152 
 153 X11InputMethodGRefNode *x11InputMethodGRefListHead = NULL;
 154 
 155 /* reference to the current X11InputMethod instance, it is always
 156    point to the global reference to the X11InputMethodObject since
 157    it could be referenced by different threads. */
 158 jobject currentX11InputMethodInstance = NULL;
 159 
 160 Window  currentFocusWindow = 0;  /* current window that has focus for input
 161                                        method. (the best place to put this
 162                                        information should be
 163                                        currentX11InputMethodInstance's pData) */
 164 static XIM X11im = NULL;
 165 Display * dpy = NULL;
 166 
 167 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)
 168 
 169 static void DestroyXIMCallback(XIM, XPointer, XPointer);
 170 static void OpenXIMCallback(Display *, XPointer, XPointer);
 171 /* Solaris XIM Extention */
 172 #define XNCommitStringCallback "commitStringCallback"
 173 static void CommitStringCallback(XIC, XPointer, XPointer);
 174 
 175 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject);
 176 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *);
 177 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *);
 178 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *);
 179 
 180 #ifdef __solaris__
 181 /* Prototype for this function is missing in Solaris X11R6 Xlib.h */
 182 extern char *XSetIMValues(
 183 #if NeedVarargsPrototypes
 184     XIM /* im */, ...
 185 #endif
 186 );
 187 #endif
 188 
 189 #ifdef XAWT_HACK
 190 /*
 191  * This function is stolen from /src/solaris/hpi/src/system_md.c
 192  * It is used in setting the time in Java-level InputEvents
 193  */
 194 jlong
 195 awt_util_nowMillisUTC()
 196 {
 197     struct timeval t;
 198     gettimeofday(&t, NULL);
 199     return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
 200 }
 201 #endif /* XAWT_HACK */
 202 
 203 /*
 204  * Converts the wchar_t string to a multi-byte string calling wcstombs(). A
 205  * buffer is allocated by malloc() to store the multi-byte string. NULL is
 206  * returned if the given wchar_t string pointer is NULL or buffer allocation is
 207  * failed.
 208  */
 209 static char *
 210 wcstombsdmp(wchar_t *wcs, int len)
 211 {
 212     size_t n;
 213     char *mbs;
 214 
 215     if (wcs == NULL)
 216         return NULL;
 217 
 218     n = len*MB_CUR_MAX + 1;
 219 
 220     mbs = (char *) malloc(n * sizeof(char));
 221     if (mbs == NULL) {
 222         THROW_OUT_OF_MEMORY_ERROR();
 223         return NULL;
 224     }
 225 
 226     /* TODO: check return values... Handle invalid characters properly...  */
 227     if (wcstombs(mbs, wcs, n) == (size_t)-1)
 228         return NULL;
 229 
 230     return mbs;
 231 }
 232 
 233 /*
 234  * Returns True if the global reference is still in the list,
 235  * otherwise False.
 236  */
 237 static Bool isX11InputMethodGRefInList(jobject imGRef) {
 238     X11InputMethodGRefNode *pX11InputMethodGRef = x11InputMethodGRefListHead;
 239 
 240     if (imGRef == NULL) {
 241         return False;
 242     }
 243 
 244     while (pX11InputMethodGRef != NULL) {
 245         if (pX11InputMethodGRef->inputMethodGRef == imGRef) {
 246             return True;
 247         }
 248         pX11InputMethodGRef = pX11InputMethodGRef->next;
 249     }
 250 
 251     return False;
 252 }
 253 
 254 /*
 255  * Add the new created global reference to the list.
 256  */
 257 static void addToX11InputMethodGRefList(jobject newX11InputMethodGRef) {
 258     X11InputMethodGRefNode *newNode = NULL;
 259 
 260     if (newX11InputMethodGRef == NULL ||
 261         isX11InputMethodGRefInList(newX11InputMethodGRef)) {
 262         return;
 263     }
 264 
 265     newNode = (X11InputMethodGRefNode *)malloc(sizeof(X11InputMethodGRefNode));
 266 
 267     if (newNode == NULL) {
 268         return;
 269     } else {
 270         newNode->inputMethodGRef = newX11InputMethodGRef;
 271         newNode->next = x11InputMethodGRefListHead;
 272         x11InputMethodGRefListHead = newNode;
 273     }
 274 }
 275 
 276 /*
 277  * Remove the global reference from the list.
 278  */
 279 static void removeX11InputMethodGRefFromList(jobject x11InputMethodGRef) {
 280      X11InputMethodGRefNode *pX11InputMethodGRef = NULL;
 281      X11InputMethodGRefNode *cX11InputMethodGRef = x11InputMethodGRefListHead;
 282 
 283      if (x11InputMethodGRefListHead == NULL ||
 284          x11InputMethodGRef == NULL) {
 285          return;
 286      }
 287 
 288      /* cX11InputMethodGRef always refers to the current node while
 289         pX11InputMethodGRef refers to the previous node.
 290      */
 291      while (cX11InputMethodGRef != NULL) {
 292          if (cX11InputMethodGRef->inputMethodGRef == x11InputMethodGRef) {
 293              break;
 294          }
 295          pX11InputMethodGRef = cX11InputMethodGRef;
 296          cX11InputMethodGRef = cX11InputMethodGRef->next;
 297      }
 298 
 299      if (cX11InputMethodGRef == NULL) {
 300          return; /* Not found. */
 301      }
 302 
 303      if (cX11InputMethodGRef == x11InputMethodGRefListHead) {
 304          x11InputMethodGRefListHead = x11InputMethodGRefListHead->next;
 305      } else {
 306          pX11InputMethodGRef->next = cX11InputMethodGRef->next;
 307      }
 308      free(cX11InputMethodGRef);
 309 
 310      return;
 311 }
 312 
 313 
 314 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) {
 315     X11InputMethodData *pX11IMData =
 316         (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData);
 317 
 318     /*
 319      * In case the XIM server was killed somehow, reset X11InputMethodData.
 320      */
 321     if (X11im == NULL && pX11IMData != NULL) {
 322         JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
 323                              "flushText",
 324                              "()V");
 325         /* IMPORTANT:
 326            The order of the following calls is critical since "imInstance" may
 327            point to the global reference itself, if "freeX11InputMethodData" is called
 328            first, the global reference will be destroyed and "setX11InputMethodData"
 329            will in fact fail silently. So pX11IMData will not be set to NULL.
 330            This could make the original java object refers to a deleted pX11IMData
 331            object.
 332         */
 333         setX11InputMethodData(env, imInstance, NULL);
 334         freeX11InputMethodData(env, pX11IMData);
 335         pX11IMData = NULL;
 336     }
 337 
 338     return pX11IMData;
 339 }
 340 
 341 static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) {
 342     JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData);
 343 }
 344 
 345 /* this function should be called within AWT_LOCK() */
 346 static void
 347 destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
 348 {
 349     /*
 350      * Destroy XICs
 351      */
 352     if (pX11IMData == NULL) {
 353         return;
 354     }
 355 
 356     if (pX11IMData->ic_active != (XIC)0) {
 357         XUnsetICFocus(pX11IMData->ic_active);
 358         XDestroyIC(pX11IMData->ic_active);
 359         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
 360             if (pX11IMData->ic_passive != (XIC)0) {
 361                 XUnsetICFocus(pX11IMData->ic_passive);
 362                 XDestroyIC(pX11IMData->ic_passive);
 363             }
 364             pX11IMData->ic_passive = (XIC)0;
 365             pX11IMData->current_ic = (XIC)0;
 366         }
 367     }
 368 
 369     freeX11InputMethodData(env, pX11IMData);
 370 }
 371 
 372 static void
 373 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData)
 374 {
 375 #if defined(__linux__) || defined(MACOSX)
 376     if (pX11IMData->statusWindow != NULL){
 377         StatusWindow *sw = pX11IMData->statusWindow;
 378         XFreeGC(awt_display, sw->lightGC);
 379         XFreeGC(awt_display, sw->dimGC);
 380         XFreeGC(awt_display, sw->bgGC);
 381         XFreeGC(awt_display, sw->fgGC);
 382         if (sw->fontset != NULL) {
 383             XFreeFontSet(awt_display, sw->fontset);
 384         }
 385         XDestroyWindow(awt_display, sw->w);
 386         free((void*)sw);
 387     }
 388 #endif
 389 
 390     if (pX11IMData->callbacks)
 391         free((void *)pX11IMData->callbacks);
 392 
 393     if (env) {
 394         /* Remove the global reference from the list, so that
 395            the callback function or whoever refers to it could know.
 396         */
 397         removeX11InputMethodGRefFromList(pX11IMData->x11inputmethod);
 398         (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod);
 399     }
 400 
 401     if (pX11IMData->lookup_buf) {
 402         free((void *)pX11IMData->lookup_buf);
 403     }
 404 
 405     free((void *)pX11IMData);
 406 }
 407 
 408 /*
 409  * Sets or unsets the focus to the given XIC.
 410  */
 411 static void
 412 setXICFocus(XIC ic, unsigned short req)
 413 {
 414     if (ic == NULL) {
 415         (void)fprintf(stderr, "Couldn't find X Input Context\n");
 416         return;
 417     }
 418     if (req == 1)
 419         XSetICFocus(ic);
 420     else
 421         XUnsetICFocus(ic);
 422 }
 423 
 424 /*
 425  * Sets the focus window to the given XIC.
 426  */
 427 static void
 428 setXICWindowFocus(XIC ic, Window w)
 429 {
 430     if (ic == NULL) {
 431         (void)fprintf(stderr, "Couldn't find X Input Context\n");
 432         return;
 433     }
 434     (void) XSetICValues(ic, XNFocusWindow, w, NULL);
 435 }
 436 
 437 /*
 438  * Invokes XmbLookupString() to get something from the XIM. It invokes
 439  * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns
 440  * committed text.  This function is called from handleKeyEvent in canvas.c and
 441  * it's under the Motif event loop thread context.
 442  *
 443  * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation,
 444  * where it never returns XBufferOverflow.  We need to allocate the initial lookup buffer
 445  * big enough, so that the possibility that user encounters this problem is relatively
 446  * small.  When this bug gets fixed, we can make the initial buffer size smaller.
 447  * Note that XmbLookupString() sometimes produces a non-null-terminated string.
 448  *
 449  * Returns True when there is a keysym value to be handled.
 450  */
 451 #define INITIAL_LOOKUP_BUF_SIZE 512
 452 
 453 Bool
 454 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp)
 455 {
 456     JNIEnv *env = GetJNIEnv();
 457     X11InputMethodData *pX11IMData = NULL;
 458     KeySym keysym = NoSymbol;
 459     Status status;
 460     int mblen;
 461     jstring javastr;
 462     XIC ic;
 463     Bool result = True;
 464     static Bool composing = False;
 465 
 466     /*
 467       printf("lookupString: entering...\n");
 468      */
 469 
 470     if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
 471         currentX11InputMethodInstance = NULL;
 472         return False;
 473     }
 474 
 475     pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
 476 
 477     if (pX11IMData == NULL) {
 478 #if defined(__linux__) || defined(MACOSX)
 479         return False;
 480 #else
 481         return result;
 482 #endif
 483     }
 484 
 485     if ((ic = pX11IMData->current_ic) == (XIC)0){
 486 #if defined(__linux__) || defined(MACOSX)
 487         return False;
 488 #else
 489         return result;
 490 #endif
 491     }
 492 
 493     /* allocate the lookup buffer at the first invocation */
 494     if (pX11IMData->lookup_buf_len == 0) {
 495         pX11IMData->lookup_buf = (char *)malloc(INITIAL_LOOKUP_BUF_SIZE);
 496         if (pX11IMData->lookup_buf == NULL) {
 497             THROW_OUT_OF_MEMORY_ERROR();
 498             return result;
 499         }
 500         pX11IMData->lookup_buf_len = INITIAL_LOOKUP_BUF_SIZE;
 501     }
 502 
 503     mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
 504                             pX11IMData->lookup_buf_len - 1, &keysym, &status);
 505 
 506     /*
 507      * In case of overflow, a buffer is allocated and it retries
 508      * XmbLookupString().
 509      */
 510     if (status == XBufferOverflow) {
 511         free((void *)pX11IMData->lookup_buf);
 512         pX11IMData->lookup_buf_len = 0;
 513         pX11IMData->lookup_buf = (char *)malloc(mblen + 1);
 514         if (pX11IMData->lookup_buf == NULL) {
 515             THROW_OUT_OF_MEMORY_ERROR();
 516             return result;
 517         }
 518         pX11IMData->lookup_buf_len = mblen + 1;
 519         mblen = XmbLookupString(ic, event, pX11IMData->lookup_buf,
 520                             pX11IMData->lookup_buf_len - 1, &keysym, &status);
 521     }
 522     pX11IMData->lookup_buf[mblen] = 0;
 523 
 524     /* Get keysym without taking modifiers into account first to map
 525      * to AWT keyCode table.
 526      */
 527     switch (status) {
 528     case XLookupBoth:
 529         if (!composing) {
 530             if (event->keycode != 0) {
 531                 *keysymp = keysym;
 532                 result = False;
 533                 break;
 534             }
 535         }
 536         composing = False;
 537         /*FALLTHRU*/
 538     case XLookupChars:
 539     /*
 540      printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n",
 541        event->type, event->state, event->keycode, keysym);
 542     */
 543         javastr = JNU_NewStringPlatform(env, (const char *)pX11IMData->lookup_buf);
 544         if (javastr != NULL) {
 545             JNU_CallMethodByName(env, NULL,
 546                                  currentX11InputMethodInstance,
 547                                  "dispatchCommittedText",
 548                                  "(Ljava/lang/String;J)V",
 549                                  javastr,
 550 #ifndef XAWT_HACK
 551                                  awt_util_nowMillisUTC_offset(event->time));
 552 #else
 553                                  event->time);
 554 #endif
 555         }
 556         break;
 557 
 558     case XLookupKeySym:
 559     /*
 560      printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n",
 561        event->type, event->state, event->keycode, keysym);
 562     */
 563         if (keysym == XK_Multi_key)
 564             composing = True;
 565         if (! composing) {
 566             *keysymp = keysym;
 567             result = False;
 568         }
 569         break;
 570 
 571     case XLookupNone:
 572     /*
 573      printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n",
 574         event->type, event->state, event->keycode, keysym);
 575     */
 576         break;
 577     }
 578 
 579     return result;
 580 }
 581 
 582 #if defined(__linux__) || defined(MACOSX)
 583 static StatusWindow *createStatusWindow(
 584                                 Window parent) {
 585     StatusWindow *statusWindow;
 586     XSetWindowAttributes attrib;
 587     unsigned long attribmask;
 588     Window containerWindow;
 589     Window status;
 590     Window child;
 591     XWindowAttributes xwa;
 592     XWindowAttributes xxwa;
 593     /* Variable for XCreateFontSet()*/
 594     char **mclr;
 595     int  mccr = 0;
 596     char *dsr;
 597     Pixel bg, fg, light, dim;
 598     int x, y, off_x, off_y, xx, yy;
 599     unsigned int w, h, bw, depth;
 600     XGCValues values;
 601     unsigned long valuemask = 0;  /*ignore XGCvalue and use defaults*/
 602     int screen = 0;
 603     int i;
 604     AwtGraphicsConfigDataPtr adata;
 605     extern int awt_numScreens;
 606     /*hardcode the size right now, should get the size base on font*/
 607     int   width=80, height=22;
 608     Window rootWindow;
 609     Window *ignoreWindowPtr;
 610     unsigned int ignoreUnit;
 611 
 612     XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
 613 
 614     attrib.override_redirect = True;
 615     attribmask = CWOverrideRedirect;
 616     for (i = 0; i < awt_numScreens; i++) {
 617         if (RootWindow(dpy, i) == rootWindow) {
 618             screen = i;
 619             break;
 620         }
 621     }
 622     adata = getDefaultConfig(screen);
 623     bg    = adata->AwtColorMatch(255, 255, 255, adata);
 624     fg    = adata->AwtColorMatch(0, 0, 0, adata);
 625     light = adata->AwtColorMatch(195, 195, 195, adata);
 626     dim   = adata->AwtColorMatch(128, 128, 128, adata);
 627 
 628     XGetWindowAttributes(dpy, parent, &xwa);
 629     bw = 2; /*xwa.border_width does not have the correct value*/
 630 
 631     /*compare the size difference between parent container
 632       and shell widget, the diff should be the border frame
 633       and title bar height (?)*/
 634 
 635     XQueryTree( dpy,
 636                 parent,
 637                 &rootWindow,
 638                 &containerWindow,
 639                 &ignoreWindowPtr,
 640                 &ignoreUnit);
 641     XGetWindowAttributes(dpy, containerWindow, &xxwa);
 642 
 643     off_x = (xxwa.width - xwa.width) / 2;
 644     off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
 645 
 646     /*get the size of root window*/
 647     XGetWindowAttributes(dpy, rootWindow, &xxwa);
 648 
 649     XTranslateCoordinates(dpy,
 650                           parent, xwa.root,
 651                           xwa.x, xwa.y,
 652                           &x, &y,
 653                           &child);
 654     xx = x - off_x;
 655     yy = y + xwa.height - off_y;
 656     if (xx < 0 ){
 657         xx = 0;
 658     }
 659     if (xx + width > xxwa.width){
 660         xx = xxwa.width - width;
 661     }
 662     if (yy + height > xxwa.height){
 663         yy = xxwa.height - height;
 664     }
 665 
 666     status =  XCreateWindow(dpy,
 667                             xwa.root,
 668                             xx, yy,
 669                             width, height,
 670                             0,
 671                             xwa.depth,
 672                             InputOutput,
 673                             adata->awt_visInfo.visual,
 674                             attribmask, &attrib);
 675     XSelectInput(dpy, status,
 676                  ExposureMask | StructureNotifyMask | EnterWindowMask |
 677                  LeaveWindowMask | VisibilityChangeMask);
 678     statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
 679     if (statusWindow == NULL){
 680         THROW_OUT_OF_MEMORY_ERROR();
 681         return NULL;
 682     }
 683     statusWindow->w = status;
 684     //12-point font
 685     statusWindow->fontset = XCreateFontSet(dpy,
 686                                            "-*-*-medium-r-normal-*-*-120-*-*-*-*",
 687                                            &mclr, &mccr, &dsr);
 688     /* In case we didn't find the font set, release the list of missing characters */
 689     if (mccr > 0) {
 690         XFreeStringList(mclr);
 691     }
 692     statusWindow->parent = parent;
 693     statusWindow->on  = False;
 694     statusWindow->x = x;
 695     statusWindow->y = y;
 696     statusWindow->width = xwa.width;
 697     statusWindow->height = xwa.height;
 698     statusWindow->off_x = off_x;
 699     statusWindow->off_y = off_y;
 700     statusWindow->bWidth  = bw;
 701     statusWindow->statusH = height;
 702     statusWindow->statusW = width;
 703     statusWindow->rootH = xxwa.height;
 704     statusWindow->rootW = xxwa.width;
 705     statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
 706     XSetForeground(dpy, statusWindow->lightGC, light);
 707     statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
 708     XSetForeground(dpy, statusWindow->dimGC, dim);
 709     statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);
 710     XSetForeground(dpy, statusWindow->fgGC, fg);
 711     statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
 712     XSetForeground(dpy, statusWindow->bgGC, bg);
 713     return statusWindow;
 714 }
 715 
 716 /* This method is to turn off or turn on the status window. */
 717 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
 718                                 Window parent,
 719                                 Bool ON){
 720     XWindowAttributes xwa;
 721     Window child;
 722     int x, y;
 723     StatusWindow *statusWindow = NULL;
 724 
 725     if (NULL == currentX11InputMethodInstance ||
 726         NULL == pX11IMData ||
 727         NULL == (statusWindow =  pX11IMData->statusWindow)){
 728         return;
 729     }
 730 
 731     if (ON == False){
 732         XUnmapWindow(dpy, statusWindow->w);
 733         statusWindow->on = False;
 734         return;
 735     }
 736     parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
 737                                   "getCurrentParentWindow",
 738                                   "()J").j;
 739     if (statusWindow->parent != parent){
 740         statusWindow->parent = parent;
 741     }
 742     XGetWindowAttributes(dpy, parent, &xwa);
 743     XTranslateCoordinates(dpy,
 744                           parent, xwa.root,
 745                           xwa.x, xwa.y,
 746                           &x, &y,
 747                           &child);
 748     if (statusWindow->x != x
 749         || statusWindow->y != y
 750         || statusWindow->height != xwa.height){
 751         statusWindow->x = x;
 752         statusWindow->y = y;
 753         statusWindow->height = xwa.height;
 754         x = statusWindow->x - statusWindow->off_x;
 755         y = statusWindow->y + statusWindow->height - statusWindow->off_y;
 756         if (x < 0 ){
 757             x = 0;
 758         }
 759         if (x + statusWindow->statusW > statusWindow->rootW){
 760             x = statusWindow->rootW - statusWindow->statusW;
 761         }
 762         if (y + statusWindow->statusH > statusWindow->rootH){
 763             y = statusWindow->rootH - statusWindow->statusH;
 764         }
 765         XMoveWindow(dpy, statusWindow->w, x, y);
 766     }
 767     statusWindow->on = True;
 768     XMapWindow(dpy, statusWindow->w);
 769 }
 770 
 771 void paintStatusWindow(StatusWindow *statusWindow){
 772     Window  win  = statusWindow->w;
 773     GC  lightgc = statusWindow->lightGC;
 774     GC  dimgc = statusWindow->dimGC;
 775     GC  bggc = statusWindow->bgGC;
 776     GC  fggc = statusWindow->fgGC;
 777 
 778     int width = statusWindow->statusW;
 779     int height = statusWindow->statusH;
 780     int bwidth = statusWindow->bWidth;
 781     XFillRectangle(dpy, win, bggc, 0, 0, width, height);
 782     /* draw border */
 783     XDrawLine(dpy, win, fggc, 0, 0, width, 0);
 784     XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
 785     XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
 786     XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
 787 
 788     XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
 789     XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
 790     XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
 791     XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
 792 
 793     XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
 794     XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
 795     XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
 796     XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
 797     if (statusWindow->fontset){
 798         XmbDrawString(dpy, win, statusWindow->fontset, fggc,
 799                       bwidth + 2, height - bwidth - 4,
 800                       statusWindow->status,
 801                       strlen(statusWindow->status));
 802     }
 803     else{
 804         /*too bad we failed to create a fontset for this locale*/
 805         XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
 806                     "[InputMethod ON]", strlen("[InputMethod ON]"));
 807     }
 808 }
 809 
 810 void statusWindowEventHandler(XEvent event){
 811     JNIEnv *env = GetJNIEnv();
 812     X11InputMethodData *pX11IMData = NULL;
 813     StatusWindow *statusWindow;
 814 
 815     if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
 816         currentX11InputMethodInstance = NULL;
 817         return;
 818     }
 819 
 820     if (NULL == currentX11InputMethodInstance
 821         || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance))
 822         || NULL == (statusWindow = pX11IMData->statusWindow)
 823         || statusWindow->w != event.xany.window){
 824         return;
 825     }
 826 
 827     switch (event.type){
 828     case Expose:
 829         paintStatusWindow(statusWindow);
 830         break;
 831     case MapNotify:
 832     case ConfigureNotify:
 833         {
 834           /*need to reset the stackMode...*/
 835             XWindowChanges xwc;
 836             int value_make = CWStackMode;
 837             xwc.stack_mode = TopIf;
 838             XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
 839         }
 840         break;
 841         /*
 842     case UnmapNotify:
 843     case VisibilityNotify:
 844         break;
 845         */
 846     default:
 847         break;
 848   }
 849 }
 850 
 851 static void adjustStatusWindow(Window shell){
 852     JNIEnv *env = GetJNIEnv();
 853     X11InputMethodData *pX11IMData = NULL;
 854     StatusWindow *statusWindow;
 855 
 856     if (NULL == currentX11InputMethodInstance
 857         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
 858         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
 859         || NULL == (statusWindow = pX11IMData->statusWindow)
 860         || !statusWindow->on) {
 861         return;
 862     }
 863     {
 864         XWindowAttributes xwa;
 865         int x, y;
 866         Window child;
 867         XGetWindowAttributes(dpy, shell, &xwa);
 868         XTranslateCoordinates(dpy,
 869                               shell, xwa.root,
 870                               xwa.x, xwa.y,
 871                               &x, &y,
 872                               &child);
 873         if (statusWindow->x != x
 874             || statusWindow->y != y
 875             || statusWindow->height != xwa.height){
 876           statusWindow->x = x;
 877           statusWindow->y = y;
 878           statusWindow->height = xwa.height;
 879 
 880           x = statusWindow->x - statusWindow->off_x;
 881           y = statusWindow->y + statusWindow->height - statusWindow->off_y;
 882           if (x < 0 ){
 883               x = 0;
 884           }
 885           if (x + statusWindow->statusW > statusWindow->rootW){
 886               x = statusWindow->rootW - statusWindow->statusW;
 887           }
 888           if (y + statusWindow->statusH > statusWindow->rootH){
 889               y = statusWindow->rootH - statusWindow->statusH;
 890           }
 891           XMoveWindow(dpy, statusWindow->w, x, y);
 892         }
 893     }
 894 }
 895 #endif  /* __linux__ || MACOSX */
 896 /*
 897  * Creates two XICs, one for active clients and the other for passive
 898  * clients. All information on those XICs are stored in the
 899  * X11InputMethodData given by the pX11IMData parameter.
 900  *
 901  * For active clients: Try to use preedit callback to support
 902  * on-the-spot. If tc is not null, the XIC to be created will
 903  * share the Status Area with Motif widgets (TextComponents). If the
 904  * preferable styles can't be used, fallback to root-window styles. If
 905  * root-window styles failed, fallback to None styles.
 906  *
 907  * For passive clients: Try to use root-window styles. If failed,
 908  * fallback to None styles.
 909  */
 910 static Bool
 911 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
 912 {
 913     XIC active_ic, passive_ic;
 914     XVaNestedList preedit = NULL;
 915     XVaNestedList status = NULL;
 916     XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
 917              active_styles = 0,
 918              passive_styles = 0,
 919              no_styles = 0;
 920     XIMCallback *callbacks;
 921     unsigned short i;
 922     XIMStyles *im_styles;
 923     char *ret = NULL;
 924 
 925     if (X11im == NULL) {
 926         return False;
 927     }
 928     if (!w) {
 929         return False;
 930     }
 931 
 932     ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
 933 
 934     if (ret != NULL) {
 935         jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
 936         return FALSE ;
 937     }
 938 
 939 #if defined(__linux__) || defined(MACOSX)
 940     on_the_spot_styles |= XIMStatusNothing;
 941 
 942     /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
 943       at the same time, so use StatusCallback to draw the status
 944       ourself
 945     */
 946     for (i = 0; i < im_styles->count_styles; i++) {
 947         if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
 948             on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
 949             break;
 950         }
 951     }
 952 #else /*! __linux__ && !MACOSX */
 953     on_the_spot_styles |= XIMStatusNothing;
 954 #endif /* __linux__ || MACOSX */
 955 
 956     for (i = 0; i < im_styles->count_styles; i++) {
 957         active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
 958         passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
 959         no_styles |= im_styles->supported_styles[i] & NO_STYLES;
 960     }
 961 
 962     XFree(im_styles);
 963 
 964     if (active_styles != on_the_spot_styles) {
 965         if (passive_styles == ROOT_WINDOW_STYLES)
 966             active_styles = passive_styles;
 967         else {
 968             if (no_styles == NO_STYLES)
 969                 active_styles = passive_styles = NO_STYLES;
 970             else
 971                 active_styles = passive_styles = 0;
 972         }
 973     } else {
 974         if (passive_styles != ROOT_WINDOW_STYLES) {
 975             if (no_styles == NO_STYLES)
 976                 active_styles = passive_styles = NO_STYLES;
 977             else
 978                 active_styles = passive_styles = 0;
 979         }
 980     }
 981 
 982     if (active_styles == on_the_spot_styles) {
 983         callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
 984         if (callbacks == (XIMCallback *)NULL)
 985             return False;
 986         pX11IMData->callbacks = callbacks;
 987 
 988         for (i = 0; i < NCALLBACKS; i++, callbacks++) {
 989             callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
 990             callbacks->callback = callback_funcs[i];
 991         }
 992 
 993         callbacks = pX11IMData->callbacks;
 994         preedit = (XVaNestedList)XVaCreateNestedList(0,
 995                         XNPreeditStartCallback, &callbacks[PreeditStartIndex],
 996                         XNPreeditDoneCallback,  &callbacks[PreeditDoneIndex],
 997                         XNPreeditDrawCallback,  &callbacks[PreeditDrawIndex],
 998                         XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
 999                         NULL);
1000         if (preedit == (XVaNestedList)NULL)
1001             goto err;
1002 #if defined(__linux__) || defined(MACOSX)
1003         /*always try XIMStatusCallbacks for active client...*/
1004         {
1005             status = (XVaNestedList)XVaCreateNestedList(0,
1006                         XNStatusStartCallback, &callbacks[StatusStartIndex],
1007                         XNStatusDoneCallback,  &callbacks[StatusDoneIndex],
1008                         XNStatusDrawCallback, &callbacks[StatusDrawIndex],
1009                         NULL);
1010 
1011             if (status == NULL)
1012                 goto err;
1013             pX11IMData->statusWindow = createStatusWindow(w);
1014             pX11IMData->ic_active = XCreateIC(X11im,
1015                                               XNClientWindow, w,
1016                                               XNFocusWindow, w,
1017                                               XNInputStyle, active_styles,
1018                                               XNPreeditAttributes, preedit,
1019                                               XNStatusAttributes, status,
1020                                               NULL);
1021             XFree((void *)status);
1022             XFree((void *)preedit);
1023         }
1024 #else /* !__linux__ && !MACOSX */
1025             pX11IMData->ic_active = XCreateIC(X11im,
1026                                               XNClientWindow, w,
1027                                               XNFocusWindow, w,
1028                                               XNInputStyle, active_styles,
1029                                               XNPreeditAttributes, preedit,
1030                                               NULL);
1031         XFree((void *)preedit);
1032 #endif /* __linux__ || MACOSX */
1033         pX11IMData->ic_passive = XCreateIC(X11im,
1034                                            XNClientWindow, w,
1035                                            XNFocusWindow, w,
1036                                            XNInputStyle, passive_styles,
1037                                            NULL);
1038 
1039     } else {
1040         pX11IMData->ic_active = XCreateIC(X11im,
1041                                           XNClientWindow, w,
1042                                           XNFocusWindow, w,
1043                                           XNInputStyle, active_styles,
1044                                           NULL);
1045         pX11IMData->ic_passive = pX11IMData->ic_active;
1046     }
1047 
1048     if (pX11IMData->ic_active == (XIC)0
1049         || pX11IMData->ic_passive == (XIC)0) {
1050         return False;
1051     }
1052 
1053     /*
1054      * Use commit string call back if possible.
1055      * This will ensure the correct order of preedit text and commit text
1056      */
1057     {
1058         XIMCallback cb;
1059         cb.client_data = (XPointer) pX11IMData->x11inputmethod;
1060         cb.callback = (XIMProc) CommitStringCallback;
1061         XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL);
1062         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1063             XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1064         }
1065     }
1066 
1067     /* Add the global reference object to X11InputMethod to the list. */
1068     addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1069 
1070     return True;
1071 
1072  err:
1073     if (preedit)
1074         XFree((void *)preedit);
1075     THROW_OUT_OF_MEMORY_ERROR();
1076     return False;
1077 }
1078 
1079 static void
1080 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1081 {
1082     /*ARGSUSED*/
1083     /* printf("Native: PreeditCaretCallback\n"); */
1084 }
1085 
1086 static void
1087 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1088 {
1089     /*ARGSUSED*/
1090     /* printf("Native: StatusStartCallback\n"); */
1091 }
1092 
1093 /*
1094  * Translate the preedit draw callback items to Java values and invoke
1095  * X11InputMethod.dispatchComposedText().
1096  *
1097  * client_data: X11InputMethod object
1098  */
1099 static void
1100 PreeditDrawCallback(XIC ic, XPointer client_data,
1101                     XIMPreeditDrawCallbackStruct *pre_draw)
1102 {
1103     JNIEnv *env = GetJNIEnv();
1104     X11InputMethodData *pX11IMData = NULL;
1105     jmethodID x11imMethodID;
1106 
1107     XIMText *text;
1108     jstring javastr = NULL;
1109     jintArray style = NULL;
1110 
1111     /* printf("Native: PreeditDrawCallback() \n"); */
1112     if (pre_draw == NULL) {
1113         return;
1114     }
1115     AWT_LOCK();
1116     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1117         if ((jobject)client_data == currentX11InputMethodInstance) {
1118             currentX11InputMethodInstance = NULL;
1119         }
1120         goto finally;
1121     }
1122     if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1123         goto finally;
1124     }
1125 
1126     if ((text = pre_draw->text) != NULL) {
1127         if (text->string.multi_byte != NULL) {
1128             if (pre_draw->text->encoding_is_wchar == False) {
1129                 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1130             } else {
1131                 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1132                 if (mbstr == NULL) {
1133                     goto finally;
1134                 }
1135                 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1136                 free(mbstr);
1137             }
1138         }
1139         if (text->feedback != NULL) {
1140             int cnt;
1141             jint *tmpstyle;
1142 
1143             style = (*env)->NewIntArray(env, text->length);
1144             if (JNU_IsNull(env, style)) {
1145                 THROW_OUT_OF_MEMORY_ERROR();
1146                 goto finally;
1147             }
1148 
1149             if (sizeof(XIMFeedback) == sizeof(jint)) {
1150                 /*
1151                  * Optimization to avoid copying the array
1152                  */
1153                 (*env)->SetIntArrayRegion(env, style, 0,
1154                                           text->length, (jint *)text->feedback);
1155             } else {
1156                 tmpstyle  = (jint *)malloc(sizeof(jint)*(text->length));
1157                 if (tmpstyle == (jint *) NULL) {
1158                     THROW_OUT_OF_MEMORY_ERROR();
1159                     goto finally;
1160                 }
1161                 for (cnt = 0; cnt < (int)text->length; cnt++)
1162                         tmpstyle[cnt] = text->feedback[cnt];
1163                 (*env)->SetIntArrayRegion(env, style, 0,
1164                                           text->length, (jint *)tmpstyle);
1165             }
1166         }
1167     }
1168     JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1169                          "dispatchComposedText",
1170                          "(Ljava/lang/String;[IIIIJ)V",
1171                          javastr,
1172                          style,
1173                          (jint)pre_draw->chg_first,
1174                          (jint)pre_draw->chg_length,
1175                          (jint)pre_draw->caret,
1176                          awt_util_nowMillisUTC());
1177 finally:
1178     AWT_UNLOCK();
1179     return;
1180 }
1181 
1182 static void
1183 PreeditCaretCallback(XIC ic, XPointer client_data,
1184                      XIMPreeditCaretCallbackStruct *pre_caret)
1185 {
1186     /*ARGSUSED*/
1187     /* printf("Native: PreeditCaretCallback\n"); */
1188 
1189 }
1190 
1191 #if defined(__linux__) || defined(MACOSX)
1192 static void
1193 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1194 {
1195     /*ARGSUSED*/
1196     /*printf("StatusStartCallback:\n");  */
1197 
1198 }
1199 
1200 static void
1201 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1202 {
1203     /*ARGSUSED*/
1204     /*printf("StatusDoneCallback:\n"); */
1205 
1206 }
1207 
1208 static void
1209 StatusDrawCallback(XIC ic, XPointer client_data,
1210                      XIMStatusDrawCallbackStruct *status_draw)
1211 {
1212     /*ARGSUSED*/
1213     /*printf("StatusDrawCallback:\n"); */
1214     JNIEnv *env = GetJNIEnv();
1215     X11InputMethodData *pX11IMData = NULL;
1216     StatusWindow *statusWindow;
1217 
1218     AWT_LOCK();
1219 
1220     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1221         if ((jobject)client_data == currentX11InputMethodInstance) {
1222             currentX11InputMethodInstance = NULL;
1223         }
1224         goto finally;
1225     }
1226 
1227     if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1228         || NULL == (statusWindow = pX11IMData->statusWindow)){
1229         goto finally;
1230     }
1231    currentX11InputMethodInstance = (jobject)client_data;
1232 
1233     if (status_draw->type == XIMTextType){
1234         XIMText *text = (status_draw->data).text;
1235         if (text != NULL){
1236           if (text->string.multi_byte != NULL){
1237               strcpy(statusWindow->status, text->string.multi_byte);
1238           }
1239           else{
1240               char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1241               strcpy(statusWindow->status, mbstr);
1242           }
1243           statusWindow->on = True;
1244           onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1245           paintStatusWindow(statusWindow);
1246         }
1247         else {
1248             statusWindow->on = False;
1249             /*just turnoff the status window
1250             paintStatusWindow(statusWindow);
1251             */
1252             onoffStatusWindow(pX11IMData, 0, False);
1253         }
1254     }
1255 
1256  finally:
1257     AWT_UNLOCK();
1258 }
1259 #endif /* __linux__ || MACOSX */
1260 
1261 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1262     JNIEnv *env = GetJNIEnv();
1263     XIMText * text = (XIMText *)call_data;
1264     X11InputMethodData *pX11IMData = NULL;
1265     jstring javastr;
1266 
1267     AWT_LOCK();
1268 
1269     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1270         if ((jobject)client_data == currentX11InputMethodInstance) {
1271             currentX11InputMethodInstance = NULL;
1272         }
1273         goto finally;
1274     }
1275 
1276     if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1277         goto finally;
1278     }
1279     currentX11InputMethodInstance = (jobject)client_data;
1280 
1281     if (text->encoding_is_wchar == False) {
1282         javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1283     } else {
1284         char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1285         if (mbstr == NULL) {
1286             goto finally;
1287         }
1288         javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1289         free(mbstr);
1290     }
1291 
1292     if (javastr != NULL) {
1293         JNU_CallMethodByName(env, NULL,
1294                                  pX11IMData->x11inputmethod,
1295                                  "dispatchCommittedText",
1296                                  "(Ljava/lang/String;J)V",
1297                                  javastr,
1298                                  awt_util_nowMillisUTC());
1299     }
1300  finally:
1301     AWT_UNLOCK();
1302 }
1303 
1304 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) {
1305     XIMCallback ximCallback;
1306 
1307     X11im = XOpenIM(display, NULL, NULL, NULL);
1308     if (X11im == NULL) {
1309         return;
1310     }
1311 
1312     ximCallback.callback = (XIMProc)DestroyXIMCallback;
1313     ximCallback.client_data = NULL;
1314     XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1315 }
1316 
1317 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1318     /* mark that XIM server was destroyed */
1319     X11im = NULL;
1320     JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1321     /* free the old pX11IMData and set it to null. this also avoids crashing
1322      * the jvm if the XIM server reappears */
1323     X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1324 }
1325 
1326 /*
1327  * Class:     sun_awt_X11InputMethod
1328  * Method:    initIDs
1329  * Signature: ()V
1330  */
1331 
1332 /* This function gets called from the static initializer for
1333    X11InputMethod.java
1334    to initialize the fieldIDs for fields that may be accessed from C */
1335 JNIEXPORT void JNICALL
1336 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1337 {
1338     x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1339 }
1340 
1341 
1342 JNIEXPORT jboolean JNICALL
1343 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1344                                           jobject this,
1345                                           jlong display)
1346 {
1347     Bool registered;
1348 
1349     AWT_LOCK();
1350 
1351     dpy = (Display *)jlong_to_ptr(display);
1352 
1353 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1354    (4768335)
1355 */
1356 #if defined(__linux__) || defined(MACOSX)
1357     registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1358                      NULL, (XIDProc)OpenXIMCallback, NULL);
1359     if (!registered) {
1360         /* directly call openXIM callback */
1361 #endif
1362         OpenXIMCallback(dpy, NULL, NULL);
1363 #if defined(__linux__) || defined(MACOSX)
1364     }
1365 #endif
1366 
1367     AWT_UNLOCK();
1368 
1369     return JNI_TRUE;
1370 }
1371 
1372 JNIEXPORT jboolean JNICALL
1373 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1374                                                   jobject this,
1375                                                   jlong window)
1376 {
1377     X11InputMethodData *pX11IMData;
1378     jobject globalRef;
1379     XIC ic;
1380 
1381     AWT_LOCK();
1382 
1383     if (!window) {
1384         JNU_ThrowNullPointerException(env, "NullPointerException");
1385         AWT_UNLOCK();
1386         return JNI_FALSE;
1387     }
1388 
1389     pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1390     if (pX11IMData == NULL) {
1391         THROW_OUT_OF_MEMORY_ERROR();
1392         AWT_UNLOCK();
1393         return JNI_FALSE;
1394     }
1395 
1396     globalRef = (*env)->NewGlobalRef(env, this);
1397     pX11IMData->x11inputmethod = globalRef;
1398 #if defined(__linux__) || defined(MACOSX)
1399     pX11IMData->statusWindow = NULL;
1400 #endif /* __linux__ || MACOSX */
1401 
1402     pX11IMData->lookup_buf = 0;
1403     pX11IMData->lookup_buf_len = 0;
1404 
1405     if (createXIC(env, pX11IMData, (Window)window)
1406         == False) {
1407         destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1408         pX11IMData = (X11InputMethodData *) NULL;
1409     }
1410 
1411     setX11InputMethodData(env, this, pX11IMData);
1412 
1413     AWT_UNLOCK();
1414     return (pX11IMData != NULL);
1415 }
1416 
1417 JNIEXPORT void JNICALL
1418 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1419                                               jobject this,
1420                                               jlong w,
1421                                               jboolean req,
1422                                               jboolean active)
1423 {
1424     X11InputMethodData *pX11IMData;
1425     AWT_LOCK();
1426     pX11IMData = getX11InputMethodData(env, this);
1427     if (pX11IMData == NULL) {
1428         AWT_UNLOCK();
1429         return;
1430     }
1431 
1432     if (req) {
1433         if (!w) {
1434             AWT_UNLOCK();
1435             return;
1436         }
1437         pX11IMData->current_ic = active ?
1438                         pX11IMData->ic_active : pX11IMData->ic_passive;
1439         /*
1440          * On Solaris2.6, setXICWindowFocus() has to be invoked
1441          * before setting focus.
1442          */
1443         setXICWindowFocus(pX11IMData->current_ic, w);
1444         setXICFocus(pX11IMData->current_ic, req);
1445         currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1446         currentFocusWindow =  w;
1447 #if defined(__linux__) || defined(MACOSX)
1448         if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1449             onoffStatusWindow(pX11IMData, w, True);
1450 #endif
1451     } else {
1452         currentX11InputMethodInstance = NULL;
1453         currentFocusWindow = 0;
1454 #if defined(__linux__) || defined(MACOSX)
1455         onoffStatusWindow(pX11IMData, 0, False);
1456         if (pX11IMData->current_ic != NULL)
1457 #endif
1458         setXICFocus(pX11IMData->current_ic, req);
1459 
1460         pX11IMData->current_ic = (XIC)0;
1461     }
1462 
1463     XFlush(dpy);
1464     AWT_UNLOCK();
1465 }
1466 
1467 JNIEXPORT void JNICALL
1468 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
1469                                                 jobject this)
1470 {
1471 #if defined(__linux__) || defined(MACOSX)
1472     X11InputMethodData *pX11IMData;
1473     StatusWindow *statusWindow;
1474 
1475     AWT_LOCK();
1476 
1477     if (NULL == currentX11InputMethodInstance
1478         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1479         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1480         || NULL == (statusWindow = pX11IMData->statusWindow)
1481         || !statusWindow->on ){
1482         AWT_UNLOCK();
1483         return;
1484     }
1485     onoffStatusWindow(pX11IMData, 0, False);
1486 
1487     AWT_UNLOCK();
1488 #endif
1489 }
1490 
1491 JNIEXPORT void JNICALL
1492 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
1493                                              jobject this)
1494 {
1495     X11InputMethodData *pX11IMData = NULL;
1496 
1497     AWT_LOCK();
1498     pX11IMData = getX11InputMethodData(env, this);
1499     if (pX11IMData == NULL) {
1500         AWT_UNLOCK();
1501         return;
1502     }
1503 
1504     setX11InputMethodData(env, this, NULL);
1505 
1506     if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1507         currentX11InputMethodInstance = NULL;
1508         currentFocusWindow = 0;
1509     }
1510     destroyX11InputMethodData(env, pX11IMData);
1511     AWT_UNLOCK();
1512 }
1513 
1514 JNIEXPORT jstring JNICALL
1515 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
1516                                            jobject this)
1517 {
1518     X11InputMethodData *pX11IMData;
1519     char *xText = NULL;
1520     jstring jText = (jstring)0;
1521 
1522     AWT_LOCK();
1523     pX11IMData = getX11InputMethodData(env, this);
1524     if (pX11IMData == NULL) {
1525         AWT_UNLOCK();
1526         return jText;
1527     }
1528 
1529     if (pX11IMData->current_ic)
1530         xText = XmbResetIC(pX11IMData->current_ic);
1531     else {
1532         /*
1533          * If there is no reference to the current XIC, try to reset both XICs.
1534          */
1535         xText = XmbResetIC(pX11IMData->ic_active);
1536         /*it may also means that the real client component does
1537           not have focus -- has been deactivated... its xic should
1538           not have the focus, bug#4284651 showes reset XIC for htt
1539           may bring the focus back, so de-focus it again.
1540         */
1541         setXICFocus(pX11IMData->ic_active, FALSE);
1542         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1543             char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1544             setXICFocus(pX11IMData->ic_passive, FALSE);
1545             if (xText == (char *)NULL && tmpText)
1546                 xText = tmpText;
1547         }
1548 
1549     }
1550     if (xText != NULL) {
1551         jText = JNU_NewStringPlatform(env, (const char *)xText);
1552         XFree((void *)xText);
1553     }
1554 
1555     AWT_UNLOCK();
1556     return jText;
1557 }
1558 
1559 /*
1560  * Class:     sun_awt_X11InputMethod
1561  * Method:    setCompositionEnabledNative
1562  * Signature: (ZJ)V
1563  *
1564  * This method tries to set the XNPreeditState attribute associated with the current
1565  * XIC to the passed in 'enable' state.
1566  *
1567  * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1568  * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1569  * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1570  * method fails due to other reasons.
1571  *
1572  */
1573 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
1574   (JNIEnv *env, jobject this, jboolean enable)
1575 {
1576     X11InputMethodData *pX11IMData;
1577     char * ret = NULL;
1578 
1579     AWT_LOCK();
1580     pX11IMData = getX11InputMethodData(env, this);
1581 
1582     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1583         AWT_UNLOCK();
1584         return JNI_FALSE;
1585     }
1586 
1587     ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1588                        (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1589     AWT_UNLOCK();
1590 
1591     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1592         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1593     }
1594 
1595     return (jboolean)(ret == 0);
1596 }
1597 
1598 /*
1599  * Class:     sun_awt_X11InputMethod
1600  * Method:    isCompositionEnabledNative
1601  * Signature: (J)Z
1602  *
1603  * This method tries to get the XNPreeditState attribute associated with the current XIC.
1604  *
1605  * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1606  * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1607  * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1608  *
1609  */
1610 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
1611   (JNIEnv *env, jobject this)
1612 {
1613     X11InputMethodData *pX11IMData = NULL;
1614     char * ret = NULL;
1615     XIMPreeditState state;
1616 
1617     AWT_LOCK();
1618     pX11IMData = getX11InputMethodData(env, this);
1619 
1620     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1621         AWT_UNLOCK();
1622         return JNI_FALSE;
1623     }
1624 
1625     ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1626     AWT_UNLOCK();
1627 
1628     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1629         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1630         return JNI_FALSE;
1631     }
1632 
1633     return (jboolean)(state == XIMPreeditEnable);
1634 }
1635 
1636 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
1637   (JNIEnv *env, jobject this, jlong window)
1638 {
1639 #if defined(__linux__) || defined(MACOSX)
1640     AWT_LOCK();
1641     adjustStatusWindow(window);
1642     AWT_UNLOCK();
1643 #endif
1644 }