1 /*
   2  * Copyright (c) 1996, 2013, 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     m_hEditCtrl       = NULL;
  70     m_bIgnoreEnChange = 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 void AwtTextComponent::Dispose()
 219 {
 220     if (m_hEditCtrl != NULL) {
 221         VERIFY(::DestroyWindow(m_hEditCtrl));
 222         m_hEditCtrl = NULL;
 223     }
 224     AwtComponent::Dispose();
 225 }
 226 
 227 
 228 LRESULT
 229 AwtTextComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
 230 
 231     switch (message) {
 232         case WM_PRINTCLIENT:
 233           {
 234             FORMATRANGE fr;
 235             HDC hPrinterDC = (HDC)wParam;
 236             int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES);
 237             int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES);
 238             int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX);
 239             int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY);
 240 
 241             // Ensure the printer DC is in MM_TEXT mode.
 242             ::SetMapMode ( hPrinterDC, MM_TEXT );
 243 
 244             // Rendering to the same DC we are measuring.
 245             ::ZeroMemory(&fr, sizeof(fr));
 246             fr.hdc = fr.hdcTarget = hPrinterDC;
 247             // Set up the page.
 248             fr.rcPage.left     = fr.rcPage.top = 0;
 249             fr.rcPage.right    = (nHorizRes/nLogPixelsX) * 1440; // in twips
 250             fr.rcPage.bottom   = (nVertRes/nLogPixelsY) * 1440;
 251             fr.rc.left   = fr.rcPage.left;
 252             fr.rc.top    = fr.rcPage.top;
 253             fr.rc.right  = fr.rcPage.right;
 254             fr.rc.bottom = fr.rcPage.bottom;
 255 
 256             // start printing from the first visible line
 257             LRESULT nLine = SendMessage(EM_GETFIRSTVISIBLELINE, 0, 0);
 258             LONG startCh = static_cast<LONG>(SendMessage(EM_LINEINDEX,
 259                                                          (WPARAM)nLine, 0));
 260             fr.chrg.cpMin = startCh;
 261             fr.chrg.cpMax = -1;
 262 
 263             SendMessage(EM_FORMATRANGE, TRUE, (LPARAM)&fr);
 264           }
 265 
 266         break;
 267     }
 268 
 269     return AwtComponent::WindowProc(message, wParam, lParam);
 270 }
 271 
 272 LONG AwtTextComponent::EditGetCharFromPos(POINT& pt) {
 273     return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0,
 274             reinterpret_cast<LPARAM>(&pt)));
 275 }
 276 
 277 /* Set a suitable font to IME against the component font. */
 278 void AwtTextComponent::SetFont(AwtFont* font)
 279 {
 280     DASSERT(font != NULL);
 281     if (font->GetAscent() < 0) {
 282         AwtFont::SetupAscent(font);
 283     }
 284 
 285     int index = font->GetInputHFontIndex();
 286     if (index < 0)
 287         /* In this case, user cannot get any suitable font for input. */
 288         index = 0;
 289 
 290     //im --- changed for over the spot composing
 291     m_hFont = font->GetHFont(index);
 292     SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(FALSE, 0));
 293     SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
 294                 MAKELPARAM(1, 1));
 295 
 296     /*
 297      * WM_SETFONT reverts foreground color to the default for
 298      * rich edit controls. So we have to restore it manually.
 299      */
 300     SetColor(GetColor());
 301     VERIFY(::InvalidateRect(GetHWnd(), NULL, TRUE));
 302     //im --- end
 303 
 304 }
 305 
 306 int AwtTextComponent::RemoveCR(WCHAR *pStr)
 307 {
 308     int i, nLen = 0;
 309 
 310     if (pStr) {
 311         /* check to see if there are any CR's */
 312         if (wcschr(pStr, L'\r') == NULL) {
 313             return static_cast<int>(wcslen(pStr));
 314         }
 315 
 316         for (i=0; pStr[i] != 0; i++) {
 317             if (m_isLFonly == TRUE) {
 318                 if (pStr[i] == L'\r') {
 319                     continue;
 320                 }
 321             } else {
 322                 if (pStr[i] == L'\r' && pStr[i + 1] != L'\n') {
 323                     continue;
 324                 }
 325             }
 326             pStr[nLen++] = pStr[i];
 327         }
 328         pStr[nLen] = 0;
 329     }
 330     return nLen;
 331 }
 332 
 333 MsgRouting
 334 AwtTextComponent::WmNotify(UINT notifyCode)
 335 {
 336     if (notifyCode == EN_CHANGE) {
 337         /*
 338          * Ignore notifications if the text hasn't been changed.
 339          * EN_CHANGE sent on character formatting changes as well.
 340          */
 341         if (m_bIgnoreEnChange == FALSE) {
 342             m_bCanUndo = TRUE;
 343             DoCallback("valueChanged", "()V");
 344         } else {
 345             m_bCanUndo = FALSE;
 346         }
 347     }
 348     return mrDoDefault;
 349 }
 350 
 351 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg)
 352 {
 353     return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK;
 354 }
 355 
 356 MsgRouting
 357 AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic)
 358 {
 359     MsgRouting returnVal;
 360 
 361     if (msg->message == WM_RBUTTONUP ||
 362                (msg->message == WM_SYSKEYDOWN && msg->wParam == VK_F10 &&
 363                 HIBYTE(::GetKeyState(VK_SHIFT)))) {
 364         POINT p;
 365         if (msg->message == WM_RBUTTONUP) {
 366             VERIFY(::GetCursorPos(&p));
 367         } else {
 368             p.x = -1;
 369             p.y = -1;
 370         }
 371 
 372         if (!::PostMessage(GetHWnd(), WM_CONTEXTMENU, (WPARAM)GetHWnd(),
 373                            MAKELPARAM(p.x, p.y))) {
 374             JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 375             JNU_ThrowInternalError(env, "Message not posted, native event queue may be full.");
 376             env->ExceptionDescribe();
 377             env->ExceptionClear();
 378         }
 379         delete msg;
 380         return mrConsume;
 381     }
 382 
 383     /*
 384      * Store the 'synthetic' parameter so that the WM_PASTE security check
 385      * happens only for synthetic events.
 386      */
 387     m_synthetic = synthetic;
 388     returnVal = AwtComponent::HandleEvent(msg, synthetic);
 389     m_synthetic = FALSE;
 390     return returnVal;
 391 }
 392 
 393 /*
 394  * If this Paste is occurring because of a synthetic Java event (e.g.,
 395  * a synthesized <CTRL>-V KeyEvent), then verify that the TextComponent
 396  * has permission to access the Clipboard before pasting. If permission
 397  * is denied, we should throw a SecurityException, but currently do not
 398  * because when we detect the security violation, we are in the Toolkit
 399  * thread, not the thread which dispatched the illegal event.
 400  */
 401 MsgRouting
 402 AwtTextComponent::WmPaste()
 403 {
 404     if (m_synthetic) {
 405         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 406         if (env->EnsureLocalCapacity(1) < 0) {
 407             return mrConsume;
 408         }
 409         jobject target = GetTarget(env);
 410         jboolean canAccessClipboard =
 411             env->CallBooleanMethod (target, AwtTextComponent::canAccessClipboardMID);
 412         env->DeleteLocalRef(target);
 413         return (canAccessClipboard) ? mrDoDefault : mrConsume;
 414     }
 415     else {
 416         return mrDoDefault;
 417     }
 418 }
 419 
 420 //im --- override to over the spot composition
 421 void AwtTextComponent::SetCompositionWindow(RECT& rc)
 422 {
 423     HWND hwnd = ImmGetHWnd();
 424     HIMC hIMC = ImmGetContext(hwnd);
 425     // rc is not used for text component.
 426     COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} };
 427     GetCaretPos(&(cf.ptCurrentPos));
 428     // the proxy is the native focus owner and it contains the composition window
 429     // let's convert the position to a coordinate space relative to proxy
 430     ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1);
 431     ImmSetCompositionWindow(hIMC, &cf);
 432 
 433     LOGFONT lf;
 434     GetObject(m_hFont, sizeof(LOGFONT), &lf);
 435     ImmSetCompositionFont(hIMC, &lf);
 436     ImmReleaseContext(hwnd, hIMC);
 437 }
 438 //im --- end
 439 
 440 LONG AwtTextComponent::getJavaSelPos(LONG orgPos)
 441 {
 442     long wlen;
 443     long pos = 0;
 444     long cur = 0;
 445     LPTSTR wbuf;
 446 
 447     if ((wlen = GetTextLength()) == 0)
 448         return 0;
 449     wbuf = new TCHAR[wlen + 1];
 450     GetText(wbuf, wlen + 1);
 451     if (m_isLFonly == TRUE) {
 452         wlen = RemoveCR(wbuf);
 453     }
 454 
 455     while (cur < orgPos && pos++ < wlen) {
 456         if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) {
 457             cur++;
 458         }
 459         cur++;
 460     }
 461     delete[] wbuf;
 462     return pos;
 463 }
 464 
 465 LONG AwtTextComponent::getWin32SelPos(LONG orgPos)
 466 {
 467     long wlen;
 468     long pos = 0;
 469     long cur = 0;
 470     LPTSTR wbuf;
 471 
 472     if ((wlen = GetTextLength()) == 0)
 473        return 0;
 474     wbuf = new TCHAR[wlen + 1];
 475     GetText(wbuf, wlen + 1);
 476     if (m_isLFonly == TRUE) {
 477         RemoveCR(wbuf);
 478     }
 479 
 480     while (cur < orgPos && pos < wlen) {
 481         if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) {
 482             pos++;
 483         }
 484         pos++;
 485         cur++;
 486     }
 487     delete[] wbuf;
 488     return pos;
 489 }
 490 
 491 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr)
 492 {
 493     if (pStr == NULL) {
 494         return;
 495     }
 496 
 497     if (GetTextLength() == 0) {
 498         m_EOLchecked = FALSE;
 499     }
 500 
 501     // check to see if there are any LF's
 502     if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) {
 503         return;
 504     }
 505 
 506     for (int i=0; pStr[i] != 0; i++) {
 507         if (pStr[i] == L'\n') {
 508             if (i > 0 && pStr[i-1] == L'\r') {
 509                 m_isLFonly = FALSE;
 510             } else {
 511                 m_isLFonly = TRUE;
 512             }
 513             m_EOLchecked = TRUE;
 514             return;
 515         }
 516     }
 517 }
 518 
 519 void AwtTextComponent::SetSelRange(LONG start, LONG end)
 520 {
 521     SendMessage(EM_SETSEL,
 522                 getWin32SelPos(start),
 523                 getWin32SelPos(end));
 524     // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing
 525     // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus
 526 }
 527 
 528 jstring AwtTextComponent::_GetText(void *param)
 529 {
 530     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 531 
 532     jobject self = (jobject)param;
 533 
 534     AwtTextComponent *c = NULL;
 535     jstring result = NULL;
 536 
 537     PDATA pData;
 538     JNI_CHECK_PEER_GOTO(self, ret);
 539 
 540     c = (AwtTextComponent *)pData;
 541     if (::IsWindow(c->GetHWnd()))
 542     {
 543         int len = ::GetWindowTextLength(c->GetHWnd());
 544         if (len == 0) {
 545             /* Make java null string */
 546             jchar *jc = new jchar[0];
 547             result = env->NewString(jc, 0);
 548             delete [] jc;
 549         } else {
 550             WCHAR* buf = new WCHAR[len + 1];
 551             c->GetText(buf, len + 1);
 552             c->RemoveCR(buf);
 553             result = JNU_NewStringPlatform(env, buf);
 554             delete [] buf;
 555         }
 556     }
 557 ret:
 558     env->DeleteGlobalRef(self);
 559 
 560     if (result != NULL)
 561     {
 562         jstring globalRef = (jstring)env->NewGlobalRef(result);
 563         env->DeleteLocalRef(result);
 564         return globalRef;
 565     }
 566     else
 567     {
 568         return NULL;
 569     }
 570 }
 571 
 572 void AwtTextComponent::_SetText(void *param)
 573 {
 574     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 575 
 576     SetTextStruct *sts = (SetTextStruct *)param;
 577     jobject self = sts->textcomponent;
 578     jstring text = sts->text;
 579 
 580     AwtTextComponent *c = NULL;
 581 
 582     PDATA pData;
 583     JNI_CHECK_PEER_GOTO(self, ret);
 584     c = (AwtTextComponent *)pData;
 585     if (::IsWindow(c->GetHWnd()))
 586     {
 587         int length = env->GetStringLength(text);
 588         WCHAR* buffer = new WCHAR[length + 1];
 589         env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer));
 590         buffer[length] = 0;
 591         c->CheckLineSeparator(buffer);
 592         c->RemoveCR(buffer);
 593         c->SetText(buffer);
 594         delete[] buffer;
 595     }
 596 ret:
 597     env->DeleteGlobalRef(self);
 598     env->DeleteGlobalRef(text);
 599 
 600     delete sts;
 601 }
 602 
 603 jint AwtTextComponent::_GetSelectionStart(void *param)
 604 {
 605     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 606 
 607     jobject self = (jobject)param;
 608 
 609     jint result = 0;
 610     AwtTextComponent *c = NULL;
 611 
 612     PDATA pData;
 613     JNI_CHECK_PEER_GOTO(self, ret);
 614     c = (AwtTextComponent *)pData;
 615     if (::IsWindow(c->GetHWnd()))
 616     {
 617         long start;
 618         c->SendMessage(EM_GETSEL, (WPARAM)&start);
 619         result = c->getJavaSelPos(start);
 620     }
 621 ret:
 622     env->DeleteGlobalRef(self);
 623 
 624     return result;
 625 }
 626 
 627 jint AwtTextComponent::_GetSelectionEnd(void *param)
 628 {
 629     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 630 
 631     jobject self = (jobject)param;
 632 
 633     jint result = 0;
 634     AwtTextComponent *c = NULL;
 635 
 636     PDATA pData;
 637     JNI_CHECK_PEER_GOTO(self, ret);
 638     c = (AwtTextComponent *)pData;
 639     if (::IsWindow(c->GetHWnd()))
 640     {
 641         long end;
 642         c->SendMessage(EM_GETSEL, 0, (LPARAM)&end);
 643         result = c->getJavaSelPos(end);
 644     }
 645 ret:
 646     env->DeleteGlobalRef(self);
 647 
 648     return result;
 649 }
 650 
 651 void AwtTextComponent::_Select(void *param)
 652 {
 653     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 654 
 655     SelectStruct *ss = (SelectStruct *)param;
 656     jobject self = ss->textcomponent;
 657     jint start = ss->start;
 658     jint end = ss->end;
 659 
 660     AwtTextComponent *c = NULL;
 661 
 662     PDATA pData;
 663     JNI_CHECK_PEER_GOTO(self, ret);
 664     c = (AwtTextComponent *)pData;
 665     if (::IsWindow(c->GetHWnd()))
 666     {
 667         c->SetSelRange(start, end);
 668         c->SendMessage(EM_SCROLLCARET);
 669     }
 670 ret:
 671     env->DeleteGlobalRef(self);
 672 
 673     delete ss;
 674 }
 675 
 676 void AwtTextComponent::_EnableEditing(void *param)
 677 {
 678     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 679 
 680     EnableEditingStruct *ees = (EnableEditingStruct *)param;
 681     jobject self = ees->textcomponent;
 682     jboolean on = ees->on;
 683 
 684     AwtTextComponent *c = NULL;
 685 
 686     PDATA pData;
 687     JNI_CHECK_PEER_GOTO(self, ret);
 688     c = (AwtTextComponent *)pData;
 689     if (::IsWindow(c->GetHWnd()))
 690     {
 691         c->SendMessage(EM_SETREADONLY, !on);
 692     }
 693 ret:
 694     env->DeleteGlobalRef(self);
 695 
 696     delete ees;
 697 }
 698 
 699 /*
 700  * Disabled edit control has grayed foreground.
 701  * Disabled RichEdit 1.0 control has original foreground.
 702  * Thus we have to set grayed foreground manually.
 703  */
 704 void AwtTextComponent::Enable(BOOL bEnable)
 705 {
 706     AwtComponent::Enable(bEnable);
 707     SetColor(GetColor());
 708 }
 709 
 710 
 711 /*
 712  * WM_CTLCOLOR is not sent by rich edit controls.
 713  * Use EM_SETCHARFORMAT and EM_SETBKGNDCOLOR to set
 714  * respectively foreground and background color.
 715  */
 716 void AwtTextComponent::SetColor(COLORREF c) {
 717     AwtComponent::SetColor(c);
 718 
 719     CHARFORMAT cf;
 720     memset(&cf, 0, sizeof(cf));
 721     cf.cbSize = sizeof(cf);
 722     cf.dwMask = CFM_COLOR;
 723 
 724     cf.crTextColor = ::IsWindowEnabled(GetHWnd()) ? GetColor() : ::GetSysColor(COLOR_3DSHADOW);
 725 
 726     /*
 727      * The documentation for EM_GETCHARFORMAT is not exactly
 728      * correct. It appears that wParam has the same meaning
 729      * as for EM_SETCHARFORMAT. Our task is to secure that
 730      * all the characters in the control have the required
 731      * formatting. That's why we use SCF_ALL.
 732      */
 733     VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf));
 734     VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf));
 735 }
 736 
 737 /*
 738  * In responce to EM_SETBKGNDCOLOR rich edit changes
 739  * its bg color and repaints itself so we don't need
 740  * to force repaint.
 741  */
 742 void AwtTextComponent::SetBackgroundColor(COLORREF c) {
 743     AwtComponent::SetBackgroundColor(c);
 744     SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor());
 745 }
 746 
 747 void AwtTextComponent::EditGetSel(CHARRANGE &cr) {
 748     SendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&cr));
 749 }
 750 
 751 
 752 /************************************************************************
 753  * WTextComponentPeer native methods
 754  */
 755 
 756 extern "C" {
 757 
 758 /*
 759  * Class:     sun_awt_windows_WTextComponentPeer
 760  * Method:    getText
 761  * Signature: ()Ljava/lang/String;
 762  */
 763 JNIEXPORT jstring JNICALL
 764 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self)
 765 {
 766     TRY;
 767 
 768     jobject selfGlobalRef = env->NewGlobalRef(self);
 769 
 770     jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall(
 771         (void*(*)(void*))AwtTextComponent::_GetText,
 772         (void *)selfGlobalRef);
 773     // selfGlobalRef is deleted in _GetText
 774     if (globalRef != NULL)
 775     {
 776         jstring localRef = (jstring)env->NewLocalRef(globalRef);
 777         env->DeleteGlobalRef(globalRef);
 778         return localRef;
 779     }
 780     else
 781     {
 782         return NULL;
 783     }
 784 
 785     CATCH_BAD_ALLOC_RET(NULL);
 786 }
 787 
 788 /*
 789  * Class:     sun_awt_windows_WTextComponentPeer
 790  * Method:    setText
 791  * Signature: (Ljava/lang/String;)V
 792  */
 793 JNIEXPORT void JNICALL
 794 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self,
 795                                                 jstring text)
 796 {
 797     TRY;
 798 
 799     SetTextStruct *sts = new SetTextStruct;
 800     sts->textcomponent = env->NewGlobalRef(self);
 801     sts->text = (jstring)env->NewGlobalRef(text);
 802 
 803     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts);
 804     // global refs and sts are deleted in _SetText
 805 
 806     CATCH_BAD_ALLOC;
 807 }
 808 
 809 /*
 810  * Class:     sun_awt_windows_WTextComponentPeer
 811  * Method:    getSelectionStart
 812  * Signature: ()I
 813  */
 814 JNIEXPORT jint JNICALL
 815 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env,
 816                                                           jobject self)
 817 {
 818     TRY;
 819 
 820     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
 821         (void *(*)(void *))AwtTextComponent::_GetSelectionStart,
 822         env->NewGlobalRef(self))));
 823     // global ref is deleted in _GetSelectionStart()
 824 
 825     CATCH_BAD_ALLOC_RET(0);
 826 }
 827 
 828 /*
 829  * Class:     sun_awt_windows_WTextComponentPeer
 830  * Method:    getSelectionEnd
 831  * Signature: ()I
 832  */
 833 JNIEXPORT jint JNICALL
 834 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env,
 835                                                         jobject self)
 836 {
 837     TRY;
 838 
 839     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
 840         (void *(*)(void *))AwtTextComponent::_GetSelectionEnd,
 841         env->NewGlobalRef(self))));
 842     // global ref is deleted in _GetSelectionEnd()
 843 
 844     CATCH_BAD_ALLOC_RET(0);
 845 }
 846 
 847 /*
 848  * Class:     sun_awt_windows_WTextComponentPeer
 849  * Method:    select
 850  * Signature: (II)V
 851  */
 852 JNIEXPORT void JNICALL
 853 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self,
 854                                                jint start, jint end)
 855 {
 856     TRY;
 857 
 858     SelectStruct *ss = new SelectStruct;
 859     ss->textcomponent = env->NewGlobalRef(self);
 860     ss->start = start;
 861     ss->end = end;
 862 
 863     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss);
 864     // global ref and ss are deleted in _Select
 865 
 866     CATCH_BAD_ALLOC;
 867 }
 868 
 869 /*
 870  * Class:     sun_awt_windows_WTextComponentPeer
 871  * Method:    enableEditing
 872  * Signature: (Z)V
 873  */
 874 JNIEXPORT void JNICALL
 875 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env,
 876                                                       jobject self,
 877                                                       jboolean on)
 878 {
 879     TRY;
 880 
 881     EnableEditingStruct *ees = new EnableEditingStruct;
 882     ees->textcomponent = env->NewGlobalRef(self);
 883     ees->on = on;
 884 
 885     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees);
 886     // global ref and ees are deleted in _EnableEditing()
 887 
 888     CATCH_BAD_ALLOC;
 889 }
 890 
 891 /*
 892  * Class:     sun_awt_windows_WTextComponentPeer
 893  * Method:    initIDs
 894  * Signature: ()V
 895  */
 896 JNIEXPORT void JNICALL
 897 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls)
 898 {
 899     TRY;
 900 
 901     jclass textComponentClassID = env->FindClass("java/awt/TextComponent");
 902     CHECK_NULL(textComponentClassID);
 903 
 904     AwtTextComponent::canAccessClipboardMID =
 905         env->GetMethodID(textComponentClassID, "canAccessClipboard", "()Z");
 906     env->DeleteLocalRef(textComponentClassID);
 907 
 908     DASSERT(AwtTextComponent::canAccessClipboardMID != NULL);
 909 
 910     CATCH_BAD_ALLOC;
 911 }
 912 
 913 
 914 AwtTextComponent::OleCallback AwtTextComponent::sm_oleCallback;
 915 
 916 /************************************************************************
 917  * Inner class OleCallback definition.
 918  */
 919 
 920 AwtTextComponent::OleCallback::OleCallback() {
 921     m_refs = 0;
 922     AddRef();
 923 }
 924 
 925 STDMETHODIMP
 926 AwtTextComponent::OleCallback::QueryInterface(REFIID riid, LPVOID * ppvObj) {
 927      if (::IsEqualIID(riid, IID_IUnknown) ||::IsEqualIID(riid, IID_IRichEditOleCallback)  ) {
 928          *ppvObj = static_cast<IRichEditOleCallback*>(this);
 929          AddRef();
 930          return S_OK;
 931      }
 932      *ppvObj = NULL;
 933      return E_NOINTERFACE;
 934 }
 935 
 936 
 937 STDMETHODIMP_(ULONG)
 938 AwtTextComponent::OleCallback::AddRef() {
 939     return ++m_refs;
 940 }
 941 
 942 STDMETHODIMP_(ULONG)
 943 AwtTextComponent::OleCallback::Release() {
 944     return (ULONG)--m_refs;
 945 }
 946 
 947 STDMETHODIMP
 948 AwtTextComponent::OleCallback::GetNewStorage(LPSTORAGE FAR * ppstg) {
 949     return E_NOTIMPL;
 950 }
 951 
 952 STDMETHODIMP
 953 AwtTextComponent::OleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe,
 954                                                  LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
 955                                                  LPOLEINPLACEFRAMEINFO pipfinfo)
 956 {
 957     return E_NOTIMPL;
 958 }
 959 
 960 STDMETHODIMP
 961 AwtTextComponent::OleCallback::ShowContainerUI(BOOL fShow) {
 962     return E_NOTIMPL;
 963 }
 964 
 965 STDMETHODIMP
 966 AwtTextComponent::OleCallback::QueryInsertObject(LPCLSID pclsid,
 967                                                  LPSTORAGE pstg,
 968                                                  LONG cp) {
 969     return S_OK;
 970 }
 971 
 972 STDMETHODIMP
 973 AwtTextComponent::OleCallback::DeleteObject(LPOLEOBJECT poleobj) {
 974     return S_OK;
 975 }
 976 
 977 STDMETHODIMP
 978 AwtTextComponent::OleCallback::QueryAcceptData(LPDATAOBJECT pdataobj,
 979                                                CLIPFORMAT *pcfFormat,
 980                                                DWORD reco,
 981                                                BOOL fReally,
 982                                                HGLOBAL hMetaPict) {
 983     if (reco == RECO_PASTE) {
 984         // If CF_TEXT format is available edit controls will select it,
 985         // otherwise if it is CF_UNICODETEXT is available it will be
 986         // selected, otherwise if CF_OEMTEXT is available it will be selected.
 987         if (::IsClipboardFormatAvailable(CF_TEXT)) {
 988             *pcfFormat = CF_TEXT;
 989         } else if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
 990             *pcfFormat = CF_UNICODETEXT;
 991         } else if (::IsClipboardFormatAvailable(CF_OEMTEXT)) {
 992             *pcfFormat = CF_OEMTEXT;
 993         } else {
 994             // Don't allow rich edit to paste clipboard data
 995             // in other formats.
 996             *pcfFormat = CF_TEXT;
 997         }
 998     }
 999 
