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