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