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