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 #include "awt.h" 27 #include "awt_p.h" 28 29 #include <sun_awt_X11InputMethodBase.h> 30 #include <sun_awt_X11InputMethod.h> 31 #include <sun_awt_X11_XInputMethod.h> 32 33 #include <langinfo.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <sys/time.h> 37 #include <wchar.h> 38 #include <wctype.h> 39 #include <X11/Intrinsic.h> 40 #include <X11/keysym.h> 41 #include <X11/Xlib.h> 42 43 #ifdef HEADLESS 44 #error This file should not be included in headless library 45 #endif 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 } 1152 } 1153 } 1154 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 1155 "dispatchComposedText", 1156 "(Ljava/lang/String;[IIIIJ)V", 1157 javastr, 1158 style, 1159 (jint)pre_draw->chg_first, 1160 (jint)pre_draw->chg_length, 1161 (jint)pre_draw->caret, 1162 awt_util_nowMillisUTC()); 1163 1164 if ((*env)->ExceptionOccurred(env)) { 1165 (*env)->ExceptionDescribe(env); 1166 (*env)->ExceptionClear(env); 1167 } 1168 1169 finally: 1170 AWT_UNLOCK(); 1171 return; 1172 } 1173 1174 static void 1175 PreeditCaretCallback(XIC ic, XPointer client_data, 1176 XIMPreeditCaretCallbackStruct *pre_caret) 1177 { 1178 XIMPreeditDrawCallbackStruct pre_draw; 1179 1180 if (pre_caret != NULL && pre_caret->direction == XIMAbsolutePosition) { 1181 pre_draw.caret = pre_caret->position; 1182 pre_draw.chg_first = 0; 1183 pre_draw.chg_length = 0; 1184 pre_draw.text = NULL; 1185 PreeditDrawCallback(ic, client_data, &pre_draw); 1186 } 1187 } 1188 1189 static void 1190 StatusStartCallback(XIC ic, XPointer client_data, XPointer call_data) 1191 { 1192 /*ARGSUSED*/ 1193 /*printf("StatusStartCallback:\n"); */ 1194 } 1195 1196 static void 1197 StatusDoneCallback(XIC ic, XPointer client_data, XPointer call_data) 1198 { 1199 /*ARGSUSED*/ 1200 /*printf("StatusDoneCallback:\n"); */ 1201 } 1202 1203 static void StatusDrawCallback 1204 (XIC ic, XPointer client_data, XIMStatusDrawCallbackStruct *status_draw) 1205 { 1206 /*ARGSUSED*/ 1207 /*printf("StatusDrawCallback:\n"); */ 1208 JNIEnv *env = GetJNIEnv(); 1209 X11InputMethodData *pX11IMData = NULL; 1210 StatusWindow *statusWindow; 1211 int value_make = CWX|CWWidth|CWHeight; 1212 XRectangle logical, ink; 1213 XWindowChanges xwc; 1214 int len; 1215 1216 AWT_LOCK(); 1217 1218 if (NULL == (pX11IMData = getX11InputMethodData(env, (jobject)client_data)) 1219 || NULL == (statusWindow = pX11IMData->statusWindow)){ 1220 goto finally; 1221 } 1222 1223 if (status_draw->type == XIMTextType) { 1224 XIMText *text = (status_draw->data).text; 1225 if (text != NULL) { 1226 if (text->string.multi_byte != NULL) { 1227 if(!strcmp(text->string.multi_byte," ")){ 1228 wcscpy(statusWindow->status, L""); 1229 onoffStatusWindow(pX11IMData, 0, False); 1230 goto finally; 1231 } 1232 mbstowcs(statusWindow->status, 1233 (const char *)text->string.multi_byte, 1234 (size_t)MAX_STATUS_LEN); 1235 } else { 1236 if (0 == st_wcslen(text->string.wide_char)){ 1237 wcscpy(statusWindow->status, L""); 1238 onoffStatusWindow(pX11IMData, 0, False); 1239 goto finally; 1240 } 1241 wcsncpy(statusWindow->status, 1242 text->string.wide_char, 1243 MAX_STATUS_LEN); 1244 } 1245 XwcTextExtents(statusWindow->fontset, statusWindow->status, 1246 st_wcslen(statusWindow->status), &ink, &logical); 1247 statusWindow->statusW = logical.width + BORDER_MARGIN; 1248 statusWindow->statusH = logical.height + BORDER_MARGIN; 1249 xwc.x = statusWindow->x - statusWindow->off_x; 1250 if (xwc.x < 0 ) xwc.x = 0; 1251 xwc.width = statusWindow->statusW; 1252 xwc.height = statusWindow->statusH; 1253 if (xwc.x + xwc.width > statusWindow->rootW){ 1254 xwc.x = statusWindow->rootW - xwc.width; 1255 } 1256 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1257 if (statusWindow->status_ready && statusWindow->on == True){ 1258 onoffStatusWindow(pX11IMData, statusWindow->parent, True); 1259 } 1260 paintStatusWindow(statusWindow); 1261 if (statusWindow->peText) 1262 draw_preedit(statusWindow); 1263 } 1264 else { 1265 wcscpy(statusWindow->status, L""); 1266 /*just turnoff the status window 1267 paintStatusWindow(statusWindow); 1268 */ 1269 onoffStatusWindow(pX11IMData, 0, False); 1270 } 1271 } 1272 1273 finally: 1274 AWT_UNLOCK(); 1275 } 1276 1277 /* return the string length without trailing spaces */ 1278 /* work around code for Japanese AIXIM is implemented. */ 1279 static int st_wcslen(wchar_t *string) 1280 { 1281 int len = (int32_t)wcslen(string); 1282 if (len == 0) 1283 return 0; 1284 for (len--;len >= 0; len--) { 1285 if (!iswspace((wint_t) string[len])) break; 1286 } 1287 return len+1; 1288 } 1289 1290 /* 1291 * Checks whether given XIMText contains a string data. 1292 */ 1293 static Bool is_text_available(XIMText * text) 1294 { 1295 if (text == NULL || text->length==0) 1296 return False; 1297 if (text->encoding_is_wchar) { 1298 if(text->string.wide_char[0] == L'\0') 1299 return False; 1300 } else { 1301 if (text->string.multi_byte[0] == '\0') 1302 return False; 1303 } 1304 return True; 1305 } 1306 1307 /* 1308 * check if preedit status is active 1309 */ 1310 static Bool isPreeditStateActive(XIC ic) 1311 { 1312 XIMPreeditState state = XIMPreeditUnKnown; 1313 XVaNestedList pr_atrb; 1314 char* nosupportAttr; 1315 1316 if (ic == NULL) return False; 1317 1318 pr_atrb = XVaCreateNestedList(0,XNPreeditState,&state,NULL); 1319 nosupportAttr=XGetICValues(ic,XNPreeditAttributes,pr_atrb,NULL); 1320 XFree(pr_atrb); 1321 if (nosupportAttr==NULL && state & XIMPreeditDisable) 1322 return False; 1323 else 1324 return True; 1325 } 1326 1327 static void * buf_insert(void * src, void * insert, int size, 1328 int src_len, int ins_len, int offset) 1329 { 1330 char *temp; 1331 1332 temp = realloc(src, size*(src_len+ins_len+1)); 1333 if (temp == NULL) { 1334 THROW_OUT_OF_MEMORY_ERROR(); 1335 return src; 1336 } 1337 if (offset != src_len) { 1338 memmove(&temp[size*(offset+ins_len)], 1339 &((char *)temp)[size*offset], 1340 size*(src_len-offset)); 1341 } 1342 memcpy(&temp[size*offset], insert, size*ins_len); 1343 1344 return (void *)temp; 1345 } 1346 1347 static void * handle_buffer(void * source, void * insert, 1348 int size,int src_len, int ins_len, 1349 int del_len, int offset) 1350 { 1351 void * temp = source; 1352 1353 if (del_len > 0) { 1354 if (del_len == ins_len) { 1355 memcpy(&((char *)source)[size*offset], insert, size*ins_len); 1356 return source; 1357 } 1358 else if (src_len > offset+del_len) { 1359 memmove(&((char *)source)[size*offset], 1360 &((char *)source)[size*(offset+del_len)], 1361 size*(src_len-offset-del_len)); 1362 } 1363 } 1364 if (ins_len > 0) { 1365 temp = buf_insert(source, insert, size, src_len, 1366 ins_len, offset); 1367 } 1368 return temp; 1369 } 1370 /* 1371 * Display the given preedit text to the root window which is ownd by 1372 * myself. All of the character is converted to wide char. 1373 * this function is used for the passive client. 1374 */ 1375 static void preedit_draw_passive(X11InputMethodData *pX11IMData, 1376 XIMPreeditDrawCallbackStruct *pre_draw) 1377 { 1378 XIMText *text; 1379 wchar_t *tempbuf = NULL; 1380 StatusWindow *statusWindow; 1381 wchar_t *cur_text; 1382 unsigned long *cur_attr; 1383 int cur_len = 0; 1384 int chg_len = pre_draw->chg_length; 1385 int chg_1st = pre_draw->chg_first; 1386 1387 if (NULL == (statusWindow = pX11IMData->statusWindow)) 1388 return; 1389 cur_text = statusWindow->peText; 1390 cur_attr = statusWindow->peAttr; 1391 if (cur_text == NULL && pre_draw->text == NULL) 1392 return; 1393 1394 if (cur_text != NULL) 1395 cur_len = (int32_t)wcslen(cur_text); 1396 text = pre_draw->text; 1397 if (text == NULL) { 1398 /* delete only */ 1399 if (cur_len > chg_1st+chg_len) { 1400 memmove(&cur_text[chg_1st], 1401 &cur_text[chg_1st+chg_len], 1402 sizeof(wchar_t)*(cur_len-chg_1st-chg_len)); 1403 memmove(&cur_attr[chg_1st], 1404 &cur_attr[chg_1st+chg_len], 1405 sizeof(long)*(cur_len-chg_1st-chg_len)); 1406 } 1407 if ((pre_draw->chg_length <= cur_len ) && (pre_draw->chg_length >0)) 1408 cur_text[cur_len-pre_draw->chg_length] =L'\0'; 1409 } else { 1410 /* insert or replace */ 1411 int ins_len = 0; 1412 void * ins_text = NULL; 1413 1414 /* if invalid offset is specified, do nothing. */ 1415 /* this fix is for aixim for eucTW */ 1416 if (cur_len < chg_1st) 1417 return; 1418 if(is_text_available(text)) { 1419 /* insert or replace the text */ 1420 if (text->encoding_is_wchar == False) { 1421 /* convert the text to wide chars. 1422 allocate enough size buffer 1423 */ 1424 tempbuf = (wchar_t *)malloc(sizeof(wchar_t)*(text->length+1)); 1425 if (tempbuf == NULL) { 1426 THROW_OUT_OF_MEMORY_ERROR(); 1427 return; 1428 } 1429 ins_len = (int32_t)mbstowcs(tempbuf, text->string.multi_byte, 1430 text->length); 1431 if (ins_len == -1) { 1432 free(tempbuf); 1433 return; 1434 } 1435 ins_text = (void *)tempbuf; 1436 } 1437 else { 1438 ins_len = text->length; 1439 ins_text = text->string.wide_char; 1440 } 1441 /* finish prepare the data to be inserted */ 1442 1443 statusWindow->peText = 1444 handle_buffer(cur_text, ins_text, sizeof(wchar_t), 1445 cur_len, ins_len, chg_len, chg_1st); 1446 statusWindow->peAttr = 1447 handle_buffer(cur_attr, text->feedback, sizeof(long), 1448 cur_len, ins_len, chg_len, chg_1st); 1449 statusWindow->peText[cur_len-chg_len+ins_len] =L'\0'; 1450 1451 if (tempbuf != NULL) 1452 free(tempbuf); 1453 } /* endof insert or replace text */ 1454 else { 1455 /* change attribute only */ 1456 memcpy(&cur_attr[chg_1st], text->feedback, 1457 sizeof(long)*text->length); 1458 } 1459 } 1460 statusWindow->peCaret= pre_draw->caret; 1461 draw_preedit(statusWindow); 1462 if (statusWindow->on && wcslen(statusWindow->peText) > 0) 1463 onoffStatusWindow(pX11IMData, statusWindow->parent, True); 1464 else if (wcslen(statusWindow->status) == 0) 1465 onoffStatusWindow(pX11IMData, 0, False); 1466 } 1467 1468 /* 1469 * reset predit test of passive mode 1470 */ 1471 static void 1472 resetPassivePreeditText(StatusWindow *statusWindow) 1473 { 1474 if (NULL == statusWindow) return; 1475 if(statusWindow->peText != NULL) { 1476 free(statusWindow->peText); 1477 statusWindow->peText = NULL; 1478 } 1479 if(statusWindow->peAttr != NULL) { 1480 free(statusWindow->peAttr); 1481 statusWindow->peAttr = NULL; 1482 } 1483 statusWindow->peCaret= 0; 1484 } 1485 1486 static void draw_caret(StatusWindow *statusWindow, GC gc, int pos) 1487 { 1488 if (NULL == statusWindow) return; 1489 XSetFunction(dpy, gc, GXinvert); 1490 XDrawLine(dpy, statusWindow->w, 1491 gc, pos, STATUS_BORDER/2, 1492 pos, STATUS_BORDER/2+statusWindow->fOff); 1493 XSetFunction(dpy, gc, GXcopy); 1494 } 1495 1496 static int get_next_attr(int len, unsigned long *attr) 1497 { 1498 int count; 1499 1500 for (count = 1; count < len; count++) { 1501 if ((attr[count-1] & PREEDIT_ATTR_MASK) 1502 != (attr[count] & PREEDIT_ATTR_MASK)) 1503 break; 1504 } 1505 return count; 1506 } 1507 1508 static void draw_preedit(StatusWindow *statusWindow) 1509 { 1510 unsigned long *attr; 1511 int x_pos,x_caret; 1512 unsigned int len; 1513 int len_disp, pos; 1514 wchar_t *str; 1515 GC gc; 1516 XRectangle ink, rect, rect_c; 1517 Bool caret_done = False; 1518 1519 if (NULL == statusWindow) return; 1520 align_status(statusWindow); 1521 XFillRectangle(dpy, statusWindow->w, 1522 statusWindow->bgGC, 1523 statusWindow->statusW,0, 1524 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 1525 statusWindow->fBot+2); 1526 1527 1528 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1529 statusWindow->statusW, 0, 1530 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0); 1531 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1532 statusWindow->statusW, statusWindow->fBot+2, 1533 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 1534 statusWindow->fBot+2); 1535 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1536 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 0, 1537 statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN, 1538 statusWindow->fBot+2); 1539 if (0 == statusWindow->statusW) 1540 XDrawLine(dpy, statusWindow->w, statusWindow->fgGC, 1541 0, 0, 0, statusWindow->fBot+2); 1542 1543 str = statusWindow->peText; 1544 1545 if (str != NULL && (len = (int32_t)wcslen(str)) != 0) { 1546 pos = 0; 1547 attr = statusWindow->peAttr; 1548 x_pos = x_caret = statusWindow->statusW + STATUS_BORDER; 1549 while((int)len-1 >= pos) { 1550 len_disp = get_next_attr(len - pos, &attr[pos]); 1551 if (attr[pos] & XIMReverse) { 1552 gc = statusWindow->bgGC; 1553 } 1554 else { 1555 gc = statusWindow->fgGC; 1556 } 1557 XwcTextExtents(statusWindow->fontset, 1558 &str[pos], 1559 len_disp, &ink, &rect); 1560 XwcDrawImageString(dpy, statusWindow->w, 1561 statusWindow->fontset, gc, 1562 x_pos, statusWindow->fOff+1, &str[pos], len_disp); 1563 if (attr[pos] & XIMUnderline) { 1564 XDrawLine(dpy, statusWindow->w, 1565 gc, x_pos, statusWindow->fBot, 1566 x_pos+rect.width, statusWindow->fBot); 1567 } 1568 if (!caret_done) { 1569 if( statusWindow->peCaret >= pos && 1570 statusWindow->peCaret <= pos+len_disp) { 1571 if (statusWindow->peCaret == 0) 1572 x_caret = x_pos; 1573 else if (statusWindow->peCaret == pos+len_disp) 1574 x_caret = x_pos+rect.width; 1575 else { 1576 XwcTextExtents(statusWindow->fontset, 1577 &str[pos], 1578 statusWindow->peCaret-pos, 1579 &ink, &rect_c); 1580 x_caret = x_pos+ rect_c.width; 1581 } 1582 x_caret-=CARET_OFFSET; 1583 caret_done = True; 1584 } 1585 } 1586 pos += len_disp; 1587 x_pos += rect.width; 1588 } 1589 if (caret_done) 1590 draw_caret(statusWindow, statusWindow->fgGC, x_caret); 1591 } 1592 } 1593 1594 /* calc required status window size and resize the window */ 1595 static void align_status(StatusWindow *statusWindow) 1596 { 1597 int len_st, len_pe = 0; 1598 XRectangle rect_st, rect_pe, ink; 1599 Dimension cur_w; 1600 int value_make = CWX|CWWidth|CWHeight; 1601 XWindowChanges xwc; 1602 1603 if (NULL == statusWindow) return; 1604 if ((len_st = st_wcslen(statusWindow->status)) == 0 1605 && (statusWindow->peText == NULL || st_wcslen(statusWindow->peText) == 0 )) 1606 return; 1607 1608 rect_pe.x = rect_pe.y = rect_pe.width = rect_pe.height = 0; 1609 1610 XwcTextExtents(statusWindow->fontset, 1611 statusWindow->status, 1612 len_st, &ink, &rect_st); 1613 if (statusWindow->peText != NULL 1614 && (len_pe = (int32_t)wcslen(statusWindow->peText)) > 0) { 1615 XwcTextExtents(statusWindow->fontset, 1616 statusWindow->peText, 1617 len_pe, &ink, &rect_pe); 1618 } 1619 statusWindow->fOff = max(-rect_st.y, -rect_pe.y); 1620 statusWindow->fBot = max(rect_st.height, rect_pe.height); 1621 statusWindow->statusW =rect_st.width; 1622 if (rect_st.width > 0) statusWindow->statusW += BORDER_MARGIN; 1623 statusWindow->peTextW = rect_pe.width; 1624 1625 xwc.x = statusWindow->x - statusWindow->off_x; 1626 if (xwc.x < 0 ) xwc.x = 0; 1627 1628 if (len_pe > 0) { 1629 xwc.width = statusWindow->statusW 1630 + statusWindow->peTextW + BORDER_MARGIN + 1; 1631 xwc.height = statusWindow->fBot + BORDER_MARGIN; 1632 } else { 1633 xwc.width = statusWindow->statusW; 1634 xwc.height = statusWindow->fBot + BORDER_MARGIN; 1635 } 1636 if (xwc.x + xwc.width > statusWindow->rootW){ 1637 xwc.x = statusWindow->rootW - xwc.width; 1638 } 1639 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1640 } 1641 1642 static void shrink_status(StatusWindow *statusWindow) 1643 { 1644 int value_make = CWX|CWWidth|CWHeight; 1645 XWindowChanges xwc; 1646 1647 if (NULL == statusWindow) return; 1648 xwc.width = statusWindow->statusW; 1649 xwc.height = statusWindow->statusH; 1650 statusWindow->peTextW = 0; 1651 xwc.x = statusWindow->x - statusWindow->off_x; 1652 if (xwc.x < 0 ) xwc.x = 0; 1653 if (xwc.x + xwc.width > statusWindow->rootW){ 1654 xwc.x = statusWindow->rootW - xwc.width; 1655 } 1656 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1657 } 1658 1659 static GC create_gc(Window win, Bool isReverse) 1660 { 1661 XGCValues xgcv; 1662 unsigned long mask; 1663 AwtScreenDataPtr defaultScreen; 1664 1665 defaultScreen = getScreenData(DefaultScreen(dpy)); 1666 1667 mask = (GCForeground | GCBackground ); 1668 if (isReverse) { 1669 xgcv.foreground = defaultScreen->whitepixel; 1670 xgcv.background = defaultScreen->blackpixel; 1671 } else { 1672 xgcv.foreground = defaultScreen->blackpixel; 1673 xgcv.background = defaultScreen->whitepixel; 1674 } 1675 return XCreateGC(dpy, win, mask, &xgcv); 1676 } 1677 1678 static Bool isNativeIm() 1679 { 1680 #define XIMMODIFIER "@im=" 1681 #define XIM_SERVER_CATEGORY "@server=" 1682 char *immodifiers; 1683 char *imserver, *imserverPtr; 1684 Atom imserverAtom; 1685 1686 if (!(immodifiers = getenv("XMODIFIERS"))) return True; 1687 if (!(imserver = calloc(1,strlen(immodifiers)+strlen(XIM_SERVER_CATEGORY)+1))) return True; 1688 if (!(immodifiers = strstr(immodifiers,XIMMODIFIER))) return True; 1689 immodifiers += strlen(XIMMODIFIER); 1690 strcpy(imserver,XIM_SERVER_CATEGORY); 1691 imserverPtr = imserver + strlen(imserver); 1692 while(*immodifiers != '@' && *immodifiers != '\0') { 1693 *imserverPtr = *immodifiers; 1694 imserverPtr++; 1695 immodifiers++; 1696 } 1697 imserverAtom = XInternAtom(awt_display, imserver, True); 1698 free(imserver); 1699 if (imserverAtom > 0) 1700 return False; 1701 else 1702 return True; 1703 } 1704 1705 static Window getGrandParent(Window parent) 1706 { 1707 Window containerWindow,rootWindow,tmp; 1708 Window *ignoreWindowPtr; 1709 unsigned int ignoreUnit; 1710 Window grandParent=0; 1711 XWindowAttributes xwa; 1712 Atom WM_STATE; 1713 Atom type = None; 1714 int32_t format; 1715 unsigned long nitems, after; 1716 unsigned char * data; 1717 1718 if (parent == 0) return grandParent; 1719 WM_STATE = XInternAtom(dpy, "WM_STATE", True); 1720 if (WM_STATE == None) return grandParent; 1721 1722 tmp=parent; 1723 while(XQueryTree(dpy, tmp, 1724 &rootWindow, &containerWindow, 1725 &ignoreWindowPtr, &ignoreUnit)){ 1726 XFree(ignoreWindowPtr); 1727 if (containerWindow == rootWindow) break; 1728 if (XGetWindowProperty(dpy, containerWindow, WM_STATE, 1729 0, 0, False, AnyPropertyType, 1730 &type, &format, &nitems, &after, &data) == Success) { 1731 XFree(data); 1732 if (type) { 1733 XGetWindowAttributes(dpy, containerWindow, &xwa); 1734 if (FALSE == xwa.override_redirect){ 1735 grandParent=containerWindow; 1736 } 1737 } 1738 } 1739 tmp=containerWindow; 1740 } 1741 return grandParent; 1742 } 1743 1744 static void moveStatusWindow(StatusWindow *statusWindow) 1745 { 1746 XWindowAttributes xwa; 1747 Window child; 1748 int x, y, width; 1749 Window target; 1750 1751 if (NULL == statusWindow) return; 1752 if (statusWindow->grandParent) { 1753 target = statusWindow->grandParent; 1754 } else { 1755 target = statusWindow->parent; 1756 } 1757 XGetWindowAttributes(dpy, target, &xwa); 1758 XTranslateCoordinates(dpy, 1759 target, xwa.root, 1760 0, 0, 1761 &x, &y, 1762 &child); 1763 if (statusWindow->x != x 1764 || statusWindow->y != y 1765 || statusWindow->width != xwa.width 1766 || statusWindow->height != xwa.height){ 1767 statusWindow->x = x; 1768 statusWindow->y = y; 1769 statusWindow->height = xwa.height; 1770 statusWindow->width = xwa.width; 1771 x = statusWindow->x - statusWindow->off_x; 1772 y = statusWindow->y + statusWindow->height + statusWindow->off_y; 1773 if (x < 0 ){ 1774 x = 0; 1775 } 1776 if (statusWindow->peTextW > 0) { 1777 width = statusWindow->statusW + statusWindow->peTextW + BORDER_MARGIN + 1; 1778 if (x + width > statusWindow->rootW){ 1779 x = statusWindow->rootW - width; 1780 } 1781 } else { 1782 if (x + statusWindow->statusW > statusWindow->rootW){ 1783 x = statusWindow->rootW - statusWindow->statusW; 1784 } 1785 } 1786 if (y + statusWindow->statusH > statusWindow->rootH){ 1787 y = statusWindow->rootH - statusWindow->statusH; 1788 } 1789 XMoveWindow(dpy, statusWindow->w, x, y); 1790 } 1791 } 1792 1793 static void arrange_window_stack(StatusWindow* statusWindow) 1794 { 1795 XWindowChanges xwc; 1796 int value_make = CWSibling|CWStackMode; 1797 Window root, parent, *children; 1798 unsigned int nchildren; 1799 1800 if (NULL == statusWindow) return; 1801 if (XQueryTree(dpy, statusWindow->parent, 1802 &root, &parent, &children, &nchildren)){ 1803 XFree(children); 1804 xwc.sibling = parent; 1805 while(XQueryTree(dpy, xwc.sibling, &root, &parent, &children, &nchildren)) { 1806 XFree(children); 1807 if (root != parent) { 1808 xwc.sibling = parent; 1809 } else { 1810 break; 1811 } 1812 } 1813 xwc.stack_mode = Above; 1814 XConfigureWindow(dpy, statusWindow->w, value_make, &xwc); 1815 } 1816 } 1817 1818 static int count_missing_fonts(char **charset_list, int charset_count) 1819 { 1820 int i,j; 1821 if (charset_count > 0) { 1822 j=charset_count; 1823 for(i=0; i < charset_count; i++) { 1824 if ((strstr(charset_list[i], "IBM-udc")) || 1825 (strstr(charset_list[i], "IBM-sbd")) || 1826 (strstr(charset_list[i], "IBM-ucdTW"))) 1827 j--; 1828 } 1829 return j; 1830 } 1831 else 1832 return 0; 1833 } 1834 1835 static XFontSet create_fontset_name(char * font_name, Bool force) 1836 { 1837 XFontSet fontset = NULL; 1838 char **charset_list; 1839 int charset_count; 1840 char *def_string; 1841 int missing_fonts; 1842 1843 fontset = XCreateFontSet(dpy, font_name, 1844 &charset_list, &charset_count, &def_string); 1845 if (charset_count > 0) { 1846 missing_fonts = count_missing_fonts(charset_list, 1847 charset_count); 1848 XFreeStringList(charset_list); 1849 if (fontset && (missing_fonts > 0)) { 1850 if (!force) { 1851 XFreeFontSet(dpy, fontset); 1852 fontset = NULL; 1853 } 1854 } 1855 } 1856 return fontset; 1857 } 1858 1859 static XFontSet create_fontset() 1860 { 1861 XFontSet fontset = NULL; 1862 int i; 1863 static char * fontlist[] = { 1864 "-dt-interface user-medium-r-normal-S*-*-*-*-*-*-*-*-*", 1865 "-*-*-medium-r-normal-*-14-*-*-*-c-*-*-*", 1866 "-*-*-medium-r-normal-*-14-*-*-*-m-*-*-*", 1867 "-*-*-medium-r-normal--14-0-0-0-m-*-*-*", 1868 "-monotype-sansmonowt-medium-r-normal--14-*-*-*-m-*-*-*", 1869 "-*--14-*", 1870 "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*", 1871 "-*--16-*", 1872 "-*--17-*", 1873 "-*--18-*", 1874 "-*--19-*", 1875 "-*--20-*", 1876 "-*--24-*", 1877 NULL}; 1878 1879 for (i=0; fontlist[i] != NULL && fontset==NULL; i++) 1880 fontset = create_fontset_name(fontlist[i], False); 1881 1882 if (!fontset) 1883 fprintf(stdout, "Cannot load fonts for IMF.\n"); 1884 return fontset; 1885 } 1886 1887 static Window get_current_focus(XIC ic) { 1888 Window w = 0; 1889 if (ic != NULL) 1890 XGetICValues(ic, XNFocusWindow, &w, NULL); 1891 return w; 1892 } 1893 1894 JNIEXPORT jboolean JNICALL 1895 Java_sun_awt_X11_XInputMethod_openXIMNative(JNIEnv *env, 1896 jobject this, 1897 jlong display) 1898 { 1899 Bool registered; 1900 1901 AWT_LOCK(); 1902 1903 dpy = (Display *)jlong_to_ptr(display); 1904 1905 if (X11im == NULL) { 1906 X11im = XOpenIM(dpy, NULL, NULL, NULL); 1907 } 1908 1909 AWT_UNLOCK(); 1910 1911 return JNI_TRUE; 1912 } 1913 1914 JNIEXPORT jboolean JNICALL 1915 Java_sun_awt_X11_XInputMethod_createXICNative(JNIEnv *env, 1916 jobject this, 1917 jlong window) 1918 { 1919 X11InputMethodData *pX11IMData; 1920 jobject globalRef; 1921 XIC ic; 1922 1923 AWT_LOCK(); 1924 1925 if (!window) { 1926 JNU_ThrowNullPointerException(env, "NullPointerException"); 1927 AWT_UNLOCK(); 1928 return JNI_FALSE; 1929 } 1930 1931 pX11IMData = (X11InputMethodData *) calloc(1, sizeof(X11InputMethodData)); 1932 if (pX11IMData == NULL) { 1933 THROW_OUT_OF_MEMORY_ERROR(); 1934 AWT_UNLOCK(); 1935 return JNI_FALSE; 1936 } 1937 1938 globalRef = (*env)->NewGlobalRef(env, this); 1939 pX11IMData->x11inputmethod = globalRef; 1940 pX11IMData->statusWindow = NULL; 1941 1942 setX11InputMethodData(env, this, pX11IMData); 1943 1944 if (createXIC(env, pX11IMData, (Window)window) == False) { 1945 destroyX11InputMethodData((JNIEnv *) NULL, pX11IMData); 1946 pX11IMData = (X11InputMethodData *) NULL; 1947 setX11InputMethodData(env, this, pX11IMData); 1948 if ((*env)->ExceptionCheck(env)) { 1949 goto finally; 1950 } 1951 } 1952 1953 finally: 1954 AWT_UNLOCK(); 1955 return (pX11IMData != NULL); 1956 } 1957 1958 JNIEXPORT void JNICALL 1959 Java_sun_awt_X11_XInputMethod_setXICFocusNative(JNIEnv *env, 1960 jobject this, 1961 jlong w, 1962 jboolean req, 1963 jboolean active) 1964 { 1965 X11InputMethodData *pX11IMData; 1966 AWT_LOCK(); 1967 pX11IMData = getX11InputMethodData(env, this); 1968 if (pX11IMData == NULL) { 1969 AWT_UNLOCK(); 1970 return; 1971 } 1972 1973 if (req) { 1974 if (!w) { 1975 AWT_UNLOCK(); 1976 return; 1977 } 1978 pX11IMData->isActiveClient = active; 1979 pX11IMData->current_ic = active ? 1980 pX11IMData->ic_active : pX11IMData->ic_passive; 1981 /* 1982 * On Solaris2.6, setXICWindowFocus() has to be invoked 1983 * before setting focus. 1984 */ 1985 get_current_focus(pX11IMData->current_ic); /* workaround for kinput2 and SCIM */ 1986 if (currentFocusWindow != w) { 1987 setXICWindowFocus(pX11IMData->current_ic, w); 1988 setXICFocus(pX11IMData->current_ic, req); 1989 currentX11InputMethodInstance = pX11IMData->x11inputmethod; 1990 currentFocusWindow = w; 1991 } else { 1992 setXICFocus(pX11IMData->current_ic, req); 1993 } 1994 if ((active || pX11IMData->passiveStatusWindow) 1995 && (pX11IMData->statusWindow && pX11IMData->statusWindow->on)) 1996 onoffStatusWindow(pX11IMData, w, True); 1997 } else { 1998 currentX11InputMethodInstance = NULL; 1999 currentFocusWindow = 0; 2000 onoffStatusWindow(pX11IMData, 0, False); 2001 if (pX11IMData->current_ic != NULL) 2002 setXICFocus(pX11IMData->current_ic, req); 2003 2004 pX11IMData->current_ic = (XIC)0; 2005 } 2006 2007 XFlush(dpy); 2008 AWT_UNLOCK(); 2009 } 2010 2011 /* 2012 * Class: sun_awt_X11InputMethodBase 2013 * Method: initIDs 2014 * Signature: ()V 2015 * This function gets called from the static initializer for 2016 * X11InputMethod.java to initialize the fieldIDs for fields 2017 * that may be accessed from C 2018 */ 2019 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_initIDs 2020 (JNIEnv *env, jclass cls) 2021 { 2022 x11InputMethodIDs.pData = (*env)->GetFieldID(env, cls, "pData", "J"); 2023 } 2024 2025 /* 2026 * Class: sun_awt_X11InputMethodBase 2027 * Method: turnoffStatusWindow 2028 * Signature: ()V 2029 */ 2030 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_turnoffStatusWindow 2031 (JNIEnv *env, jobject this) 2032 { 2033 X11InputMethodData *pX11IMData; 2034 StatusWindow *statusWindow; 2035 2036 AWT_LOCK(); 2037 2038 if (NULL == currentX11InputMethodInstance 2039 || NULL == (pX11IMData = getX11InputMethodData(env,currentX11InputMethodInstance)) 2040 || NULL == (statusWindow = pX11IMData->statusWindow) 2041 || !statusWindow->on ){ 2042 AWT_UNLOCK(); 2043 return; 2044 } 2045 onoffStatusWindow(pX11IMData, 0, False); 2046 statusWindow->on = False; 2047 2048 AWT_UNLOCK(); 2049 } 2050 2051 /* 2052 * Class: sun_awt_X11InputMethodBase 2053 * Method: disposeXIC 2054 * Signature: ()V 2055 */ 2056 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethodBase_disposeXIC 2057 (JNIEnv *env, jobject this) 2058 { 2059 X11InputMethodData *pX11IMData = NULL; 2060 2061 AWT_LOCK(); 2062 pX11IMData = getX11InputMethodData(env, this); 2063 if (pX11IMData == NULL) { 2064 AWT_UNLOCK(); 2065 return; 2066 } 2067 2068 setX11InputMethodData(env, this, NULL); 2069 2070 if (pX11IMData->x11inputmethod == currentX11InputMethodInstance) { 2071 currentX11InputMethodInstance = NULL; 2072 currentFocusWindow = 0; 2073 } 2074 destroyX11InputMethodData(env, pX11IMData); 2075 AWT_UNLOCK(); 2076 } 2077 2078 /* 2079 * Class: sun_awt_X11InputMethodBase 2080 * Method: resetXIC 2081 * Signature: ()Ljava/lang/String; 2082 */ 2083 JNIEXPORT jstring JNICALL Java_sun_awt_X11InputMethodBase_resetXIC 2084 (JNIEnv *env, jobject this) 2085 { 2086 X11InputMethodData *pX11IMData; 2087 char *xText = NULL; 2088 jstring jText = (jstring)0; 2089 2090 AWT_LOCK(); 2091 pX11IMData = getX11InputMethodData(env, this); 2092 if (pX11IMData == NULL) { 2093 AWT_UNLOCK(); 2094 return jText; 2095 } 2096 2097 if (pX11IMData->current_ic) { 2098 if (!isPreeditStateActive(pX11IMData->current_ic)) { 2099 xText = NULL; 2100 } else { 2101 if (!(pX11IMData->forceReset)) 2102 setXICFocus(pX11IMData->current_ic, FALSE); 2103 xText = XmbResetIC(pX11IMData->current_ic); 2104 if (!(pX11IMData->forceReset)) 2105 setXICFocus(pX11IMData->current_ic, TRUE); 2106 } 2107 } else { 2108 /* 2109 * If there is no reference to the current XIC, try to reset both XICs. 2110 */ 2111 if (!isPreeditStateActive(pX11IMData->ic_active)) 2112 xText = NULL; 2113 else 2114 xText = XmbResetIC(pX11IMData->ic_active); 2115 /*it may also means that the real client component does 2116 not have focus -- has been deactivated... its xic should 2117 not have the focus, bug#4284651 showes reset XIC for htt 2118 may bring the focus back, so de-focus it again. 2119 */ 2120 setXICFocus(pX11IMData->ic_active, FALSE); 2121 if (pX11IMData->ic_active != pX11IMData->ic_passive) { 2122 char *tmpText; 2123 if (!isPreeditStateActive(pX11IMData->ic_passive)) 2124 tmpText = NULL; 2125 else 2126 tmpText = XmbResetIC(pX11IMData->ic_passive); 2127 setXICFocus(pX11IMData->ic_passive, FALSE); 2128 if (xText == (char *)NULL && tmpText) 2129 xText = tmpText; 2130 } 2131 } 2132 if (xText != NULL) { 2133 jText = JNU_NewStringPlatform(env, (const char *)xText); 2134 XFree((void *)xText); 2135 } 2136 2137 /* workaround 2138 * Some IME do not call PreeditDoneCallback routine even 2139 * when XmbResetIC is called. I force to reset the preedit string. 2140 */ 2141 if (!pX11IMData->isActiveClient) { 2142 resetPassivePreeditText(pX11IMData->statusWindow); 2143 shrink_status(pX11IMData->statusWindow); 2144 } else { 2145 JNU_CallMethodByName(env, NULL, pX11IMData->x11inputmethod, 2146 "clearComposedText", 2147 "()V"); 2148 if ((*env)->ExceptionOccurred(env)) { 2149 (*env)->ExceptionDescribe(env); 2150 (*env)->ExceptionClear(env); 2151 } 2152 } 2153 2154 AWT_UNLOCK(); 2155 return jText; 2156 } 2157 2158 /* 2159 * Class: sun_awt_X11InputMethodBase 2160 * Method: setCompositionEnabledNative 2161 * Signature: (Z)Z 2162 * 2163 * This method tries to set the XNPreeditState attribute associated with the current 2164 * XIC to the passed in 'enable' state. 2165 * 2166 * Return JNI_TRUE if XNPreeditState attribute is successfully changed to the 2167 * 'enable' state; Otherwise, if XSetICValues fails to set this attribute, 2168 * java.lang.UnsupportedOperationException will be thrown. JNI_FALSE is returned if this 2169 * method fails due to other reasons. 2170 */ 2171 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_setCompositionEnabledNative 2172 (JNIEnv *env, jobject this, jboolean enable) 2173 { 2174 X11InputMethodData *pX11IMData; 2175 char * ret = NULL; 2176 XVaNestedList pr_atrb; 2177 2178 AWT_LOCK(); 2179 pX11IMData = getX11InputMethodData(env, this); 2180 2181 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 2182 AWT_UNLOCK(); 2183 return JNI_FALSE; 2184 } 2185 2186 pr_atrb = XVaCreateNestedList(0, XNPreeditState, 2187 (enable ? XIMPreeditEnable : XIMPreeditDisable), NULL); 2188 ret = XSetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); 2189 XFree((void *)pr_atrb); 2190 AWT_UNLOCK(); 2191 2192 if ((ret != 0) && 2193 ((strcmp(ret, XNPreeditAttributes) == 0) 2194 || (strcmp(ret, XNPreeditState) == 0))) { 2195 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 2196 } 2197 2198 return (jboolean)(ret == 0); 2199 } 2200 2201 /* 2202 * Class: sun_awt_X11InputMethodBase 2203 * Method: isCompositionEnabledNative 2204 * Signature: ()Z 2205 * 2206 * This method tries to get the XNPreeditState attribute associated with the current XIC. 2207 * 2208 * Return JNI_TRUE if the XNPreeditState is successfully retrieved. Otherwise, if 2209 * XGetICValues fails to get this attribute, java.lang.UnsupportedOperationException 2210 * will be thrown. JNI_FALSE is returned if this method fails due to other reasons. 2211 */ 2212 JNIEXPORT jboolean JNICALL Java_sun_awt_X11InputMethodBase_isCompositionEnabledNative 2213 (JNIEnv *env, jobject this) 2214 { 2215 X11InputMethodData *pX11IMData = NULL; 2216 char * ret = NULL; 2217 XIMPreeditState state = XIMPreeditUnKnown; 2218 XVaNestedList pr_atrb; 2219 2220 AWT_LOCK(); 2221 pX11IMData = getX11InputMethodData(env, this); 2222 2223 if ((pX11IMData == NULL) || (pX11IMData->current_ic == NULL)) { 2224 AWT_UNLOCK(); 2225 return JNI_FALSE; 2226 } 2227 2228 pr_atrb = XVaCreateNestedList(0, XNPreeditState, &state, NULL); 2229 ret = XGetICValues(pX11IMData->current_ic, XNPreeditAttributes, pr_atrb, NULL); 2230 XFree((void *)pr_atrb); 2231 AWT_UNLOCK(); 2232 2233 if ((ret != 0) && 2234 ((strcmp(ret, XNPreeditAttributes) == 0) 2235 || (strcmp(ret, XNPreeditState) == 0))) { 2236 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", ""); 2237 return JNI_FALSE; 2238 } 2239 2240 return (jboolean)(state == XIMPreeditEnable); 2241 } 2242 2243 JNIEXPORT void JNICALL Java_sun_awt_X11_XInputMethod_adjustStatusWindow 2244 (JNIEnv *env, jobject this, jlong window) 2245 { 2246 2247 } 2248 2249 /* 2250 * Class: sun_awt_X11InputMethod 2251 * Method: setStatusAreaVisible 2252 * Signature: (ZJ)V 2253 */ 2254 JNIEXPORT void JNICALL Java_sun_awt_X11InputMethod_setStatusAreaVisible 2255 (JNIEnv *env, jobject this, jboolean value, jlong data) 2256 { 2257 X11InputMethodData *pX11IMData; 2258 2259 pX11IMData = getX11InputMethodData(env, this); 2260 if (NULL == pX11IMData) return; 2261 if (NULL == pX11IMData->statusWindow) return; 2262 2263 if ((int)value){ 2264 pX11IMData->statusWindow->on = True; 2265 }else{ 2266 pX11IMData->statusWindow->on = False; 2267 } 2268 return; 2269 }