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