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