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