1 /* 2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #ifdef HEADLESS 27 #error This file should not be included in headless library 28 #endif 29 30 #include "awt.h" 31 #include "awt_p.h" 32 33 #include <sun_awt_X11InputMethodBase.h> 34 #include <sun_awt_X11InputMethod.h> 35 #include <sun_awt_X11_XInputMethod.h> 36 37 #include <langinfo.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <sys/time.h> 41 #include <wchar.h> 42 #include <wctype.h> 43 #include <X11/Intrinsic.h> 44 #include <X11/keysym.h> 45 #include <X11/Xlib.h> 46 47 #define THROW_OUT_OF_MEMORY_ERROR() \ 48 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL) 49 50 struct X11InputMethodIDs { 51 jfieldID pData; 52 } x11InputMethodIDs; 53 54 static int PreeditStartCallback(XIC, XPointer, XPointer); 55 static void PreeditDoneCallback(XIC, XPointer, XPointer); 56 static void PreeditDrawCallback(XIC, XPointer, 57 XIMPreeditDrawCallbackStruct *); 58 static void PreeditCaretCallback(XIC, XPointer, 59 XIMPreeditCaretCallbackStruct *); 60 static void StatusStartCallback(XIC, XPointer, XPointer); 61 static void StatusDoneCallback(XIC, XPointer, XPointer); 62 static void StatusDrawCallback(XIC, XPointer, 63 XIMStatusDrawCallbackStruct *); 64 65 #define ROOT_WINDOW_STYLES (XIMPreeditNothing | XIMStatusNothing) 66 #define NO_STYLES (XIMPreeditNone | XIMStatusNone) 67 /* added style to allow for in-place composition, such as "dead" keys for accents */ 68 #define IN_PLACE_STYLES (XIMPreeditNothing | XIMStatusNone) 69 70 #define PreeditStartIndex 0 71 #define PreeditDoneIndex 1 72 #define PreeditDrawIndex 2 73 #define PreeditCaretIndex 3 74 #define StatusStartIndex 4 75 #define StatusDoneIndex 5 76 #define StatusDrawIndex 6 77 #define NCALLBACKS 7 78 79 #define STATUS_BORDER 2 /* Status Border width */ 80 #define CARET_OFFSET 1 /* Offset of caret position (pixel) */ 81 #define BORDER_MARGIN 3 /* BORDER MARGIN width */ 82 #define STATUS_MARGIN 7 /* Margin between the status window and its parent window */ 83 #define PREEDIT_ATTR_MASK (XIMReverse|XIMUnderline) 84 /* Preedit attribute which host adapter can handle */ 85 86 /* 87 * Callback function pointers: the order has to match the *Index 88 * values above. 89 */ 90 static XIMProc callback_funcs[NCALLBACKS] = { 91 (XIMProc)PreeditStartCallback, 92 (XIMProc)PreeditDoneCallback, 93 (XIMProc)PreeditDrawCallback, 94 (XIMProc)PreeditCaretCallback, 95 (XIMProc)StatusStartCallback, 96 (XIMProc)StatusDoneCallback, 97 (XIMProc)StatusDrawCallback, 98 }; 99 100 #define MAX_STATUS_LEN 100 101 typedef struct { 102 Window w; /*status window id */ 103 Window root; /*the root window id */ 104 Window parent; /*parent shell window */ 105 Window grandParent; /*window has WM frame */ 106 int x, y; /*parent's upperleft position */ 107 int width, height; /*parent's width, height */ 108 GC lightGC; /*gc for light border */ 109 GC dimGC; /*gc for dim border */ 110 GC bgGC; /*normal painting */ 111 GC fgGC; /*normal painting */ 112 int statusW, statusH; /*status window's w, h */ 113 int rootW, rootH; /*root window's w, h */ 114 int bWidth; /*border width */ 115 wchar_t status[MAX_STATUS_LEN + 1]; /*status text */ 116 XFontSet fontset; /*fontset for drawing */ 117 int off_x, off_y; 118 Bool on; /*if the status window on*/ 119 int fOff; /* font base line(in pixel) from top */ 120 int fBot; /* font bottom line(in pixel) from top */ 121 int peTextW; /* Composition text width in pixel */ 122 wchar_t* peText; /* Composed string (wide char.) */ 123 XIMFeedback* peAttr; /* Composed text attribute */ 124 int peCaret; /* Caret position in number of character */ 125 Bool status_ready; /* Not draw Status at XCreateIC */ 126 } StatusWindow; 127 128 /* 129 * X11InputMethodData keeps per X11InputMethod instance information. A pointer 130 * to this data structure is kept in an X11InputMethod object (pData). 131 */ 132 typedef struct _X11InputMethodData { 133 XIC current_ic; /* current X Input Context */ 134 XIC ic_active; /* X Input Context for active clients */ 135 XIC ic_passive; /* X Input Context for passive clients */ 136 XIMCallback *callbacks; /* callback parameters */ 137 jobject x11inputmethod; /* global ref to X11InputMethod instance */ 138 /* associated with the XIC */ 139 StatusWindow *statusWindow; /* our own status window */ 140 Bool passiveStatusWindow;/* Passive Client uses StatusWindow */ 141 Bool isActiveClient; /* True:clinet is active */ 142 Bool forceReset; /* True: call resetXIC before UnsetICFocus */ 143 } X11InputMethodData; 144 145 /* reference to the current X11InputMethod instance, it is always 146 point to the global reference to the X11InputMethodObject since 147 it could be referenced by different threads. */ 148 jobject currentX11InputMethodInstance = NULL; 149 150 Window currentFocusWindow = 0; /* current window that has focus for input 151 method. (the best place to put this 152 information should be 153 currentX11InputMethodInstance's pData) */ 154 static XIM X11im = NULL; 155 Display * dpy = NULL; 156 157 #define GetJNIEnv() (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2) 158 159 static X11InputMethodData * getX11InputMethodData(JNIEnv *, jobject); 160 static void setX11InputMethodData(JNIEnv *, jobject, X11InputMethodData *); 161 static void destroyX11InputMethodData(JNIEnv *, X11InputMethodData *); 162 static void freeX11InputMethodData(JNIEnv *, X11InputMethodData *); 163 164 /* Prototype for this function is missing in AIX Xlib.h */ 165 extern char *XSetIMValues( 166 #if NeedVarargsPrototypes 167 XIM /* im */, ... 168 #endif 169 ); 170 171 static int st_wcslen(wchar_t *string); 172 static Bool isPreeditStateActive(XIC ic); 173 static void * buf_insert(void * src, void * insert, int size, 174 int src_len, int ins_len, int offset); 175 static void * handle_buffer(void * source, void * insert, 176 int size, int src_len, int ins_len, 177 int del_len, int offset); 178 static void preedit_draw_passive(X11InputMethodData *pX11IMData, 179 XIMPreeditDrawCallbackStruct *pre_draw); 180 static void resetPassivePreeditText(StatusWindow *statusWindow); 181 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos); 182 static int get_next_attr(int len, unsigned long *attr); 183 static void draw_preedit(StatusWindow *statusWindow); 184 static void align_status(StatusWindow *statusWindow); 185 static void shrink_status(StatusWindow *statusWindow); 186 static GC create_gc(Window win, Bool isReverse); 187 static XFontSet create_fontset(void); 188 static Bool is_text_available(XIMText * text); 189 static Bool isNativeIm(); 190 static Window getGrandParent(Window parent); 191 static void moveStatusWindow(StatusWindow *statusWindow); 192 static void arrange_window_stack(StatusWindow* statusWindow); 193 static Window get_current_focus(XIC ic); 194 195 /* 196 * This function is stolen from /src/solaris/hpi/src/system_md.c 197 * It is used in setting the time in Java-level InputEvents 198 */ 199 jlong 200 awt_util_nowMillisUTC() 201 { 202 struct timeval t; 203 gettimeofday(&t, NULL); 204 return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000); 205 } 206 207 /* 208 * Converts the wchar_t string to a multi-byte string calling wcstombs(). A 209 * buffer is allocated by malloc() to store the multi-byte string. NULL is 210 * returned if the given wchar_t string pointer is NULL or buffer allocation is 211 * failed. 212 */ 213 static char * 214 wcstombsdmp(wchar_t *wcs, int len) 215 { 216 size_t n; 217 char *mbs; 218 219 if (wcs == NULL) 220 return NULL; 221 222 n = len*MB_CUR_MAX + 1; 223 224 mbs = (char *) malloc(n * sizeof(char)); 225 if (mbs == NULL) { 226 THROW_OUT_OF_MEMORY_ERROR(); 227 return NULL; 228 } 229 230 /* TODO: check return values... Handle invalid characters properly... */ 231 if (wcstombs(mbs, wcs, n) == (size_t)-1) { 232 free(mbs); 233 return NULL; 234 } 235 236 return mbs; 237 } 238 239 static X11InputMethodData * getX11InputMethodData(JNIEnv * env, jobject imInstance) { 240 X11InputMethodData *pX11IMData = 241 (X11InputMethodData *)JNU_GetLongFieldAsPtr(env, imInstance, x11InputMethodIDs.pData); 242 243 /* 244 * In case the XIM server was killed somehow, reset X11InputMethodData. 245 */ 246 if (X11im == NULL && pX11IMData != NULL) { 247 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 248 "flushText", 249 "()V"); 250 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 251 /* IMPORTANT: 252 The order of the following calls is critical since "imInstance" may 253 point to the global reference itself, if "freeX11InputMethodData" is called 254 first, the global reference will be destroyed and "setX11InputMethodData" 255 will in fact fail silently. So pX11IMData will not be set to NULL. 256 This could make the original java object refers to a deleted pX11IMData 257 object. 258 */ 259 setX11InputMethodData(env, imInstance, NULL); 260 freeX11InputMethodData(env, pX11IMData); 261 pX11IMData = NULL; 262 } 263 264 return pX11IMData; 265 } 266 267 static void setX11InputMethodData(JNIEnv * env, jobject imInstance, X11InputMethodData *pX11IMData) { 268 JNU_SetLongFieldFromPtr(env, imInstance, x11InputMethodIDs.pData, pX11IMData); 269 } 270 271 /* this function should be called within AWT_LOCK() */ 272 static void 273 destroyX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData) 274 { 275 /* 276 * Destroy XICs 277 */ 278 if (pX11IMData == NULL) { 279 return; 280 } 281 282 if (pX11IMData->ic_active != (XIC)0) { 283 XUnsetICFocus(pX11IMData->ic_active); 284 XDestroyIC(pX11IMData->ic_active); 285 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 286 if (pX11IMData->ic_passive != (XIC)0) { 287 XUnsetICFocus(pX11IMData->ic_passive); 288 XDestroyIC(pX11IMData->ic_passive); 289 } 290 pX11IMData->ic_passive = (XIC)0; 291 pX11IMData->current_ic = (XIC)0; 292 } 293 } 294 295 freeX11InputMethodData(env, pX11IMData); 296 } 297 298 static void 299 freeX11InputMethodData(JNIEnv *env, X11InputMethodData *pX11IMData) 300 { 301 if (pX11IMData->statusWindow != NULL){ 302 StatusWindow *sw = pX11IMData->statusWindow; 303 XFreeGC(awt_display, sw->lightGC); 304 XFreeGC(awt_display, sw->dimGC); 305 XFreeGC(awt_display, sw->bgGC); 306 XFreeGC(awt_display, sw->fgGC); 307 if (sw->fontset != NULL) { 308 XFreeFontSet(awt_display, sw->fontset); 309 } 310 XDestroyWindow(awt_display, sw->w); 311 if (pX11IMData->statusWindow->peText){ 312 free((void *)pX11IMData->statusWindow->peText); 313 pX11IMData->statusWindow->peText = NULL; 314 } 315 if (pX11IMData->statusWindow->peAttr){ 316 free((void *)pX11IMData->statusWindow->peAttr); 317 pX11IMData->statusWindow->peAttr = NULL; 318 } 319 free((void*)sw); 320 } 321 322 if (pX11IMData->callbacks) 323 free((void *)pX11IMData->callbacks); 324 325 if (env) { 326 (*env)->DeleteGlobalRef(env, pX11IMData->x11inputmethod); 327 } 328 329 free((void *)pX11IMData); 330 } 331 332 /* 333 * Sets or unsets the focus to the given XIC. 334 */ 335 static void 336 setXICFocus(XIC ic, unsigned short req) 337 { 338 if (ic == NULL) { 339 (void)fprintf(stderr, "Couldn't find X Input Context\n"); 340 return; 341 } 342 if (req == 1) 343 XSetICFocus(ic); 344 else 345 XUnsetICFocus(ic); 346 } 347 348 /* 349 * Sets the focus window to the given XIC. 350 */ 351 static void 352 setXICWindowFocus(XIC ic, Window w) 353 { 354 if (ic == NULL) { 355 (void)fprintf(stderr, "Couldn't find X Input Context\n"); 356 return; 357 } 358 (void) XSetICValues(ic, XNFocusWindow, w, NULL); 359 } 360 361 /* 362 * Invokes XmbLookupString() to get something from the XIM. It invokes 363 * X11InputMethod.dispatchCommittedText() if XmbLookupString() returns 364 * committed text. This function is called from handleKeyEvent in canvas.c and 365 * it's under the Motif event loop thread context. 366 * 367 * Buffer usage: There is a bug in XFree86-4.3.0 XmbLookupString implementation, 368 * where it never returns XBufferOverflow. We need to allocate the initial lookup buffer 369 * big enough, so that the possibility that user encounters this problem is relatively 370 * small. When this bug gets fixed, we can make the initial buffer size smaller. 371 * Note that XmbLookupString() sometimes produces a non-null-terminated string. 372 * 373 * Returns True when there is a keysym value to be handled. 374 */ 375 #define INITIAL_LOOKUP_BUF_SIZE 512 376 377 Boolean 378 awt_x11inputmethod_lookupString(XKeyPressedEvent *event, KeySym *keysymp) 379 { 380 JNIEnv *env = GetJNIEnv(); 381 X11InputMethodData *pX11IMData = NULL; 382 int buf_len = INITIAL_LOOKUP_BUF_SIZE; 383 char mbbuf[INITIAL_LOOKUP_BUF_SIZE]; 384 char *buf; 385 KeySym keysym = NoSymbol; 386 Status status; 387 int mblen; 388 jstring javastr; 389 XIC ic; 390 Boolean result = True; 391 static Boolean composing = False; 392 393 /* 394 printf("lookupString: entering...\n"); 395 */ 396 397 pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance); 398 399 if (pX11IMData == NULL) { 400 return False; 401 } 402 403 if ((ic = pX11IMData->current_ic) == (XIC)0){ 404 return False; 405 } 406 407 buf = mbbuf; 408 mblen = XmbLookupString(ic, event, buf, 409 buf_len - 1, &keysym, &status); 410 411 /* 412 * In case of overflow, a buffer is allocated and it retries 413 * XmbLookupString(). 414 */ 415 if (status == XBufferOverflow) { 416 buf_len = mblen + 1; 417 buf = (char *)malloc(buf_len); 418 if (buf == NULL) { 419 THROW_OUT_OF_MEMORY_ERROR(); 420 return result; 421 } 422 mblen = XmbLookupString(ic, event, buf, buf_len, &keysym, &status); 423 } 424 buf[mblen] = 0; 425 426 /* Get keysym without taking modifiers into account first to map 427 * to AWT keyCode table. 428 */ 429 switch (status) { 430 case XLookupBoth: 431 if (!composing) { 432 if (event->keycode != 0) { 433 *keysymp = keysym; 434 result = False; 435 break; 436 } 437 } 438 composing = False; 439 /*FALLTHRU*/ 440 case XLookupChars: 441 /* 442 printf("lookupString: status=XLookupChars, type=%d, state=%x, keycode=%x, keysym=%x\n", 443 event->type, event->state, event->keycode, keysym); 444 */ 445 javastr = JNU_NewStringPlatform(env, (const char *)buf); 446 if (javastr != NULL) { 447 JNU_CallMethodByName(env, NULL, 448 currentX11InputMethodInstance, 449 "dispatchCommittedText", 450 "(Ljava/lang/String;J)V", 451 javastr, 452 event->time); 453 if ((*env)->ExceptionOccurred(env)) { 454 (*env)->ExceptionDescribe(env); 455 (*env)->ExceptionClear(env); 456 } 457 } 458 break; 459 460 case XLookupKeySym: 461 /* 462 printf("lookupString: status=XLookupKeySym, type=%d, state=%x, keycode=%x, keysym=%x\n", 463 event->type, event->state, event->keycode, keysym); 464 */ 465 if (keysym == XK_Multi_key) 466 composing = True; 467 if (! composing) { 468 *keysymp = keysym; 469 result = False; 470 } 471 break; 472 473 case XLookupNone: 474 /* 475 printf("lookupString: status=XLookupNone, type=%d, state=%x, keycode=%x, keysym=%x\n", 476 event->type, event->state, event->keycode, keysym); 477 */ 478 break; 479 } 480 481 if (buf != mbbuf) { 482 free(buf); 483 } 484 return result; 485 } 486 487 static StatusWindow *createStatusWindow(Window parent) { 488 StatusWindow *statusWindow; 489 XSetWindowAttributes attrib; 490 unsigned long attribmask; 491 Window containerWindow; 492 Window status; 493 Window child; 494 XWindowAttributes xwa; 495 XWindowAttributes xxwa; 496 /* Variable for XCreateFontSet()*/ 497 char **mclr; 498 int mccr = 0; 499 char *dsr; 500 unsigned long bg, fg, light, dim; 501 int x, y, off_x, off_y, xx, yy; 502 unsigned int w, h, bw, depth; 503 XGCValues values; 504 unsigned long valuemask = 0; /*ignore XGCvalue and use defaults*/ 505 int screen = 0; 506 int i; 507 AwtGraphicsConfigDataPtr adata; 508 extern int awt_numScreens; 509 /*hardcode the size right now, should get the size base on font*/ 510 int width=80, height=22; 511 Window rootWindow; 512 Window *ignoreWindowPtr; 513 unsigned int ignoreUnit; 514 Window grandParent; 515 Window target; 516 XFontSet fontset; 517 518 fontset = create_fontset(); 519 if (NULL == fontset) { 520 return NULL; 521 } 522 523 XGetGeometry(dpy, parent, &rootWindow, &x, &y, &w, &h, &bw, &depth); 524 525 attrib.override_redirect = True; 526 attribmask = CWOverrideRedirect; 527 for (i = 0; i < awt_numScreens; i++) { 528 if (RootWindow(dpy, i) == rootWindow) { 529 screen = i; 530 break; 531 } 532 } 533 adata = getDefaultConfig(screen); 534 bg = adata->AwtColorMatch(255, 255, 255, adata); 535 fg = adata->AwtColorMatch(0, 0, 0, adata); 536 light = adata->AwtColorMatch(195, 195, 195, adata); 537 dim = adata->AwtColorMatch(128, 128, 128, adata); 538 539 grandParent = getGrandParent(parent); 540 target = (grandParent == 0) ? parent : grandParent; 541 XGetWindowAttributes(dpy, target, &xwa); 542 bw = 2; /*xwa.border_width does not have the correct value*/ 543 544 /*compare the size difference between parent container 545 and shell widget, the diff should be the border frame 546 and title bar height (?)*/ 547 548 XQueryTree( dpy, 549 target, 550 &rootWindow, 551 &containerWindow, 552 &ignoreWindowPtr, 553 &ignoreUnit); 554 XGetWindowAttributes(dpy, containerWindow, &xxwa); 555 556 XTranslateCoordinates(dpy, 557 target, xwa.root, 558 0, 0, 559 &x, &y, &child); 560 561 if (containerWindow == rootWindow) { 562 off_x = 0; off_y = STATUS_MARGIN; 563 } else { 564 XGetWindowAttributes(dpy, containerWindow, &xxwa); 565 off_x = (xxwa.width - xwa.width) / 2; 566 /* off_y = xxwa.height - xwa.height - off_x;*/ /*it's magic:-) */ 567 { 568 int cx, cy; 569 XTranslateCoordinates(dpy, 570 containerWindow, xxwa.root, 571 0, 0, 572 &cx, &cy, 573 &child); 574 off_y = (xxwa.height + cy) - (xwa.height + y); 575 } 576 } 577 578 /*get the size of root window*/ 579 XGetWindowAttributes(dpy, rootWindow, &xxwa); 580 581 XTranslateCoordinates(dpy, 582 target, xwa.root, 583 xwa.x, xwa.y, 584 &x, &y, 585 &child); 586 xx = x - off_x; 587 yy = y + xwa.height - off_y; 588 if (xx < 0 ){ 589 xx = 0; 590 } 591 if (xx + width > xxwa.width) { 592 xx = xxwa.width - width; 593 } 594 if (yy + height > xxwa.height) { 595 yy = xxwa.height - height; 596 } 597 598 if ((DefaultVisual(dpy,screen))->class != adata->awt_visInfo.visual->class && 599 adata->awt_visInfo.visual->class == TrueColor) { 600 attrib.colormap = XCreateColormap(dpy, xwa.root, 601 adata->awt_visInfo.visual, AllocNone ); 602 attrib.border_pixel = BlackPixel(dpy, screen) ; 603 attribmask |= CWColormap | CWBorderPixel; 604 } 605 606 status = XCreateWindow(dpy, 607 xwa.root, 608 xx, yy, 609 width, height, 610 0, 611 xwa.depth, 612 InputOutput, 613 adata->awt_visInfo.visual, 614 attribmask, &attrib); 615 XSelectInput(dpy, status, 616 ExposureMask | StructureNotifyMask | EnterWindowMask | 617 LeaveWindowMask | VisibilityChangeMask); 618 if (grandParent != 0){ 619 long mask; 620 XGetWindowAttributes(dpy, grandParent, &xwa); 621 mask = xwa.your_event_mask | StructureNotifyMask | 622 VisibilityChangeMask | PropertyChangeMask; 623 XSelectInput(dpy, grandParent,mask); 624 } 625 626 statusWindow = (StatusWindow*) calloc(1, sizeof(StatusWindow)); 627 if (statusWindow == NULL){ 628 THROW_OUT_OF_MEMORY_ERROR(); 629 return NULL; 630 } 631 statusWindow->w = status; 632 statusWindow->fontset = fontset; 633 statusWindow->parent = parent; 634 statusWindow->grandParent = grandParent; 635 statusWindow->on = False; 636 statusWindow->x = x; 637 statusWindow->y = y; 638 statusWindow->width = xwa.width; 639 statusWindow->height = xwa.height; 640 statusWindow->off_x = off_x; 641 statusWindow->off_y = off_y; 642 statusWindow->bWidth = bw; 643 statusWindow->statusH = height; 644 statusWindow->statusW = width; 645 statusWindow->peTextW = 0; 646 statusWindow->rootH = xxwa.height; 647 statusWindow->rootW = xxwa.width; 648 statusWindow->lightGC = XCreateGC(dpy, status, valuemask, &values); 649 XSetForeground(dpy, statusWindow->lightGC, light); 650 statusWindow->dimGC = XCreateGC(dpy, status, valuemask, &values); 651 XSetForeground(dpy, statusWindow->dimGC, dim); 652 statusWindow->fgGC = create_gc(status, FALSE); 653 XSetForeground(dpy, statusWindow->fgGC, fg); 654 statusWindow->bgGC = create_gc(status, TRUE); 655 XSetForeground(dpy, statusWindow->bgGC, bg); 656 statusWindow->status_ready = False; 657 wcscpy(statusWindow->status, L""); 658 return statusWindow; 659 } 660 661 /* This method is to turn off or turn on the status window. */ 662 static void onoffStatusWindow(X11InputMethodData* pX11IMData, 663 Window parent, 664 Bool ON){ 665 XWindowAttributes xwa; 666 Window child; 667 int x, y; 668 StatusWindow *statusWindow = NULL; 669 670 if (NULL == pX11IMData || 671 NULL == (statusWindow = pX11IMData->statusWindow)){ 672 return; 673 } 674 675 if (ON == False) { 676 XUnmapWindow(dpy, statusWindow->w); 677 return; 678 } 679 if (NULL == currentX11InputMethodInstance){ 680 return; 681 } 682 { 683 JNIEnv *env = GetJNIEnv(); 684 parent = JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 685 "getCurrentParentWindow", 686 "()J").j; 687 if ((*env)->ExceptionOccurred(env)) { 688 (*env)->ExceptionDescribe(env); 689 (*env)->ExceptionClear(env); 690 } 691 } 692 if (statusWindow->parent != parent) { 693 statusWindow->parent = parent; 694 } 695 if (st_wcslen(statusWindow->status) > 0 || 696 (statusWindow->peText != NULL && st_wcslen(statusWindow->peText) > 0 )) { 697 moveStatusWindow(statusWindow); 698 XMapRaised(dpy, statusWindow->w); 699 } 700 } 701 702 void paintStatusWindow(StatusWindow *statusWindow){ 703 Window win = statusWindow->w; 704 GC lightgc = statusWindow->lightGC; 705 GC dimgc = statusWindow->dimGC; 706 GC bggc = statusWindow->bgGC; 707 GC fggc = statusWindow->fgGC; 708 709 int width = statusWindow->statusW; 710 int height = statusWindow->statusH; 711 int bwidth = statusWindow->bWidth; 712 int len; 713 XRectangle logical, ink; 714 715 if (NULL == statusWindow) return; 716 if ((len = st_wcslen(statusWindow->status)) == 0) { 717 return; 718 } 719 XwcTextExtents(statusWindow->fontset, statusWindow->status, 720 len, &ink, &logical); 721 width = logical.width; 722 height = logical.height; 723 724 XFillRectangle(dpy, win, bggc, 0, 0, width+2, height+2); 725 726 XDrawLine(dpy, win, fggc, 0, 0, width+2, 0); 727 XDrawLine(dpy, win, fggc, 0, height+2, width+2, height+2); 728 XDrawLine(dpy, win, fggc, 0, 0, 0, height+2); 729 XDrawLine(dpy, win, fggc, width+2, 0, width+2, height+2); 730 731 if (statusWindow->fontset) { 732 XwcDrawString(dpy, win, statusWindow->fontset, fggc, 733 -logical.x + 1, -logical.y + 1, 734 statusWindow->status, 735 st_wcslen(statusWindow->status)); 736 } else { 737 /*too bad we failed to create a fontset for this locale*/ 738 XDrawString(dpy, win, fggc, bwidth + 2, height - bwidth - 4, 739 "[InputMethod ON]", strlen("[InputMethod ON]")); 740 } 741 } 742 743 Bool statusWindowEventHandler(XEvent event) { 744 JNIEnv *env = GetJNIEnv(); 745 X11InputMethodData *pX11IMData = NULL; 746 StatusWindow *statusWindow; 747 748 if (NULL == currentX11InputMethodInstance || 749 NULL == (pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance)) || 750 NULL == (statusWindow = pX11IMData->statusWindow)) 751 { 752 return False; 753 } 754 755 if (statusWindow->w == event.xany.window) { 756 switch (event.type) { 757 case Expose: 758 paintStatusWindow(statusWindow); 759 if (statusWindow->peText) 760 draw_preedit(statusWindow); 761 arrange_window_stack(statusWindow); 762 break; 763 case ConfigureNotify: 764 case VisibilityNotify: 765 arrange_window_stack(statusWindow); 766 break; 767 /* 768 case UnmapNotify: 769 case VisibilityNotify: 770 break; 771 */ 772 default: 773 break; 774 } 775 return True; 776 } else if ((statusWindow->parent == event.xany.window) || 777 (statusWindow->grandParent && statusWindow->grandParent == event.xany.window)) { 778 switch (event.type) { 779 case MapNotify: 780 if (statusWindow->on) { 781 onoffStatusWindow(pX11IMData, statusWindow->parent, True); 782 } 783 break; 784 case UnmapNotify: 785 onoffStatusWindow(pX11IMData, 0, False); 786 break; 787 case VisibilityNotify: 788 if (statusWindow->on) { 789 arrange_window_stack(statusWindow); 790 } 791 break; 792 case ConfigureNotify: 793 if (statusWindow->grandParent && statusWindow->on) { 794 moveStatusWindow(statusWindow); 795 } 796 case PropertyNotify: 797 if (statusWindow->on) { 798 arrange_window_stack(statusWindow); 799 } 800 break; 801 default: 802 break; 803 } 804 } 805 return False; 806 } 807 808 static void adjustStatusWindow(Window shell) { 809 JNIEnv *env = GetJNIEnv(); 810 X11InputMethodData *pX11IMData = NULL; 811 StatusWindow *statusWindow; 812 813 if (NULL == currentX11InputMethodInstance 814 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 815 || NULL == (statusWindow = pX11IMData->statusWindow) 816 || !statusWindow->on) 817 { 818 return; 819 } 820 821 moveStatusWindow(statusWindow); 822 } 823 824 /* 825 * Creates two XICs, one for active clients and the other for passive 826 * clients. All information on those XICs are stored in the 827 * X11InputMethodData given by the pX11IMData parameter. 828 * 829 * For active clients: Try to use preedit callback to support 830 * on-the-spot. If tc is not null, the XIC to be created will 831 * share the Status Area with Motif widgets (TextComponents). If the 832 * preferable styles can't be used, fallback to root-window styles. If 833 * root-window styles failed, fallback to None styles. 834 * 835 * For passive clients: Try to use root-window styles. If failed, 836 * fallback to None styles. 837 */ 838 static Bool 839 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w) 840 { 841 XVaNestedList preedit = NULL; 842 XVaNestedList status = NULL; 843 XIMStyle on_the_spot_styles = XIMPreeditCallbacks, 844 in_place_styles = 0, 845 active_styles = 0, 846 passive_styles = 0, 847 no_styles = 0; 848 XIMCallback *callbacks; 849 unsigned short i; 850 XIMStyles *im_styles; 851 char *ret = NULL; 852 Bool passiveStatusWindow = False; 853 pX11IMData->statusWindow = NULL; 854 855 if (X11im == NULL) { 856 return False; 857 } 858 if (!w) { 859 return False; 860 } 861 862 if (getenv("IBMJAVA_PASSIVE") == NULL) { 863 passiveStatusWindow = False; 864 } else { 865 passiveStatusWindow = True; 866 } 867 868 if (isNativeIm()) { passiveStatusWindow = True; } 869 870 ret = XGetIMValues(X11im, XNQueryInputStyle, &im_styles, NULL); 871 872 if (ret != NULL) { 873 jio_fprintf(stderr,"XGetIMValues: %s\n",ret); 874 return FALSE ; 875 } 876 877 on_the_spot_styles |= XIMStatusNothing; 878 879 /*kinput does not support XIMPreeditCallbacks and XIMStatusArea 880 at the same time, so use StatusCallback to draw the status 881 ourself 882 */ 883 for (i = 0; i < im_styles->count_styles; i++) { 884 if (im_styles->supported_styles[i] == (XIMPreeditCallbacks | XIMStatusCallbacks)) { 885 on_the_spot_styles = (XIMPreeditCallbacks | XIMStatusCallbacks); 886 break; 887 } 888 } 889 890 for (i = 0; i < im_styles->count_styles; i++) { 891 if (im_styles->supported_styles[i] == on_the_spot_styles) 892 active_styles = im_styles->supported_styles[i]; 893 if (im_styles->supported_styles[i] == ROOT_WINDOW_STYLES) 894 passive_styles = im_styles->supported_styles[i]; 895 if (im_styles->supported_styles[i] == IN_PLACE_STYLES) { 896 in_place_styles = im_styles->supported_styles[i]; 897 } 898 if (im_styles->supported_styles[i] == NO_STYLES) { 899 no_styles = im_styles->supported_styles[i]; 900 } 901 } 902 903 XFree(im_styles); 904 905 if (active_styles != on_the_spot_styles) { 906 if (passive_styles == ROOT_WINDOW_STYLES) 907 active_styles = passive_styles; 908 else { 909 if (in_place_styles == IN_PLACE_STYLES){ 910 active_styles = passive_styles = IN_PLACE_STYLES; 911 } else { 912 if (no_styles == NO_STYLES) 913 active_styles = passive_styles = NO_STYLES; 914 else 915 active_styles = passive_styles = 0; 916 } 917 } 918 } else { 919 if (!passiveStatusWindow) { 920 if (passive_styles != ROOT_WINDOW_STYLES) { 921 if (no_styles == NO_STYLES) 922 active_styles = passive_styles = NO_STYLES; 923 else 924 active_styles = passive_styles = 0; 925 } 926 } else 927 passive_styles = active_styles; 928 } 929 930 if (active_styles == on_the_spot_styles) { 931 callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS); 932 if (callbacks == (XIMCallback *)NULL) 933 return False; 934 pX11IMData->callbacks = callbacks; 935 936 for (i = 0; i < NCALLBACKS; i++, callbacks++) { 937 callbacks->client_data = (XPointer) pX11IMData->x11inputmethod; 938 callbacks->callback = callback_funcs[i]; 939 } 940 941 callbacks = pX11IMData->callbacks; 942 preedit = (XVaNestedList)XVaCreateNestedList(0, 943 XNPreeditStartCallback, &callbacks[PreeditStartIndex], 944 XNPreeditDoneCallback, &callbacks[PreeditDoneIndex], 945 XNPreeditDrawCallback, &callbacks[PreeditDrawIndex], 946 XNPreeditCaretCallback, &callbacks[PreeditCaretIndex], 947 NULL); 948 if (preedit == (XVaNestedList)NULL) 949 goto err; 950 /*always try XIMStatusCallbacks for active client...*/ 951 { 952 if (on_the_spot_styles & XIMStatusCallbacks) { 953 status = (XVaNestedList)XVaCreateNestedList(0, 954 XNStatusStartCallback, &callbacks[StatusStartIndex], 955 XNStatusDoneCallback, &callbacks[StatusDoneIndex], 956 XNStatusDrawCallback, &callbacks[StatusDrawIndex], 957 NULL); 958 959 if (status == NULL) 960 goto err; 961 } 962 pX11IMData->statusWindow = createStatusWindow(w); 963 pX11IMData->ic_active = XCreateIC(X11im, 964 XNClientWindow, w, 965 XNFocusWindow, w, 966 XNInputStyle, active_styles, 967 XNPreeditAttributes, preedit, 968 XNStatusAttributes, status, 969 NULL); 970 if (NULL != pX11IMData->statusWindow) { 971 pX11IMData->statusWindow->status_ready = True; 972 } 973 XFree((void *)status); 974 XFree((void *)preedit); 975 } 976 if (passiveStatusWindow) { 977 pX11IMData->ic_passive = pX11IMData->ic_active; 978 } else { 979 pX11IMData->ic_passive = XCreateIC(X11im, 980 XNClientWindow, w, 981 XNFocusWindow, w, 982 XNInputStyle, passive_styles, 983 NULL); 984 } 985 } else { 986 pX11IMData->ic_active = XCreateIC(X11im, 987 XNClientWindow, w, 988 XNFocusWindow, w, 989 XNInputStyle, active_styles, 990 NULL); 991 pX11IMData->ic_passive = pX11IMData->ic_active; 992 } 993 994 // The code set the IC mode that the preedit state is not initialied 995 // at XmbResetIC. This attribute can be set at XCreateIC. I separately 996 // set the attribute to avoid the failure of XCreateIC at some platform 997 // which does not support the attribute. 998 if (pX11IMData->ic_active != 0) 999 XSetICValues(pX11IMData->ic_active, 1000 XNResetState, XIMPreserveState, NULL); 1001 if (pX11IMData->ic_passive != 0 && 1002 pX11IMData->ic_active != pX11IMData->ic_passive) 1003 XSetICValues(pX11IMData->ic_passive, 1004 XNResetState, XIMInitialState, NULL); 1005 1006 pX11IMData->passiveStatusWindow = passiveStatusWindow; 1007 1008 if (pX11IMData->ic_active == (XIC)0 1009 || pX11IMData->ic_passive == (XIC)0) { 1010 return False; 1011 } 1012 1013 /* Unset focus to avoid unexpected IM on */ 1014 setXICFocus(pX11IMData->ic_active, False); 1015 if (pX11IMData->ic_active != pX11IMData->ic_passive) 1016 setXICFocus(pX11IMData->ic_passive, False); 1017 1018 return True; 1019 1020 err: 1021 if (preedit) 1022 XFree((void *)preedit); 1023 THROW_OUT_OF_MEMORY_ERROR(); 1024 return False; 1025 } 1026 1027 static int 1028 PreeditStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1029 { 1030 JNIEnv *env = GetJNIEnv(); 1031 X11InputMethodData *pX11IMData; 1032 1033 pX11IMData = getX11InputMethodData(env, (jobject)client_data); 1034 if (pX11IMData == NULL || pX11IMData->statusWindow == NULL) { 1035 return 0; 1036 } 1037 resetPassivePreeditText(pX11IMData->statusWindow); 1038 1039 return -1; /* unlimited length for preedit text */ 1040 } 1041 1042 static void 1043 PreeditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1044 { 1045 JNIEnv *env = GetJNIEnv(); 1046 X11InputMethodData *pX11IMData; 1047 1048 pX11IMData = getX11InputMethodData(env, (jobject)client_data); 1049 if (pX11IMData == NULL) { 1050 return; 1051 } 1052 1053 if (!pX11IMData->isActiveClient) { 1054 resetPassivePreeditText(pX11IMData->statusWindow); 1055 shrink_status(pX11IMData->statusWindow); 1056 } 1057 else{ 1058 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 1059 "clearComposedText", 1060 "(J)V", 1061 awt_util_nowMillisUTC()); 1062 if ((*env)->ExceptionOccurred(env)) { 1063 (*env)->ExceptionDescribe(env); 1064 (*env)->ExceptionClear(env); 1065 } 1066 } 1067 } 1068 1069 /* 1070 * Translate the preedit draw callback items to Java values and invoke 1071 * X11InputMethod.dispatchComposedText(). 1072 * 1073 * client_data: X11InputMethod object 1074 */ 1075 static void 1076 PreeditDrawCallback(XIC ic, XPointer client_data, 1077 XIMPreeditDrawCallbackStruct *pre_draw) 1078 { 1079 JNIEnv *env = GetJNIEnv(); 1080 X11InputMethodData *pX11IMData = NULL; 1081 jmethodID x11imMethodID; 1082 1083 XIMText *text; 1084 jstring javastr = NULL; 1085 jintArray style = NULL; 1086 1087 /* printf("Native: PreeditDrawCallback() \n"); */ 1088 if (pre_draw == NULL) { 1089 return; 1090 } 1091 AWT_LOCK(); 1092 if ((pX11IMData = getX11InputMethodData(env, (jobject)client_data)) == NULL) { 1093 goto finally; 1094 } 1095 1096 if (!pX11IMData->isActiveClient){ 1097 if (ic == pX11IMData->ic_passive) { 1098 preedit_draw_passive(pX11IMData, pre_draw); 1099 } 1100 goto finally; 1101 } 1102 1103 if ((text = pre_draw->text) != NULL) { 1104 if (is_text_available(text)) { 1105 if (text->string.multi_byte != NULL) { 1106 if (pre_draw->text->encoding_is_wchar == False) { 1107 javastr = JNU_NewStringPlatform(env, (const char *)text->string.multi_byte); 1108 if (javastr == NULL) { 1109 goto finally; 1110 } 1111 } else { 1112 char *mbstr = wcstombsdmp(text->string.wide_char, text->length); 1113 if (mbstr == NULL) { 1114 goto finally; 1115 } 1116 javastr = JNU_NewStringPlatform(env, (const char *)mbstr); 1117 free(mbstr); 1118 if (javastr == NULL) { 1119 goto finally; 1120 } 1121 } 1122 } 1123 } 1124 if (text->feedback != NULL) { 1125 int cnt; 1126 jint *tmpstyle; 1127 1128 style = (*env)->NewIntArray(env, text->length); 1129 if (JNU_IsNull(env, style)) { 1130 (*env)->ExceptionClear(env); 1131 THROW_OUT_OF_MEMORY_ERROR(); 1132 goto finally; 1133 } 1134 1135 if (sizeof(XIMFeedback) == sizeof(jint)) { 1136 /* 1137 * Optimization to avoid copying the array 1138 */ 1139 (*env)->SetIntArrayRegion(env, style, 0, 1140 text->length, (jint *)text->feedback); 1141 } else { 1142 tmpstyle = (jint *)malloc(sizeof(jint)*(text->length)); 1143 if (tmpstyle == (jint *) NULL) { 1144 THROW_OUT_OF_MEMORY_ERROR(); 1145 goto finally; 1146 } 1147 for (cnt = 0; cnt < (int)text->length; cnt++) 1148 tmpstyle[cnt] = text->feedback[cnt]; 1149 (*env)->SetIntArrayRegion(env, style, 0, 1150 text->length, (jint *)tmpstyle); 1151 free(tmpstyle); 1152 } 1153 } 1154 } 1155 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 1156 "dispatchComposedText", 1157 "(Ljava/lang/String;[IIIIJ)V", 1158 javastr, 1159 style, 1160 (jint)pre_draw->chg_first, 1161 (jint)pre_draw->chg_length, 1162 (jint)pre_draw->caret, 1163 awt_util_nowMillisUTC()); 1164 1165 if ((*env)->ExceptionOccurred(env)) { 1166 (*env)->ExceptionDescribe(env); 1167 (*env)->ExceptionClear(env); 1168 } 1169 1170 finally: 1171 AWT_UNLOCK(); 1172 return; 1173 } 1174 1175 static void 1176 PreeditCaretCallback(XIC ic, XPointer client_data, 1177 XIMPreeditCaretCallbackStruct *pre_caret) 1178 { 1179 XIMPreeditDrawCallbackStruct pre_draw; 1180 1181 if (pre_caret != NULL && pre_caret->direction == XIMAbsolutePosition) { 1182 pre_draw.caret = pre_caret->position; 1183 pre_draw.chg_first = 0; 1184 pre_draw.chg_length = 0; 1185 pre_draw.text = NULL; 1186 PreeditDrawCallback(ic, client_data, &pre_draw); 1187 } 1188 } 1189 1190 static void 1191 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1192 { 1193 /*ARGSUSED*/ 1194 /*printf("StatusStartCallback:\n"); */ 1195 } 1196 1197 static void 1198 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1199 { 1200 /*ARGSUSED*/ 1201 /*printf("StatusDoneCallback:\n"); */ 1202 } 1203 1204 static void StatusDrawCallback 1205 (XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *status_draw) 1206 { 1207 /*ARGSUSED*/ 1208 /*printf("StatusDrawCallback:\n"); */ 1209 JNIEnv *env = GetJNIEnv(); 1210 X11InputMethodData *pX11IMData = NULL; 1211 StatusWindow *statusWindow; 1212 int value_make = CWX|CWWidth|CWHeight; 1213 XRectangle logical, ink; 1214 XWindowChanges xwc; 1215 int len; 1216 1217 AWT_LOCK(); 1218 1219 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data)) 1220 || NULL == (statusWindow = pX11IMData->statusWindow)){ 1221 goto finally; 1222 } 1223 1224 if (status_draw->type == XIMTextType) { 1225 XIMText *text = (status_draw->data).text; 1226 if (text != NULL) { 1227 if (text->string.multi_byte != NULL) { 1228 if(!strcmp(text->string.multi_byte," ")){ 1229 wcscpy(statusWindow->status, L""); 1230 onoffStatusWindow(pX11IMData, 0, False); 1231 goto finally; 1232 } 1233 mbstowcs(statusWindow->status, 1234 (const char *)text->string.multi_byte, 1235 (size_t)MAX_STATUS_LEN); 1236 } else { 1237 if (0 == st_wcslen(text->string.wide_char)){ 1238 wcscpy(statusWindow->status, L""); 1239 onoffStatusWindow(pX11IMData, 0, False); 1240 goto finally; 1241 } 1242 wcsncpy(statusWindow->status, 1243 text->string.wide_char, 1244 MAX_STATUS_LEN); 1245 } 1246 XwcTextExtents(statusWindow->fontset, statusWindow->status, 1247 st_wcslen(statusWindow->status), &ink, &logical); 1248 statusWindow->statusW = logical.width + BORDER_MARGIN; 1249 statusWindow->statusH = logical.height + BORDER_MARGIN; 1250 xwc.x = statusWindow->x - statusWindow->off_x; 1251 if (xwc.x < 0 ) xwc.x = 0; 1252 xwc.width = statusWindow->statusW; 1253 xwc.height = statusWindow->statusH; 1254 if (xwc.x + xwc.width > statusWindow->rootW){ 1255 xwc.x = statusWindow->rootW - xwc.width; 1256 } 1257 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1258 if (statusWindow->status_ready && statusWindow->on == True){ 1259 onoffStatusWindow(pX11IMData, statusWindow->parent, True); 1260 } 1261 paintStatusWindow(statusWindow); 1262 if (statusWindow->peText) 1263 draw_preedit(statusWindow); 1264 } 1265 else { 1266 wcscpy(statusWindow->status, L""); 1267 /*just turnoff the status window 1268 paintStatusWindow(statusWindow); 1269 */ 1270 onoffStatusWindow(pX11IMData, 0, False); 1271 } 1272 } 1273 1274 finally: 1275 AWT_UNLOCK(); 1276 } 1277 1278 /* return the string length without trailing spaces */ 1279 /* work around code for Japanese AIXIM is implemented. */ 1280 static int st_wcslen(wchar_t *string) 1281 { 1282 int len = (int32_t)wcslen(string); 1283 if (len == 0) 1284 return 0; 1285 for (len--;len >= 0; len--) { 1286 if (!iswspace((wint_t) string[len])) break; 1287 } 1288 return len+1; 1289 } 1290 1291 /* 1292 * Checks whether given XIMText contains a string data. 1293 */ 1294 static Bool is_text_available(XIMText * text) 1295 { 1296 if (text == NULL || text->length==0) 1297 return False; 1298 if (text->encoding_is_wchar) { 1299 if(text->string.wide_char[0] == L'\0') 1300 return False; 1301 } else { 1302 if (text->string.multi_byte[0] == '\0') 1303 return False; 1304 } 1305 return True; 1306 } 1307 1308 /* 1309 * check if preedit status is active 1310 */ 1311 static Bool isPreeditStateActive(XIC ic) 1312 { 1313 XIMPreeditState state = XIMPreeditUnKnown; 1314 XVaNestedList pr_atrb; 1315 char* nosupportAttr; 1316 1317 if (ic == NULL) return False; 1318 1319 pr_atrb = XVaCreateNestedList(0,XNPreeditState,&state,NULL); 1320 nosupportAttr=XGetICValues(ic,XNPreeditAttributes,pr_atrb,NULL); 1321 XFree(pr_atrb); 1322 if (nosupportAttr==NULL && state & XIMPreeditDisable) 1323 return False; 1324 else 1325 return True; 1326 } 1327 1328 static void * buf_insert(void * src, void * insert, int size, 1329 int src_len, int ins_len, int offset) 1330 { 1331 char *temp; 1332 1333 temp = realloc(src, size*(src_len+ins_len+1)); 1334 if (temp == NULL) { 1335 THROW_OUT_OF_MEMORY_ERROR(); 1336 return src; 1337 } 1338 if (offset != src_len) { 1339 memmove(&temp[size*(offset+ins_len)], 1340 &((char *)temp)[size*offset], 1341 size*(src_len-offset)); 1342 } 1343 memcpy(&temp[size*offset], insert, size*ins_len); 1344 1345 return (void *)temp; 1346 } 1347 1348 static void * handle_buffer(void * source, void * insert, 1349 int size,int src_len, int ins_len, 1350 int del_len, int offset) 1351 { 1352 void * temp = source; 1353 1354 if (del_len > 0) { 1355 if (del_len == ins_len) { 1356 memcpy(&((char *)source)[size*offset], insert, size*ins_len); 1357 return source; 1358 } 1359 else if (src_len > offset+del_len) { 1360 memmove(&((char *)source)[size*offset], 1361 &((char *)source)[size*(offset+del_len)], 1362 size*(src_len-offset-del_len)); 1363 } 1364 } 1365 if (ins_len > 0) { 1366 temp = buf_insert(source, insert, size, src_len, 1367 ins_len, offset); 1368 } 1369 return temp; 1370 } 1371 /* 1372 * Display the given preedit text to the root window which is ownd by 1373 * myself. All of the character is converted to wide char. 1374 * this function is used for the passive client. 1375 */ 1376 static void preedit_draw_passive(X11InputMethodData *pX11IMData, 1377 XIMPreeditDrawCallbackStruct *pre_draw) 1378 { 1379 XIMText *text; 1380 wchar_t *tempbuf = NULL; 1381 StatusWindow *statusWindow; 1382 wchar_t *cur_text; 1383 unsigned long *cur_attr; 1384 int cur_len = 0; 1385 int chg_len = pre_draw->chg_length; 1386 int chg_1st = pre_draw->chg_first; 1387 1388 if (NULL == (statusWindow = pX11IMData->statusWindow)) 1389 return; 1390 cur_text = statusWindow->peText; 1391 cur_attr = statusWindow->peAttr; 1392 if (cur_text == NULL && pre_draw->text == NULL) 1393 return; 1394 1395 if (cur_text != NULL) 1396 cur_len = (int32_t)wcslen(cur_text); 1397 text = pre_draw->text; 1398 if (text == NULL) { 1399 /* delete only */ 1400 if (cur_len > chg_1st+chg_len) { 1401 memmove(&cur_text[chg_1st], 1402 &cur_text[chg_1st+chg_len], 1403 sizeof(wchar_t)*(cur_len-chg_1st-chg_len)); 1404 memmove(&cur_attr[chg_1st], 1405 &cur_attr[chg_1st+chg_len], 1406 sizeof(long)*(cur_len-chg_1st-chg_len)); 1407 } 1408 if ((pre_draw->chg_length <= cur_len ) && (pre_draw->chg_length >0)) 1409 cur_text[cur_len-pre_draw->chg_length] =L'\0'; 1410 } else { 1411 /* insert or replace */ 1412 int ins_len = 0; 1413 void * ins_text = NULL; 1414 1415 /* if invalid offset is specified, do nothing. */ 1416 /* this fix is for aixim for eucTW */ 1417 if (cur_len < chg_1st) 1418 return; 1419 if(is_text_available(text)) { 1420 /* insert or replace the text */ 1421 if (text->encoding_is_wchar == False) { 1422 /* convert the text to wide chars. 1423 allocate enough size buffer 1424 */ 1425 tempbuf = (wchar_t *)malloc(sizeof(wchar_t)*(text->length+1)); 1426 if (tempbuf == NULL) { 1427 THROW_OUT_OF_MEMORY_ERROR(); 1428 return; 1429 } 1430 ins_len = (int32_t)mbstowcs(tempbuf, text->string.multi_byte, 1431 text->length); 1432 if (ins_len == -1) { 1433 free(tempbuf); 1434 return; 1435 } 1436 ins_text = (void *)tempbuf; 1437 } 1438 else { 1439 ins_len = text->length; 1440 ins_text = text->string.wide_char; 1441 } 1442 /* finish prepare the data to be inserted */ 1443 1444 statusWindow->peText = 1445 handle_buffer(cur_text, ins_text, sizeof(wchar_t), 1446 cur_len, ins_len, chg_len, chg_1st); 1447 statusWindow->peAttr = 1448 handle_buffer(cur_attr, text->feedback, sizeof(long), 1449 cur_len, ins_len, chg_len, chg_1st); 1450 statusWindow->peText[cur_len-chg_len+ins_len] =L'\0'; 1451 1452 if (tempbuf != NULL) 1453 free(tempbuf); 1454 } /* endof insert or replace text */ 1455 else { 1456 /* change attribute only */ 1457 memcpy(&cur_attr[chg_1st], text->feedback, 1458 sizeof(long)*text->length); 1459 } 1460 } 1461 statusWindow->peCaret= pre_draw->caret; 1462 draw_preedit(statusWindow); 1463 if (statusWindow->on && wcslen(statusWindow->peText) > 0) 1464 onoffStatusWindow(pX11IMData, statusWindow->parent, True); 1465 else if (wcslen(statusWindow->status) == 0) 1466 onoffStatusWindow(pX11IMData, 0, False); 1467 } 1468 1469 /* 1470 * reset predit test of passive mode 1471 */ 1472 static void 1473 resetPassivePreeditText(StatusWindow *statusWindow) 1474 { 1475 if (NULL == statusWindow) return; 1476 if(statusWindow->peText != NULL) { 1477 free(statusWindow->peText); 1478 statusWindow->peText = NULL; 1479 } 1480 if(statusWindow->peAttr != NULL) { 1481 free(statusWindow->peAttr); 1482 statusWindow->peAttr = NULL; 1483 } 1484 statusWindow->peCaret= 0; 1485 } 1486 1487 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos) 1488 { 1489 if (NULL == statusWindow) return; 1490 XSetFunction(dpy, gc, GXinvert); 1491 XDrawLine(dpy, statusWindow->w, 1492 gc, pos, STATUS_BORDER/2, 1493 pos, STATUS_BORDER/2+statusWindow->fOff); 1494 XSetFunction(dpy, gc, GXcopy); 1495 } 1496 1497 static int get_next_attr(int len, unsigned long *attr) 1498 { 1499 int count; 1500 1501 for (count = 1; count < len; count++) { 1502 if ((attr[count-1] & PREEDIT_ATTR_MASK) 1503 != (attr[count] & PREEDIT_ATTR_MASK)) 1504 break; 1505 } 1506 return count; 1507 } 1508 1509 static void draw_preedit(StatusWindow *statusWindow) 1510 { 1511 unsigned long *attr; 1512 int x_pos,x_caret; 1513 unsigned int len; 1514 int len_disp, pos; 1515 wchar_t *str; 1516 GC gc; 1517 XRectangle ink, rect, rect_c; 1518 Bool caret_done = False; 1519 1520 if (NULL == statusWindow) return; 1521 align_status(statusWindow); 1522 XFillRectangle(dpy, statusWindow->w, 1523 statusWindow->bgGC, 1524 statusWindow->statusW,0, 1525 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 1526 statusWindow->fBot+2); 1527 1528 1529 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1530 statusWindow->statusW, 0, 1531 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0); 1532 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1533 statusWindow->statusW, statusWindow->fBot+2, 1534 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 1535 statusWindow->fBot+2); 1536 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1537 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0, 1538 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 1539 statusWindow->fBot+2); 1540 if (0 == statusWindow->statusW) 1541 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1542 0, 0, 0, statusWindow->fBot+2); 1543 1544 str = statusWindow->peText; 1545 1546 if (str != NULL && (len = (int32_t)wcslen(str)) != 0) { 1547 pos = 0; 1548 attr = statusWindow->peAttr; 1549 x_pos = x_caret = statusWindow->statusW + STATUS_BORDER; 1550 while((int)len-1 >= pos) { 1551 len_disp = get_next_attr(len - pos, &attr[pos]); 1552 if (attr[pos] & XIMReverse) { 1553 gc = statusWindow->bgGC; 1554 } 1555 else { 1556 gc = statusWindow->fgGC; 1557 } 1558 XwcTextExtents(statusWindow->fontset, 1559 &str[pos], 1560 len_disp, &ink, &rect); 1561 XwcDrawImageString(dpy, statusWindow->w, 1562 statusWindow->fontset, gc, 1563 x_pos, statusWindow->fOff+1, &str[pos], len_disp); 1564 if (attr[pos] & XIMUnderline) { 1565 XDrawLine(dpy, statusWindow->w, 1566 gc, x_pos, statusWindow->fBot, 1567 x_pos+rect.width, statusWindow->fBot); 1568 } 1569 if (!caret_done) { 1570 if( statusWindow->peCaret >= pos && 1571 statusWindow->peCaret <= pos+len_disp) { 1572 if (statusWindow->peCaret == 0) 1573 x_caret = x_pos; 1574 else if (statusWindow->peCaret == pos+len_disp) 1575 x_caret = x_pos+rect.width; 1576 else { 1577 XwcTextExtents(statusWindow->fontset, 1578 &str[pos], 1579 statusWindow->peCaret-pos, 1580 &ink, &rect_c); 1581 x_caret = x_pos+ rect_c.width; 1582 } 1583 x_caret-=CARET_OFFSET; 1584 caret_done = True; 1585 } 1586 } 1587 pos += len_disp; 1588 x_pos += rect.width; 1589 } 1590 if (caret_done) 1591 draw_caret(statusWindow, statusWindow->fgGC, x_caret); 1592 } 1593 } 1594 1595 /* calc required status window size and resize the window */ 1596 static void align_status(StatusWindow *statusWindow) 1597 { 1598 int len_st, len_pe = 0; 1599 XRectangle rect_st, rect_pe, ink; 1600 Dimension cur_w; 1601 int value_make = CWX|CWWidth|CWHeight; 1602 XWindowChanges xwc; 1603 1604 if (NULL == statusWindow) return; 1605 if ((len_st = st_wcslen(statusWindow->status)) == 0 1606 && (statusWindow->peText == NULL || st_wcslen(statusWindow->peText) == 0 )) 1607 return; 1608 1609 rect_pe.x = rect_pe.y = rect_pe.width = rect_pe.height = 0; 1610 1611 XwcTextExtents(statusWindow->fontset, 1612 statusWindow->status, 1613 len_st, &ink, &rect_st); 1614 if (statusWindow->peText != NULL 1615 && (len_pe = (int32_t)wcslen(statusWindow->peText)) > 0) { 1616 XwcTextExtents(statusWindow->fontset, 1617 statusWindow->peText, 1618 len_pe, &ink, &rect_pe); 1619 } 1620 statusWindow->fOff = max(-rect_st.y, -rect_pe.y); 1621 statusWindow->fBot = max(rect_st.height, rect_pe.height); 1622 statusWindow->statusW =rect_st.width; 1623 if (rect_st.width > 0) statusWindow->statusW += BORDER_MARGIN; 1624 statusWindow->peTextW = rect_pe.width; 1625 1626 xwc.x = statusWindow->x - statusWindow->off_x; 1627 if (xwc.x < 0 ) xwc.x = 0; 1628 1629 if (len_pe > 0) { 1630 xwc.width = statusWindow->statusW 1631 + statusWindow->peTextW + BORDER_MARGIN + 1; 1632 xwc.height = statusWindow->fBot + BORDER_MARGIN; 1633 } else { 1634 xwc.width = statusWindow->statusW; 1635 xwc.height = statusWindow->fBot + BORDER_MARGIN; 1636 } 1637 if (xwc.x + xwc.width > statusWindow->rootW){ 1638 xwc.x = statusWindow->rootW - xwc.width; 1639 } 1640 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1641 } 1642 1643 static void shrink_status(StatusWindow *statusWindow) 1644 { 1645 int value_make = CWX|CWWidth|CWHeight; 1646 XWindowChanges xwc; 1647 1648 if (NULL == statusWindow) return; 1649 xwc.width = statusWindow->statusW; 1650 xwc.height = statusWindow->statusH; 1651 statusWindow->peTextW = 0; 1652 xwc.x = statusWindow->x - statusWindow->off_x; 1653 if (xwc.x < 0 ) xwc.x = 0; 1654 if (xwc.x + xwc.width > statusWindow->rootW){ 1655 xwc.x = statusWindow->rootW - xwc.width; 1656 } 1657 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1658 } 1659 1660 static GC create_gc(Window win, Bool isReverse) 1661 { 1662 XGCValues xgcv; 1663 unsigned long mask; 1664 AwtScreenDataPtr defaultScreen; 1665 1666 defaultScreen = getScreenData(DefaultScreen(dpy)); 1667 1668 mask = (GCForeground | GCBackground ); 1669 if (isReverse) { 1670 xgcv.foreground = defaultScreen->whitepixel; 1671 xgcv.background = defaultScreen->blackpixel; 1672 } else { 1673 xgcv.foreground = defaultScreen->blackpixel; 1674 xgcv.background = defaultScreen->whitepixel; 1675 } 1676 return XCreateGC(dpy, win, mask, &xgcv); 1677 } 1678 1679 static Bool isNativeIm() 1680 { 1681 #define XIMMODIFIER "@im=" 1682 #define XIM_SERVER_CATEGORY "@server=" 1683 char *immodifiers; 1684 char *imserver, *imserverPtr; 1685 Atom imserverAtom; 1686 1687 if (!(immodifiers = getenv("XMODIFIERS"))) return True; 1688 if (!(imserver = calloc(1,strlen(immodifiers)+strlen(XIM_SERVER_CATEGORY)+1))) return True; 1689 if (!(immodifiers = strstr(immodifiers,XIMMODIFIER))) return True; 1690 immodifiers += strlen(XIMMODIFIER); 1691 strcpy(imserver,XIM_SERVER_CATEGORY); 1692 imserverPtr = imserver + strlen(imserver); 1693 while(*immodifiers != '@' && *immodifiers != '\0') { 1694 *imserverPtr = *immodifiers; 1695 imserverPtr++; 1696 immodifiers++; 1697 } 1698 imserverAtom = XInternAtom(awt_display, imserver, True); 1699 free(imserver); 1700 if (imserverAtom > 0) 1701 return False; 1702 else 1703 return True; 1704 } 1705 1706 static Window getGrandParent(Window parent) 1707 { 1708 Window containerWindow,rootWindow,tmp; 1709 Window *ignoreWindowPtr; 1710 unsigned int ignoreUnit; 1711 Window grandParent=0; 1712 XWindowAttributes xwa; 1713 Atom WM_STATE; 1714 Atom type = None; 1715 int32_t format; 1716 unsigned long nitems, after; 1717 unsigned char * data; 1718 1719 if (parent == 0) return grandParent; 1720 WM_STATE = XInternAtom(dpy, "WM_STATE", True); 1721 if (WM_STATE == None) return grandParent; 1722 1723 tmp=parent; 1724 while(XQueryTree(dpy, tmp, 1725 &rootWindow, &containerWindow, 1726 &ignoreWindowPtr, &ignoreUnit)){ 1727 XFree(ignoreWindowPtr); 1728 if (containerWindow == rootWindow) break; 1729 if (XGetWindowProperty(dpy, containerWindow, WM_STATE, 1730 0, 0, False, AnyPropertyType, 1731 &type, &format, &nitems, &after, &data) == Success) { 1732 XFree(data); 1733 if (type) { 1734 XGetWindowAttributes(dpy, containerWindow, &xwa); 1735 if (FALSE == xwa.override_redirect){ 1736 grandParent=containerWindow; 1737 } 1738 } 1739 } 1740 tmp=containerWindow; 1741 } 1742 return grandParent; 1743 } 1744 1745 static void moveStatusWindow(StatusWindow *statusWindow) 1746 { 1747 XWindowAttributes xwa; 1748 Window child; 1749 int x, y, width; 1750 Window target; 1751 1752 if (NULL == statusWindow) return; 1753 if (statusWindow->grandParent) { 1754 target = statusWindow->grandParent; 1755 } else { 1756 target = statusWindow->parent; 1757 } 1758 XGetWindowAttributes(dpy, target, &xwa); 1759 XTranslateCoordinates(dpy, 1760 target, xwa.root, 1761 0, 0, 1762 &x, &y, 1763 &child); 1764 if (statusWindow->x != x 1765 || statusWindow->y != y 1766 || statusWindow->width != xwa.width 1767 || statusWindow->height != xwa.height){ 1768 statusWindow->x = x; 1769 statusWindow->y = y; 1770 statusWindow->height = xwa.height; 1771 statusWindow->width = xwa.width; 1772 x = statusWindow->x - statusWindow->off_x; 1773 y = statusWindow->y + statusWindow->height + statusWindow->off_y; 1774 if (x < 0 ){ 1775 x = 0; 1776 } 1777 if (statusWindow->peTextW > 0) { 1778 width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1; 1779 if (x + width > statusWindow->rootW){ 1780 x = statusWindow->rootW - width; 1781 } 1782 } else { 1783 if (x + statusWindow->statusW > statusWindow->rootW){ 1784 x = statusWindow->rootW - statusWindow->statusW; 1785 } 1786 } 1787 if (y + statusWindow->statusH > statusWindow->rootH){ 1788 y = statusWindow->rootH - statusWindow->statusH; 1789 } 1790 XMoveWindow(dpy, statusWindow->w, x, y); 1791 } 1792 } 1793 1794 static void arrange_window_stack(StatusWindow* statusWindow) 1795 { 1796 XWindowChanges xwc; 1797 int value_make = CWSibling|CWStackMode; 1798 Window root, parent, *children; 1799 unsigned int nchildren; 1800 1801 if (NULL == statusWindow) return; 1802 if (XQueryTree(dpy, statusWindow->parent, 1803 &root, &parent, &children, &nchildren)){ 1804 XFree(children); 1805 xwc.sibling = parent; 1806 while(XQueryTree(dpy, xwc.sibling, &root, &parent, &children, &nchildren)) { 1807 XFree(children); 1808 if (root != parent) { 1809 xwc.sibling = parent; 1810 } else { 1811 break; 1812 } 1813 } 1814 xwc.stack_mode = Above; 1815 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1816 } 1817 } 1818 1819 static int count_missing_fonts(char **charset_list, int charset_count) 1820 { 1821 int i,j; 1822 if (charset_count > 0) { 1823 j=charset_count; 1824 for(i=0; i < charset_count; i++) { 1825 if ((strstr(charset_list[i], "IBM-udc")) || 1826 (strstr(charset_list[i], "IBM-sbd")) || 1827 (strstr(charset_list[i], "IBM-ucdTW"))) 1828 j--; 1829 } 1830 return j; 1831 } 1832 else 1833 return 0; 1834 } 1835 1836 static XFontSet create_fontset_name(char * font_name, Bool force) 1837 { 1838 XFontSet fontset = NULL; 1839 char **charset_list; 1840 int charset_count; 1841 char *def_string; 1842 int missing_fonts; 1843 1844 fontset = XCreateFontSet(dpy, font_name, 1845 &charset_list, &charset_count, &def_string); 1846 if (charset_count > 0) { 1847 missing_fonts = count_missing_fonts(charset_list, 1848 charset_count); 1849 XFreeStringList(charset_list); 1850 if (fontset && (missing_fonts > 0)) { 1851 if (!force) { 1852 XFreeFontSet(dpy, fontset); 1853 fontset = NULL; 1854 } 1855 } 1856 } 1857 return fontset; 1858 } 1859 1860 static XFontSet create_fontset() 1861 { 1862 XFontSet fontset = NULL; 1863 int i; 1864 static char * fontlist[] = { 1865 "-dt-interface user-medium-r-normal-S*-*-*-*-*-*-*-*-*", 1866 "-*-*-medium-r-normal-*-14-*-*-*-c-*-*-*", 1867 "-*-*-medium-r-normal-*-14-*-*-*-m-*-*-*", 1868 "-*-*-medium-r-normal--14-0-0-0-m-*-*-*", 1869 "-monotype-sansmonowt-medium-r-normal--14-*-*-*-m-*-*-*", 1870 "-*--14-*", 1871 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*", 1872 "-*--16-*", 1873 "-*--17-*", 1874 "-*--18-*", 1875 "-*--19-*", 1876 "-*--20-*", 1877 "-*--24-*", 1878 NULL}; 1879 1880 for (i=0; fontlist[i] != NULL && fontset==NULL; i++) 1881 fontset = create_fontset_name(fontlist[i], False); 1882 1883 if (!fontset) 1884 fprintf(stdout, "Cannot load fonts for IMF.\n"); 1885 return fontset; 1886 } 1887 1888 static Window get_current_focus(XIC ic) { 1889 Window w = 0; 1890 if (ic != NULL) 1891 XGetICValues(ic, XNFocusWindow, &w, NULL); 1892 return w; 1893 } 1894 1895 JNIEXPORT jboolean JNICALL 1896 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env, 1897 jobject this, 1898 jlong display) 1899 { 1900 Bool registered; 1901 1902 AWT_LOCK(); 1903 1904 dpy = (Display *)jlong_to_ptr(display); 1905 1906 if (X11im == NULL) { 1907 X11im = XOpenIM(dpy, NULL, NULL, NULL); 1908 } 1909 1910 AWT_UNLOCK(); 1911 1912 return JNI_TRUE; 1913 } 1914 1915 JNIEXPORT jboolean JNICALL 1916 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env, 1917 jobject this, 1918 jlong window) 1919 { 1920 X11InputMethodData *pX11IMData; 1921 jobject globalRef; 1922 XIC ic; 1923 1924 AWT_LOCK(); 1925 1926 if (!window) { 1927 JNU_ThrowNullPointerException(env, "NullPointerException"); 1928 AWT_UNLOCK(); 1929 return JNI_FALSE; 1930 } 1931 1932 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData)); 1933 if (pX11IMData == NULL) { 1934 THROW_OUT_OF_MEMORY_ERROR(); 1935 AWT_UNLOCK(); 1936 return JNI_FALSE; 1937 } 1938 1939 globalRef = (*env)->NewGlobalRef(env, this); 1940 pX11IMData->x11inputmethod = globalRef; 1941 pX11IMData->statusWindow = NULL; 1942 1943 setX11InputMethodData(env, this, pX11IMData); 1944 1945 if (createXIC(env, pX11IMData, (Window)window) == False) { 1946 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); 1947 pX11IMData = (X11InputMethodData *) NULL; 1948 setX11InputMethodData(env, this, pX11IMData); 1949 if ((*env)->ExceptionCheck(env)) { 1950 goto finally; 1951 } 1952 } 1953 1954 finally: 1955 AWT_UNLOCK(); 1956 return (pX11IMData != NULL); 1957 } 1958 1959 JNIEXPORT void JNICALL 1960 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, 1961 jobject this, 1962 jlong w, 1963 jboolean req, 1964 jboolean active) 1965 { 1966 X11InputMethodData *pX11IMData; 1967 AWT_LOCK(); 1968 pX11IMData = getX11InputMethodData(env, this); 1969 if (pX11IMData == NULL) { 1970 AWT_UNLOCK(); 1971 return; 1972 } 1973 1974 if (req) { 1975 if (!w) { 1976 AWT_UNLOCK(); 1977 return; 1978 } 1979 pX11IMData->isActiveClient = active; 1980 pX11IMData->current_ic = active ? 1981 pX11IMData->ic_active : pX11IMData->ic_passive; 1982 /* 1983 * On Solaris2.6, setXICWindowFocus() has to be invoked 1984 * before setting focus. 1985 */ 1986 get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */ 1987 if (currentFocusWindow != w) { 1988 setXICWindowFocus(pX11IMData->current_ic, w); 1989 setXICFocus(pX11IMData->current_ic, req); 1990 currentX11InputMethodInstance = pX11IMData->x11inputmethod; 1991 currentFocusWindow = w; 1992 } else { 1993 setXICFocus(pX11IMData->current_ic, req); 1994 } 1995 if ((active || pX11IMData->passiveStatusWindow) 1996 && (pX11IMData->statusWindow && pX11IMData->statusWindow->on)) 1997 onoffStatusWindow(pX11IMData, w, True); 1998 } else { 1999 currentX11InputMethodInstance = NULL; 2000 currentFocusWindow = 0; 2001 onoffStatusWindow(pX11IMData, 0, False); 2002 if (pX11IMData->current_ic != NULL) 2003 setXICFocus(pX11IMData->current_ic, req); 2004 2005 pX11IMData->current_ic = (XIC)0; 2006 } 2007 2008 XFlush(dpy); 2009 AWT_UNLOCK(); 2010 } 2011 2012 /* 2013 * Class: sun_awt_X11InputMethodBase 2014 * Method: initIDs 2015 * Signature: ()V 2016 * This function gets called from the static initializer for 2017 * X11InputMethod.java to initialize the fieldIDs for fields 2018 * that may be accessed from C 2019 */ 2020 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_initIDs 2021 (JNIEnv *env, jclass cls) 2022 { 2023 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); 2024 } 2025 2026 /* 2027 * Class: sun_awt_X11InputMethodBase 2028 * Method: turnoffStatusWindow 2029 * Signature: ()V 2030 */ 2031 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow 2032 (JNIEnv *env, jobject this) 2033 { 2034 X11InputMethodData *pX11IMData; 2035 StatusWindow *statusWindow; 2036 2037 AWT_LOCK(); 2038 2039 if (NULL == currentX11InputMethodInstance 2040 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 2041 || NULL == (statusWindow = pX11IMData->statusWindow) 2042 || !statusWindow->on ){ 2043 AWT_UNLOCK(); 2044 return; 2045 } 2046 onoffStatusWindow(pX11IMData, 0, False); 2047 statusWindow->on = False; 2048 2049 AWT_UNLOCK(); 2050 } 2051 2052 /* 2053 * Class: sun_awt_X11InputMethodBase 2054 * Method: disposeXIC 2055 * Signature: ()V 2056 */ 2057 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_disposeXIC 2058 (JNIEnv *env, jobject this) 2059 { 2060 X11InputMethodData *pX11IMData = NULL; 2061 2062 AWT_LOCK(); 2063 pX11IMData = getX11InputMethodData(env, this); 2064 if (pX11IMData == NULL) { 2065 AWT_UNLOCK(); 2066 return; 2067 } 2068 2069 setX11InputMethodData(env, this, NULL); 2070 2071 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) { 2072 currentX11InputMethodInstance = NULL; 2073 currentFocusWindow = 0; 2074 } 2075 destroyX11InputMethodData(env, pX11IMData); 2076 AWT_UNLOCK(); 2077 } 2078 2079 /* 2080 * Class: sun_awt_X11InputMethodBase 2081 * Method: resetXIC 2082 * Signature: ()Ljava/lang/String; 2083 */ 2084 JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_resetXIC 2085 (JNIEnv *env, jobject this) 2086 { 2087 X11InputMethodData *pX11IMData; 2088 char *xText = NULL; 2089 jstring jText = (jstring)0; 2090 2091 AWT_LOCK(); 2092 pX11IMData = getX11InputMethodData(env, this); 2093 if (pX11IMData == NULL) { 2094 AWT_UNLOCK(); 2095 return jText; 2096 } 2097 2098 if (pX11IMData->current_ic) { 2099 if (!isPreeditStateActive(pX11IMData->current_ic)) { 2100 xText = NULL; 2101 } else { 2102 if (!(pX11IMData->forceReset)) 2103 setXICFocus(pX11IMData->current_ic, FALSE); 2104 xText = XmbResetIC(pX11IMData->current_ic); 2105 if (!(pX11IMData->forceReset)) 2106 setXICFocus(pX11IMData->current_ic, TRUE); 2107 } 2108 } else { 2109 /* 2110 * If there is no reference to the current XIC, try to reset both XICs. 2111 */ 2112 if (!isPreeditStateActive(pX11IMData->ic_active)) 2113 xText = NULL; 2114 else 2115 xText = XmbResetIC(pX11IMData->ic_active); 2116 /*it may also means that the real client component does 2117 not have focus -- has been deactivated... its xic should 2118 not have the focus, bug#4284651 showes reset XIC for htt 2119 may bring the focus back, so de-focus it again. 2120 */ 2121 setXICFocus(pX11IMData->ic_active, FALSE); 2122 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 2123 char *tmpText; 2124 if (!isPreeditStateActive(pX11IMData->ic_passive)) 2125 tmpText = NULL; 2126 else 2127 tmpText = XmbResetIC(pX11IMData->ic_passive); 2128 setXICFocus(pX11IMData->ic_passive, FALSE); 2129 if (xText == (char *)NULL && tmpText) 2130 xText = tmpText; 2131 } 2132 } 2133 if (xText != NULL) { 2134 jText = JNU_NewStringPlatform(env, (const char *)xText); 2135 XFree((void *)xText); 2136 } 2137 2138 /* workaround 2139 * Some IME do not call PreeditDoneCallback routine even 2140 * when XmbResetIC is called. I force to reset the preedit string. 2141 */ 2142 if (!pX11IMData->isActiveClient) { 2143 resetPassivePreeditText(pX11IMData->statusWindow); 2144 shrink_status(pX11IMData->statusWindow); 2145 } else { 2146 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 2147 "clearComposedText", 2148 "()V"); 2149 if ((*env)->ExceptionOccurred(env)) { 2150 (*env)->ExceptionDescribe(env); 2151 (*env)->ExceptionClear(env); 2152 } 2153 } 2154 2155 AWT_UNLOCK(); 2156 return jText; 2157 } 2158 2159 /* 2160 * Class: sun_awt_X11InputMethodBase 2161 * Method: setCompositionEnabledNative 2162 * Signature: (Z)Z 2163 * 2164 * This method tries to set the XNPreeditState attribute associated with the current 2165 * XIC to the passed in 'enable' state. 2166 * 2167 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the 2168 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute, 2169 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this 2170 * method fails due to other reasons. 2171 */ 2172 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_setCompositionEnabledNative 2173 (JNIEnv *env, jobject this, jboolean enable) 2174 { 2175 X11InputMethodData *pX11IMData; 2176 char * ret = NULL; 2177 XVaNestedList pr_atrb; 2178 2179 AWT_LOCK(); 2180 pX11IMData = getX11InputMethodData(env, this); 2181 2182 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 2183 AWT_UNLOCK(); 2184 return JNI_FALSE; 2185 } 2186 2187 pr_atrb = XVaCreateNestedList(0, XNPreeditState, 2188 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); 2189 ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); 2190 XFree((void *)pr_atrb); 2191 AWT_UNLOCK(); 2192 2193 if ((ret != 0) && 2194 ((strcmp(ret, XNPreeditAttributes) == 0) 2195 || (strcmp(ret, XNPreeditState) == 0))) { 2196 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 2197 } 2198 2199 return (jboolean)(ret == 0); 2200 } 2201 2202 /* 2203 * Class: sun_awt_X11InputMethodBase 2204 * Method: isCompositionEnabledNative 2205 * Signature: ()Z 2206 * 2207 * This method tries to get the XNPreeditState attribute associated with the current XIC. 2208 * 2209 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if 2210 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException 2211 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons. 2212 */ 2213 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_isCompositionEnabledNative 2214 (JNIEnv *env, jobject this) 2215 { 2216 X11InputMethodData *pX11IMData = NULL; 2217 char * ret = NULL; 2218 XIMPreeditState state = XIMPreeditUnKnown; 2219 XVaNestedList pr_atrb; 2220 2221 AWT_LOCK(); 2222 pX11IMData = getX11InputMethodData(env, this); 2223 2224 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 2225 AWT_UNLOCK(); 2226 return JNI_FALSE; 2227 } 2228 2229 pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL); 2230 ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); 2231 XFree((void *)pr_atrb); 2232 AWT_UNLOCK(); 2233 2234 if ((ret != 0) && 2235 ((strcmp(ret, XNPreeditAttributes) == 0) 2236 || (strcmp(ret, XNPreeditState) == 0))) { 2237 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 2238 return JNI_FALSE; 2239 } 2240 2241 return (jboolean)(state == XIMPreeditEnable); 2242 } 2243 2244 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow 2245 (JNIEnv *env, jobject this, jlong window) 2246 { 2247 2248 } 2249 2250 /* 2251 * Class: sun_awt_X11InputMethod 2252 * Method: setStatusAreaVisible 2253 * Signature: (ZJ)V 2254 */ 2255 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_setStatusAreaVisible 2256 (JNIEnv *env, jobject this, jboolean value, jlong data) 2257 { 2258 X11InputMethodData *pX11IMData; 2259 2260 pX11IMData = getX11InputMethodData(env, this); 2261 if (NULL == pX11IMData) return; 2262 if (NULL == pX11IMData->statusWindow) return; 2263 2264 if ((int)value){ 2265 pX11IMData->statusWindow->on = True; 2266 }else{ 2267 pX11IMData->statusWindow->on = False; 2268 } 2269 return; 2270 }