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     JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1477     X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
1478 }
1479 
1480 /*
1481  * Class:     java_sun_awt_motif_X11InputMethod
1482  * Method:    initIDs
1483  * Signature: ()V
1484  */
1485 
1486 /* This function gets called from the static initializer for
1487    X11InputMethod.java
1488    to initialize the fieldIDs for fields that may be accessed from C */
1489 JNIEXPORT void JNICALL
1490 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls)
1491 {
1492     x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J");
1493 }
1494 
1495 
1496 JNIEXPORT jboolean JNICALL
1497 #ifdef XAWT
1498 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env,
1499                                           jobject this,
1500                                           jlong display)
1501 #else
1502 Java_sun_awt_motif_MInputMethod_openXIMNative(JNIEnv *env,
1503                                           jobject this)
1504 #endif
1505 {
1506     Bool registered;
1507 
1508     AWT_LOCK();
1509 
1510 #ifdef XAWT
1511     dpy = (Display *)display;
1512 #else
1513     dpy = awt_display;
1514 #endif
1515 
1516 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris
1517    (4768335)
1518 */
1519 #ifdef __linux__
1520     registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL,
1521                      NULL, (XIMProc)OpenXIMCallback, NULL);
1522     if (!registered) {
1523         /* directly call openXIM callback */
1524 #endif
1525         OpenXIMCallback(dpy, NULL, NULL);
1526 #ifdef __linux__
1527     }
1528 #endif
1529 
1530     AWT_UNLOCK();
1531 
1532     return JNI_TRUE;
1533 }
1534 
1535 JNIEXPORT jboolean JNICALL
1536 #ifdef XAWT
1537 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env,
1538                                                   jobject this,
1539                                                   jlong window)
1540 {
1541 #else /* !XAWT */
1542 Java_sun_awt_motif_MInputMethod_createXICNative(JNIEnv *env,
1543                                                   jobject this,
1544                                                   jobject comp,
1545                                                   jobject tc)
1546 {
1547     struct ComponentData *cdata;
1548 #endif /* XAWT */
1549     X11InputMethodData *pX11IMData;
1550     jobject globalRef;
1551     XIC ic;
1552 
1553     AWT_LOCK();
1554 
1555 #ifdef XAWT
1556     if (window == NULL) {
1557 #else /* !XAWT */
1558     if (JNU_IsNull(env, comp)) {
1559 #endif /* XAWT */
1560         JNU_ThrowNullPointerException(env, "NullPointerException");
1561         AWT_UNLOCK();
1562         return JNI_FALSE;
1563     }
1564 
1565     pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData));
1566     if (pX11IMData == NULL) {
1567         THROW_OUT_OF_MEMORY_ERROR();
1568         AWT_UNLOCK();
1569         return JNI_FALSE;
1570     }
1571 
1572 #ifndef XAWT
1573     if (mcompClass == NULL) {
1574         mcompClass = findClass(MCOMPONENTPEER_CLASS_NAME);
1575         mcompPDataID = (*env)->GetFieldID(env, mcompClass, "pData", "J");
1576     }
1577     cdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,comp,mcompPDataID);
1578 
1579     if (cdata == 0) {
1580         free((void *)pX11IMData);
1581         JNU_ThrowNullPointerException(env, "createXIC");
1582         AWT_UNLOCK();
1583         return JNI_FALSE;
1584     }
1585 
1586     pX11IMData->peer = (*env)->NewGlobalRef(env, comp);
1587 #endif /* XAWT */
1588     globalRef = (*env)->NewGlobalRef(env, this);
1589     pX11IMData->x11inputmethod = globalRef;
1590 #ifdef __linux__
1591     pX11IMData->statusWindow = NULL;
1592 #else /* __linux__ */
1593 #ifndef XAWT
1594     pX11IMData->statusWidget = (Widget) NULL;
1595 #endif /* XAWT */
1596 #endif /* __linux__ */
1597 
1598     pX11IMData->lookup_buf = 0;
1599     pX11IMData->lookup_buf_len = 0;
1600 
1601 #ifdef XAWT
1602     if (createXIC(env, pX11IMData, (Window)window)
1603 #else /* !XAWT */
1604     if (createXIC(cdata->widget, pX11IMData, tc, comp)
1605 #endif /* XAWT */
1606         == False) {
1607         destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1608         pX11IMData = (X11InputMethodData *) NULL;
1609     }
1610 
1611     setX11InputMethodData(env, this, pX11IMData);
1612 
1613     AWT_UNLOCK();
1614     return (pX11IMData != NULL);
1615 }
1616 
1617 #ifndef XAWT
1618 JNIEXPORT void JNICALL
1619 Java_sun_awt_motif_MInputMethod_reconfigureXICNative(JNIEnv *env,
1620                                                        jobject this,
1621                                                        jobject comp,
1622                                                        jobject tc)
1623 {
1624     X11InputMethodData *pX11IMData;
1625 
1626     AWT_LOCK();
1627 
1628     pX11IMData = getX11InputMethodData(env, this);
1629     if (pX11IMData == NULL) {
1630         AWT_UNLOCK();
1631         return;
1632     }
1633 
1634     if (pX11IMData->current_ic == (XIC)0) {
1635         destroyX11InputMethodData(env, pX11IMData);
1636         pX11IMData = (X11InputMethodData *)NULL;
1637     } else {
1638         Bool active;
1639         struct ComponentData *cdata;
1640 
1641         active = pX11IMData->current_ic == pX11IMData->ic_active;
1642         if (mcompClass == NULL) {
1643             mcompClass = findClass(MCOMPONENTPEER_CLASS_NAME);
1644             mcompPDataID = (*env)->GetFieldID(env, mcompClass, "pData", "J");
1645         }
1646         cdata = (struct ComponentData *) JNU_GetLongFieldAsPtr(env,comp,mcompPDataID);
1647         if (cdata == 0) {
1648             JNU_ThrowNullPointerException(env, "reconfigureXICNative");
1649             destroyX11InputMethodData(env, pX11IMData);
1650             pX11IMData = (X11InputMethodData *)NULL;
1651         }
1652         XDestroyIC(pX11IMData->ic_active);
1653         if (pX11IMData->ic_active != pX11IMData->ic_passive)
1654             XDestroyIC(pX11IMData->ic_passive);
1655         pX11IMData->current_ic = (XIC)0;
1656         pX11IMData->ic_active = (XIC)0;
1657         pX11IMData->ic_passive = (XIC)0;
1658         if (createXIC(cdata->widget, pX11IMData, tc, comp)) {
1659             pX11IMData->current_ic = active ?
1660                         pX11IMData->ic_active : pX11IMData->ic_passive;
1661             /*
1662              * On Solaris2.6, setXICWindowFocus() has to be invoked
1663              * before setting focus.
1664              */
1665             setXICWindowFocus(pX11IMData->current_ic, XtWindow(cdata->widget));
1666             setXICFocus(pX11IMData->current_ic, True);
1667         } else {
1668             destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData);
1669             pX11IMData = (X11InputMethodData *)NULL;
1670         }
1671     }
1672 
1673     setX11InputMethodData(env, this, pX11IMData);
1674 
1675     AWT_UNLOCK();
1676 }
1677 
1678 JNIEXPORT void JNICALL
1679 Java_sun_awt_motif_MInputMethod_setXICFocusNative(JNIEnv *env,
1680                                               jobject this,
1681                                               jobject comp,
1682                                               jboolean req,
1683                                               jboolean active)
1684 {
1685     struct ComponentData *cdata;
1686     Widget w;
1687 #else /* !XAWT */
1688 JNIEXPORT void JNICALL
1689 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env,
1690                                               jobject this,
1691                                               jlong w,
1692                                               jboolean req,
1693                                               jboolean active)
1694 {
1695 #endif /* XAWT */
1696     X11InputMethodData *pX11IMData;
1697     AWT_LOCK();
1698     pX11IMData = getX11InputMethodData(env, this);
1699     if (pX11IMData == NULL) {
1700         AWT_UNLOCK();
1701         return;
1702     }
1703 
1704     if (req) {
1705 #ifdef XAWT
1706         if (w == NULL) {
1707             AWT_UNLOCK();
1708             return;
1709         }
1710 #else /* !XAWT */
1711         struct ComponentData *cdata;
1712 
1713         if (JNU_IsNull(env, comp)) {
1714             AWT_UNLOCK();
1715             return;
1716         }
1717         if (mcompClass == NULL) {
1718             mcompClass = findClass(MCOMPONENTPEER_CLASS_NAME);
1719             mcompPDataID = (*env)->GetFieldID(env, mcompClass, "pData", "J");
1720         }
1721         cdata = (struct ComponentData *)JNU_GetLongFieldAsPtr(env, comp,
1722                                                               mcompPDataID);
1723         if (cdata == 0) {
1724             JNU_ThrowNullPointerException(env, "setXICFocus pData");
1725             AWT_UNLOCK();
1726             return;
1727         }
1728 #endif /* XAWT */
1729 
1730         pX11IMData->current_ic = active ?
1731                         pX11IMData->ic_active : pX11IMData->ic_passive;
1732         /*
1733          * On Solaris2.6, setXICWindowFocus() has to be invoked
1734          * before setting focus.
1735          */
1736 #ifndef XAWT
1737         w = cdata->widget;
1738 #endif /* XAWT */
1739         setXICWindowFocus(pX11IMData->current_ic, XtWindow(w));
1740         setXICFocus(pX11IMData->current_ic, req);
1741         currentX11InputMethodInstance = pX11IMData->x11inputmethod;
1742         currentFocusWindow =  XtWindow(w);
1743 #ifdef __linux__
1744         if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on)
1745             onoffStatusWindow(pX11IMData, w, True);
1746 #endif
1747     } else {
1748         currentX11InputMethodInstance = NULL;
1749         currentFocusWindow = 0;
1750 #ifdef __linux__
1751         onoffStatusWindow(pX11IMData, 0, False);
1752         if (pX11IMData->current_ic != NULL)
1753 #endif
1754         setXICFocus(pX11IMData->current_ic, req);
1755 
1756         pX11IMData->current_ic = (XIC)0;
1757     }
1758 
1759     XFlush(dpy);
1760     AWT_UNLOCK();
1761 }
1762 
1763 JNIEXPORT void JNICALL
1764 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env,
1765                                                 jobject this)
1766 {
1767 #ifdef __linux__
1768     X11InputMethodData *pX11IMData;
1769     StatusWindow *statusWindow;
1770 
1771     AWT_LOCK();
1772 
1773     if (NULL == currentX11InputMethodInstance
1774         || !isX11InputMethodGRefInList(currentX11InputMethodInstance)
1775         || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance))
1776         || NULL == (statusWindow = pX11IMData->statusWindow)
1777         || !statusWindow->on ){
1778         AWT_UNLOCK();
1779         return;
1780     }
1781     onoffStatusWindow(pX11IMData, 0, False);
1782 
1783     AWT_UNLOCK();
1784 #endif
1785 }
1786 
1787 JNIEXPORT void JNICALL
1788 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env,
1789                                              jobject this)
1790 {
1791     X11InputMethodData *pX11IMData = NULL;
1792 
1793     AWT_LOCK();
1794     pX11IMData = getX11InputMethodData(env, this);
1795     if (pX11IMData == NULL) {
1796         AWT_UNLOCK();
1797         return;
1798     }
1799 
1800     setX11InputMethodData(env, this, NULL);
1801 
1802     if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) {
1803         currentX11InputMethodInstance = NULL;
1804         currentFocusWindow = 0;
1805     }
1806     destroyX11InputMethodData(env, pX11IMData);
1807     AWT_UNLOCK();
1808 }
1809 
1810 JNIEXPORT jstring JNICALL
1811 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env,
1812                                            jobject this)
1813 {
1814     X11InputMethodData *pX11IMData;
1815     char *xText = NULL;
1816     jstring jText = (jstring)0;
1817 
1818     AWT_LOCK();
1819     pX11IMData = getX11InputMethodData(env, this);
1820     if (pX11IMData == NULL) {
1821         AWT_UNLOCK();
1822         return jText;
1823     }
1824 
1825     if (pX11IMData->current_ic)
1826         xText = XmbResetIC(pX11IMData->current_ic);
1827     else {
1828         /*
1829          * If there is no reference to the current XIC, try to reset both XICs.
1830          */
1831         xText = XmbResetIC(pX11IMData->ic_active);
1832         /*it may also means that the real client component does
1833           not have focus -- has been deactivated... its xic should
1834           not have the focus, bug#4284651 showes reset XIC for htt
1835           may bring the focus back, so de-focus it again.
1836         */
1837         setXICFocus(pX11IMData->ic_active, FALSE);
1838         if (pX11IMData->ic_active != pX11IMData->ic_passive) {
1839             char *tmpText = XmbResetIC(pX11IMData->ic_passive);
1840             setXICFocus(pX11IMData->ic_passive, FALSE);
1841             if (xText == (char *)NULL && tmpText)
1842                 xText = tmpText;
1843         }
1844 
1845     }
1846     if (xText != NULL) {
1847         jText = JNU_NewStringPlatform(env, (const char *)xText);
1848         XFree((void *)xText);
1849     }
1850 
1851     AWT_UNLOCK();
1852     return jText;
1853 }
1854 
1855 #ifndef XAWT
1856 JNIEXPORT void JNICALL
1857 Java_sun_awt_motif_MInputMethod_configureStatusAreaNative(JNIEnv *env,
1858                                                             jobject this,
1859                                                             jobject tc)
1860 {
1861     X11InputMethodData *pX11IMData;
1862     XVaNestedList status;
1863 
1864 #ifdef __linux__
1865       /*do nothing for linux? */
1866 #else
1867     AWT_LOCK();
1868     pX11IMData = getX11InputMethodData(env, this);
1869 
1870     if ((pX11IMData == NULL) || (pX11IMData->ic_active == (XIC)0)) {
1871         AWT_UNLOCK();
1872         return;
1873     }
1874 
1875     if (pX11IMData->statusWidget) {
1876         status = awt_motif_getXICStatusAreaList(pX11IMData->statusWidget, tc);
1877         if (status != (XVaNestedList)NULL) {
1878             XSetICValues(pX11IMData->ic_active,
1879                          XNStatusAttributes, status,
1880                          NULL);
1881             XFree((void *)status);
1882         }
1883     }
1884     AWT_UNLOCK();
1885 #endif
1886 }
1887 #endif /* XAWT */
1888 
1889 /*
1890  * Class:     sun_awt_X11InputMethod
1891  * Method:    setCompositionEnabledNative
1892  * Signature: (ZJ)V
1893  *
1894  * This method tries to set the XNPreeditState attribute associated with the current
1895  * XIC to the passed in 'enable' state.
1896  *
1897  * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the
1898  * 'enable' state; Otherwise, if XSetICValues fails to set this attribute,
1899  * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this
1900  * method fails due to other reasons.
1901  *
1902  */
1903 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative
1904   (JNIEnv *env, jobject this, jboolean enable)
1905 {
1906     X11InputMethodData *pX11IMData;
1907     char * ret = NULL;
1908 
1909     AWT_LOCK();
1910     pX11IMData = getX11InputMethodData(env, this);
1911 
1912     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1913         AWT_UNLOCK();
1914         return JNI_FALSE;
1915     }
1916 
1917     ret = XSetICValues(pX11IMData->current_ic, XNPreeditState,
1918                        (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL);
1919     AWT_UNLOCK();
1920 
1921     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1922         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1923     }
1924 
1925     return (jboolean)(ret == 0);
1926 }
1927 
1928 /*
1929  * Class:     sun_awt_X11InputMethod
1930  * Method:    isCompositionEnabledNative
1931  * Signature: (J)Z
1932  *
1933  * This method tries to get the XNPreeditState attribute associated with the current XIC.
1934  *
1935  * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if
1936  * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException
1937  * will be thrown. JNI_FALSE is returned if this method fails due to other reasons.
1938  *
1939  */
1940 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative
1941   (JNIEnv *env, jobject this)
1942 {
1943     X11InputMethodData *pX11IMData = NULL;
1944     char * ret = NULL;
1945     XIMPreeditState state;
1946 
1947     AWT_LOCK();
1948     pX11IMData = getX11InputMethodData(env, this);
1949 
1950     if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) {
1951         AWT_UNLOCK();
1952         return JNI_FALSE;
1953     }
1954 
1955     ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL);
1956     AWT_UNLOCK();
1957 
1958     if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) {
1959         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "");
1960         return JNI_FALSE;
1961     }
1962 
1963     return (jboolean)(state == XIMPreeditEnable);
1964 }
1965 
1966 #ifdef XAWT
1967 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow
1968   (JNIEnv *env, jobject this, jlong window)
1969 {
1970 #ifdef __linux__
1971     AWT_LOCK();
1972     adjustStatusWindow(window);
1973     AWT_UNLOCK();
1974 #endif
1975 }
1976 #endif