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