1000     return S_OK;
1001 }
1002 
1003 STDMETHODIMP
1004 AwtTextComponent::OleCallback::ContextSensitiveHelp(BOOL fEnterMode) {
1005     return S_OK;
1006 }
1007 
1008 STDMETHODIMP
1009 AwtTextComponent::OleCallback::GetClipboardData(CHARRANGE *pchrg,
1010                                                 DWORD reco,
1011                                                 LPDATAOBJECT *ppdataobj) {
1012     return E_NOTIMPL;
1013 }
1014 
1015 STDMETHODIMP
1016 AwtTextComponent::OleCallback::GetDragDropEffect(BOOL fDrag,
1017                                                  DWORD grfKeyState,
1018                                                  LPDWORD pdwEffect) {
1019 
1020     return E_NOTIMPL;
1021 }
1022 
1023 
1024 STDMETHODIMP
1025 AwtTextComponent::OleCallback::GetContextMenu(WORD seltype,
1026                                               LPOLEOBJECT lpoleobj,
1027                                               CHARRANGE FAR * lpchrg,
1028                                               HMENU FAR * lphmenu) {
1029     return E_NOTIMPL;
1030 }
1031 
1032 
1033 /*
1034  * This routine is a window procedure for the subclass of the standard edit control
1035  * used to generate context menu. RichEdit controls don't have built-in context menu.
1036  * To implement this functionality we have to create an invisible edit control and
1037  * forward WM_CONTEXTMENU messages from a RichEdit control to this helper edit control.
1038  * While the edit control context menu is active we intercept the message generated in
1039  * response to particular item selection and forward it back to the RichEdit control.
1040  * (See AwtTextArea::WmContextMenu for more details).
1041  */
1042 
1043 WNDPROC AwtTextComponent::sm_pDefWindowProc = NULL;
1044 
1045 LRESULT
1046 AwtTextComponent::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
1047 
1048     static BOOL bContextMenuActive = FALSE;
1049 
1050     LRESULT retValue = 0;
1051     MsgRouting mr = mrDoDefault;
1052 
1053     DASSERT(::IsWindow(::GetParent(hWnd)));
1054 
1055     switch (message) {
1056     case WM_UNDO:
1057     case WM_CUT:
1058     case WM_COPY:
1059     case WM_PASTE:
1060     case WM_CLEAR:
1061     case EM_SETSEL:
1062         if (bContextMenuActive) {
1063             ::SendMessage(::GetParent(hWnd), message, wParam, lParam);
1064             mr = mrConsume;
1065         }
1066         break;
1067     case WM_CONTEXTMENU:
1068         bContextMenuActive = TRUE;
1069         break;
1070     }
1071 
1072     if (mr == mrDoDefault) {
1073         DASSERT(sm_pDefWindowProc != NULL);
1074         retValue = ::CallWindowProc(sm_pDefWindowProc,
1075                                     hWnd, message, wParam, lParam);
1076     }
1077 
1078     if (message == WM_CONTEXTMENU) {
1079         bContextMenuActive = FALSE;
1080     }
1081 
1082     return retValue;
1083 }
1084 
1085 MsgRouting
1086 AwtTextComponent::WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos) {
1087     /* Use the system provided edit control class to generate context menu. */
1088     if (m_hEditCtrl == NULL) {
1089         DWORD dwStyle = WS_CHILD;
1090         DWORD dwExStyle = 0;
1091         m_hEditCtrl = ::CreateWindowEx(dwExStyle,
1092                                         L"EDIT",
1093                                         L"TEXT",
1094                                         dwStyle,
1095                                         0, 0, 0, 0,
1096                                         GetHWnd(),
1097                                         reinterpret_cast<HMENU>(
1098                                          static_cast<INT_PTR>(
1099                                              CreateControlID())),
1100                                         AwtToolkit::GetInstance().GetModuleHandle(),
1101                                         NULL);
1102         DASSERT(m_hEditCtrl != NULL);
1103         if (sm_pDefWindowProc == NULL) {
1104             sm_pDefWindowProc = (WNDPROC)::GetWindowLongPtr(m_hEditCtrl,
1105                                                          GWLP_WNDPROC);
1106         }
1107         ::SetLastError(0);
1108         INT_PTR ret = ::SetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC,
1109                                    (INT_PTR)AwtTextArea::EditProc);
1110         DASSERT(ret != 0 || ::GetLastError() == 0);
1111     }
1112 
1113     /*
1114      * Tricks on the edit control to ensure that its context menu has
1115      * the correct set of enabled items according to the RichEdit state.
1116      */
1117     ::SetWindowText(m_hEditCtrl, TEXT("TEXT"));
1118 
1119     if (m_bCanUndo == TRUE && SendMessage(EM_CANUNDO)) {
1120         /* Enable 'Undo' item. */
1121         ::SendMessage(m_hEditCtrl, WM_CHAR, 'A', 0);
1122     }
1123 
1124     {
1125         /*
1126          * Initial selection for the edit control - (0,1).
1127          * This enables 'Cut', 'Copy' and 'Delete' and 'Select All'.
1128          */
1129         INT nStart = 0;
1130         INT nEnd = 1;
1131         if (SendMessage(EM_SELECTIONTYPE) == SEL_EMPTY) {
1132             /*
1133              * RichEdit selection is empty - clear selection of the edit control.
1134              * This disables 'Cut', 'Copy' and 'Delete'.
1135              */
1136             nStart = -1;
1137             nEnd = 0;
1138         } else {
1139 
1140             CHARRANGE cr;
1141             EditGetSel(cr);
1142             /* Check if all the text is selected. */
1143             if (cr.cpMin == 0) {
1144 
1145                 int len = ::GetWindowTextLength(GetHWnd());
1146                 if (cr.cpMin == 0 && cr.cpMax >= len) {
1147                     /*
1148                      * All the text is selected in RichEdit - select all the
1149                      * text in the edit control. This disables 'Select All'.
1150                      */
1151                     nStart = 0;
1152                     nEnd = -1;
1153                 }
1154             }
1155         }
1156         ::SendMessage(m_hEditCtrl, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
1157     }
1158 
1159     /* Disable 'Paste' item if the RichEdit control is read-only. */
1160     ::SendMessage(m_hEditCtrl, EM_SETREADONLY,
1161                   GetStyle() & ES_READONLY ? TRUE : FALSE, 0);
1162 
1163     POINT p;
1164     p.x = xPos;
1165     p.y = yPos;
1166 
1167     /*
1168      * If the context menu is requested with SHIFT+F10 or VK_APPS key,
1169      * we position its top left corner to the center of the RichEdit
1170      * client rect.
1171      */
1172     if (p.x == -1 && p.y == -1) {
1173         RECT r;
1174         VERIFY(::GetClientRect(GetHWnd(), &r));
1175         p.x = (r.left + r.right) / 2;
1176         p.y = (r.top + r.bottom) / 2;
1177         VERIFY(::ClientToScreen(GetHWnd(), &p));
1178     }
1179 
1180     // The context menu steals focus from the proxy.
1181     // So, set the focus-restore flag up.
1182     SetRestoreFocus(TRUE);
1183     ::SendMessage(m_hEditCtrl, WM_CONTEXTMENU, (WPARAM)m_hEditCtrl, MAKELPARAM(p.x, p.y));
1184     SetRestoreFocus(FALSE);
1185 
1186     return mrConsume;
1187 }
1188 
1189 //
1190 // Accessibility support
1191 //
1192 
1193 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead
1194 /*
1195  * Handle WmKeyDown to catch keystrokes which may move the caret,
1196  * and fire events as appropriate when that happens, if they are wanted
1197  *
1198  * Note: mouse clicks come through WmKeyDown as well (do they??!?!)
1199  *
1200 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt,
1201                                    UINT flags, BOOL system) {
1202 
1203     printf("AwtTextComponent::WmKeyDown called\r\n");
1204 
1205 
1206     // NOTE: WmKeyDown won't be processed 'till well after we return
1207     //       so we need to modify the values based on the keystroke
1208     //
1209     static long oldStart = -1;
1210     static long oldEnd = -1;
1211 
1212     // most keystrokes can move the caret
1213     // so we'll simply check to see if the caret has moved!
1214     if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) {
1215         long start;
1216         long end;
1217         SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
1218         if (start != oldStart || end != oldEnd) {
1219 
1220             printf("  -> calling TextComponent.selectionValuesChanged()\r\n");
1221             printf("  -> old = (%d, %d); new = (%d, %d)\r\n",
1222                     oldStart, oldEnd, start, end);
1223 
1224             DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details...
1225             oldStart = start;
1226             oldEnd = end;
1227         }
1228     }
1229 
1230     return AwtComponent::WmKeyDown(wkey, repCnt, flags, system);
1231 }
1232 */
1233 } /* extern "C" */