1 /* 2 * Copyright (c) 1996, 2009, 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_Toolkit.h" 27 #include "awt_TextComponent.h" 28 #include "awt_Canvas.h" 29 30 #include "jni.h" 31 #include "awt_Font.h" 32 33 34 /***********************************************************************/ 35 // struct for _SetText() method 36 struct SetTextStruct { 37 jobject textcomponent; 38 jstring text; 39 }; 40 // struct for _Select() method 41 struct SelectStruct { 42 jobject textcomponent; 43 jint start, end; 44 }; 45 // struct for _EnableEditing() method 46 struct EnableEditingStruct { 47 jobject textcomponent; 48 jboolean on; 49 }; 50 /************************************************************************ 51 * AwtTextComponent fields 52 */ 53 54 /* java.awt.TextComponent fields */ 55 jfieldID AwtTextComponent::canAccessClipboardID; 56 57 58 /************************************************************************ 59 * AwtTextComponent methods 60 */ 61 62 AwtTextComponent::AwtTextComponent() { 63 m_synthetic = FALSE; 64 m_lStartPos = -1; 65 m_lEndPos = -1; 66 m_lLastPos = -1; 67 m_isLFonly = FALSE; 68 m_EOLchecked = FALSE; 69 // javaEventsMask = 0; // accessibility support 70 } 71 72 LPCTSTR AwtTextComponent::GetClassName() { 73 return TEXT("EDIT"); /* System provided edit control class */ 74 } 75 76 /* Set a suitable font to IME against the component font. */ 77 void AwtTextComponent::SetFont(AwtFont* font) 78 { 79 DASSERT(font != NULL); 80 if (font->GetAscent() < 0) { 81 AwtFont::SetupAscent(font); 82 } 83 84 int index = font->GetInputHFontIndex(); 85 if (index < 0) 86 /* In this case, user cannot get any suitable font for input. */ 87 index = 0; 88 89 //im --- changed for over the spot composing 90 m_hFont = font->GetHFont(index); 91 SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(FALSE, 0)); 92 SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, 93 MAKELPARAM(1, 1)); 94 95 /* 96 * WM_SETFONT reverts foreground color to the default for 97 * rich edit controls. So we have to restore it manually. 98 */ 99 SetColor(GetColor()); 100 VERIFY(::InvalidateRect(GetHWnd(), NULL, TRUE)); 101 //im --- end 102 103 } 104 105 int AwtTextComponent::RemoveCR(WCHAR *pStr) 106 { 107 int i, nLen = 0; 108 109 if (pStr) { 110 /* check to see if there are any CR's */ 111 if (wcschr(pStr, L'\r') == NULL) { 112 return static_cast<int>(wcslen(pStr)); 113 } 114 115 for (i=0; pStr[i] != 0; i++) { 116 if (m_isLFonly == TRUE) { 117 if (pStr[i] == L'\r') { 118 continue; 119 } 120 } else { 121 if (pStr[i] == L'\r' && pStr[i + 1] != L'\n') { 122 continue; 123 } 124 } 125 pStr[nLen++] = pStr[i]; 126 } 127 pStr[nLen] = 0; 128 } 129 return nLen; 130 } 131 132 MsgRouting 133 AwtTextComponent::WmNotify(UINT notifyCode) 134 { 135 if (notifyCode == EN_CHANGE) { 136 DoCallback("valueChanged", "()V"); 137 } 138 return mrDoDefault; 139 } 140 141 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg) 142 { 143 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK; 144 } 145 146 MsgRouting 147 AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic) 148 { 149 MsgRouting returnVal; 150 151 /* 152 * Store the 'synthetic' parameter so that the WM_PASTE security check 153 * happens only for synthetic events. 154 */ 155 m_synthetic = synthetic; 156 returnVal = AwtComponent::HandleEvent(msg, synthetic); 157 m_synthetic = FALSE; 158 return returnVal; 159 } 160 161 /* 162 * If this Paste is occuring because of a synthetic Java event (e.g., 163 * a synthesized <CTRL>-V KeyEvent), then verify that the TextComponent 164 * has permission to access the Clipboard before pasting. If permission 165 * is denied, we should throw a SecurityException, but currently do not 166 * because when we detect the security violation, we are in the Toolkit 167 * thread, not the thread which dispatched the illegal event. 168 */ 169 MsgRouting 170 AwtTextComponent::WmPaste() 171 { 172 if (m_synthetic) { 173 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 174 if (env->EnsureLocalCapacity(1) < 0) { 175 return mrConsume; 176 } 177 jobject target = GetTarget(env); 178 jboolean canAccessClipboard = 179 env->GetBooleanField(target, 180 AwtTextComponent::canAccessClipboardID); 181 env->DeleteLocalRef(target); 182 return (canAccessClipboard) ? mrDoDefault : mrConsume; 183 } 184 else { 185 return mrDoDefault; 186 } 187 } 188 189 //im --- override to over the spot composition 190 void AwtTextComponent::SetCompositionWindow(RECT& rc) 191 { 192 HIMC hIMC = ImmGetContext(); 193 // rc is not used for text component. 194 COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} }; 195 GetCaretPos(&(cf.ptCurrentPos)); 196 // the proxy is the native focus owner and it contains the composition window 197 // let's convert the position to a coordinate space relative to proxy 198 ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1); 199 ImmSetCompositionWindow(hIMC, &cf); 200 201 LOGFONT lf; 202 GetObject(m_hFont, sizeof(LOGFONT), &lf); 203 ImmSetCompositionFont(hIMC, &lf); 204 } 205 //im --- end 206 207 LONG AwtTextComponent::getJavaSelPos(LONG orgPos) 208 { 209 long wlen; 210 long pos = 0; 211 long cur = 0; 212 LPTSTR wbuf; 213 214 if ((wlen = GetTextLength()) == 0) 215 return 0; 216 wbuf = new TCHAR[wlen + 1]; 217 GetText(wbuf, wlen + 1); 218 if (m_isLFonly == TRUE) { 219 wlen = RemoveCR(wbuf); 220 } 221 222 while (cur < orgPos && pos++ < wlen) { 223 if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) { 224 cur++; 225 } 226 cur++; 227 } 228 delete[] wbuf; 229 return pos; 230 } 231 232 LONG AwtTextComponent::getWin32SelPos(LONG orgPos) 233 { 234 long wlen; 235 long pos = 0; 236 long cur = 0; 237 LPTSTR wbuf; 238 239 if ((wlen = GetTextLength()) == 0) 240 return 0; 241 wbuf = new TCHAR[wlen + 1]; 242 GetText(wbuf, wlen + 1); 243 if (m_isLFonly == TRUE) { 244 RemoveCR(wbuf); 245 } 246 247 while (cur < orgPos && pos < wlen) { 248 if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) { 249 pos++; 250 } 251 pos++; 252 cur++; 253 } 254 delete[] wbuf; 255 return pos; 256 } 257 258 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr) 259 { 260 if (pStr == NULL) { 261 return; 262 } 263 264 if (GetTextLength() == 0) { 265 m_EOLchecked = FALSE; 266 } 267 268 // check to see if there are any LF's 269 if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) { 270 return; 271 } 272 273 for (int i=0; pStr[i] != 0; i++) { 274 if (pStr[i] == L'\n') { 275 if (i > 0 && pStr[i-1] == L'\r') { 276 m_isLFonly = FALSE; 277 } else { 278 m_isLFonly = TRUE; 279 } 280 m_EOLchecked = TRUE; 281 return; 282 } 283 } 284 } 285 286 void AwtTextComponent::SetSelRange(LONG start, LONG end) 287 { 288 SendMessage(EM_SETSEL, 289 getWin32SelPos(start), 290 getWin32SelPos(end)); 291 // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing 292 // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus 293 } 294 295 jstring AwtTextComponent::_GetText(void *param) 296 { 297 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 298 299 jobject self = (jobject)param; 300 301 AwtTextComponent *c = NULL; 302 jstring result = NULL; 303 304 PDATA pData; 305 JNI_CHECK_PEER_GOTO(self, ret); 306 307 c = (AwtTextComponent *)pData; 308 if (::IsWindow(c->GetHWnd())) 309 { 310 int len = ::GetWindowTextLength(c->GetHWnd()); 311 if (len == 0) { 312 /* Make java null string */ 313 jchar *jc = new jchar[0]; 314 result = env->NewString(jc, 0); 315 delete [] jc; 316 } else { 317 WCHAR* buf = new WCHAR[len + 1]; 318 c->GetText(buf, len + 1); 319 c->RemoveCR(buf); 320 result = JNU_NewStringPlatform(env, buf); 321 delete [] buf; 322 } 323 } 324 ret: 325 env->DeleteGlobalRef(self); 326 327 if (result != NULL) 328 { 329 jstring globalRef = (jstring)env->NewGlobalRef(result); 330 env->DeleteLocalRef(result); 331 return globalRef; 332 } 333 else 334 { 335 return NULL; 336 } 337 } 338 339 void AwtTextComponent::_SetText(void *param) 340 { 341 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 342 343 SetTextStruct *sts = (SetTextStruct *)param; 344 jobject self = sts->textcomponent; 345 jstring text = sts->text; 346 347 AwtTextComponent *c = NULL; 348 349 PDATA pData; 350 JNI_CHECK_PEER_GOTO(self, ret); 351 c = (AwtTextComponent *)pData; 352 if (::IsWindow(c->GetHWnd())) 353 { 354 int length = env->GetStringLength(text); 355 WCHAR* buffer = new WCHAR[length + 1]; 356 env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer)); 357 buffer[length] = 0; 358 c->CheckLineSeparator(buffer); 359 c->RemoveCR(buffer); 360 c->SetText(buffer); 361 delete[] buffer; 362 } 363 ret: 364 env->DeleteGlobalRef(self); 365 env->DeleteGlobalRef(text); 366 367 delete sts; 368 } 369 370 jint AwtTextComponent::_GetSelectionStart(void *param) 371 { 372 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 373 374 jobject self = (jobject)param; 375 376 jint result = 0; 377 AwtTextComponent *c = NULL; 378 379 PDATA pData; 380 JNI_CHECK_PEER_GOTO(self, ret); 381 c = (AwtTextComponent *)pData; 382 if (::IsWindow(c->GetHWnd())) 383 { 384 long start; 385 c->SendMessage(EM_GETSEL, (WPARAM)&start); 386 result = c->getJavaSelPos(start); 387 } 388 ret: 389 env->DeleteGlobalRef(self); 390 391 return result; 392 } 393 394 jint AwtTextComponent::_GetSelectionEnd(void *param) 395 { 396 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 397 398 jobject self = (jobject)param; 399 400 jint result = 0; 401 AwtTextComponent *c = NULL; 402 403 PDATA pData; 404 JNI_CHECK_PEER_GOTO(self, ret); 405 c = (AwtTextComponent *)pData; 406 if (::IsWindow(c->GetHWnd())) 407 { 408 long end; 409 c->SendMessage(EM_GETSEL, 0, (LPARAM)&end); 410 result = c->getJavaSelPos(end); 411 } 412 ret: 413 env->DeleteGlobalRef(self); 414 415 return result; 416 } 417 418 void AwtTextComponent::_Select(void *param) 419 { 420 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 421 422 SelectStruct *ss = (SelectStruct *)param; 423 jobject self = ss->textcomponent; 424 jint start = ss->start; 425 jint end = ss->end; 426 427 AwtTextComponent *c = NULL; 428 429 PDATA pData; 430 JNI_CHECK_PEER_GOTO(self, ret); 431 c = (AwtTextComponent *)pData; 432 if (::IsWindow(c->GetHWnd())) 433 { 434 c->SetSelRange(start, end); 435 c->SendMessage(EM_SCROLLCARET); 436 } 437 ret: 438 env->DeleteGlobalRef(self); 439 440 delete ss; 441 } 442 443 void AwtTextComponent::_EnableEditing(void *param) 444 { 445 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 446 447 EnableEditingStruct *ees = (EnableEditingStruct *)param; 448 jobject self = ees->textcomponent; 449 jboolean on = ees->on; 450 451 AwtTextComponent *c = NULL; 452 453 PDATA pData; 454 JNI_CHECK_PEER_GOTO(self, ret); 455 c = (AwtTextComponent *)pData; 456 if (::IsWindow(c->GetHWnd())) 457 { 458 c->SendMessage(EM_SETREADONLY, !on); 459 } 460 ret: 461 env->DeleteGlobalRef(self); 462 463 delete ees; 464 } 465 466 467 /************************************************************************ 468 * WTextComponentPeer native methods 469 */ 470 471 extern "C" { 472 473 /* 474 * Class: sun_awt_windows_WTextComponentPeer 475 * Method: getText 476 * Signature: ()Ljava/lang/String; 477 */ 478 JNIEXPORT jstring JNICALL 479 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self) 480 { 481 TRY; 482 483 jobject selfGlobalRef = env->NewGlobalRef(self); 484 485 jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall( 486 (void*(*)(void*))AwtTextComponent::_GetText, 487 (void *)selfGlobalRef); 488 // selfGlobalRef is deleted in _GetText 489 if (globalRef != NULL) 490 { 491 jstring localRef = (jstring)env->NewLocalRef(globalRef); 492 env->DeleteGlobalRef(globalRef); 493 return localRef; 494 } 495 else 496 { 497 return NULL; 498 } 499 500 CATCH_BAD_ALLOC_RET(NULL); 501 } 502 503 /* 504 * Class: sun_awt_windows_WTextComponentPeer 505 * Method: setText 506 * Signature: (Ljava/lang/String;)V 507 */ 508 JNIEXPORT void JNICALL 509 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self, 510 jstring text) 511 { 512 TRY; 513 514 SetTextStruct *sts = new SetTextStruct; 515 sts->textcomponent = env->NewGlobalRef(self); 516 sts->text = (jstring)env->NewGlobalRef(text); 517 518 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts); 519 // global refs and sts are deleted in _SetText 520 521 CATCH_BAD_ALLOC; 522 } 523 524 /* 525 * Class: sun_awt_windows_WTextComponentPeer 526 * Method: getSelectionStart 527 * Signature: ()I 528 */ 529 JNIEXPORT jint JNICALL 530 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env, 531 jobject self) 532 { 533 TRY; 534 535 return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall( 536 (void *(*)(void *))AwtTextComponent::_GetSelectionStart, 537 env->NewGlobalRef(self)))); 538 // global ref is deleted in _GetSelectionStart() 539 540 CATCH_BAD_ALLOC_RET(0); 541 } 542 543 /* 544 * Class: sun_awt_windows_WTextComponentPeer 545 * Method: getSelectionEnd 546 * Signature: ()I 547 */ 548 JNIEXPORT jint JNICALL 549 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env, 550 jobject self) 551 { 552 TRY; 553 554 return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall( 555 (void *(*)(void *))AwtTextComponent::_GetSelectionEnd, 556 env->NewGlobalRef(self)))); 557 // global ref is deleted in _GetSelectionEnd() 558 559 CATCH_BAD_ALLOC_RET(0); 560 } 561 562 /* 563 * Class: sun_awt_windows_WTextComponentPeer 564 * Method: select 565 * Signature: (II)V 566 */ 567 JNIEXPORT void JNICALL 568 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self, 569 jint start, jint end) 570 { 571 TRY; 572 573 SelectStruct *ss = new SelectStruct; 574 ss->textcomponent = env->NewGlobalRef(self); 575 ss->start = start; 576 ss->end = end; 577 578 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss); 579 // global ref and ss are deleted in _Select 580 581 CATCH_BAD_ALLOC; 582 } 583 584 /* 585 * Class: sun_awt_windows_WTextComponentPeer 586 * Method: enableEditing 587 * Signature: (Z)V 588 */ 589 JNIEXPORT void JNICALL 590 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env, 591 jobject self, 592 jboolean on) 593 { 594 TRY; 595 596 EnableEditingStruct *ees = new EnableEditingStruct; 597 ees->textcomponent = env->NewGlobalRef(self); 598 ees->on = on; 599 600 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees); 601 // global ref and ees are deleted in _EnableEditing() 602 603 CATCH_BAD_ALLOC; 604 } 605 606 /* 607 * Class: sun_awt_windows_WTextComponentPeer 608 * Method: initIDs 609 * Signature: ()V 610 */ 611 JNIEXPORT void JNICALL 612 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls) 613 { 614 TRY; 615 616 cls = env->FindClass("java/awt/TextComponent"); 617 if (cls != NULL) { 618 AwtTextComponent::canAccessClipboardID = 619 env->GetFieldID(cls, "canAccessClipboard", "Z"); 620 DASSERT(AwtTextComponent::canAccessClipboardID != NULL); 621 } 622 623 CATCH_BAD_ALLOC; 624 } 625 626 // 627 // Accessibility support 628 // 629 630 /* To be fully implemented in a future release 631 * 632 * Class: sun_awt_windows_WTextComponentPeer 633 * Method: getIndexAtPoint 634 * Signature: (II)I 635 * 636 JNIEXPORT jlong JNICALL 637 Java_sun_awt_windows_WTextComponentPeer_filterEvents(JNIEnv *env, jobject self, jlong mask) 638 { 639 TRY; 640 641 PDATA pData; 642 JNI_CHECK_PEER_RETURN_NULL(self); 643 AwtTextComponent* c = (AwtTextComponent*)pData; 644 645 jlong oldMask = c->javaEventsMask; 646 c->javaEventsMask = mask; 647 648 return oldMask; 649 650 CATCH_BAD_ALLOC_RET(0); 651 } 652 */ 653 654 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead 655 /* 656 * Handle WmKeyDown to catch keystrokes which may move the caret, 657 * and fire events as appropriate when that happens, if they are wanted 658 * 659 * Note: mouse clicks come through WmKeyDown as well (do they??!?!) 660 * 661 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt, 662 UINT flags, BOOL system) { 663 664 printf("AwtTextComponent::WmKeyDown called\r\n"); 665 666 667 // NOTE: WmKeyDown won't be processed 'till well after we return 668 // so we need to modify the values based on the keystroke 669 // 670 static long oldStart = -1; 671 static long oldEnd = -1; 672 673 // most keystrokes can move the caret 674 // so we'll simply check to see if the caret has moved! 675 if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) { 676 long start; 677 long end; 678 SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 679 if (start != oldStart || end != oldEnd) { 680 681 printf(" -> calling TextComponent.selectionValuesChanged()\r\n"); 682 printf(" -> old = (%d, %d); new = (%d, %d)\r\n", 683 oldStart, oldEnd, start, end); 684 685 DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details... 686 oldStart = start; 687 oldEnd = end; 688 } 689 } 690 691 return AwtComponent::WmKeyDown(wkey, repCnt, flags, system); 692 } 693 */ 694 695 /* To be fully implemented in a future release 696 * 697 * Class: sun_awt_windows_WTextComponentPeer 698 * Method: getIndexAtPoint 699 * Signature: (II)I 700 * 701 JNIEXPORT jint JNICALL 702 Java_sun_awt_windows_WTextComponentPeer_getIndexAtPoint(JNIEnv *env, jobject self, jint x, jint y) 703 { 704 TRY; 705 706 PDATA pData; 707 // JNI_CHECK_PEER_RETURN_VAL(self, -1); [[[FIXME]]] Peter Korn -> should return -1 here 708 JNI_CHECK_PEER_RETURN_NULL(self); 709 AwtTextComponent* c = (AwtTextComponent*)pData; 710 int indicies = c->SendMessage(EM_CHARFROMPOS, (WPARAM) 0, (LPARAM) MAKELPARAM(x, y)); 711 int index = LOWORD(indicies); // index into the line the (x,y) coord is on 712 int lineIndex = c->SendMessage(EM_LINEINDEX, HIWORD(indicies)); // index of start of line 713 return (index + lineIndex); 714 715 CATCH_BAD_ALLOC_RET(-1); 716 } 717 */ 718 719 /* To be fully implemented in a future release 720 * 721 * Class: sun_awt_windows_WTextComponentPeer 722 * Method: getCharacterBounds 723 * Signature: (I)Ljava/awt/Rectangle; 724 * 725 JNIEXPORT jobject JNICALL 726 Java_sun_awt_windows_WTextComponentPeer_getCharacterBounds(JNIEnv *env, jobject self, jint i) 727 { 728 729 // loop through lines with EM_LINELENGTH? e.g.: 730 // line = 0; ttl = 0; // index is passed in as 'i' above 731 // while (ttl < index) { 732 // ttl += SendMessage(EM_LINELENGTH, line++); 733 // } 734 // line-- (decrement back again) 735 // alternately, we could use EM_LINEINDEX to the same effect; perhaps slightly cleaner: 736 // computedIndex = 0; line = 0; 737 // while (computedIndex < index) { 738 // computedIndex = SendMessage(EM_LINEINDEX, 1 + line++); 739 // } 740 // line--; 741 742 // EM_POSFROMCHAR - convert char index into a Point 743 // wParam = (LPPOINT) lpPoint; // address of structure 744 // receiving character position 745 // lParam = (LPARAM) wCharIndex; // zero-based index of character 746 // 747 // still need to turn the above into a Rect somehow... 748 // (use font metrics on font info for letter to get height? use 749 // getLineHeight type of message?). 750 751 // WM_GETFONT - get the font struct for the window control 752 // wParam = lParam = 0 753 // returns an HFONT 754 // -or- 755 // GetTextMetrics(hDC) to get the text info for the font selected 756 // into the hDC of the control (tmHeight is what we want in the 757 // TEXTMETRIC struct). 758 // also GetCharWidth32() with the char at the index in question to get 759 // the width of that char 760 // *** Can't use GetTextMetrics/GetCharWidth32, as we don't have an hDC!! *** 761 762 TRY; 763 764 PDATA pData; 765 JNI_CHECK_PEER_RETURN_NULL(self); 766 AwtComponent* c = (AwtComponent*)pData; 767 /* 768 int line = 0; 769 int lineIndex = 0; 770 while (lineIndex < i) { 771 lineIndex = c->SendMessage(EM_LINEINDEX, 1 + line++); 772 } 773 line--; // line is now the line which contains our character at position 'i' 774 int offsetIndex = i - lineIndex; // offsetIndex is now distance in on the line 775 * / 776 POINT p; 777 778 c->SendMessage(EM_POSFROMCHAR, (WPARAM) &p, (LPARAM) i); // x coord is meaningful; y may not be 779 780 // need to calculate charWidth, charHeight, and set p.y to something meangful 781 782 jint charWidth; 783 jint charHeight; 784 785 /* 786 HFONT font = c->SendMessage(WM_GETFONT); 787 if (GetCharWidth32(c->hdc, i, i, &charWidth) != 0) { // [[[FIXME]]] need to get hDC! 788 789 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 790 jobject rect = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V", 791 (jint) p.x, (jint) p.y, charWidth, charHeight); 792 793 return rect; 794 } 795 * / 796 return (jobject) 0; 797 798 CATCH_BAD_ALLOC_RET(0); 799 } 800 */ 801 802 } /* extern "C" */