1 /* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #ifdef HEADLESS 27 #error This file should not be included in headless library 28 #endif 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <X11/Xlib.h> 33 #include <X11/keysym.h> 34 #include <sys/time.h> 35 36 #include "awt.h" 37 #include "awt_p.h" 38 39 #include <sun_awt_X11InputMethod.h> 40 #include <sun_awt_X11_XInputMethod.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( 580 Window parent) { 581 StatusWindow *statusWindow; 582 XSetWindowAttributes attrib; 583 unsigned long attribmask; 584 Window containerWindow; 585 Window status; 586 Window child; 587 XWindowAttributes xwa; 588 XWindowAttributes xxwa; 589 /* Variable for XCreateFontSet()*/ 590 char **mclr; 591 int mccr = 0; 592 char *dsr; 593 unsigned long bg, fg, light, dim; 594 int x, y, off_x, off_y, xx, yy; 595 unsigned int w, h, bw, depth; 596 XGCValues values; 597 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/ 598 int screen = 0; 599 int i; 600 AwtGraphicsConfigDataPtr adata; 601 extern int awt_numScreens; 602 /*hardcode the size right now, should get the size base on font*/ 603 int width=80, height=22; 604 Window rootWindow; 605 Window *ignoreWindowPtr; 606 unsigned int ignoreUnit; 607 608 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth); 609 610 attrib.override_redirect = True; 611 attribmask = CWOverrideRedirect; 612 for (i = 0; i < awt_numScreens; i++) { 613 if (RootWindow(dpy, i) == rootWindow) { 614 screen = i; 615 break; 616 } 617 } 618 adata = getDefaultConfig(screen); 619 bg = adata->AwtColorMatch(255, 255, 255, adata); 620 fg = adata->AwtColorMatch(0, 0, 0, adata); 621 light = adata->AwtColorMatch(195, 195, 195, adata); 622 dim = adata->AwtColorMatch(128, 128, 128, adata); 623 624 XGetWindowAttributes(dpy, parent, &xwa); 625 bw = 2; /*xwa.border_width does not have the correct value*/ 626 627 /*compare the size difference between parent container 628 and shell widget, the diff should be the border frame 629 and title bar height (?)*/ 630 631 XQueryTree( dpy, 632 parent, 633 &rootWindow, 634 &containerWindow, 635 &ignoreWindowPtr, 636 &ignoreUnit); 637 XGetWindowAttributes(dpy, containerWindow, &xxwa); 638 639 off_x = (xxwa.width - xwa.width) / 2; 640 off_y = xxwa.height - xwa.height - off_x; /*it's magic:-) */ 641 642 /*get the size of root window*/ 643 XGetWindowAttributes(dpy, rootWindow, &xxwa); 644 645 XTranslateCoordinates(dpy, 646 parent, xwa.root, 647 xwa.x, xwa.y, 648 &x, &y, 649 &child); 650 xx = x - off_x; 651 yy = y + xwa.height - off_y; 652 if (xx < 0 ){ 653 xx = 0; 654 } 655 if (xx + width > xxwa.width){ 656 xx = xxwa.width - width; 657 } 658 if (yy + height > xxwa.height){ 659 yy = xxwa.height - height; 660 } 661 662 status = XCreateWindow(dpy, 663 xwa.root, 664 xx, yy, 665 width, height, 666 0, 667 xwa.depth, 668 InputOutput, 669 adata->awt_visInfo.visual, 670 attribmask, &attrib); 671 XSelectInput(dpy, status, 672 ExposureMask | StructureNotifyMask | EnterWindowMask | 673 LeaveWindowMask | VisibilityChangeMask); 674 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow)); 675 if (statusWindow == NULL){ 676 THROW_OUT_OF_MEMORY_ERROR(); 677 return NULL; 678 } 679 statusWindow->w = status; 680 //12-point font 681 statusWindow->fontset = XCreateFontSet(dpy, 682 "-*-*-medium-r-normal-*-*-120-*-*-*-*", 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 statusWindow->x = x; 748 statusWindow->y = y; 749 statusWindow->height = xwa.height; 750 x = statusWindow->x - statusWindow->off_x; 751 y = statusWindow->y + statusWindow->height - statusWindow->off_y; 752 if (x < 0 ){ 753 x = 0; 754 } 755 if (x + statusWindow->statusW > statusWindow->rootW){ 756 x = statusWindow->rootW - statusWindow->statusW; 757 } 758 if (y + statusWindow->statusH > statusWindow->rootH){ 759 y = statusWindow->rootH - statusWindow->statusH; 760 } 761 XMoveWindow(dpy, statusWindow->w, x, y); 762 } 763 statusWindow->on = True; 764 XMapWindow(dpy, statusWindow->w); 765 } 766 767 void paintStatusWindow(StatusWindow *statusWindow){ 768 Window win = statusWindow->w; 769 GC lightgc = statusWindow->lightGC; 770 GC dimgc = statusWindow->dimGC; 771 GC bggc = statusWindow->bgGC; 772 GC fggc = statusWindow->fgGC; 773 774 int width = statusWindow->statusW; 775 int height = statusWindow->statusH; 776 int bwidth = statusWindow->bWidth; 777 XFillRectangle(dpy, win, bggc, 0, 0, width, height); 778 /* draw border */ 779 XDrawLine(dpy, win, fggc, 0, 0, width, 0); 780 XDrawLine(dpy, win, fggc, 0, height-1, width-1, height-1); 781 XDrawLine(dpy, win, fggc, 0, 0, 0, height-1); 782 XDrawLine(dpy, win, fggc, width-1, 0, width-1, height-1); 783 784 XDrawLine(dpy, win, lightgc, 1, 1, width-bwidth, 1); 785 XDrawLine(dpy, win, lightgc, 1, 1, 1, height-2); 786 XDrawLine(dpy, win, lightgc, 1, height-2, width-bwidth, height-2); 787 XDrawLine(dpy, win, lightgc, width-bwidth-1, 1, width-bwidth-1, height-2); 788 789 XDrawLine(dpy, win, dimgc, 2, 2, 2, height-3); 790 XDrawLine(dpy, win, dimgc, 2, height-3, width-bwidth-1, height-3); 791 XDrawLine(dpy, win, dimgc, 2, 2, width-bwidth-2, 2); 792 XDrawLine(dpy, win, dimgc, width-bwidth, 2, width-bwidth, height-3); 793 if (statusWindow->fontset){ 794 XmbDrawString(dpy, win, statusWindow->fontset, fggc, 795 bwidth + 2, height - bwidth - 4, 796 statusWindow->status, 797 strlen(statusWindow->status)); 798 } 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 void statusWindowEventHandler(XEvent event){ 807 JNIEnv *env = GetJNIEnv(); 808 X11InputMethodData *pX11IMData = NULL; 809 StatusWindow *statusWindow; 810 811 if (!isX11InputMethodGRefInList(currentX11InputMethodInstance)) { 812 currentX11InputMethodInstance = NULL; 813 return; 814 } 815 816 if (NULL == currentX11InputMethodInstance 817 || NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) 818 || NULL == (statusWindow = pX11IMData->statusWindow) 819 || statusWindow->w != event.xany.window){ 820 return; 821 } 822 823 switch (event.type){ 824 case Expose: 825 paintStatusWindow(statusWindow); 826 break; 827 case MapNotify: 828 case ConfigureNotify: 829 { 830 /*need to reset the stackMode...*/ 831 XWindowChanges xwc; 832 int value_make = CWStackMode; 833 xwc.stack_mode = TopIf; 834 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 835 } 836 break; 837 /* 838 case UnmapNotify: 839 case VisibilityNotify: 840 break; 841 */ 842 default: 843 break; 844 } 845 } 846 847 static void adjustStatusWindow(Window shell){ 848 JNIEnv *env = GetJNIEnv(); 849 X11InputMethodData *pX11IMData = NULL; 850 StatusWindow *statusWindow; 851 852 if (NULL == currentX11InputMethodInstance 853 || !isX11InputMethodGRefInList(currentX11InputMethodInstance) 854 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 855 || NULL == (statusWindow = pX11IMData->statusWindow) 856 || !statusWindow->on) { 857 return; 858 } 859 { 860 XWindowAttributes xwa; 861 int x, y; 862 Window child; 863 XGetWindowAttributes(dpy, shell, &xwa); 864 XTranslateCoordinates(dpy, 865 shell, xwa.root, 866 xwa.x, xwa.y, 867 &x, &y, 868 &child); 869 if (statusWindow->x != x 870 || statusWindow->y != y 871 || statusWindow->height != xwa.height){ 872 statusWindow->x = x; 873 statusWindow->y = y; 874 statusWindow->height = xwa.height; 875 876 x = statusWindow->x - statusWindow->off_x; 877 y = statusWindow->y + statusWindow->height - statusWindow->off_y; 878 if (x < 0 ){ 879 x = 0; 880 } 881 if (x + statusWindow->statusW > statusWindow->rootW){ 882 x = statusWindow->rootW - statusWindow->statusW; 883 } 884 if (y + statusWindow->statusH > statusWindow->rootH){ 885 y = statusWindow->rootH - statusWindow->statusH; 886 } 887 XMoveWindow(dpy, statusWindow->w, x, y); 888 } 889 } 890 } 891 #endif /* __linux__ || MACOSX */ 892 /* 893 * Creates two XICs, one for active clients and the other for passive 894 * clients. All information on those XICs are stored in the 895 * X11InputMethodData given by the pX11IMData parameter. 896 * 897 * For active clients: Try to use preedit callback to support 898 * on-the-spot. If tc is not null, the XIC to be created will 899 * share the Status Area with Motif widgets (TextComponents). If the 900 * preferable styles can't be used, fallback to root-window styles. If 901 * root-window styles failed, fallback to None styles. 902 * 903 * For passive clients: Try to use root-window styles. If failed, 904 * fallback to None styles. 905 */ 906 static Bool 907 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w) 908 { 909 XVaNestedList preedit = NULL; 910 XVaNestedList status = NULL; 911 XIMStyle on_the_spot_styles = XIMPreeditCallbacks, 912 active_styles = 0, 913 passive_styles = 0, 914 no_styles = 0; 915 XIMCallback *callbacks; 916 unsigned short i; 917 XIMStyles *im_styles; 918 char *ret = NULL; 919 920 if (X11im == NULL) { 921 return False; 922 } 923 if (!w) { 924 return False; 925 } 926 927 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL); 928 929 if (ret != NULL) { 930 jio_fprintf(stderr,"XGetIMValues: %s\n",ret); 931 return FALSE ; 932 } 933 934 #if defined(__linux__) || defined(MACOSX) 935 on_the_spot_styles |= XIMStatusNothing; 936 937 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea 938 at the same time, so use StatusCallback to draw the status 939 ourself 940 */ 941 for (i = 0; i < im_styles->count_styles; i++) { 942 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) { 943 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks); 944 break; 945 } 946 } 947 #else /*! __linux__ && !MACOSX */ 948 on_the_spot_styles |= XIMStatusNothing; 949 #endif /* __linux__ || MACOSX */ 950 951 for (i = 0; i < im_styles->count_styles; i++) { 952 active_styles |= im_styles->supported_styles[i] & on_the_spot_styles; 953 passive_styles |= im_styles->supported_styles[i] & ROOT_WINDOW_STYLES; 954 no_styles |= im_styles->supported_styles[i] & NO_STYLES; 955 } 956 957 XFree(im_styles); 958 959 if (active_styles != on_the_spot_styles) { 960 if (passive_styles == ROOT_WINDOW_STYLES) 961 active_styles = passive_styles; 962 else { 963 if (no_styles == NO_STYLES) 964 active_styles = passive_styles = NO_STYLES; 965 else 966 active_styles = passive_styles = 0; 967 } 968 } else { 969 if (passive_styles != ROOT_WINDOW_STYLES) { 970 if (no_styles == NO_STYLES) 971 active_styles = passive_styles = NO_STYLES; 972 else 973 active_styles = passive_styles = 0; 974 } 975 } 976 977 if (active_styles == on_the_spot_styles) { 978 pX11IMData->ic_passive = XCreateIC(X11im, 979 XNClientWindow, w, 980 XNFocusWindow, w, 981 XNInputStyle, passive_styles, 982 NULL); 983 984 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS); 985 if (callbacks == (XIMCallback *)NULL) 986 return False; 987 pX11IMData->callbacks = callbacks; 988 989 for (i = 0; i < NCALLBACKS; i++, callbacks++) { 990 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod; 991 callbacks->callback = callback_funcs[i]; 992 } 993 994 callbacks = pX11IMData->callbacks; 995 preedit = (XVaNestedList)XVaCreateNestedList(0, 996 XNPreeditStartCallback, &callbacks[PreeditStartIndex], 997 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex], 998 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex], 999 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex], 1000 NULL); 1001 if (preedit == (XVaNestedList)NULL) 1002 goto err; 1003 #if defined(__linux__) || defined(MACOSX) 1004 /*always try XIMStatusCallbacks for active client...*/ 1005 { 1006 status = (XVaNestedList)XVaCreateNestedList(0, 1007 XNStatusStartCallback, &callbacks[StatusStartIndex], 1008 XNStatusDoneCallback, &callbacks[StatusDoneIndex], 1009 XNStatusDrawCallback, &callbacks[StatusDrawIndex], 1010 NULL); 1011 1012 if (status == NULL) 1013 goto err; 1014 pX11IMData->statusWindow = createStatusWindow(w); 1015 pX11IMData->ic_active = XCreateIC(X11im, 1016 XNClientWindow, w, 1017 XNFocusWindow, w, 1018 XNInputStyle, active_styles, 1019 XNPreeditAttributes, preedit, 1020 XNStatusAttributes, status, 1021 NULL); 1022 XFree((void *)status); 1023 XFree((void *)preedit); 1024 } 1025 #else /* !__linux__ && !MACOSX */ 1026 pX11IMData->ic_active = XCreateIC(X11im, 1027 XNClientWindow, w, 1028 XNFocusWindow, w, 1029 XNInputStyle, active_styles, 1030 XNPreeditAttributes, preedit, 1031 NULL); 1032 XFree((void *)preedit); 1033 #endif /* __linux__ || MACOSX */ 1034 } else { 1035 pX11IMData->ic_active = XCreateIC(X11im, 1036 XNClientWindow, w, 1037 XNFocusWindow, w, 1038 XNInputStyle, active_styles, 1039 NULL); 1040 pX11IMData->ic_passive = pX11IMData->ic_active; 1041 } 1042 1043 if (pX11IMData->ic_active == (XIC)0 1044 || pX11IMData->ic_passive == (XIC)0) { 1045 return False; 1046 } 1047 1048 /* 1049 * Use commit string call back if possible. 1050 * This will ensure the correct order of preedit text and commit text 1051 */ 1052 { 1053 XIMCallback cb; 1054 cb.client_data = (XPointer) pX11IMData->x11inputmethod; 1055 cb.callback = (XIMProc) CommitStringCallback; 1056 XSetICValues (pX11IMData->ic_active, XNCommitStringCallback, &cb, NULL); 1057 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 1058 XSetICValues (pX11IMData->ic_passive, XNCommitStringCallback, &cb, NULL); 1059 } 1060 } 1061 1062 /* Add the global reference object to X11InputMethod to the list. */ 1063 addToX11InputMethodGRefList(pX11IMData->x11inputmethod); 1064 1065 return True; 1066 1067 err: 1068 if (preedit) 1069 XFree((void *)preedit); 1070 THROW_OUT_OF_MEMORY_ERROR(); 1071 return False; 1072 } 1073 1074 static void 1075 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1076 { 1077 /*ARGSUSED*/ 1078 /* printf("Native: PreeditCaretCallback\n"); */ 1079 } 1080 1081 static void 1082 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1083 { 1084 /*ARGSUSED*/ 1085 /* printf("Native: StatusStartCallback\n"); */ 1086 } 1087 1088 /* 1089 * Translate the preedit draw callback items to Java values and invoke 1090 * X11InputMethod.dispatchComposedText(). 1091 * 1092 * client_data: X11InputMethod object 1093 */ 1094 static void 1095 PreeditDrawCallback(XIC ic, XPointer client_data, 1096 XIMPreeditDrawCallbackStruct *pre_draw) 1097 { 1098 JNIEnv *env = GetJNIEnv(); 1099 X11InputMethodData *pX11IMData = NULL; 1100 jmethodID x11imMethodID; 1101 1102 XIMText *text; 1103 jstring javastr = NULL; 1104 jintArray style = NULL; 1105 1106 /* printf("Native: PreeditDrawCallback() \n"); */ 1107 if (pre_draw == NULL) { 1108 return; 1109 } 1110 AWT_LOCK(); 1111 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1112 if ((jobject)client_data == currentX11InputMethodInstance) { 1113 currentX11InputMethodInstance = NULL; 1114 } 1115 goto finally; 1116 } 1117 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { 1118 goto finally; 1119 } 1120 1121 if ((text = pre_draw->text) != NULL) { 1122 if (text->string.multi_byte != NULL) { 1123 if (pre_draw->text->encoding_is_wchar == False) { 1124 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); 1125 if (javastr == NULL) { 1126 goto finally; 1127 } 1128 } else { 1129 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1130 if (mbstr == NULL) { 1131 goto finally; 1132 } 1133 javastr = JNU_NewStringPlatform(env, (const char *)mbstr); 1134 free(mbstr); 1135 if (javastr == NULL) { 1136 goto finally; 1137 } 1138 } 1139 } 1140 if (text->feedback != NULL) { 1141 int cnt; 1142 jint *tmpstyle; 1143 1144 style = (*env)->NewIntArray(env, text->length); 1145 if (JNU_IsNull(env, style)) { 1146 (*env)->ExceptionClear(env); 1147 THROW_OUT_OF_MEMORY_ERROR(); 1148 goto finally; 1149 } 1150 1151 if (sizeof(XIMFeedback) == sizeof(jint)) { 1152 /* 1153 * Optimization to avoid copying the array 1154 */ 1155 (*env)->SetIntArrayRegion(env, style, 0, 1156 text->length, (jint *)text->feedback); 1157 } else { 1158 tmpstyle = (jint *)malloc(sizeof(jint)*(text->length)); 1159 if (tmpstyle == (jint *) NULL) { 1160 THROW_OUT_OF_MEMORY_ERROR(); 1161 goto finally; 1162 } 1163 for (cnt = 0; cnt < (int)text->length; cnt++) 1164 tmpstyle[cnt] = text->feedback[cnt]; 1165 (*env)->SetIntArrayRegion(env, style, 0, 1166 text->length, (jint *)tmpstyle); 1167 } 1168 } 1169 } 1170 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 1171 "dispatchComposedText", 1172 "(Ljava/lang/String;[IIIIJ)V", 1173 javastr, 1174 style, 1175 (jint)pre_draw->chg_first, 1176 (jint)pre_draw->chg_length, 1177 (jint)pre_draw->caret, 1178 awt_util_nowMillisUTC()); 1179 finally: 1180 AWT_UNLOCK(); 1181 return; 1182 } 1183 1184 static void 1185 PreeditCaretCallback(XIC ic, XPointer client_data, 1186 XIMPreeditCaretCallbackStruct *pre_caret) 1187 { 1188 /*ARGSUSED*/ 1189 /* printf("Native: PreeditCaretCallback\n"); */ 1190 1191 } 1192 1193 #if defined(__linux__) || defined(MACOSX) 1194 static void 1195 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1196 { 1197 /*ARGSUSED*/ 1198 /*printf("StatusStartCallback:\n"); */ 1199 1200 } 1201 1202 static void 1203 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1204 { 1205 /*ARGSUSED*/ 1206 /*printf("StatusDoneCallback:\n"); */ 1207 1208 } 1209 1210 static void 1211 StatusDrawCallback(XIC ic, XPointer client_data, 1212 XIMStatusDrawCallbackStruct *status_draw) 1213 { 1214 /*ARGSUSED*/ 1215 /*printf("StatusDrawCallback:\n"); */ 1216 JNIEnv *env = GetJNIEnv(); 1217 X11InputMethodData *pX11IMData = NULL; 1218 StatusWindow *statusWindow; 1219 1220 AWT_LOCK(); 1221 1222 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1223 if ((jobject)client_data == currentX11InputMethodInstance) { 1224 currentX11InputMethodInstance = NULL; 1225 } 1226 goto finally; 1227 } 1228 1229 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data)) 1230 || NULL == (statusWindow = pX11IMData->statusWindow)){ 1231 goto finally; 1232 } 1233 currentX11InputMethodInstance = (jobject)client_data; 1234 1235 if (status_draw->type == XIMTextType){ 1236 XIMText *text = (status_draw->data).text; 1237 if (text != NULL){ 1238 if (text->string.multi_byte != NULL) { 1239 strncpy(statusWindow->status, text->string.multi_byte, MAX_STATUS_LEN); 1240 statusWindow->status[MAX_STATUS_LEN-1] = '\0'; 1241 } 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 } 1251 else { 1252 statusWindow->on = False; 1253 /*just turnoff the status window 1254 paintStatusWindow(statusWindow); 1255 */ 1256 onoffStatusWindow(pX11IMData, 0, False); 1257 } 1258 } 1259 1260 finally: 1261 AWT_UNLOCK(); 1262 } 1263 #endif /* __linux__ || MACOSX */ 1264 1265 static void CommitStringCallback(XIC ic, XPointer client_data, XPointer call_data) { 1266 JNIEnv *env = GetJNIEnv(); 1267 XIMText * text = (XIMText *)call_data; 1268 X11InputMethodData *pX11IMData = NULL; 1269 jstring javastr; 1270 1271 AWT_LOCK(); 1272 1273 if (!isX11InputMethodGRefInList((jobject)client_data)) { 1274 if ((jobject)client_data == currentX11InputMethodInstance) { 1275 currentX11InputMethodInstance = NULL; 1276 } 1277 goto finally; 1278 } 1279 1280 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { 1281 goto finally; 1282 } 1283 currentX11InputMethodInstance = (jobject)client_data; 1284 1285 if (text->encoding_is_wchar == False) { 1286 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); 1287 } else { 1288 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1289 if (mbstr == NULL) { 1290 goto finally; 1291 } 1292 javastr = JNU_NewStringPlatform(env, (const char *)mbstr); 1293 free(mbstr); 1294 } 1295 1296 if (javastr != NULL) { 1297 JNU_CallMethodByName(env, NULL, 1298 pX11IMData->x11inputmethod, 1299 "dispatchCommittedText", 1300 "(Ljava/lang/String;J)V", 1301 javastr, 1302 awt_util_nowMillisUTC()); 1303 } 1304 finally: 1305 AWT_UNLOCK(); 1306 } 1307 1308 static void OpenXIMCallback(Display *display, XPointer client_data, XPointer call_data) { 1309 XIMCallback ximCallback; 1310 1311 X11im = XOpenIM(display, NULL, NULL, NULL); 1312 if (X11im == NULL) { 1313 return; 1314 } 1315 1316 ximCallback.callback = (XIMProc)DestroyXIMCallback; 1317 ximCallback.client_data = NULL; 1318 XSetIMValues(X11im, XNDestroyCallback, &ximCallback, NULL); 1319 } 1320 1321 static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) { 1322 /* mark that XIM server was destroyed */ 1323 X11im = NULL; 1324 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1325 /* free the old pX11IMData and set it to null. this also avoids crashing 1326 * the jvm if the XIM server reappears */ 1327 X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance); 1328 } 1329 1330 /* 1331 * Class: sun_awt_X11InputMethod 1332 * Method: initIDs 1333 * Signature: ()V 1334 */ 1335 1336 /* This function gets called from the static initializer for 1337 X11InputMethod.java 1338 to initialize the fieldIDs for fields that may be accessed from C */ 1339 JNIEXPORT void JNICALL 1340 Java_sun_awt_X11InputMethod_initIDs(JNIEnv *env, jclass cls) 1341 { 1342 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); 1343 } 1344 1345 1346 JNIEXPORT jboolean JNICALL 1347 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env, 1348 jobject this, 1349 jlong display) 1350 { 1351 Bool registered; 1352 1353 AWT_LOCK(); 1354 1355 dpy = (Display *)jlong_to_ptr(display); 1356 1357 /* Use IMInstantiate call back only on Linux, as there is a bug in Solaris 1358 (4768335) 1359 */ 1360 #if defined(__linux__) || defined(MACOSX) 1361 registered = XRegisterIMInstantiateCallback(dpy, NULL, NULL, 1362 NULL, (XIDProc)OpenXIMCallback, NULL); 1363 if (!registered) { 1364 /* directly call openXIM callback */ 1365 #endif 1366 OpenXIMCallback(dpy, NULL, NULL); 1367 #if defined(__linux__) || defined(MACOSX) 1368 } 1369 #endif 1370 1371 AWT_UNLOCK(); 1372 1373 return JNI_TRUE; 1374 } 1375 1376 JNIEXPORT jboolean JNICALL 1377 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env, 1378 jobject this, 1379 jlong window) 1380 { 1381 X11InputMethodData *pX11IMData; 1382 jobject globalRef; 1383 XIC ic; 1384 1385 AWT_LOCK(); 1386 1387 if (!window) { 1388 JNU_ThrowNullPointerException(env, "NullPointerException"); 1389 AWT_UNLOCK(); 1390 return JNI_FALSE; 1391 } 1392 1393 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData)); 1394 if (pX11IMData == NULL) { 1395 THROW_OUT_OF_MEMORY_ERROR(); 1396 AWT_UNLOCK(); 1397 return JNI_FALSE; 1398 } 1399 1400 globalRef = (*env)->NewGlobalRef(env, this); 1401 pX11IMData->x11inputmethod = globalRef; 1402 #if defined(__linux__) || defined(MACOSX) 1403 pX11IMData->statusWindow = NULL; 1404 #endif /* __linux__ || MACOSX */ 1405 1406 pX11IMData->lookup_buf = 0; 1407 pX11IMData->lookup_buf_len = 0; 1408 1409 if (createXIC(env, pX11IMData, (Window)window) == False) { 1410 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); 1411 pX11IMData = (X11InputMethodData *) NULL; 1412 if ((*env)->ExceptionCheck(env)) { 1413 goto finally; 1414 } 1415 } 1416 1417 setX11InputMethodData(env, this, pX11IMData); 1418 1419 finally: 1420 AWT_UNLOCK(); 1421 return (pX11IMData != NULL); 1422 } 1423 1424 JNIEXPORT void JNICALL 1425 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, 1426 jobject this, 1427 jlong w, 1428 jboolean req, 1429 jboolean active) 1430 { 1431 X11InputMethodData *pX11IMData; 1432 AWT_LOCK(); 1433 pX11IMData = getX11InputMethodData(env, this); 1434 if (pX11IMData == NULL) { 1435 AWT_UNLOCK(); 1436 return; 1437 } 1438 1439 if (req) { 1440 if (!w) { 1441 AWT_UNLOCK(); 1442 return; 1443 } 1444 pX11IMData->current_ic = active ? 1445 pX11IMData->ic_active : pX11IMData->ic_passive; 1446 /* 1447 * On Solaris2.6, setXICWindowFocus() has to be invoked 1448 * before setting focus. 1449 */ 1450 setXICWindowFocus(pX11IMData->current_ic, w); 1451 setXICFocus(pX11IMData->current_ic, req); 1452 currentX11InputMethodInstance = pX11IMData->x11inputmethod; 1453 currentFocusWindow = w; 1454 #if defined(__linux__) || defined(MACOSX) 1455 if (active && pX11IMData->statusWindow && pX11IMData->statusWindow->on) 1456 onoffStatusWindow(pX11IMData, w, True); 1457 #endif 1458 } else { 1459 currentX11InputMethodInstance = NULL; 1460 currentFocusWindow = 0; 1461 #if defined(__linux__) || defined(MACOSX) 1462 onoffStatusWindow(pX11IMData, 0, False); 1463 if (pX11IMData->current_ic != NULL) 1464 #endif 1465 setXICFocus(pX11IMData->current_ic, req); 1466 1467 pX11IMData->current_ic = (XIC)0; 1468 } 1469 1470 XFlush(dpy); 1471 AWT_UNLOCK(); 1472 } 1473 1474 JNIEXPORT void JNICALL 1475 Java_sun_awt_X11InputMethod_turnoffStatusWindow(JNIEnv *env, 1476 jobject this) 1477 { 1478 #if defined(__linux__) || defined(MACOSX) 1479 X11InputMethodData *pX11IMData; 1480 StatusWindow *statusWindow; 1481 1482 AWT_LOCK(); 1483 1484 if (NULL == currentX11InputMethodInstance 1485 || !isX11InputMethodGRefInList(currentX11InputMethodInstance) 1486 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 1487 || NULL == (statusWindow = pX11IMData->statusWindow) 1488 || !statusWindow->on ){ 1489 AWT_UNLOCK(); 1490 return; 1491 } 1492 onoffStatusWindow(pX11IMData, 0, False); 1493 1494 AWT_UNLOCK(); 1495 #endif 1496 } 1497 1498 JNIEXPORT void JNICALL 1499 Java_sun_awt_X11InputMethod_disposeXIC(JNIEnv *env, 1500 jobject this) 1501 { 1502 X11InputMethodData *pX11IMData = NULL; 1503 1504 AWT_LOCK(); 1505 pX11IMData = getX11InputMethodData(env, this); 1506 if (pX11IMData == NULL) { 1507 AWT_UNLOCK(); 1508 return; 1509 } 1510 1511 setX11InputMethodData(env, this, NULL); 1512 1513 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) { 1514 currentX11InputMethodInstance = NULL; 1515 currentFocusWindow = 0; 1516 } 1517 destroyX11InputMethodData(env, pX11IMData); 1518 AWT_UNLOCK(); 1519 } 1520 1521 JNIEXPORT jstring JNICALL 1522 Java_sun_awt_X11InputMethod_resetXIC(JNIEnv *env, 1523 jobject this) 1524 { 1525 X11InputMethodData *pX11IMData; 1526 char *xText = NULL; 1527 jstring jText = (jstring)0; 1528 1529 AWT_LOCK(); 1530 pX11IMData = getX11InputMethodData(env, this); 1531 if (pX11IMData == NULL) { 1532 AWT_UNLOCK(); 1533 return jText; 1534 } 1535 1536 if (pX11IMData->current_ic) 1537 xText = XmbResetIC(pX11IMData->current_ic); 1538 else { 1539 /* 1540 * If there is no reference to the current XIC, try to reset both XICs. 1541 */ 1542 xText = XmbResetIC(pX11IMData->ic_active); 1543 /*it may also means that the real client component does 1544 not have focus -- has been deactivated... its xic should 1545 not have the focus, bug#4284651 showes reset XIC for htt 1546 may bring the focus back, so de-focus it again. 1547 */ 1548 setXICFocus(pX11IMData->ic_active, FALSE); 1549 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 1550 char *tmpText = XmbResetIC(pX11IMData->ic_passive); 1551 setXICFocus(pX11IMData->ic_passive, FALSE); 1552 if (xText == (char *)NULL && tmpText) 1553 xText = tmpText; 1554 } 1555 1556 } 1557 if (xText != NULL) { 1558 jText = JNU_NewStringPlatform(env, (const char *)xText); 1559 XFree((void *)xText); 1560 } 1561 1562 AWT_UNLOCK(); 1563 return jText; 1564 } 1565 1566 /* 1567 * Class: sun_awt_X11InputMethod 1568 * Method: setCompositionEnabledNative 1569 * Signature: (ZJ)V 1570 * 1571 * This method tries to set the XNPreeditState attribute associated with the current 1572 * XIC to the passed in 'enable' state. 1573 * 1574 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the 1575 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute, 1576 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this 1577 * method fails due to other reasons. 1578 * 1579 */ 1580 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_setCompositionEnabledNative 1581 (JNIEnv *env, jobject this, jboolean enable) 1582 { 1583 X11InputMethodData *pX11IMData; 1584 char * ret = NULL; 1585 1586 AWT_LOCK(); 1587 pX11IMData = getX11InputMethodData(env, this); 1588 1589 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 1590 AWT_UNLOCK(); 1591 return JNI_FALSE; 1592 } 1593 1594 ret = XSetICValues(pX11IMData->current_ic, XNPreeditState, 1595 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); 1596 AWT_UNLOCK(); 1597 1598 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { 1599 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 1600 } 1601 1602 return (jboolean)(ret == 0); 1603 } 1604 1605 /* 1606 * Class: sun_awt_X11InputMethod 1607 * Method: isCompositionEnabledNative 1608 * Signature: (J)Z 1609 * 1610 * This method tries to get the XNPreeditState attribute associated with the current XIC. 1611 * 1612 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if 1613 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException 1614 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons. 1615 * 1616 */ 1617 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethod_isCompositionEnabledNative 1618 (JNIEnv *env, jobject this) 1619 { 1620 X11InputMethodData *pX11IMData = NULL; 1621 char * ret = NULL; 1622 XIMPreeditState state; 1623 1624 AWT_LOCK(); 1625 pX11IMData = getX11InputMethodData(env, this); 1626 1627 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 1628 AWT_UNLOCK(); 1629 return JNI_FALSE; 1630 } 1631 1632 ret = XGetICValues(pX11IMData->current_ic, XNPreeditState, &state, NULL); 1633 AWT_UNLOCK(); 1634 1635 if ((ret != 0) && (strcmp(ret, XNPreeditState) == 0)) { 1636 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 1637 return JNI_FALSE; 1638 } 1639 1640 return (jboolean)(state == XIMPreeditEnable); 1641 } 1642 1643 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow 1644 (JNIEnv *env, jobject this, jlong window) 1645 { 1646 #if defined(__linux__) || defined(MACOSX) 1647 AWT_LOCK(); 1648 adjustStatusWindow(window); 1649 AWT_UNLOCK(); 1650 #endif 1651 }