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