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