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     HWND hwnd = ImmGetHWnd();
 193     HIMC hIMC = ImmGetContext(hwnd);
 194     // rc is not used for text component.
 195     COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} };
 196     GetCaretPos(&(cf.ptCurrentPos));
 197     // the proxy is the native focus owner and it contains the composition window
 198     // let's convert the position to a coordinate space relative to proxy
 199     ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1);
 200     ImmSetCompositionWindow(hIMC, &cf);
 201 
 202     LOGFONT lf;
 203     GetObject(m_hFont, sizeof(LOGFONT), &lf);
 204     ImmSetCompositionFont(hIMC, &lf);
 205     ImmReleaseContext(hwnd, hIMC);
 206 }
 207 //im --- end
 208 
 209 LONG AwtTextComponent::getJavaSelPos(LONG orgPos)
 210 {
 211     long wlen;
 212     long pos = 0;
 213     long cur = 0;
 214     LPTSTR wbuf;
 215 
 216     if ((wlen = GetTextLength()) == 0)
 217         return 0;
 218     wbuf = new TCHAR[wlen + 1];
 219     GetText(wbuf, wlen + 1);
 220     if (m_isLFonly == TRUE) {
 221         wlen = RemoveCR(wbuf);
 222     }
 223 
 224     while (cur < orgPos && pos++ < wlen) {
 225         if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) {
 226             cur++;
 227         }
 228         cur++;
 229     }
 230     delete[] wbuf;
 231     return pos;
 232 }
 233 
 234 LONG AwtTextComponent::getWin32SelPos(LONG orgPos)
 235 {
 236     long wlen;
 237     long pos = 0;
 238     long cur = 0;
 239     LPTSTR wbuf;
 240 
 241     if ((wlen = GetTextLength()) == 0)
 242        return 0;
 243     wbuf = new TCHAR[wlen + 1];
 244     GetText(wbuf, wlen + 1);
 245     if (m_isLFonly == TRUE) {
 246         RemoveCR(wbuf);
 247     }
 248 
 249     while (cur < orgPos && pos < wlen) {
 250         if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) {
 251             pos++;
 252         }
 253         pos++;
 254         cur++;
 255     }
 256     delete[] wbuf;
 257     return pos;
 258 }
 259 
 260 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr)
 261 {
 262     if (pStr == NULL) {
 263         return;
 264     }
 265 
 266     if (GetTextLength() == 0) {
 267         m_EOLchecked = FALSE;
 268     }
 269 
 270     // check to see if there are any LF's
 271     if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) {
 272         return;
 273     }
 274 
 275     for (int i=0; pStr[i] != 0; i++) {
 276         if (pStr[i] == L'\n') {
 277             if (i > 0 && pStr[i-1] == L'\r') {
 278                 m_isLFonly = FALSE;
 279             } else {
 280                 m_isLFonly = TRUE;
 281             }
 282             m_EOLchecked = TRUE;
 283             return;
 284         }
 285     }
 286 }
 287 
 288 void AwtTextComponent::SetSelRange(LONG start, LONG end)
 289 {
 290     SendMessage(EM_SETSEL,
 291                 getWin32SelPos(start),
 292                 getWin32SelPos(end));
 293     // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing
 294     // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus
 295 }
 296 
 297 jstring AwtTextComponent::_GetText(void *param)
 298 {
 299     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 300 
 301     jobject self = (jobject)param;
 302 
 303     AwtTextComponent *c = NULL;
 304     jstring result = NULL;
 305 
 306     PDATA pData;
 307     JNI_CHECK_PEER_GOTO(self, ret);
 308 
 309     c = (AwtTextComponent *)pData;
 310     if (::IsWindow(c->GetHWnd()))
 311     {
 312         int len = ::GetWindowTextLength(c->GetHWnd());
 313         if (len == 0) {
 314             /* Make java null string */
 315             jchar *jc = new jchar[0];
 316             result = env->NewString(jc, 0);
 317             delete [] jc;
 318         } else {
 319             WCHAR* buf = new WCHAR[len + 1];
 320             c->GetText(buf, len + 1);
 321             c->RemoveCR(buf);
 322             result = JNU_NewStringPlatform(env, buf);
 323             delete [] buf;
 324         }
 325     }
 326 ret:
 327     env->DeleteGlobalRef(self);
 328 
 329     if (result != NULL)
 330     {
 331         jstring globalRef = (jstring)env->NewGlobalRef(result);
 332         env->DeleteLocalRef(result);
 333         return globalRef;
 334     }
 335     else
 336     {
 337         return NULL;
 338     }
 339 }
 340 
 341 void AwtTextComponent::_SetText(void *param)
 342 {
 343     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 344 
 345     SetTextStruct *sts = (SetTextStruct *)param;
 346     jobject self = sts->textcomponent;
 347     jstring text = sts->text;
 348 
 349     AwtTextComponent *c = NULL;
 350 
 351     PDATA pData;
 352     JNI_CHECK_PEER_GOTO(self, ret);
 353     c = (AwtTextComponent *)pData;
 354     if (::IsWindow(c->GetHWnd()))
 355     {
 356         int length = env->GetStringLength(text);
 357         WCHAR* buffer = new WCHAR[length + 1];
 358         env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer));
 359         buffer[length] = 0;
 360         c->CheckLineSeparator(buffer);
 361         c->RemoveCR(buffer);
 362         c->SetText(buffer);
 363         delete[] buffer;
 364     }
 365 ret:
 366     env->DeleteGlobalRef(self);
 367     env->DeleteGlobalRef(text);
 368 
 369     delete sts;
 370 }
 371 
 372 jint AwtTextComponent::_GetSelectionStart(void *param)
 373 {
 374     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 375 
 376     jobject self = (jobject)param;
 377 
 378     jint result = 0;
 379     AwtTextComponent *c = NULL;
 380 
 381     PDATA pData;
 382     JNI_CHECK_PEER_GOTO(self, ret);
 383     c = (AwtTextComponent *)pData;
 384     if (::IsWindow(c->GetHWnd()))
 385     {
 386         long start;
 387         c->SendMessage(EM_GETSEL, (WPARAM)&start);
 388         result = c->getJavaSelPos(start);
 389     }
 390 ret:
 391     env->DeleteGlobalRef(self);
 392 
 393     return result;
 394 }
 395 
 396 jint AwtTextComponent::_GetSelectionEnd(void *param)
 397 {
 398     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 399 
 400     jobject self = (jobject)param;
 401 
 402     jint result = 0;
 403     AwtTextComponent *c = NULL;
 404 
 405     PDATA pData;
 406     JNI_CHECK_PEER_GOTO(self, ret);
 407     c = (AwtTextComponent *)pData;
 408     if (::IsWindow(c->GetHWnd()))
 409     {
 410         long end;
 411         c->SendMessage(EM_GETSEL, 0, (LPARAM)&end);
 412         result = c->getJavaSelPos(end);
 413     }
 414 ret:
 415     env->DeleteGlobalRef(self);
 416 
 417     return result;
 418 }
 419 
 420 void AwtTextComponent::_Select(void *param)
 421 {
 422     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 423 
 424     SelectStruct *ss = (SelectStruct *)param;
 425     jobject self = ss->textcomponent;
 426     jint start = ss->start;
 427     jint end = ss->end;
 428 
 429     AwtTextComponent *c = NULL;
 430 
 431     PDATA pData;
 432     JNI_CHECK_PEER_GOTO(self, ret);
 433     c = (AwtTextComponent *)pData;
 434     if (::IsWindow(c->GetHWnd()))
 435     {
 436         c->SetSelRange(start, end);
 437         c->SendMessage(EM_SCROLLCARET);
 438     }
 439 ret:
 440     env->DeleteGlobalRef(self);
 441 
 442     delete ss;
 443 }
 444 
 445 void AwtTextComponent::_EnableEditing(void *param)
 446 {
 447     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 448 
 449     EnableEditingStruct *ees = (EnableEditingStruct *)param;
 450     jobject self = ees->textcomponent;
 451     jboolean on = ees->on;
 452 
 453     AwtTextComponent *c = NULL;
 454 
 455     PDATA pData;
 456     JNI_CHECK_PEER_GOTO(self, ret);
 457     c = (AwtTextComponent *)pData;
 458     if (::IsWindow(c->GetHWnd()))
 459     {
 460         c->SendMessage(EM_SETREADONLY, !on);
 461     }
 462 ret:
 463     env->DeleteGlobalRef(self);
 464 
 465     delete ees;
 466 }
 467 
 468 
 469 /************************************************************************
 470  * WTextComponentPeer native methods
 471  */
 472 
 473 extern "C" {
 474 
 475 /*
 476  * Class:     sun_awt_windows_WTextComponentPeer
 477  * Method:    getText
 478  * Signature: ()Ljava/lang/String;
 479  */
 480 JNIEXPORT jstring JNICALL
 481 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self)
 482 {
 483     TRY;
 484 
 485     jobject selfGlobalRef = env->NewGlobalRef(self);
 486 
 487     jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall(
 488         (void*(*)(void*))AwtTextComponent::_GetText,
 489         (void *)selfGlobalRef);
 490     // selfGlobalRef is deleted in _GetText
 491     if (globalRef != NULL)
 492     {
 493         jstring localRef = (jstring)env->NewLocalRef(globalRef);
 494         env->DeleteGlobalRef(globalRef);
 495         return localRef;
 496     }
 497     else
 498     {
 499         return NULL;
 500     }
 501 
 502     CATCH_BAD_ALLOC_RET(NULL);
 503 }
 504 
 505 /*
 506  * Class:     sun_awt_windows_WTextComponentPeer
 507  * Method:    setText
 508  * Signature: (Ljava/lang/String;)V
 509  */
 510 JNIEXPORT void JNICALL
 511 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self,
 512                                                 jstring text)
 513 {
 514     TRY;
 515 
 516     SetTextStruct *sts = new SetTextStruct;
 517     sts->textcomponent = env->NewGlobalRef(self);
 518     sts->text = (jstring)env->NewGlobalRef(text);
 519 
 520     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts);
 521     // global refs and sts are deleted in _SetText
 522 
 523     CATCH_BAD_ALLOC;
 524 }
 525 
 526 /*
 527  * Class:     sun_awt_windows_WTextComponentPeer
 528  * Method:    getSelectionStart
 529  * Signature: ()I
 530  */
 531 JNIEXPORT jint JNICALL
 532 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env,
 533                                                           jobject self)
 534 {
 535     TRY;
 536 
 537     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
 538         (void *(*)(void *))AwtTextComponent::_GetSelectionStart,
 539         env->NewGlobalRef(self))));
 540     // global ref is deleted in _GetSelectionStart()
 541 
 542     CATCH_BAD_ALLOC_RET(0);
 543 }
 544 
 545 /*
 546  * Class:     sun_awt_windows_WTextComponentPeer
 547  * Method:    getSelectionEnd
 548  * Signature: ()I
 549  */
 550 JNIEXPORT jint JNICALL
 551 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env,
 552                                                         jobject self)
 553 {
 554     TRY;
 555 
 556     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
 557         (void *(*)(void *))AwtTextComponent::_GetSelectionEnd,
 558         env->NewGlobalRef(self))));
 559     // global ref is deleted in _GetSelectionEnd()
 560 
 561     CATCH_BAD_ALLOC_RET(0);
 562 }
 563 
 564 /*
 565  * Class:     sun_awt_windows_WTextComponentPeer
 566  * Method:    select
 567  * Signature: (II)V
 568  */
 569 JNIEXPORT void JNICALL
 570 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self,
 571                                                jint start, jint end)
 572 {
 573     TRY;
 574 
 575     SelectStruct *ss = new SelectStruct;
 576     ss->textcomponent = env->NewGlobalRef(self);
 577     ss->start = start;
 578     ss->end = end;
 579 
 580     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss);
 581     // global ref and ss are deleted in _Select
 582 
 583     CATCH_BAD_ALLOC;
 584 }
 585 
 586 /*
 587  * Class:     sun_awt_windows_WTextComponentPeer
 588  * Method:    enableEditing
 589  * Signature: (Z)V
 590  */
 591 JNIEXPORT void JNICALL
 592 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env,
 593                                                       jobject self,
 594                                                       jboolean on)
 595 {
 596     TRY;
 597 
 598     EnableEditingStruct *ees = new EnableEditingStruct;
 599     ees->textcomponent = env->NewGlobalRef(self);
 600     ees->on = on;
 601 
 602     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees);
 603     // global ref and ees are deleted in _EnableEditing()
 604 
 605     CATCH_BAD_ALLOC;
 606 }
 607 
 608 /*
 609  * Class:     sun_awt_windows_WTextComponentPeer
 610  * Method:    initIDs
 611  * Signature: ()V
 612  */
 613 JNIEXPORT void JNICALL
 614 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls)
 615 {
 616     TRY;
 617 
 618     cls = env->FindClass("java/awt/TextComponent");
 619     if (cls != NULL) {
 620         AwtTextComponent::canAccessClipboardID =
 621             env->GetFieldID(cls, "canAccessClipboard", "Z");
 622         DASSERT(AwtTextComponent::canAccessClipboardID != NULL);
 623     }
 624 
 625     CATCH_BAD_ALLOC;
 626 }
 627 
 628 //
 629 // Accessibility support
 630 //
 631 
 632 /* To be fully implemented in a future release
 633  *
 634  * Class:     sun_awt_windows_WTextComponentPeer
 635  * Method:    getIndexAtPoint
 636  * Signature: (II)I
 637  *
 638 JNIEXPORT jlong JNICALL
 639 Java_sun_awt_windows_WTextComponentPeer_filterEvents(JNIEnv *env, jobject self, jlong mask)
 640 {
 641     TRY;
 642 
 643     PDATA pData;
 644     JNI_CHECK_PEER_RETURN_NULL(self);
 645     AwtTextComponent* c = (AwtTextComponent*)pData;
 646 
 647     jlong oldMask = c->javaEventsMask;
 648     c->javaEventsMask = mask;
 649 
 650     return oldMask;
 651 
 652     CATCH_BAD_ALLOC_RET(0);
 653 }
 654 */
 655 
 656 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead
 657 /*
 658  * Handle WmKeyDown to catch keystrokes which may move the caret,
 659  * and fire events as appropriate when that happens, if they are wanted
 660  *
 661  * Note: mouse clicks come through WmKeyDown as well (do they??!?!)
 662  *
 663 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt,
 664                                    UINT flags, BOOL system) {
 665 
 666     printf("AwtTextComponent::WmKeyDown called\r\n");
 667 
 668 
 669     // NOTE: WmKeyDown won't be processed 'till well after we return
 670     //       so we need to modify the values based on the keystroke
 671     //
 672     static long oldStart = -1;
 673     static long oldEnd = -1;
 674 
 675     // most keystrokes can move the caret
 676     // so we'll simply check to see if the caret has moved!
 677     if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) {
 678         long start;
 679         long end;
 680         SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
 681         if (start != oldStart || end != oldEnd) {
 682 
 683             printf("  -> calling TextComponent.selectionValuesChanged()\r\n");
 684             printf("  -> old = (%d, %d); new = (%d, %d)\r\n",
 685                     oldStart, oldEnd, start, end);
 686 
 687             DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details...
 688             oldStart = start;
 689             oldEnd = end;
 690         }
 691     }
 692 
 693     return AwtComponent::WmKeyDown(wkey, repCnt, flags, system);
 694 }
 695 */
 696 
 697 /* To be fully implemented in a future release
 698  *
 699  * Class:     sun_awt_windows_WTextComponentPeer
 700  * Method:    getIndexAtPoint
 701  * Signature: (II)I
 702  *
 703 JNIEXPORT jint JNICALL
 704 Java_sun_awt_windows_WTextComponentPeer_getIndexAtPoint(JNIEnv *env, jobject self, jint x, jint y)
 705 {
 706     TRY;
 707 
 708     PDATA pData;
 709 //    JNI_CHECK_PEER_RETURN_VAL(self, -1);   [[[FIXME]]] Peter Korn -> should return -1 here
 710     JNI_CHECK_PEER_RETURN_NULL(self);
 711     AwtTextComponent* c = (AwtTextComponent*)pData;
 712     int indicies = c->SendMessage(EM_CHARFROMPOS, (WPARAM) 0, (LPARAM) MAKELPARAM(x, y));
 713     int index = LOWORD(indicies);   // index into the line the (x,y) coord is on
 714     int lineIndex = c->SendMessage(EM_LINEINDEX, HIWORD(indicies));  // index of start of line
 715     return (index + lineIndex);
 716 
 717     CATCH_BAD_ALLOC_RET(-1);
 718 }
 719 */
 720 
 721 /* To be fully implemented in a future release
 722  *
 723  * Class:     sun_awt_windows_WTextComponentPeer
 724  * Method:    getCharacterBounds
 725  * Signature: (I)Ljava/awt/Rectangle;
 726  *
 727 JNIEXPORT jobject JNICALL
 728 Java_sun_awt_windows_WTextComponentPeer_getCharacterBounds(JNIEnv *env, jobject self, jint i)
 729 {
 730 
 731     //  loop through lines with EM_LINELENGTH?  e.g.:
 732     //     line = 0; ttl = 0;   // index is passed in as 'i' above
 733     //     while (ttl < index) {
 734     //        ttl += SendMessage(EM_LINELENGTH, line++);
 735     //     }
 736     //     line-- (decrement back again)
 737     //  alternately, we could use EM_LINEINDEX to the same effect; perhaps slightly cleaner:
 738     //     computedIndex = 0; line = 0;
 739     //     while (computedIndex < index) {
 740     //        computedIndex = SendMessage(EM_LINEINDEX, 1 + line++);
 741     //     }
 742     //     line--;
 743 
 744     // EM_POSFROMCHAR  - convert char index into a Point
 745     // wParam = (LPPOINT) lpPoint;        // address of structure
 746                                                   // receiving character position
 747     // lParam = (LPARAM) wCharIndex;      // zero-based index of character
 748     //
 749     // still need to turn the above into a Rect somehow...
 750     // (use font metrics on font info for letter to get height?  use
 751     // getLineHeight type of message?).
 752 
 753     // WM_GETFONT - get the font struct for the window control
 754     // wParam = lParam = 0
 755     // returns an HFONT
 756     //  -or-
 757     // GetTextMetrics(hDC) to get the text info for the font selected
 758     // into the hDC of the control (tmHeight is what we want in the
 759     // TEXTMETRIC struct).
 760     // also GetCharWidth32() with the char at the index in question to get
 761     // the width of that char
 762     // *** Can't use GetTextMetrics/GetCharWidth32, as we don't have an hDC!! ***
 763 
 764     TRY;
 765 
 766     PDATA pData;
 767     JNI_CHECK_PEER_RETURN_NULL(self);
 768     AwtComponent* c = (AwtComponent*)pData;
 769 /*
 770     int line = 0;
 771     int lineIndex = 0;
 772     while (lineIndex < i) {
 773         lineIndex = c->SendMessage(EM_LINEINDEX, 1 + line++);
 774     }
 775     line--;     // line is now the line which contains our character at position 'i'
 776     int offsetIndex = i - lineIndex;    // offsetIndex is now distance in on the line
 777 * /
 778     POINT p;
 779 
 780     c->SendMessage(EM_POSFROMCHAR, (WPARAM) &p, (LPARAM) i);    // x coord is meaningful; y may not be
 781 
 782     // need to calculate charWidth, charHeight, and set p.y to something meangful
 783 
 784     jint charWidth;
 785     jint charHeight;
 786 
 787 /*
 788     HFONT font = c->SendMessage(WM_GETFONT);
 789     if (GetCharWidth32(c->hdc, i, i, &charWidth) != 0) {        // [[[FIXME]]] need to get hDC!
 790 
 791         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 792         jobject rect = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V",
 793                                            (jint) p.x, (jint) p.y, charWidth, charHeight);
 794 
 795         return rect;
 796     }
 797 * /
 798     return (jobject) 0;
 799 
 800     CATCH_BAD_ALLOC_RET(0);
 801 }
 802 */
 803 
 804 } /* extern "C" */