1 /*
   2  * Copyright (c) 1996, 2012, 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_TextArea.h"
  29 #include "awt_TextField.h"
  30 #include "awt_Canvas.h"
  31 
  32 #include "jni.h"
  33 #include "awt_Font.h"
  34 
  35 
  36 /***********************************************************************/
  37 // struct for _SetText() method
  38 struct SetTextStruct {
  39     jobject textcomponent;
  40     jstring text;
  41 };
  42 // struct for _Select() method
  43 struct SelectStruct {
  44     jobject textcomponent;
  45     jint start, end;
  46 };
  47 // struct for _EnableEditing() method
  48 struct EnableEditingStruct {
  49     jobject textcomponent;
  50     jboolean on;
  51 };
  52 /************************************************************************
  53  * AwtTextComponent fields
  54  */
  55 
  56 /************************************************************************
  57  * AwtTextComponent methods
  58  */
  59 
  60 jmethodID AwtTextComponent::canAccessClipboardMID;
  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     static BOOL richedLibraryLoaded = FALSE;
  74     if (!richedLibraryLoaded) {
  75         JDK_LoadSystemLibrary("RICHED20.DLL");
  76         richedLibraryLoaded = TRUE;
  77     }
  78     return RICHEDIT_CLASS;
  79 }
  80 
  81 /* Create a new AwtTextArea or AwtTextField object and window.   */
  82 AwtTextComponent* AwtTextComponent::Create(jobject peer, jobject parent, BOOL isMultiline)
  83 {
  84     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  85 
  86     jobject target = NULL;
  87     AwtTextComponent* c = NULL;
  88 
  89     try {
  90         if (env->EnsureLocalCapacity(1) < 0) {
  91             return NULL;
  92         }
  93 
  94         PDATA pData;
  95         AwtCanvas* awtParent;
  96         JNI_CHECK_PEER_GOTO(parent, done);
  97 
  98         awtParent = (AwtCanvas*)pData;
  99         JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done);
 100 
 101         target = env->GetObjectField(peer, AwtObject::targetID);
 102         JNI_CHECK_NULL_GOTO(target, "null target", done);
 103 
 104         if(isMultiline){
 105             c = new AwtTextArea();
 106         }else{
 107             c = new AwtTextField();
 108         }
 109 
 110         {
 111             /* Adjust style for scrollbar visibility and word wrap  */
 112             DWORD scroll_style;
 113 
 114             if(isMultiline){
 115 
 116                  jint scrollbarVisibility =
 117                      env->GetIntField(target, AwtTextArea::scrollbarVisibilityID);
 118 
 119                  switch (scrollbarVisibility) {
 120                      case java_awt_TextArea_SCROLLBARS_NONE:
 121                          scroll_style = ES_AUTOVSCROLL;
 122                          break;
 123                      case java_awt_TextArea_SCROLLBARS_VERTICAL_ONLY:
 124                          scroll_style = WS_VSCROLL | ES_AUTOVSCROLL;
 125                          break;
 126                      case java_awt_TextArea_SCROLLBARS_HORIZONTAL_ONLY:
 127                          scroll_style = WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL;
 128                          break;
 129                      case java_awt_TextArea_SCROLLBARS_BOTH:
 130                          scroll_style = WS_VSCROLL | WS_HSCROLL |
 131                              ES_AUTOVSCROLL | ES_AUTOHSCROLL;
 132                          break;
 133                 }
 134             }
 135 
 136           DWORD style = WS_CHILD | WS_CLIPSIBLINGS | ES_LEFT;
 137 
 138           /*
 139            * Specify ES_DISABLENOSCROLL - RichEdit control style to disable
 140            * scrollbars instead of hiding them when not needed.
 141            */
 142           style |= isMultiline ?  ES_MULTILINE | ES_WANTRETURN | scroll_style
 143               | ES_DISABLENOSCROLL : ES_AUTOHSCROLL;
 144 
 145 
 146           DWORD exStyle = WS_EX_CLIENTEDGE;
 147           if (GetRTL()) {
 148               exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
 149               if (GetRTLReadingOrder())
 150                   exStyle |= WS_EX_RTLREADING;
 151           }
 152 
 153 
 154           jint x = env->GetIntField(target, AwtComponent::xID);
 155           jint y = env->GetIntField(target, AwtComponent::yID);
 156           jint width = env->GetIntField(target, AwtComponent::widthID);
 157           jint height = env->GetIntField(target, AwtComponent::heightID);
 158 
 159           c->CreateHWnd(env, L"", style, exStyle,
 160                         x, y, width, height,
 161                         awtParent->GetHWnd(),
 162                         reinterpret_cast<HMENU>(static_cast<INT_PTR>(
 163                 awtParent->CreateControlID())),
 164                         ::GetSysColor(COLOR_WINDOWTEXT),
 165                         ::GetSysColor(COLOR_WINDOW),
 166                         peer);
 167 
 168           // Fix for 4753116.
 169           // If it is not win95 (we are using Richedit 2.0)
 170           // we set plain text mode, in which the control is
 171           // similar to a standard edit control:
 172           //  - The text in a plain text control can have only
 173           //    one format.
 174           //  - The user cannot paste rich text formats, such as RTF
 175           //    or embedded objects into a plain text control.
 176           //  - Rich text mode controls always have a default
 177           //    end-of-document marker or carriage return,
 178           //    to format paragraphs.
 179           // kdm@sparc.spb.su
 180           c->SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT, 0);
 181 
 182           c->m_backgroundColorSet = TRUE;
 183           /* suppress inheriting parent's color. */
 184           c->UpdateBackground(env, target);
 185           c->SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
 186                          MAKELPARAM(1, 1));
 187           /*
 188            * Fix for BugTraq Id 4260109.
 189            * Set the text limit to the maximum.
 190            * Use EM_EXLIMITTEXT for RichEdit controls.
 191            * For some reason RichEdit 1.0 becomes read-only if the
 192            * specified limit is greater than 0x7FFFFFFD.
 193            */
 194           c->SendMessage(EM_EXLIMITTEXT, 0, 0x7FFFFFFD);
 195 
 196           /* Unregister RichEdit built-in drop target. */
 197           VERIFY(::RevokeDragDrop(c->GetHWnd()) != DRAGDROP_E_INVALIDHWND);
 198 
 199           /* To enforce CF_TEXT format for paste operations. */
 200           VERIFY(c->SendMessage(EM_SETOLECALLBACK, 0,
 201                                 (LPARAM)&GetOleCallback()));
 202 
 203           c->SendMessage(EM_SETEVENTMASK, 0, ENM_CHANGE);
 204         }
 205     } catch (...) {
 206         env->DeleteLocalRef(target);
 207         throw;
 208     }
 209 
 210 done:
 211     env->DeleteLocalRef(target);
 212 
 213     return c;
 214 }
 215 
 216 LRESULT
 217 AwtTextComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
 218 
 219     switch (message) {
 220         case WM_PRINTCLIENT:
 221           {
 222             FORMATRANGE fr;
 223             HDC hPrinterDC = (HDC)wParam;
 224             int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES);
 225             int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES);
 226             int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX);
 227             int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY);
 228 
 229             // Ensure the printer DC is in MM_TEXT mode.
 230             ::SetMapMode ( hPrinterDC, MM_TEXT );
 231 
 232             // Rendering to the same DC we are measuring.
 233             ::ZeroMemory(&fr, sizeof(fr));
 234             fr.hdc = fr.hdcTarget = hPrinterDC;
 235             // Set up the page.
 236             fr.rcPage.left     = fr.rcPage.top = 0;
 237             fr.rcPage.right    = (nHorizRes/nLogPixelsX) * 1440; // in twips
 238             fr.rcPage.bottom   = (nVertRes/nLogPixelsY) * 1440;
 239             fr.rc.left   = fr.rcPage.left;
 240             fr.rc.top    = fr.rcPage.top;
 241             fr.rc.right  = fr.rcPage.right;
 242             fr.rc.bottom = fr.rcPage.bottom;
 243 
 244             // start printing from the first visible line
 245             LRESULT nLine = SendMessage(EM_GETFIRSTVISIBLELINE, 0, 0);
 246             LONG startCh = static_cast<LONG>(SendMessage(EM_LINEINDEX,
 247                                                          (WPARAM)nLine, 0));
 248             fr.chrg.cpMin = startCh;
 249             fr.chrg.cpMax = -1;
 250 
 251             SendMessage(EM_FORMATRANGE, TRUE, (LPARAM)&fr);
 252           }
 253 
 254         break;
 255     }
 256 
 257     return AwtComponent::WindowProc(message, wParam, lParam);
 258 }
 259 
 260 LONG AwtTextComponent::EditGetCharFromPos(POINT& pt) {
 261     return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0,
 262             reinterpret_cast<LPARAM>(&pt)));
 263 }
 264 
 265 /* Set a suitable font to IME against the component font. */
 266 void AwtTextComponent::SetFont(AwtFont* font)
 267 {
 268     DASSERT(font != NULL);
 269     if (font->GetAscent() < 0) {
 270         AwtFont::SetupAscent(font);
 271     }
 272 
 273     int index = font->GetInputHFontIndex();
 274     if (index < 0)
 275         /* In this case, user cannot get any suitable font for input. */
 276         index = 0;
 277 
 278     //im --- changed for over the spot composing
 279     m_hFont = font->GetHFont(index);
 280     SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(FALSE, 0));
 281     SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
 282                 MAKELPARAM(1, 1));
 283 
 284     /*
 285      * WM_SETFONT reverts foreground color to the default for
 286      * rich edit controls. So we have to restore it manually.
 287      */
 288     SetColor(GetColor());
 289     VERIFY(::InvalidateRect(GetHWnd(), NULL, TRUE));
 290     //im --- end
 291 
 292 }
 293 
 294 int AwtTextComponent::RemoveCR(WCHAR *pStr)
 295 {
 296     int i, nLen = 0;
 297 
 298     if (pStr) {
 299         /* check to see if there are any CR's */
 300         if (wcschr(pStr, L'\r') == NULL) {
 301             return static_cast<int>(wcslen(pStr));
 302         }
 303 
 304         for (i=0; pStr[i] != 0; i++) {
 305             if (m_isLFonly == TRUE) {
 306                 if (pStr[i] == L'\r') {
 307                     continue;
 308                 }
 309             } else {
 310                 if (pStr[i] == L'\r' && pStr[i + 1] != L'\n') {
 311                     continue;
 312                 }
 313             }
 314             pStr[nLen++] = pStr[i];
 315         }
 316         pStr[nLen] = 0;
 317     }
 318     return nLen;
 319 }
 320 
 321 MsgRouting
 322 AwtTextComponent::WmNotify(UINT notifyCode)
 323 {
 324     if (notifyCode == EN_CHANGE) {
 325       DoCallback("valueChanged", "()V");
 326     }
 327     return mrDoDefault;
 328 }
 329 
 330 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg)
 331 {
 332     return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK;
 333 }
 334 
 335 MsgRouting
 336 AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic)
 337 {
 338     MsgRouting returnVal;
 339 
 340     /*
 341      * Store the 'synthetic' parameter so that the WM_PASTE security check
 342      * happens only for synthetic events.
 343      */
 344     m_synthetic = synthetic;
 345     returnVal = AwtComponent::HandleEvent(msg, synthetic);
 346     m_synthetic = FALSE;
 347     return returnVal;
 348 }
 349 
 350 /*
 351  * If this Paste is occuring because of a synthetic Java event (e.g.,
 352  * a synthesized <CTRL>-V KeyEvent), then verify that the TextComponent
 353  * has permission to access the Clipboard before pasting. If permission
 354  * is denied, we should throw a SecurityException, but currently do not
 355  * because when we detect the security violation, we are in the Toolkit
 356  * thread, not the thread which dispatched the illegal event.
 357  */
 358 MsgRouting
 359 AwtTextComponent::WmPaste()
 360 {
 361     if (m_synthetic) {
 362         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 363         if (env->EnsureLocalCapacity(1) < 0) {
 364             return mrConsume;
 365         }
 366         jobject target = GetTarget(env);
 367         jboolean canAccessClipboard =
 368             env->CallBooleanMethod (target, AwtTextComponent::canAccessClipboardMID);
 369         env->DeleteLocalRef(target);
 370         return (canAccessClipboard) ? mrDoDefault : mrConsume;
 371     }
 372     else {
 373         return mrDoDefault;
 374     }
 375 }
 376 
 377 //im --- override to over the spot composition
 378 void AwtTextComponent::SetCompositionWindow(RECT& rc)
 379 {
 380     HWND hwnd = ImmGetHWnd();
 381     HIMC hIMC = ImmGetContext(hwnd);
 382     // rc is not used for text component.
 383     COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} };
 384     GetCaretPos(&(cf.ptCurrentPos));
 385     // the proxy is the native focus owner and it contains the composition window
 386     // let's convert the position to a coordinate space relative to proxy
 387     ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1);
 388     ImmSetCompositionWindow(hIMC, &cf);
 389 
 390     LOGFONT lf;
 391     GetObject(m_hFont, sizeof(LOGFONT), &lf);
 392     ImmSetCompositionFont(hIMC, &lf);
 393     ImmReleaseContext(hwnd, hIMC);
 394 }
 395 //im --- end
 396 
 397 LONG AwtTextComponent::getJavaSelPos(LONG orgPos)
 398 {
 399     long wlen;
 400     long pos = 0;
 401     long cur = 0;
 402     LPTSTR wbuf;
 403 
 404     if ((wlen = GetTextLength()) == 0)
 405         return 0;
 406     wbuf = new TCHAR[wlen + 1];
 407     GetText(wbuf, wlen + 1);
 408     if (m_isLFonly == TRUE) {
 409         wlen = RemoveCR(wbuf);
 410     }
 411 
 412     while (cur < orgPos && pos++ < wlen) {
 413         if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) {
 414             cur++;
 415         }
 416         cur++;
 417     }
 418     delete[] wbuf;
 419     return pos;
 420 }
 421 
 422 LONG AwtTextComponent::getWin32SelPos(LONG orgPos)
 423 {
 424     long wlen;
 425     long pos = 0;
 426     long cur = 0;
 427     LPTSTR wbuf;
 428 
 429     if ((wlen = GetTextLength()) == 0)
 430        return 0;
 431     wbuf = new TCHAR[wlen + 1];
 432     GetText(wbuf, wlen + 1);
 433     if (m_isLFonly == TRUE) {
 434         RemoveCR(wbuf);
 435     }
 436 
 437     while (cur < orgPos && pos < wlen) {
 438         if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) {
 439             pos++;
 440         }
 441         pos++;
 442         cur++;
 443     }
 444     delete[] wbuf;
 445     return pos;
 446 }
 447 
 448 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr)
 449 {
 450     if (pStr == NULL) {
 451         return;
 452     }
 453 
 454     if (GetTextLength() == 0) {
 455         m_EOLchecked = FALSE;
 456     }
 457 
 458     // check to see if there are any LF's
 459     if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) {
 460         return;
 461     }
 462 
 463     for (int i=0; pStr[i] != 0; i++) {
 464         if (pStr[i] == L'\n') {
 465             if (i > 0 && pStr[i-1] == L'\r') {
 466                 m_isLFonly = FALSE;
 467             } else {
 468                 m_isLFonly = TRUE;
 469             }
 470             m_EOLchecked = TRUE;
 471             return;
 472         }
 473     }
 474 }
 475 
 476 void AwtTextComponent::SetSelRange(LONG start, LONG end)
 477 {
 478     SendMessage(EM_SETSEL,
 479                 getWin32SelPos(start),
 480                 getWin32SelPos(end));
 481     // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing
 482     // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus
 483 }
 484 
 485 jstring AwtTextComponent::_GetText(void *param)
 486 {
 487     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 488 
 489     jobject self = (jobject)param;
 490 
 491     AwtTextComponent *c = NULL;
 492     jstring result = NULL;
 493 
 494     PDATA pData;
 495     JNI_CHECK_PEER_GOTO(self, ret);
 496 
 497     c = (AwtTextComponent *)pData;
 498     if (::IsWindow(c->GetHWnd()))
 499     {
 500         int len = ::GetWindowTextLength(c->GetHWnd());
 501         if (len == 0) {
 502             /* Make java null string */
 503             jchar *jc = new jchar[0];
 504             result = env->NewString(jc, 0);
 505             delete [] jc;
 506         } else {
 507             WCHAR* buf = new WCHAR[len + 1];
 508             c->GetText(buf, len + 1);
 509             c->RemoveCR(buf);
 510             result = JNU_NewStringPlatform(env, buf);
 511             delete [] buf;
 512         }
 513     }
 514 ret:
 515     env->DeleteGlobalRef(self);
 516 
 517     if (result != NULL)
 518     {
 519         jstring globalRef = (jstring)env->NewGlobalRef(result);
 520         env->DeleteLocalRef(result);
 521         return globalRef;
 522     }
 523     else
 524     {
 525         return NULL;
 526     }
 527 }
 528 
 529 void AwtTextComponent::_SetText(void *param)
 530 {
 531     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 532 
 533     SetTextStruct *sts = (SetTextStruct *)param;
 534     jobject self = sts->textcomponent;
 535     jstring text = sts->text;
 536 
 537     AwtTextComponent *c = NULL;
 538 
 539     PDATA pData;
 540     JNI_CHECK_PEER_GOTO(self, ret);
 541     c = (AwtTextComponent *)pData;
 542     if (::IsWindow(c->GetHWnd()))
 543     {
 544         int length = env->GetStringLength(text);
 545         WCHAR* buffer = new WCHAR[length + 1];
 546         env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer));
 547         buffer[length] = 0;
 548         c->CheckLineSeparator(buffer);
 549         c->RemoveCR(buffer);
 550         c->SetText(buffer);
 551         delete[] buffer;
 552     }
 553 ret:
 554     env->DeleteGlobalRef(self);
 555     env->DeleteGlobalRef(text);
 556 
 557     delete sts;
 558 }
 559 
 560 jint AwtTextComponent::_GetSelectionStart(void *param)
 561 {
 562     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 563 
 564     jobject self = (jobject)param;
 565 
 566     jint result = 0;
 567     AwtTextComponent *c = NULL;
 568 
 569     PDATA pData;
 570     JNI_CHECK_PEER_GOTO(self, ret);
 571     c = (AwtTextComponent *)pData;
 572     if (::IsWindow(c->GetHWnd()))
 573     {
 574         long start;
 575         c->SendMessage(EM_GETSEL, (WPARAM)&start);
 576         result = c->getJavaSelPos(start);
 577     }
 578 ret:
 579     env->DeleteGlobalRef(self);
 580 
 581     return result;
 582 }
 583 
 584 jint AwtTextComponent::_GetSelectionEnd(void *param)
 585 {
 586     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 587 
 588     jobject self = (jobject)param;
 589 
 590     jint result = 0;
 591     AwtTextComponent *c = NULL;
 592 
 593     PDATA pData;
 594     JNI_CHECK_PEER_GOTO(self, ret);
 595     c = (AwtTextComponent *)pData;
 596     if (::IsWindow(c->GetHWnd()))
 597     {
 598         long end;
 599         c->SendMessage(EM_GETSEL, 0, (LPARAM)&end);
 600         result = c->getJavaSelPos(end);
 601     }
 602 ret:
 603     env->DeleteGlobalRef(self);
 604 
 605     return result;
 606 }
 607 
 608 void AwtTextComponent::_Select(void *param)
 609 {
 610     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 611 
 612     SelectStruct *ss = (SelectStruct *)param;
 613     jobject self = ss->textcomponent;
 614     jint start = ss->start;
 615     jint end = ss->end;
 616 
 617     AwtTextComponent *c = NULL;
 618 
 619     PDATA pData;
 620     JNI_CHECK_PEER_GOTO(self, ret);
 621     c = (AwtTextComponent *)pData;
 622     if (::IsWindow(c->GetHWnd()))
 623     {
 624         c->SetSelRange(start, end);
 625         c->SendMessage(EM_SCROLLCARET);
 626     }
 627 ret:
 628     env->DeleteGlobalRef(self);
 629 
 630     delete ss;
 631 }
 632 
 633 void AwtTextComponent::_EnableEditing(void *param)
 634 {
 635     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 636 
 637     EnableEditingStruct *ees = (EnableEditingStruct *)param;
 638     jobject self = ees->textcomponent;
 639     jboolean on = ees->on;
 640 
 641     AwtTextComponent *c = NULL;
 642 
 643     PDATA pData;
 644     JNI_CHECK_PEER_GOTO(self, ret);
 645     c = (AwtTextComponent *)pData;
 646     if (::IsWindow(c->GetHWnd()))
 647     {
 648         c->SendMessage(EM_SETREADONLY, !on);
 649     }
 650 ret:
 651     env->DeleteGlobalRef(self);
 652 
 653     delete ees;
 654 }
 655 
 656 /*
 657  * Disabled edit control has grayed foreground.
 658  * Disabled RichEdit 1.0 control has original foreground.
 659  * Thus we have to set grayed foreground manually.
 660  */
 661 void AwtTextComponent::Enable(BOOL bEnable)
 662 {
 663     AwtComponent::Enable(bEnable);
 664     SetColor(GetColor());
 665 }
 666 
 667 
 668 /*
 669  * WM_CTLCOLOR is not sent by rich edit controls.
 670  * Use EM_SETCHARFORMAT and EM_SETBKGNDCOLOR to set
 671  * respectively foreground and background color.
 672  */
 673 void AwtTextComponent::SetColor(COLORREF c) {
 674     AwtComponent::SetColor(c);
 675 
 676     CHARFORMAT cf;
 677     memset(&cf, 0, sizeof(cf));
 678     cf.cbSize = sizeof(cf);
 679     cf.dwMask = CFM_COLOR;
 680 
 681     cf.crTextColor = ::IsWindowEnabled(GetHWnd()) ? GetColor() : ::GetSysColor(COLOR_3DSHADOW);
 682 
 683     /*
 684      * The documentation for EM_GETCHARFORMAT is not exactly
 685      * correct. It appears that wParam has the same meaning
 686      * as for EM_SETCHARFORMAT. Our task is to secure that
 687      * all the characters in the control have the required
 688      * formatting. That's why we use SCF_ALL.
 689      */
 690     VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf));
 691     VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf));
 692 }
 693 
 694 /*
 695  * In responce to EM_SETBKGNDCOLOR rich edit changes
 696  * its bg color and repaints itself so we don't need
 697  * to force repaint.
 698  */
 699 void AwtTextComponent::SetBackgroundColor(COLORREF c) {
 700     AwtComponent::SetBackgroundColor(c);
 701     SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor());
 702 }
 703 
 704 
 705 /************************************************************************
 706  * WTextComponentPeer native methods
 707  */
 708 
 709 extern "C" {
 710 
 711 /*
 712  * Class:     sun_awt_windows_WTextComponentPeer
 713  * Method:    getText
 714  * Signature: ()Ljava/lang/String;
 715  */
 716 JNIEXPORT jstring JNICALL
 717 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self)
 718 {
 719     TRY;
 720 
 721     jobject selfGlobalRef = env->NewGlobalRef(self);
 722 
 723     jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall(
 724         (void*(*)(void*))AwtTextComponent::_GetText,
 725         (void *)selfGlobalRef);
 726     // selfGlobalRef is deleted in _GetText
 727     if (globalRef != NULL)
 728     {
 729         jstring localRef = (jstring)env->NewLocalRef(globalRef);
 730         env->DeleteGlobalRef(globalRef);
 731         return localRef;
 732     }
 733     else
 734     {
 735         return NULL;
 736     }
 737 
 738     CATCH_BAD_ALLOC_RET(NULL);
 739 }
 740 
 741 /*
 742  * Class:     sun_awt_windows_WTextComponentPeer
 743  * Method:    setText
 744  * Signature: (Ljava/lang/String;)V
 745  */
 746 JNIEXPORT void JNICALL
 747 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self,
 748                                                 jstring text)
 749 {
 750     TRY;
 751 
 752     SetTextStruct *sts = new SetTextStruct;
 753     sts->textcomponent = env->NewGlobalRef(self);
 754     sts->text = (jstring)env->NewGlobalRef(text);
 755 
 756     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts);
 757     // global refs and sts are deleted in _SetText
 758 
 759     CATCH_BAD_ALLOC;
 760 }
 761 
 762 /*
 763  * Class:     sun_awt_windows_WTextComponentPeer
 764  * Method:    getSelectionStart
 765  * Signature: ()I
 766  */
 767 JNIEXPORT jint JNICALL
 768 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env,
 769                                                           jobject self)
 770 {
 771     TRY;
 772 
 773     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
 774         (void *(*)(void *))AwtTextComponent::_GetSelectionStart,
 775         env->NewGlobalRef(self))));
 776     // global ref is deleted in _GetSelectionStart()
 777 
 778     CATCH_BAD_ALLOC_RET(0);
 779 }
 780 
 781 /*
 782  * Class:     sun_awt_windows_WTextComponentPeer
 783  * Method:    getSelectionEnd
 784  * Signature: ()I
 785  */
 786 JNIEXPORT jint JNICALL
 787 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env,
 788                                                         jobject self)
 789 {
 790     TRY;
 791 
 792     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
 793         (void *(*)(void *))AwtTextComponent::_GetSelectionEnd,
 794         env->NewGlobalRef(self))));
 795     // global ref is deleted in _GetSelectionEnd()
 796 
 797     CATCH_BAD_ALLOC_RET(0);
 798 }
 799 
 800 /*
 801  * Class:     sun_awt_windows_WTextComponentPeer
 802  * Method:    select
 803  * Signature: (II)V
 804  */
 805 JNIEXPORT void JNICALL
 806 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self,
 807                                                jint start, jint end)
 808 {
 809     TRY;
 810 
 811     SelectStruct *ss = new SelectStruct;
 812     ss->textcomponent = env->NewGlobalRef(self);
 813     ss->start = start;
 814     ss->end = end;
 815 
 816     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss);
 817     // global ref and ss are deleted in _Select
 818 
 819     CATCH_BAD_ALLOC;
 820 }
 821 
 822 /*
 823  * Class:     sun_awt_windows_WTextComponentPeer
 824  * Method:    enableEditing
 825  * Signature: (Z)V
 826  */
 827 JNIEXPORT void JNICALL
 828 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env,
 829                                                       jobject self,
 830                                                       jboolean on)
 831 {
 832     TRY;
 833 
 834     EnableEditingStruct *ees = new EnableEditingStruct;
 835     ees->textcomponent = env->NewGlobalRef(self);
 836     ees->on = on;
 837 
 838     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees);
 839     // global ref and ees are deleted in _EnableEditing()
 840 
 841     CATCH_BAD_ALLOC;
 842 }
 843 
 844 /*
 845  * Class:     sun_awt_windows_WTextComponentPeer
 846  * Method:    initIDs
 847  * Signature: ()V
 848  */
 849 JNIEXPORT void JNICALL
 850 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls)
 851 {
 852     TRY;
 853 
 854     jclass textComponentClassID = env->FindClass("java/awt/TextComponent");
 855     AwtTextComponent::canAccessClipboardMID =
 856         env->GetMethodID(textComponentClassID,
 857         "canAccessClipboard", "()Z");
 858     env->DeleteLocalRef(textComponentClassID);
 859 
 860     DASSERT(AwtTextComponent::canAccessClipboardMID != NULL)
 861 
 862     CATCH_BAD_ALLOC;
 863 }
 864 
 865 
 866 AwtTextComponent::OleCallback AwtTextComponent::sm_oleCallback;
 867 
 868 /************************************************************************
 869  * Inner class OleCallback definition.
 870  */
 871 
 872 AwtTextComponent::OleCallback::OleCallback() {
 873     m_refs = 0;
 874     AddRef();
 875 }
 876 
 877 STDMETHODIMP
 878 AwtTextComponent::OleCallback::QueryInterface(REFIID riid, LPVOID * ppvObj) {
 879      if (::IsEqualIID(riid, IID_IUnknown) ||::IsEqualIID(riid, IID_IRichEditOleCallback)  ) {
 880          *ppvObj = static_cast<IRichEditOleCallback*>(this);
 881          AddRef();
 882          return S_OK;
 883      }
 884      *ppvObj = NULL;
 885      return E_NOINTERFACE;
 886 }
 887 
 888 
 889 STDMETHODIMP_(ULONG)
 890 AwtTextComponent::OleCallback::AddRef() {
 891     return ++m_refs;
 892 }
 893 
 894 STDMETHODIMP_(ULONG)
 895 AwtTextComponent::OleCallback::Release() {
 896     return (ULONG)--m_refs;
 897 }
 898 
 899 STDMETHODIMP
 900 AwtTextComponent::OleCallback::GetNewStorage(LPSTORAGE FAR * ppstg) {
 901     return E_NOTIMPL;
 902 }
 903 
 904 STDMETHODIMP
 905 AwtTextComponent::OleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe,
 906                                                  LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
 907                                                  LPOLEINPLACEFRAMEINFO pipfinfo)
 908 {
 909     return E_NOTIMPL;
 910 }
 911 
 912 STDMETHODIMP
 913 AwtTextComponent::OleCallback::ShowContainerUI(BOOL fShow) {
 914     return E_NOTIMPL;
 915 }
 916 
 917 STDMETHODIMP
 918 AwtTextComponent::OleCallback::QueryInsertObject(LPCLSID pclsid,
 919                                                  LPSTORAGE pstg,
 920                                                  LONG cp) {
 921     return S_OK;
 922 }
 923 
 924 STDMETHODIMP
 925 AwtTextComponent::OleCallback::DeleteObject(LPOLEOBJECT poleobj) {
 926     return S_OK;
 927 }
 928 
 929 STDMETHODIMP
 930 AwtTextComponent::OleCallback::QueryAcceptData(LPDATAOBJECT pdataobj,
 931                                                CLIPFORMAT *pcfFormat,
 932                                                DWORD reco,
 933                                                BOOL fReally,
 934                                                HGLOBAL hMetaPict) {
 935     if (reco == RECO_PASTE) {
 936         // If CF_TEXT format is available edit controls will select it,
 937         // otherwise if it is CF_UNICODETEXT is available it will be
 938         // selected, otherwise if CF_OEMTEXT is available it will be selected.
 939         if (::IsClipboardFormatAvailable(CF_TEXT)) {
 940             *pcfFormat = CF_TEXT;
 941         } else if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
 942             *pcfFormat = CF_UNICODETEXT;
 943         } else if (::IsClipboardFormatAvailable(CF_OEMTEXT)) {
 944             *pcfFormat = CF_OEMTEXT;
 945         } else {
 946             // Don't allow rich edit to paste clipboard data
 947             // in other formats.
 948             *pcfFormat = CF_TEXT;
 949         }
 950     }
 951 
 952     return S_OK;
 953 }
 954 
 955 STDMETHODIMP
 956 AwtTextComponent::OleCallback::ContextSensitiveHelp(BOOL fEnterMode) {
 957     return S_OK;
 958 }
 959 
 960 STDMETHODIMP
 961 AwtTextComponent::OleCallback::GetClipboardData(CHARRANGE *pchrg,
 962                                                 DWORD reco,
 963                                                 LPDATAOBJECT *ppdataobj) {
 964     return E_NOTIMPL;
 965 }
 966 
 967 STDMETHODIMP
 968 AwtTextComponent::OleCallback::GetDragDropEffect(BOOL fDrag,
 969                                                  DWORD grfKeyState,
 970                                                  LPDWORD pdwEffect) {
 971 
 972     return E_NOTIMPL;
 973 }
 974 
 975 
 976 STDMETHODIMP
 977 AwtTextComponent::OleCallback::GetContextMenu(WORD seltype,
 978                                               LPOLEOBJECT lpoleobj,
 979                                               CHARRANGE FAR * lpchrg,
 980                                               HMENU FAR * lphmenu) {
 981     return E_NOTIMPL;
 982 }
 983 
 984 
 985 
 986 //
 987 // Accessibility support
 988 //
 989 
 990 /* To be fully implemented in a future release
 991  *
 992  * Class:     sun_awt_windows_WTextComponentPeer
 993  * Method:    getIndexAtPoint
 994  * Signature: (II)I
 995  *
 996 JNIEXPORT jlong JNICALL
 997 Java_sun_awt_windows_WTextComponentPeer_filterEvents(JNIEnv *env, jobject self, jlong mask)
 998 {
 999     TRY;
1000 
1001     PDATA pData;
1002     JNI_CHECK_PEER_RETURN_NULL(self);
1003     AwtTextComponent* c = (AwtTextComponent*)pData;
1004 
1005     jlong oldMask = c->javaEventsMask;
1006     c->javaEventsMask = mask;
1007 
1008     return oldMask;
1009 
1010     CATCH_BAD_ALLOC_RET(0);
1011 }
1012 */
1013 
1014 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead
1015 /*
1016  * Handle WmKeyDown to catch keystrokes which may move the caret,
1017  * and fire events as appropriate when that happens, if they are wanted
1018  *
1019  * Note: mouse clicks come through WmKeyDown as well (do they??!?!)
1020  *
1021 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt,
1022                                    UINT flags, BOOL system) {
1023 
1024     printf("AwtTextComponent::WmKeyDown called\r\n");
1025 
1026 
1027     // NOTE: WmKeyDown won't be processed 'till well after we return
1028     //       so we need to modify the values based on the keystroke
1029     //
1030     static long oldStart = -1;
1031     static long oldEnd = -1;
1032 
1033     // most keystrokes can move the caret
1034     // so we'll simply check to see if the caret has moved!
1035     if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) {
1036         long start;
1037         long end;
1038         SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
1039         if (start != oldStart || end != oldEnd) {
1040 
1041             printf("  -> calling TextComponent.selectionValuesChanged()\r\n");
1042             printf("  -> old = (%d, %d); new = (%d, %d)\r\n",
1043                     oldStart, oldEnd, start, end);
1044 
1045             DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details...
1046             oldStart = start;
1047             oldEnd = end;
1048         }
1049     }
1050 
1051     return AwtComponent::WmKeyDown(wkey, repCnt, flags, system);
1052 }
1053 */
1054 
1055 /* To be fully implemented in a future release
1056  *
1057  * Class:     sun_awt_windows_WTextComponentPeer
1058  * Method:    getIndexAtPoint
1059  * Signature: (II)I
1060  *
1061 JNIEXPORT jint JNICALL
1062 Java_sun_awt_windows_WTextComponentPeer_getIndexAtPoint(JNIEnv *env, jobject self, jint x, jint y)
1063 {
1064     TRY;
1065 
1066     PDATA pData;
1067 //    JNI_CHECK_PEER_RETURN_VAL(self, -1);   [[[FIXME]]] Peter Korn -> should return -1 here
1068     JNI_CHECK_PEER_RETURN_NULL(self);
1069     AwtTextComponent* c = (AwtTextComponent*)pData;
1070     int indicies = c->SendMessage(EM_CHARFROMPOS, (WPARAM) 0, (LPARAM) MAKELPARAM(x, y));
1071     int index = LOWORD(indicies);   // index into the line the (x,y) coord is on
1072     int lineIndex = c->SendMessage(EM_LINEINDEX, HIWORD(indicies));  // index of start of line
1073     return (index + lineIndex);
1074 
1075     CATCH_BAD_ALLOC_RET(-1);
1076 }
1077 */
1078 
1079 /* To be fully implemented in a future release
1080  *
1081  * Class:     sun_awt_windows_WTextComponentPeer
1082  * Method:    getCharacterBounds
1083  * Signature: (I)Ljava/awt/Rectangle;
1084  *
1085 JNIEXPORT jobject JNICALL
1086 Java_sun_awt_windows_WTextComponentPeer_getCharacterBounds(JNIEnv *env, jobject self, jint i)
1087 {
1088 
1089     //  loop through lines with EM_LINELENGTH?  e.g.:
1090     //     line = 0; ttl = 0;   // index is passed in as 'i' above
1091     //     while (ttl < index) {
1092     //        ttl += SendMessage(EM_LINELENGTH, line++);
1093     //     }
1094     //     line-- (decrement back again)
1095     //  alternately, we could use EM_LINEINDEX to the same effect; perhaps slightly cleaner:
1096     //     computedIndex = 0; line = 0;
1097     //     while (computedIndex < index) {
1098     //        computedIndex = SendMessage(EM_LINEINDEX, 1 + line++);
1099     //     }
1100     //     line--;
1101 
1102     // EM_POSFROMCHAR  - convert char index into a Point
1103     // wParam = (LPPOINT) lpPoint;        // address of structure
1104                                                   // receiving character position
1105     // lParam = (LPARAM) wCharIndex;      // zero-based index of character
1106     //
1107     // still need to turn the above into a Rect somehow...
1108     // (use font metrics on font info for letter to get height?  use
1109     // getLineHeight type of message?).
1110 
1111     // WM_GETFONT - get the font struct for the window control
1112     // wParam = lParam = 0
1113     // returns an HFONT
1114     //  -or-
1115     // GetTextMetrics(hDC) to get the text info for the font selected
1116     // into the hDC of the control (tmHeight is what we want in the
1117     // TEXTMETRIC struct).
1118     // also GetCharWidth32() with the char at the index in question to get
1119     // the width of that char
1120     // *** Can't use GetTextMetrics/GetCharWidth32, as we don't have an hDC!! ***
1121 
1122     TRY;
1123 
1124     PDATA pData;
1125     JNI_CHECK_PEER_RETURN_NULL(self);
1126     AwtComponent* c = (AwtComponent*)pData;
1127 /*
1128     int line = 0;
1129     int lineIndex = 0;
1130     while (lineIndex < i) {
1131         lineIndex = c->SendMessage(EM_LINEINDEX, 1 + line++);
1132     }
1133     line--;     // line is now the line which contains our character at position 'i'
1134     int offsetIndex = i - lineIndex;    // offsetIndex is now distance in on the line
1135 * /
1136     POINT p;
1137 
1138     c->SendMessage(EM_POSFROMCHAR, (WPARAM) &p, (LPARAM) i);    // x coord is meaningful; y may not be
1139 
1140     // need to calculate charWidth, charHeight, and set p.y to something meangful
1141 
1142     jint charWidth;
1143     jint charHeight;
1144 
1145 /*
1146     HFONT font = c->SendMessage(WM_GETFONT);
1147     if (GetCharWidth32(c->hdc, i, i, &charWidth) != 0) {        // [[[FIXME]]] need to get hDC!
1148 
1149         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
1150         jobject rect = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V",
1151                                            (jint) p.x, (jint) p.y, charWidth, charHeight);
1152 
1153         return rect;
1154     }
1155 * /
1156     return (jobject) 0;
1157 
1158     CATCH_BAD_ALLOC_RET(0);
1159 }
1160 */
1161 
1162 } /* extern "C" */