1 /*
   2  * Copyright (c) 1997, 2016, 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 <X11/keysym.h>
  34 #include <sys/time.h>
  35 
  36 #include "awt.h"
  37 #include "awt_p.h"
  38 
  39 #include <sun_awt_X11InputMethod.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 
  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(
 580                                 Window parent) {
 581     StatusWindow *statusWindow;
 582     XSetWindowAttributes attrib;
 583     unsigned long attribmask;
 584     Window containerWindow;
 585     Window status;
 586     Window child;
 587     XWindowAttributes xwa;
 588     XWindowAttributes xxwa;
 589     /* Variable for XCreateFontSet()*/
 590     char **mclr;
 591     int  mccr = 0;
 592     char *dsr;
 593     unsigned long bg, fg, light, dim;
 594     int x, y, off_x, off_y, xx, yy;
 595     unsigned int w, h, bw, depth;
 596     XGCValues values;
 597     unsigned long valuemask = 0;  /*ignore XGCvalue and use defaults*/
 598     int screen = 0;
 599     int i;
 600     AwtGraphicsConfigDataPtr adata;
 601     extern int awt_numScreens;
 602     /*hardcode the size right now, should get the size base on font*/
 603     int   width=80, height=22;
 604     Window rootWindow;
 605     Window *ignoreWindowPtr;
 606     unsigned int ignoreUnit;
 607 
 608     XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth);
 609 
 610     attrib.override_redirect = True;
 611     attribmask = CWOverrideRedirect;
 612     for (i = 0; i < awt_numScreens; i++) {
 613         if (RootWindow(dpy, i) == rootWindow) {
 614             screen = i;
 615             break;
 616         }
 617     }
 618     adata = getDefaultConfig(screen);
 619     bg    = adata->AwtColorMatch(255, 255, 255, adata);
 620     fg    = adata->AwtColorMatch(0, 0, 0, adata);
 621     light = adata->AwtColorMatch(195, 195, 195, adata);
 622     dim   = adata->AwtColorMatch(128, 128, 128, adata);
 623 
 624     XGetWindowAttributes(dpy, parent, &xwa);
 625     bw = 2; /*xwa.border_width does not have the correct value*/
 626 
 627     /*compare the size difference between parent container
 628       and shell widget, the diff should be the border frame
 629       and title bar height (?)*/
 630 
 631     XQueryTree( dpy,
 632                 parent,
 633                 &rootWindow,
 634                 &containerWindow,
 635                 &ignoreWindowPtr,
 636                 &ignoreUnit);
 637     XGetWindowAttributes(dpy, containerWindow, &xxwa);
 638 
 639     off_x = (xxwa.width - xwa.width) / 2;
 640     off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */
 641 
 642     /*get the size of root window*/
 643     XGetWindowAttributes(dpy, rootWindow, &xxwa);
 644 
 645     XTranslateCoordinates(dpy,
 646                           parent, xwa.root,
 647                           xwa.x, xwa.y,
 648                           &x, &y,
 649                           &child);
 650     xx = x - off_x;
 651     yy = y + xwa.height - off_y;
 652     if (xx < 0 ){
 653         xx = 0;
 654     }
 655     if (xx + width > xxwa.width){
 656         xx = xxwa.width - width;
 657     }
 658     if (yy + height > xxwa.height){
 659         yy = xxwa.height - height;
 660     }
 661 
 662     status =  XCreateWindow(dpy,
 663                             xwa.root,
 664                             xx, yy,
 665                             width, height,
 666                             0,
 667                             xwa.depth,
 668                             InputOutput,
 669                             adata->awt_visInfo.visual,
 670                             attribmask, &attrib);
 671     XSelectInput(dpy, status,
 672                  ExposureMask | StructureNotifyMask | EnterWindowMask |
 673                  LeaveWindowMask | VisibilityChangeMask);
 674     statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow));
 675     if (statusWindow == NULL){
 676         THROW_OUT_OF_MEMORY_ERROR();
 677         return NULL;
 678     }
 679     statusWindow->w = status;
 680     //12-point font
 681     statusWindow->fontset = XCreateFontSet(dpy,
 682                                            "-*-*-medium-r-normal-*-*-120-*-*-*-*," \
 683                                            "-*-*-medium-r-normal-*-*-130-*-*-*-*",
 684                                            &mclr, &mccr, &dsr);
 685     /* In case we didn't find the font set, release the list of missing characters */
 686     if (mccr > 0) {
 687         XFreeStringList(mclr);
 688     }
 689     statusWindow->parent = parent;
 690     statusWindow->on  = False;
 691     statusWindow->x = x;
 692     statusWindow->y = y;
 693     statusWindow->width = xwa.width;
 694     statusWindow->height = xwa.height;
 695     statusWindow->off_x = off_x;
 696     statusWindow->off_y = off_y;
 697     statusWindow->bWidth  = bw;
 698     statusWindow->statusH = height;
 699     statusWindow->statusW = width;
 700     statusWindow->rootH = xxwa.height;
 701     statusWindow->rootW = xxwa.width;
 702     statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values);
 703     XSetForeground(dpy, statusWindow->lightGC, light);
 704     statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values);
 705     XSetForeground(dpy, statusWindow->dimGC, dim);
 706     statusWindow->fgGC = XCreateGC(dpy, status, valuemask, &values);
 707     XSetForeground(dpy, statusWindow->fgGC, fg);
 708     statusWindow->bgGC = XCreateGC(dpy, status, valuemask, &values);
 709     XSetForeground(dpy, statusWindow->bgGC, bg);
 710     return statusWindow;
 711 }
 712 
 713 /* This method is to turn off or turn on the status window. */
 714 static void onoffStatusWindow(X11InputMethodData* pX11IMData,
 715                                 Window parent,
 716                                 Bool ON){
 717     XWindowAttributes xwa;
 718     Window child;
 719     int x, y;
 720     StatusWindow *statusWindow = NULL;
 721 
 722     if (NULL == currentX11InputMethodInstance ||
 723         NULL == pX11IMData ||
 724         NULL == (statusWindow =  pX11IMData->statusWindow)){
 725         return;
 726     }
 727 
 728     if (ON == False){
 729         XUnmapWindow(dpy, statusWindow->w);
 730         statusWindow->on = False;
 731         return;
 732     }
 733     parent = JNU_CallMethodByName(GetJNIEnv(), NULL, pX11IMData->x11inputmethod,
 734                                   "getCurrentParentWindow",
 735                                   "()J").j;
 736     if (statusWindow->parent != parent){
 737         statusWindow->parent = parent;
 738     }
 739     XGetWindowAttributes(dpy, parent, &xwa);
 740     XTranslateCoordinates(dpy,
 741                           parent, xwa.root,
 742                           xwa.x, xwa.y,
 743                           &x, &y,
 744                           &child);
 745     if (statusWindow->x != x
 746         || statusWindow->y != y
 747         || statusWindow->height != xwa.height){
 748         statusWindow->x = x;
 749         statusWindow->y = y;
 750         statusWindow->height = xwa.height;
 751         x = statusWindow->x - statusWindow->off_x;
 752         y = statusWindow->y + statusWindow->height - statusWindow->off_y;
 753         if (x < 0 ){
 754             x = 0;
 755         }
 756         if (x + statusWindow->statusW > statusWindow->rootW){
 757             x = statusWindow->rootW - statusWindow->statusW;
 758         }
 759         if (y + statusWindow->statusH > statusWindow->rootH){
 760             y = statusWindow->rootH - statusWindow->statusH;
 761         }
 762         XMoveWindow(dpy, statusWindow->w, x, y);
 763     }
 764     statusWindow->on = True;
 765     XMapWindow(dpy, statusWindow->w);
 766 }
 767 
 768 void paintStatusWindow(StatusWindow *statusWindow){
 769     Window  win  = statusWindow->w;
 770     GC  lightgc = statusWindow->lightGC;
 771     GC  dimgc = statusWindow->dimGC;
 772     GC  bggc = statusWindow->bgGC;
 773     GC  fggc = statusWindow->fgGC;
 774 
 775     int width = statusWindow->statusW;
 776     int height = statusWindow->statusH;
 777     int bwidth = statusWindow->bWidth;
 778     XFillRectangle(dpy, win, bggc, 0, 0, width, height);
 779     /* draw border */
 780     XDrawLine(dpy, win, fggc, 0, 0, width, 0);
 781     XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1);
 782     XDrawLine(dpy, win, fggc, 0, 0, 0, height-1);
 783     XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1);
 784 
 785     XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1);
 786     XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2);
 787     XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2);
 788     XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2);
 789 
 790     XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3);
 791     XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3);
 792     XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2);
 793     XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3);
 794     if (statusWindow->fontset){
 795         XmbDrawString(dpy, win, statusWindow->fontset, fggc,
 796                       bwidth + 2, height - bwidth - 4,
 797                       statusWindow->status,
 798                       strlen(statusWindow->status));
 799     }
 800     else{
 801         /*too bad we failed to create a fontset for this locale*/
 802         XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4,
 803                     "[InputMethod ON]", strlen("[InputMethod ON]"));
 804     }
 805 }
 806 
 807 void statusWindowEventHandler(XEvent event){
 808     JNIEnv *env = GetJNIEnv();
 809     X11InputMethodData *pX11IMData = NULL;
 810     StatusWindow *statusWindow;
 811 
 812     if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) {
 813         currentX11InputMethodInstance = NULL;
 814         return;
 815     }
 816 
 817     if (NULL == currentX11InputMethodInstance
 818         || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance))
 819         || NULL == (statusWindow = pX11IMData->statusWindow)
 820         || statusWindow->w != event.xany.window){
 821         return;
 822     }
 823 
 824     switch (event.type){
 825     case Expose:
 826         paintStatusWindow(statusWindow);
 827         break;
 828     case MapNotify:
 829     case ConfigureNotify:
 830         {
 831           /*need to reset the stackMode...*/
 832             XWindowChanges xwc;
 833             int value_make = CWStackMode;
 834             xwc.stack_mode = TopIf;
 835             XConfigureWindow(dpy, statusWindow->w, value_make, &xwc);
 836         }
 837         break;
 838         /*
 839     case UnmapNotify:
 840     case VisibilityNotify:
 841         break;
 842         */
 843     default:
 844         break;
 845   }
 846 }
 847 
 848 static void adjustStatusWindow(Window shell){
 849     JNIEnv *env = GetJNIEnv();
 850     X11InputMethodData *pX11IMData = NULL;
 851     StatusWindow *statusWindow;
 852 
 853     if (NULL == currentX11InputMethodInstance
 854         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
 855         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
 856         || NULL == (statusWindow = pX11IMData->statusWindow)
 857         || !statusWindow->on) {
 858         return;
 859     }
 860     {
 861         XWindowAttributes xwa;
 862         int x, y;
 863         Window child;
 864         XGetWindowAttributes(dpy, shell, &xwa);
 865         XTranslateCoordinates(dpy,
 866                               shell, xwa.root,
 867                               xwa.x, xwa.y,
 868                               &x, &y,
 869                               &child);
 870         if (statusWindow->x != x
 871             || statusWindow->y != y
 872             || statusWindow->height != xwa.height){
 873           statusWindow->x = x;
 874           statusWindow->y = y;
 875           statusWindow->height = xwa.height;
 876 
 877           x = statusWindow->x - statusWindow->off_x;
 878           y = statusWindow->y + statusWindow->height - statusWindow->off_y;
 879           if (x < 0 ){
 880               x = 0;
 881           }
 882           if (x + statusWindow->statusW > statusWindow->rootW){
 883               x = statusWindow->rootW - statusWindow->statusW;
 884           }
 885           if (y + statusWindow->statusH > statusWindow->rootH){
 886               y = statusWindow->rootH - statusWindow->statusH;
 887           }
 888           XMoveWindow(dpy, statusWindow->w, x, y);
 889         }
 890     }
 891 }
 892 #endif  /* __linux__ || MACOSX */
 893 /*
 894  * Creates two XICs, one for active clients and the other for passive
 895  * clients. All information on those XICs are stored in the
 896  * X11InputMethodData given by the pX11IMData parameter.
 897  *
 898  * For active clients: Try to use preedit callback to support
 899  * on-the-spot. If tc is not null, the XIC to be created will
 900  * share the Status Area with Motif widgets (TextComponents). If the
 901  * preferable styles can't be used, fallback to root-window styles. If
 902  * root-window styles failed, fallback to None styles.
 903  *
 904  * For passive clients: Try to use root-window styles. If failed,
 905  * fallback to None styles.
 906  */
 907 static Bool
 908 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
 909 {
 910     XVaNestedList preedit = NULL;
 911     XVaNestedList status = NULL;
 912     XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
 913              active_styles = 0,
 914              passive_styles = 0,
 915              no_styles = 0;
 916     XIMCallback *callbacks;
 917     unsigned short i;
 918     XIMStyles *im_styles;
 919     char *ret = NULL;
 920 
 921     if (X11im == NULL) {
 922         return False;
 923     }
 924     if (!w) {
 925         return False;
 926     }
 927 
 928     ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL);
 929 
 930     if (ret != NULL) {
 931         jio_fprintf(stderr,"XGetIMValues: %s\n",ret);
 932         return FALSE ;
 933     }
 934 
 935 #if defined(__linux__) || defined(MACOSX)
 936     on_the_spot_styles |= XIMStatusNothing;
 937 
 938     /*kinput does not support XIMPreeditCallbacks and XIMStatusArea
 939       at the same time, so use StatusCallback to draw the status
 940       ourself
 941     */
 942     for (i = 0; i < im_styles->count_styles; i++) {
 943         if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) {
 944             on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks);
 945             break;
 946         }
 947     }
 948 #else /*! __linux__ && !MACOSX */
 949     on_the_spot_styles |= XIMStatusNothing;
 950 #endif /* __linux__ || MACOSX */
 951 
 952     for (i = 0; i < im_styles->count_styles; i++) {
 953         active_styles |= im_styles->supported_styles[i] & on_the_spot_styles;
 954         passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES;
 955         no_styles |= im_styles->supported_styles[i] & NO_STYLES;
 956     }
 957 
 958     XFree(im_styles);
 959 
 960     if (active_styles != on_the_spot_styles) {
 961         if (passive_styles == ROOT_WINDOW_STYLES)
 962             active_styles = passive_styles;
 963         else {
 964             if (no_styles == NO_STYLES)
 965                 active_styles = passive_styles = NO_STYLES;
 966             else
 967                 active_styles = passive_styles = 0;
 968         }
 969     } else {
 970         if (passive_styles != ROOT_WINDOW_STYLES) {
 971             if (no_styles == NO_STYLES)
 972                 active_styles = passive_styles = NO_STYLES;
 973             else
 974                 active_styles = passive_styles = 0;
 975         }
 976     }
 977 
 978     if (active_styles == on_the_spot_styles) {
 979         pX11IMData->ic_passive = XCreateIC(X11im,
 980                                    XNClientWindow, w,
 981                                    XNFocusWindow, w,
 982                                    XNInputStyle, passive_styles,
 983                                    NULL);
 984 
 985         callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
 986         if (callbacks == (XIMCallback *)NULL)
 987             return False;
 988         pX11IMData->callbacks = callbacks;
 989 
 990         for (i = 0; i < NCALLBACKS; i++, callbacks++) {
 991             callbacks->client_data = (XPointer) pX11IMData->x11inputmethod;
 992             callbacks->callback = callback_funcs[i];
 993         }
 994 
 995         callbacks = pX11IMData->callbacks;
 996         preedit = (XVaNestedList)XVaCreateNestedList(0,
 997                         XNPreeditStartCallback, &callbacks[PreeditStartIndex],
 998                         XNPreeditDoneCallback,  &callbacks[PreeditDoneIndex],
 999                         XNPreeditDrawCallback,  &callbacks[PreeditDrawIndex],
1000                         XNPreeditCaretCallback, &callbacks[PreeditCaretIndex],
1001                         NULL);
1002         if (preedit == (XVaNestedList)NULL)
1003             goto err;
1004 #if defined(__linux__) || defined(MACOSX)
1005         /*always try XIMStatusCallbacks for active client...*/
1006         {
1007             status = (XVaNestedList)XVaCreateNestedList(0,
1008                         XNStatusStartCallback, &callbacks[StatusStartIndex],
1009                         XNStatusDoneCallback,  &callbacks[StatusDoneIndex],
1010                         XNStatusDrawCallback, &callbacks[StatusDrawIndex],
1011                         NULL);
1012 
1013             if (status == NULL)
1014                 goto err;
1015             pX11IMData->statusWindow = createStatusWindow(w);
1016             pX11IMData->ic_active = XCreateIC(X11im,
1017                                               XNClientWindow, w,
1018                                               XNFocusWindow, w,
1019                                               XNInputStyle, active_styles,
1020                                               XNPreeditAttributes, preedit,
1021                                               XNStatusAttributes, status,
1022                                               NULL);
1023             XFree((void *)status);
1024             XFree((void *)preedit);
1025         }
1026 #else /* !__linux__ && !MACOSX */
1027             pX11IMData->ic_active = XCreateIC(X11im,
1028                                               XNClientWindow, w,
1029                                               XNFocusWindow, w,
1030                                               XNInputStyle, active_styles,
1031                                               XNPreeditAttributes, preedit,
1032                                               NULL);
1033         XFree((void *)preedit);
1034 #endif /* __linux__ || MACOSX */
1035     } else {
1036         pX11IMData->ic_active = XCreateIC(X11im,
1037                                           XNClientWindow, w,
1038                                           XNFocusWindow, w,
1039                                           XNInputStyle, active_styles,
1040                                           NULL);
1041         pX11IMData->ic_passive = pX11IMData->ic_active;
1042     }
1043 
1044     if (pX11IMData->ic_active == (XIC)0
1045         || pX11IMData->ic_passive == (XIC)0) {
1046         return False;
1047     }
1048 
1049     /*
1050      * Use commit string call back if possible.
1051      * This will ensure the correct order of preedit text and commit text
1052      */
1053     {
1054         XIMCallback cb;
1055         cb.client_data = (XPointer) pX11IMData->x11inputmethod;
1056         cb.callback = (XIMProc) CommitStringCallback;
1057         XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL);
1058         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1059             XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL);
1060         }
1061     }
1062 
1063     /* Add the global reference object to X11InputMethod to the list. */
1064     addToX11InputMethodGRefList(pX11IMData->x11inputmethod);
1065 
1066     return True;
1067 
1068  err:
1069     if (preedit)
1070         XFree((void *)preedit);
1071     THROW_OUT_OF_MEMORY_ERROR();
1072     return False;
1073 }
1074 
1075 static void
1076 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1077 {
1078     /*ARGSUSED*/
1079     /* printf("Native: PreeditCaretCallback\n"); */
1080 }
1081 
1082 static void
1083 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1084 {
1085     /*ARGSUSED*/
1086     /* printf("Native: StatusStartCallback\n"); */
1087 }
1088 
1089 /*
1090  * Translate the preedit draw callback items to Java values and invoke
1091  * X11InputMethod.dispatchComposedText().
1092  *
1093  * client_data: X11InputMethod object
1094  */
1095 static void
1096 PreeditDrawCallback(XIC ic, XPointer client_data,
1097                     XIMPreeditDrawCallbackStruct *pre_draw)
1098 {
1099     JNIEnv *env = GetJNIEnv();
1100     X11InputMethodData *pX11IMData = NULL;
1101     jmethodID x11imMethodID;
1102 
1103     XIMText *text;
1104     jstring javastr = NULL;
1105     jintArray style = NULL;
1106 
1107     /* printf("Native: PreeditDrawCallback() \n"); */
1108     if (pre_draw == NULL) {
1109         return;
1110     }
1111     AWT_LOCK();
1112     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1113         if ((jobject)client_data == currentX11InputMethodInstance) {
1114             currentX11InputMethodInstance = NULL;
1115         }
1116         goto finally;
1117     }
1118     if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1119         goto finally;
1120     }
1121 
1122     if ((text = pre_draw->text) != NULL) {
1123         if (text->string.multi_byte != NULL) {
1124             if (pre_draw->text->encoding_is_wchar == False) {
1125                 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1126                 if (javastr == NULL) {
1127                     goto finally;
1128                 }
1129             } else {
1130                 char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1131                 if (mbstr == NULL) {
1132                     goto finally;
1133                 }
1134                 javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1135                 free(mbstr);
1136                 if (javastr == NULL) {
1137                     goto finally;
1138                 }
1139             }
1140         }
1141         if (text->feedback != NULL) {
1142             int cnt;
1143             jint *tmpstyle;
1144 
1145             style = (*env)->NewIntArray(env, text->length);
1146             if (JNU_IsNull(env, style)) {
1147                 (*env)->ExceptionClear(env);
1148                 THROW_OUT_OF_MEMORY_ERROR();
1149                 goto finally;
1150             }
1151 
1152             if (sizeof(XIMFeedback) == sizeof(jint)) {
1153                 /*
1154                  * Optimization to avoid copying the array
1155                  */
1156                 (*env)->SetIntArrayRegion(env, style, 0,
1157                                           text->length, (jint *)text->feedback);
1158             } else {
1159                 tmpstyle  = (jint *)malloc(sizeof(jint)*(text->length));
1160                 if (tmpstyle == (jint *) NULL) {
1161                     THROW_OUT_OF_MEMORY_ERROR();
1162                     goto finally;
1163                 }
1164                 for (cnt = 0; cnt < (int)text->length; cnt++)
1165                         tmpstyle[cnt] = text->feedback[cnt];
1166                 (*env)->SetIntArrayRegion(env, style, 0,
1167                                           text->length, (jint *)tmpstyle);
1168             }
1169         }
1170     }
1171     JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod,
1172                          "dispatchComposedText",
1173                          "(Ljava/lang/String;[IIIIJ)V",
1174                          javastr,
1175                          style,
1176                          (jint)pre_draw->chg_first,
1177                          (jint)pre_draw->chg_length,
1178                          (jint)pre_draw->caret,
1179                          awt_util_nowMillisUTC());
1180 finally:
1181     AWT_UNLOCK();
1182     return;
1183 }
1184 
1185 static void
1186 PreeditCaretCallback(XIC ic, XPointer client_data,
1187                      XIMPreeditCaretCallbackStruct *pre_caret)
1188 {
1189     /*ARGSUSED*/
1190     /* printf("Native: PreeditCaretCallback\n"); */
1191 
1192 }
1193 
1194 #if defined(__linux__) || defined(MACOSX)
1195 static void
1196 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data)
1197 {
1198     /*ARGSUSED*/
1199     /*printf("StatusStartCallback:\n");  */
1200 
1201 }
1202 
1203 static void
1204 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data)
1205 {
1206     /*ARGSUSED*/
1207     /*printf("StatusDoneCallback:\n"); */
1208 
1209 }
1210 
1211 static void
1212 StatusDrawCallback(XIC ic, XPointer client_data,
1213                      XIMStatusDrawCallbackStruct *status_draw)
1214 {
1215     /*ARGSUSED*/
1216     /*printf("StatusDrawCallback:\n"); */
1217     JNIEnv *env = GetJNIEnv();
1218     X11InputMethodData *pX11IMData = NULL;
1219     StatusWindow *statusWindow;
1220 
1221     AWT_LOCK();
1222 
1223     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1224         if ((jobject)client_data == currentX11InputMethodInstance) {
1225             currentX11InputMethodInstance = NULL;
1226         }
1227         goto finally;
1228     }
1229 
1230     if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data))
1231         || NULL == (statusWindow = pX11IMData->statusWindow)){
1232         goto finally;
1233     }
1234    currentX11InputMethodInstance = (jobject)client_data;
1235 
1236     if (status_draw->type == XIMTextType){
1237         XIMText *text = (status_draw->data).text;
1238         if (text != NULL){
1239           if (text->string.multi_byte != NULL) {
1240               strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN);
1241               statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1242           }
1243           else {
1244               char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1245               strncpy(statusWindow->status, mbstr, MAX_STATUS_LEN);
1246               statusWindow->status[MAX_STATUS_LEN - 1] = '\0';
1247           }
1248           statusWindow->on = True;
1249           onoffStatusWindow(pX11IMData, statusWindow->parent, True);
1250           paintStatusWindow(statusWindow);
1251         }
1252         else {
1253             statusWindow->on = False;
1254             /*just turnoff the status window
1255             paintStatusWindow(statusWindow);
1256             */
1257             onoffStatusWindow(pX11IMData, 0, False);
1258         }
1259     }
1260 
1261  finally:
1262     AWT_UNLOCK();
1263 }
1264 #endif /* __linux__ || MACOSX */
1265 
1266 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) {
1267     JNIEnv *env = GetJNIEnv();
1268     XIMText * text = (XIMText *)call_data;
1269     X11InputMethodData *pX11IMData = NULL;
1270     jstring javastr;
1271 
1272     AWT_LOCK();
1273 
1274     if (!isX11InputMethodGRefInList((jobject)client_data)) {
1275         if ((jobject)client_data == currentX11InputMethodInstance) {
1276             currentX11InputMethodInstance = NULL;
1277         }
1278         goto finally;
1279     }
1280 
1281     if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) {
1282         goto finally;
1283     }
1284     currentX11InputMethodInstance = (jobject)client_data;
1285 
1286     if (text->encoding_is_wchar == False) {
1287         javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte);
1288     } else {
1289         char *mbstr = wcstombsdmp(text->string.wide_char, text->length);
1290         if (mbstr == NULL) {
1291             goto finally;
1292         }
1293         javastr = JNU_NewStringPlatform(env, (const char *)mbstr);
1294         free(mbstr);
1295     }
1296 
1297     if (javastr != NULL) {
1298         JNU_CallMethodByName(env, NULL,
1299                                  pX11IMData->x11inputmethod,
1300                                  "dispatchCommittedText",
1301                                  "(Ljava/lang/String;J)V",
1302                                  javastr,
1303                                  awt_util_nowMillisUTC());
1304     }
1305  finally:
1306     AWT_UNLOCK();
1307 }
1308 
1309 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) {
1310     XIMCallback ximCallback;
1311 
1312     X11im = XOpenIM(display, NULL, NULL, NULL);
1313     if (X11im == NULL) {
1314         return;
1315     }
1316 
1317     ximCallback.callback = (XIMProc)DestroyXIMCallback;
1318     ximCallback.client_data = NULL;
1319     XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL);
1320 }
1321 
1322 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
1323     /* mark that XIM server was destroyed */
1324     X11im = NULL;
1325     JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1326     /* free the old pX11IMData and set it to null. this also avoids crashing
1327      * the jvm if the XIM server reappears */
1328     X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1329 }
1330 
1331 /*
1332  * Class:     sun_awt_X11InputMethod
1333  * Method:    initIDs
1334  * Signature: ()V
1335  */
1336 
1337 /* This function gets called from the static initializer for
1338    X11InputMethod.java
1339    to initialize the fieldIDs for fields that may be accessed from C */
1340 JNIEXPORT void JNICALL
1341 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1342 {
1343     x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1344 }
1345 
1346 
1347 JNIEXPORT jboolean JNICALL
1348 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1349                                           jobject this,
1350                                           jlong display)
1351 {
1352     Bool registered;
1353 
1354     AWT_LOCK();
1355 
1356     dpy = (Display *)jlong_to_ptr(display);
1357 
1358 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1359    (4768335)
1360 */
1361 #if defined(__linux__) || defined(MACOSX)
1362     registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1363                      NULL, (XIDProc)OpenXIMCallback, NULL);
1364     if (!registered) {
1365         /* directly call openXIM callback */
1366 #endif
1367         OpenXIMCallback(dpy, NULL, NULL);
1368 #if defined(__linux__) || defined(MACOSX)
1369     }
1370 #endif
1371 
1372     AWT_UNLOCK();
1373 
1374     return JNI_TRUE;
1375 }
1376 
1377 JNIEXPORT jboolean JNICALL
1378 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1379                                                   jobject this,
1380                                                   jlong window)
1381 {
1382     X11InputMethodData *pX11IMData;
1383     jobject globalRef;
1384     XIC ic;
1385 
1386     AWT_LOCK();
1387 
1388     if (!window) {
1389         JNU_ThrowNullPointerException(env, "NullPointerException");
1390         AWT_UNLOCK();
1391         return JNI_FALSE;
1392     }
1393 
1394     pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1395     if (pX11IMData == NULL) {
1396         THROW_OUT_OF_MEMORY_ERROR();
1397         AWT_UNLOCK();
1398         return JNI_FALSE;
1399     }
1400 
1401     globalRef = (*env)->NewGlobalRef(env, this);
1402     pX11IMData->x11inputmethod = globalRef;
1403 #if defined(__linux__) || defined(MACOSX)
1404     pX11IMData->statusWindow = NULL;
1405 #endif /* __linux__ || MACOSX */
1406 
1407     pX11IMData->lookup_buf = 0;
1408     pX11IMData->lookup_buf_len = 0;
1409 
1410     if (createXIC(env, pX11IMData, (Window)window) == False) {
1411         destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1412         pX11IMData = (X11InputMethodData *) NULL;
1413         if ((*env)->ExceptionCheck(env)) {
1414             goto finally;
1415         }
1416     }
1417 
1418     setX11InputMethodData(env, this, pX11IMData);
1419 
1420 finally:
1421     AWT_UNLOCK();
1422     return (pX11IMData != NULL);
1423 }
1424 
1425 JNIEXPORT void JNICALL
1426 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1427                                               jobject this,
1428                                               jlong w,
1429                                               jboolean req,
1430                                               jboolean active)
1431 {
1432     X11InputMethodData *pX11IMData;
1433     AWT_LOCK();
1434     pX11IMData = getX11InputMethodData(env, this);
1435     if (pX11IMData == NULL) {
1436         AWT_UNLOCK();
1437         return;
1438     }
1439 
1440     if (req) {
1441         if (!w) {
1442             AWT_UNLOCK();
1443             return;
1444         }
1445         pX11IMData->current_ic = active ?
1446                         pX11IMData->ic_active : pX11IMData->ic_passive;
1447         /*
1448          * On Solaris2.6, setXICWindowFocus() has to be invoked
1449          * before setting focus.
1450          */
1451         setXICWindowFocus(pX11IMData->current_ic, w);
1452         setXICFocus(pX11IMData->current_ic, req);
1453         currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1454         currentFocusWindow =  w;
1455 #if defined(__linux__) || defined(MACOSX)
1456         if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1457             onoffStatusWindow(pX11IMData, w, True);
1458 #endif
1459     } else {
1460         currentX11InputMethodInstance = NULL;
1461         currentFocusWindow = 0;
1462 #if defined(__linux__) || defined(MACOSX)
1463         onoffStatusWindow(pX11IMData, 0, False);
1464         if (pX11IMData->current_ic != NULL)
1465 #endif
1466         setXICFocus(pX11IMData->current_ic, req);
1467 
1468         pX11IMData->current_ic = (XIC)0;
1469     }
1470 
1471     XFlush(dpy);
1472     AWT_UNLOCK();
1473 }
1474 
1475 JNIEXPORT void JNICALL
1476 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
1477                                                 jobject this)
1478 {
1479 #if defined(__linux__) || defined(MACOSX)
1480     X11InputMethodData *pX11IMData;
1481     StatusWindow *statusWindow;
1482 
1483     AWT_LOCK();
1484 
1485     if (NULL == currentX11InputMethodInstance
1486         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1487         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1488         || NULL == (statusWindow = pX11IMData->statusWindow)
1489         || !statusWindow->on ){
1490         AWT_UNLOCK();
1491         return;
1492     }
1493     onoffStatusWindow(pX11IMData, 0, False);
1494 
1495     AWT_UNLOCK();
1496 #endif
1497 }
1498 
1499 JNIEXPORT void JNICALL
1500 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
1501                                              jobject this)
1502 {
1503     X11InputMethodData *pX11IMData = NULL;
1504 
1505     AWT_LOCK();
1506     pX11IMData = getX11InputMethodData(env, this);
1507     if (pX11IMData == NULL) {
1508         AWT_UNLOCK();
1509         return;
1510     }
1511 
1512     setX11InputMethodData(env, this, NULL);
1513 
1514     if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1515         currentX11InputMethodInstance = NULL;
1516         currentFocusWindow = 0;
1517     }
1518     destroyX11InputMethodData(env, pX11IMData);
1519     AWT_UNLOCK();
1520 }
1521 
1522 JNIEXPORT jstring JNICALL
1523 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
1524                                            jobject this)
1525 {
1526     X11InputMethodData *pX11IMData;
1527     char *xText = NULL;
1528     jstring jText = (jstring)0;
1529 
1530     AWT_LOCK();
1531     pX11IMData = getX11InputMethodData(env, this);
1532     if (pX11IMData == NULL) {
1533         AWT_UNLOCK();
1534         return jText;
1535     }
1536 
1537     if (pX11IMData->current_ic)
1538         xText = XmbResetIC(pX11IMData->current_ic);
1539     else {
1540         /*
1541          * If there is no reference to the current XIC, try to reset both XICs.
1542          */
1543         xText = XmbResetIC(pX11IMData->ic_active);
1544         /*it may also means that the real client component does
1545           not have focus -- has been deactivated... its xic should
1546           not have the focus, bug#4284651 showes reset XIC for htt
1547           may bring the focus back, so de-focus it again.
1548         */
1549         setXICFocus(pX11IMData->ic_active, FALSE);
1550         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1551             char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1552             setXICFocus(pX11IMData->ic_passive, FALSE);
1553             if (xText == (char *)NULL && tmpText)
1554                 xText = tmpText;
1555         }
1556 
1557     }
1558     if (xText != NULL) {
1559         jText = JNU_NewStringPlatform(env, (const char *)xText);
1560         XFree((void *)xText);
1561     }
1562 
1563     AWT_UNLOCK();
1564     return jText;
1565 }
1566 
1567 /*
1568  * Class:     sun_awt_X11InputMethod
1569  * Method:    setCompositionEnabledNative
1570  * Signature: (ZJ)V
1571  *
1572  * This method tries to set the XNPreeditState attribute associated with the current
1573  * XIC to the passed in 'enable' state.
1574  *
1575  * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1576  * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1577  * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1578  * method fails due to other reasons.
1579  *
1580  */
1581 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
1582   (JNIEnv *env, jobject this, jboolean enable)
1583 {
1584     X11InputMethodData *pX11IMData;
1585     char * ret = NULL;
1586 
1587     AWT_LOCK();
1588     pX11IMData = getX11InputMethodData(env, this);
1589 
1590     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1591         AWT_UNLOCK();
1592         return JNI_FALSE;
1593     }
1594 
1595     ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1596                        (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1597     AWT_UNLOCK();
1598 
1599     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1600         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1601     }
1602 
1603     return (jboolean)(ret == 0);
1604 }
1605 
1606 /*
1607  * Class:     sun_awt_X11InputMethod
1608  * Method:    isCompositionEnabledNative
1609  * Signature: (J)Z
1610  *
1611  * This method tries to get the XNPreeditState attribute associated with the current XIC.
1612  *
1613  * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1614  * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1615  * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1616  *
1617  */
1618 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
1619   (JNIEnv *env, jobject this)
1620 {
1621     X11InputMethodData *pX11IMData = NULL;
1622     char * ret = NULL;
1623     XIMPreeditState state;
1624 
1625     AWT_LOCK();
1626     pX11IMData = getX11InputMethodData(env, this);
1627 
1628     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1629         AWT_UNLOCK();
1630         return JNI_FALSE;
1631     }
1632 
1633     ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1634     AWT_UNLOCK();
1635 
1636     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1637         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1638         return JNI_FALSE;
1639     }
1640 
1641     return (jboolean)(state == XIMPreeditEnable);
1642 }
1643 
1644 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
1645   (JNIEnv *env, jobject this, jlong window)
1646 {
1647 #if defined(__linux__) || defined(MACOSX)
1648     AWT_LOCK();
1649     adjustStatusWindow(window);
1650     AWT_UNLOCK();
1651 #endif
1652 }