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