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