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