1 /*
   2  * Copyright (c) 1996, 2014, 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_List.h"
  27 #include "awt_Canvas.h"
  28 #include "awt_Dimension.h"
  29 #include "awt_Toolkit.h"
  30 #include "awt_Window.h"
  31 
  32 #include "ComCtl32Util.h"
  33 
  34 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
  35  */
  36 
  37 /***********************************************************************/
  38 // struct for _AddItems() method
  39 struct AddItemsStruct {
  40     jobject list;
  41     jobjectArray items;
  42     jint index;
  43     jint width;
  44 };
  45 // struct for _DelItems() method
  46 struct DelItemsStruct {
  47     jobject list;
  48     jint start, end;
  49 };
  50 // struct for _IsSelected(), _Select(), _Deselect() and _MakeVisible() methods
  51 struct SelectElementStruct {
  52     jobject list;
  53     jint index;
  54 };
  55 // struct for _SetMultipleSelections() method
  56 struct SetMultipleSelectionsStruct {
  57     jobject list;
  58     jboolean on;
  59 };
  60 /************************************************************************
  61  * AwtList methods
  62  */
  63 
  64 AwtList::AwtList() {
  65     isMultiSelect = FALSE;
  66     isWrapperPrint = FALSE;
  67 }
  68 
  69 AwtList::~AwtList()
  70 {
  71 }
  72 
  73 LPCTSTR AwtList::GetClassName() {
  74     return TEXT("LISTBOX");
  75 }
  76 
  77 /* Create a new AwtList object and window.   */
  78 AwtList* AwtList::Create(jobject peer, jobject parent)
  79 {
  80     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  81 
  82     jobject target = NULL;
  83     AwtList* c = NULL;
  84 
  85     try {
  86         if (env->EnsureLocalCapacity(1) < 0) {
  87             return NULL;
  88         }
  89 
  90         PDATA pData;
  91         AwtCanvas* awtParent;
  92         JNI_CHECK_PEER_GOTO(parent, done);
  93 
  94         awtParent = (AwtCanvas*)pData;
  95         JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done);
  96 
  97         /* target is Hjava_awt_List * */
  98         target = env->GetObjectField(peer, AwtObject::targetID);
  99         JNI_CHECK_NULL_GOTO(target, "null target", done);
 100 
 101         c = new AwtList();
 102 
 103         {
 104 
 105             /*
 106              * NOTE: WS_CLIPCHILDREN is excluded so that repaint requests
 107              * from Java will pass through the wrap to the native listbox.
 108              */
 109             DWORD wrapStyle = WS_CHILD | WS_CLIPSIBLINGS;
 110             DWORD wrapExStyle = 0;
 111 
 112             DWORD style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL |
 113                 LBS_NOINTEGRALHEIGHT | LBS_NOTIFY | LBS_OWNERDRAWFIXED;
 114             DWORD exStyle = WS_EX_CLIENTEDGE;
 115 
 116             /*
 117              * NOTE: WS_VISIBLE is always set for the listbox. Listbox
 118              * visibility is controlled by toggling the wrap's WS_VISIBLE bit.
 119              */
 120             style |= WS_VISIBLE;
 121 
 122             if (GetRTL()) {
 123                 exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
 124                 if (GetRTLReadingOrder())
 125                     exStyle |= WS_EX_RTLREADING;
 126             }
 127 
 128             jint x = env->GetIntField(target, AwtComponent::xID);
 129             jint y = env->GetIntField(target, AwtComponent::yID);
 130             jint width = env->GetIntField(target, AwtComponent::widthID);
 131             jint height = env->GetIntField(target, AwtComponent::heightID);
 132 
 133             c->CreateHWnd(env, L"", style, exStyle,
 134                           x, y, width, height,
 135                           awtParent->GetHWnd(),
 136                           NULL,
 137                           ::GetSysColor(COLOR_WINDOWTEXT),
 138                           ::GetSysColor(COLOR_WINDOW),
 139                           peer
 140                           );
 141 
 142             /* suppress inheriting awtParent's color. */
 143             c->m_backgroundColorSet = TRUE;
 144             c->UpdateBackground(env, target);
 145         }
 146     } catch (...) {
 147         env->DeleteLocalRef(target);
 148         throw;
 149     }
 150 
 151 done:
 152     env->DeleteLocalRef(target);
 153     return c;
 154 }
 155 
 156 void AwtList::SetDragCapture(UINT flags)
 157 {
 158     // don't want to interfere with other controls
 159     if (::GetCapture() == NULL) {
 160         ::SetCapture(GetListHandle());
 161     }
 162 }
 163 
 164 void AwtList::ReleaseDragCapture(UINT flags)
 165 {
 166     if ((::GetCapture() == GetListHandle()) && ((flags & ALL_MK_BUTTONS) == 0)) {
 167         ::ReleaseCapture();
 168     }
 169 }
 170 
 171 void AwtList::Reshape(int x, int y, int w, int h)
 172 {
 173     AwtComponent::Reshape(x, y, w, h);
 174 
 175 /*
 176     HWND hList = GetListHandle();
 177     if (hList != NULL) {
 178         long flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS;
 179         /*
 180          * Fix for bug 4046446.
 181          * /
 182         SetWindowPos(hList, 0, 0, 0, w, h, flags);
 183     }
 184 */
 185 }
 186 
 187 //Netscape : Override the AwtComponent method so we can set the item height
 188 //for each item in the list.  Modified by echawkes to avoid race condition.
 189 
 190 void AwtList::SetFont(AwtFont* font)
 191 {
 192     DASSERT(font != NULL);
 193     if (font->GetAscent() < 0)
 194     {
 195         AwtFont::SetupAscent(font);
 196     }
 197     HANDLE hFont = font->GetHFont();
 198     SendListMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(FALSE, 0));
 199 
 200     HDC hDC = ::GetDC(GetHWnd());
 201 
 202     TEXTMETRIC tm;
 203     VERIFY(::SelectObject(hDC, hFont) != NULL);
 204     VERIFY(::GetTextMetrics(hDC, &tm));
 205 
 206     ::ReleaseDC(GetHWnd(), hDC);
 207 
 208     long h = tm.tmHeight + tm.tmExternalLeading;
 209     // Listbox is LBS_OWNERDRAWFIXED so the items have the same height
 210     VERIFY(SendListMessage(LB_SETITEMHEIGHT, 0, MAKELPARAM(h, 0)) != LB_ERR);
 211     VERIFY(::RedrawWindow(GetHWnd(), NULL, NULL, RDW_INVALIDATE |RDW_FRAME |RDW_ERASE));
 212 }
 213 
 214 void AwtList::SetMultiSelect(BOOL ms) {
 215     if (ms == isMultiSelect) {
 216         return;
 217     }
 218 
 219     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 220 
 221     /* Copy current box's contents to string array */
 222     const int nCount = GetCount();
 223     LPTSTR * strings = new LPTSTR[nCount];
 224     int i;
 225 
 226     for(i = 0; i < nCount; i++) {
 227         LRESULT len = SendListMessage(LB_GETTEXTLEN, i);
 228         LPTSTR text = NULL;
 229         try {
 230             text = new TCHAR[len + 1];
 231         } catch (std::bad_alloc&) {
 232             // free char * already allocated
 233             for (int j = 0; j < i; j++) {
 234                 delete [] strings[j];
 235             }
 236             delete [] strings;
 237             throw;
 238         }
 239 
 240         VERIFY(SendListMessage(LB_GETTEXT, i, (LPARAM)text) != LB_ERR);
 241         strings[i] = text;
 242     }
 243 
 244     // index for selected item after multi-select mode change
 245     int toSelect = SendListMessage(LB_GETCURSEL);
 246     if (!isMultiSelect)
 247     {
 248         // MSDN: for single-select lists LB_GETCURSEL returns
 249         // index of selected item or LB_ERR if no item is selected
 250         if (toSelect == LB_ERR)
 251         {
 252             toSelect = -1;
 253         }
 254     }
 255     else
 256     {
 257         // MSDN: for multi-select lists LB_GETCURSEL returns index
 258         // of the focused item or 0 if no items are selected; if
 259         // some item has focus and is not selected then LB_GETCURSEL
 260         // return its index, so we need IsItemSelected too
 261         if ((toSelect == LB_ERR) ||
 262             (SendListMessage(LB_GETSELCOUNT) == 0) ||
 263             (IsItemSelected(toSelect) == 0))
 264         {
 265             toSelect = -1;
 266         }
 267     }
 268 
 269     isMultiSelect = ms;
 270 
 271     HWND parentHWnd = GetParent()->GetHWnd();
 272 
 273     /* Save old list box's attributes */
 274     RECT rect;
 275     GetWindowRect(GetListHandle(), &rect);
 276     MapWindowPoints(0, parentHWnd, (LPPOINT)&rect, 2);
 277 
 278     HANDLE font = (HANDLE)SendListMessage(WM_GETFONT);
 279     LRESULT itemHeight = SendListMessage(LB_GETITEMHEIGHT, 0);
 280     DWORD style = ::GetWindowLong(GetListHandle(), GWL_STYLE) | WS_VSCROLL | WS_HSCROLL;
 281     if (isMultiSelect) {
 282         style |= LBS_MULTIPLESEL;
 283     } else {
 284         style &= ~LBS_MULTIPLESEL;
 285     }
 286     DWORD exStyle = ::GetWindowLong(GetListHandle(), GWL_EXSTYLE);
 287 
 288     jobject peer = GetPeer(env);
 289 
 290     UnsubclassHWND();
 291     AwtToolkit::DestroyComponentHWND(m_hwnd);
 292     CreateHWnd(env, L"", style, exStyle,
 293                rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
 294                parentHWnd,
 295                NULL,
 296                ::GetSysColor(COLOR_WINDOWTEXT),
 297                ::GetSysColor(COLOR_WINDOW),
 298                peer);
 299 
 300     SendListMessage(WM_SETFONT, (WPARAM)font, (LPARAM)FALSE);
 301     SendListMessage(LB_SETITEMHEIGHT, 0, MAKELPARAM(itemHeight, 0));
 302     SendListMessage(LB_RESETCONTENT);
 303     for (i = 0; i < nCount; i++) {
 304         InsertString(i, strings[i]);
 305         delete [] strings[i];
 306     }
 307     delete[] strings;
 308     if (toSelect != -1) {
 309         Select(toSelect);
 310     }
 311 
 312     AdjustHorizontalScrollbar();
 313 }
 314 
 315 /*
 316  * There currently is no good place to cache java.awt.Dimension field
 317  * ids. If this method gets called a lot, one such place should be found.
 318  * -- br 07/18/97.
 319  */
 320 jobject AwtList::PreferredItemSize(JNIEnv *env)
 321 {
 322     jobject peer = GetPeer(env);
 323     jobject dimension = JNU_CallMethodByName(env, NULL, peer, "preferredSize",
 324                                              "(I)Ljava/awt/Dimension;",
 325                                              1).l;
 326 
 327     DASSERT(!safe_ExceptionOccurred(env));
 328     if (dimension == NULL) {
 329         return NULL;
 330     }
 331     /* This size is too big for each item height. */
 332     (env)->SetIntField(dimension, AwtDimension::heightID, GetFontHeight(env));
 333 
 334     return dimension;
 335 }
 336 
 337 // Every time something gets added to the list, we increase the max width
 338 // of items that have ever been added.  If it surpasses the width of the
 339 // listbox, we show the scrollbar.  When things get deleted, we shrink
 340 // the scroll region back down and hide the scrollbar, if needed.
 341 void AwtList::AdjustHorizontalScrollbar()
 342 {
 343     // The border width is added to the horizontal extent to ensure that we
 344     // can view all of the text when we move the horz. scrollbar to the end.
 345     int  cxBorders = GetSystemMetrics( SM_CXBORDER ) * 2;
 346     RECT rect;
 347     VERIFY(::GetClientRect(GetListHandle(), &rect));
 348     LRESULT iHorzExt = SendListMessage(LB_GETHORIZONTALEXTENT, 0, 0L ) - cxBorders;
 349     if ( (m_nMaxWidth > rect.left)  // if strings wider than listbox
 350       || (iHorzExt != m_nMaxWidth) ) //   or scrollbar not needed anymore.
 351     {
 352         SendListMessage(LB_SETHORIZONTALEXTENT, m_nMaxWidth + cxBorders, 0L);
 353     }
 354 }
 355 
 356 // This function goes through all strings in the list to find the width,
 357 // in pixels, of the longest string in the list.
 358 void AwtList::UpdateMaxItemWidth()
 359 {
 360     m_nMaxWidth = 0;
 361 
 362     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 363     if (env->EnsureLocalCapacity(2) < 0)
 364         return;
 365 
 366     HDC hDC = ::GetDC(GetHWnd());
 367 
 368     jobject self = GetPeer(env);
 369     DASSERT(self);
 370 
 371     /* target is java.awt.List */
 372     jobject target = env->GetObjectField(self, AwtObject::targetID);
 373     jobject font = GET_FONT(target, self);
 374 
 375     int nCount = GetCount();
 376     for ( int i=0; i < nCount; i++ )
 377     {
 378         jstring jstr = GetItemString( env, target, i );
 379         SIZE size = AwtFont::getMFStringSize( hDC, font, jstr );
 380         if ( size.cx > m_nMaxWidth )
 381             m_nMaxWidth = size.cx;
 382         env->DeleteLocalRef( jstr );
 383     }
 384 
 385     // free up the shared DC and release local refs
 386     ::ReleaseDC(GetHWnd(), hDC);
 387     env->DeleteLocalRef( target );
 388     env->DeleteLocalRef( font );
 389 
 390     // Now adjust the horizontal scrollbar extent
 391     AdjustHorizontalScrollbar();
 392 }
 393 
 394 MsgRouting
 395 AwtList::WmSize(UINT type, int w, int h)
 396 {
 397     AdjustHorizontalScrollbar();
 398     return AwtComponent::WmSize(type, w, h);
 399 }
 400 
 401 MsgRouting
 402 AwtList::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo)
 403 {
 404     AwtComponent::DrawListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), drawInfo);
 405     return mrConsume;
 406 }
 407 
 408 MsgRouting
 409 AwtList::OwnerMeasureItem(UINT /*ctrlId*/, MEASUREITEMSTRUCT& measureInfo)
 410 {
 411     AwtComponent::MeasureListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), measureInfo);
 412     return mrConsume;
 413 }
 414 
 415 MsgRouting
 416 AwtList::WmNcHitTest(UINT x, UINT y, LRESULT& retVal)
 417 {
 418     if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd())))) {
 419         retVal = HTCLIENT;
 420         return mrConsume;
 421     }
 422     return AwtComponent::WmNcHitTest(x, y, retVal);
 423 }
 424 
 425 MsgRouting
 426 AwtList::WmMouseUp(UINT flags, int x, int y, int button)
 427 {
 428     MsgRouting result = mrDoDefault;
 429     // if this list is in the modal blocked window, this message should be consumed,
 430     // however AwtComponent::WmMouseUp must be called anyway
 431     if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd())))) {
 432         result = mrConsume;
 433     } else {
 434         if (button == LEFT_BUTTON) {
 435             WmCommand(0, GetListHandle(), LBN_SELCHANGE);
 436         }
 437     }
 438     MsgRouting compResult = AwtComponent::WmMouseUp(flags, x, y, button);
 439     return (result == mrConsume) ? result : compResult;
 440 }
 441 
 442 MsgRouting
 443 AwtList::WmMouseDown(UINT flags, int x, int y, int button)
 444 {
 445     MsgRouting mrResult = AwtComponent::WmMouseDown(flags, x, y, button);
 446 
 447     if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd()))))
 448     {
 449         return mrConsume;
 450     }
 451 
 452     /*
 453      * As we consume WM_LBUTONDOWN the list won't trigger ActionEvent by double click.
 454      * We trigger it ourselves. (see also 6240202)
 455      */
 456     int clickCount = GetClickCount();
 457     if (button == LEFT_BUTTON && clickCount >= 2 && clickCount % 2 == 0) {
 458         WmCommand(0, GetListHandle(), LBN_DBLCLK);
 459     }
 460     return mrResult;
 461 }
 462 
 463 MsgRouting
 464 AwtList::WmCtlColor(HDC hDC, HWND hCtrl, UINT ctlColor, HBRUSH& retBrush)
 465 {
 466     DASSERT(ctlColor == CTLCOLOR_LISTBOX);
 467     DASSERT(hCtrl == GetListHandle());
 468     ::SetBkColor(hDC, GetBackgroundColor());
 469     ::SetTextColor(hDC, GetColor());
 470     retBrush = GetBackgroundBrush();
 471     return mrConsume;
 472 }
 473 
 474 BOOL AwtList::IsFocusingMouseMessage(MSG *pMsg)
 475 {
 476     return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK;
 477 }
 478 
 479 MsgRouting AwtList::HandleEvent(MSG *msg, BOOL synthetic)
 480 {
 481     if (IsFocusingMouseMessage(msg)) {
 482         LONG item = static_cast<LONG>(SendListMessage(LB_ITEMFROMPOINT, 0, msg->lParam));
 483         if (item != LB_ERR) {
 484             if (isMultiSelect) {
 485                 if (IsItemSelected(item)) {
 486                     Deselect(item);
 487                 } else {
 488                     Select(item);
 489                 }
 490             } else {
 491                 Select(item);
 492             }
 493         }
 494         delete msg;
 495         return mrConsume;
 496     }
 497     if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN) {
 498         WmNotify(LBN_DBLCLK);
 499     }
 500     return AwtComponent::HandleEvent(msg, synthetic);
 501 }
 502 
 503 // Fix for 4665745.
 504 // Override WmPrint to catch when the list control (not wrapper) should
 505 // operate WM_PRINT to be compatible with the "smooth scrolling" feature.
 506 MsgRouting AwtList::WmPrint(HDC hDC, LPARAM flags)
 507 {
 508     if (!isWrapperPrint &&
 509         (flags & PRF_CLIENT) &&
 510         (GetStyleEx() & WS_EX_CLIENTEDGE))
 511     {
 512         int nOriginalDC = ::SaveDC(hDC);
 513         DASSERT(nOriginalDC != 0);
 514         // Save a copy of the DC for WmPrintClient
 515         VERIFY(::SaveDC(hDC));
 516         DefWindowProc(WM_PRINT, (WPARAM) hDC,
 517             (flags & (PRF_CLIENT | PRF_CHECKVISIBLE | PRF_ERASEBKGND)));
 518         VERIFY(::RestoreDC(hDC, nOriginalDC));
 519 
 520         flags &= ~PRF_CLIENT;
 521     }
 522 
 523     return AwtComponent::WmPrint(hDC, flags);
 524 }
 525 
 526 MsgRouting
 527 AwtList::WmNotify(UINT notifyCode)
 528 {
 529     if (notifyCode == LBN_SELCHANGE || notifyCode == LBN_DBLCLK) {
 530         /* Fixed an asserion failure when clicking on an empty List. */
 531         int nCurrentSelection = SendListMessage(LB_GETCURSEL);
 532         if (nCurrentSelection != LB_ERR && GetCount() > 0) {
 533             if (notifyCode == LBN_SELCHANGE) {
 534                 DoCallback("handleListChanged", "(I)V", nCurrentSelection);
 535             }
 536             else if (notifyCode == LBN_DBLCLK) {
 537                 DoCallback("handleAction", "(IJI)V", nCurrentSelection,
 538                            ::JVM_CurrentTimeMillis(NULL, 0),
 539                            (jint)AwtComponent::GetJavaModifiers());
 540             }
 541         }
 542     }
 543     return mrDoDefault;
 544 }
 545 
 546 BOOL AwtList::InheritsNativeMouseWheelBehavior() {return true;}
 547 
 548 jint AwtList::_GetMaxWidth(void *param)
 549 {
 550     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 551 
 552     jobject self = (jobject)param;
 553 
 554     jint result = 0;
 555     AwtList *l = NULL;
 556 
 557     PDATA pData;
 558     JNI_CHECK_PEER_GOTO(self, ret);
 559     l = (AwtList *)pData;
 560     if (::IsWindow(l->GetHWnd()))
 561     {
 562         result = l->GetMaxWidth();
 563     }
 564 ret:
 565     env->DeleteGlobalRef(self);
 566 
 567     return result;
 568 }
 569 
 570 void AwtList::_UpdateMaxItemWidth(void *param)
 571 {
 572     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 573 
 574     jobject self = (jobject)param;
 575 
 576     AwtList *l = NULL;
 577 
 578     PDATA pData;
 579     JNI_CHECK_PEER_GOTO(self, ret);
 580     l = (AwtList *)pData;
 581     if (::IsWindow(l->GetHWnd()))
 582     {
 583         l->UpdateMaxItemWidth();
 584     }
 585 ret:
 586     env->DeleteGlobalRef(self);
 587 }
 588 
 589 void AwtList::_AddItems(void *param)
 590 {
 591     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 592 
 593     AddItemsStruct *ais = (AddItemsStruct *)param;
 594     jobject self = ais->list;
 595     jobjectArray items = ais->items;
 596     jint index = ais->index;
 597     jint width = ais->width;
 598 
 599     int badAlloc = 0;
 600     AwtList *l = NULL;
 601 
 602     PDATA pData;
 603     JNI_CHECK_PEER_GOTO(self, ret);
 604     JNI_CHECK_NULL_GOTO(items, "null items", ret);
 605     l = (AwtList*)pData;
 606     if (::IsWindow(l->GetHWnd()))
 607     {
 608         int itemCount = env->GetArrayLength(items);
 609         if (itemCount > 0)
 610         {
 611             AwtList* l = (AwtList*)pData;
 612             l->SendListMessage(WM_SETREDRAW, (WPARAM)FALSE, 0);
 613             for (jsize i=0; i < itemCount; i++)
 614             {
 615                 LPTSTR itemPtr = NULL;
 616                 jstring item = (jstring)env->GetObjectArrayElement(items, i);
 617                 if (env->ExceptionCheck()) goto ret;
 618                 if (item == NULL) goto next_item;
 619                 itemPtr = (LPTSTR)JNU_GetStringPlatformChars(env, item, 0);
 620                 if (itemPtr == NULL)
 621                 {
 622                     badAlloc = 1;
 623                 }
 624                 else
 625                 {
 626                     l->InsertString(index+i, itemPtr);
 627                     JNU_ReleaseStringPlatformChars(env, item, itemPtr);
 628                 }
 629                 env->DeleteLocalRef(item);
 630 next_item:
 631                 ;
 632             }
 633             l->SendListMessage(WM_SETREDRAW, (WPARAM)TRUE, 0);
 634             l->InvalidateList(NULL, TRUE);
 635             l->CheckMaxWidth(width);
 636         }
 637     }
 638 ret:
 639     env->DeleteGlobalRef(self);
 640     env->DeleteGlobalRef(items);
 641 
 642     delete ais;
 643 
 644     if (badAlloc)
 645     {
 646         throw std::bad_alloc();
 647     }
 648 }
 649 
 650 void AwtList::_DelItems(void *param)
 651 {        JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 652 
 653     DelItemsStruct *dis = (DelItemsStruct *)param;
 654     jobject self = dis->list;
 655     jint start = dis->start;
 656     jint end = dis->end;
 657 
 658     AwtList *l = NULL;
 659 
 660     PDATA pData;
 661     JNI_CHECK_PEER_GOTO(self, ret);
 662     l = (AwtList*)pData;
 663     if (::IsWindow(l->GetHWnd()))
 664     {
 665         int count = l->GetCount();
 666 
 667         if (start == 0 && end == count)
 668         {
 669             l->SendListMessage(LB_RESETCONTENT);
 670         }
 671         else
 672         {
 673             for (int i = start; i <= end; i++)
 674             {
 675                 l->SendListMessage(LB_DELETESTRING, start);
 676             }
 677         }
 678 
 679         l->UpdateMaxItemWidth();
 680     }
 681 ret:
 682     env->DeleteGlobalRef(self);
 683 
 684     delete dis;
 685 }
 686 
 687 void AwtList::_Select(void *param)
 688 {
 689     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 690 
 691     SelectElementStruct *ses = (SelectElementStruct *)param;
 692     jobject self = ses->list;
 693     jint index = ses->index;
 694 
 695     AwtList *l = NULL;
 696 
 697     PDATA pData;
 698     JNI_CHECK_PEER_GOTO(self, ret);
 699     l = (AwtList*)pData;
 700     if (::IsWindow(l->GetHWnd()))
 701     {
 702         l->Select(index);
 703     }
 704 ret:
 705     env->DeleteGlobalRef(self);
 706 
 707     delete ses;
 708 }
 709 
 710 void AwtList::_Deselect(void *param)
 711 {
 712     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 713 
 714     SelectElementStruct *ses = (SelectElementStruct *)param;
 715     jobject self = ses->list;
 716     jint index = ses->index;
 717 
 718     AwtList *l = NULL;
 719 
 720     PDATA pData;
 721     JNI_CHECK_PEER_GOTO(self, ret);
 722     l = (AwtList*)pData;
 723     if (::IsWindow(l->GetHWnd()))
 724     {
 725         l->Deselect(index);
 726     }
 727 ret:
 728     env->DeleteGlobalRef(self);
 729 
 730     delete ses;
 731 }
 732 
 733 void AwtList::_MakeVisible(void *param)
 734 {
 735     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 736 
 737     SelectElementStruct *ses = (SelectElementStruct *)param;
 738     jobject self = ses->list;
 739     jint index = ses->index;
 740 
 741     AwtList *l = NULL;
 742 
 743     PDATA pData;
 744     JNI_CHECK_PEER_GOTO(self, ret);
 745     l = (AwtList*)pData;
 746     if (::IsWindow(l->GetHWnd()))
 747     {
 748         l->SendListMessage(LB_SETTOPINDEX, index);
 749     }
 750 ret:
 751     env->DeleteGlobalRef(self);
 752 
 753     delete ses;
 754 }
 755 
 756 jboolean AwtList::_IsSelected(void *param)
 757 {
 758     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 759 
 760     SelectElementStruct *ses = (SelectElementStruct *)param;
 761     jobject self = ses->list;
 762     jint index = ses->index;
 763 
 764     jboolean result = JNI_FALSE;
 765     AwtList *l = NULL;
 766 
 767     PDATA pData;
 768     JNI_CHECK_PEER_GOTO(self, ret);
 769     l = (AwtList*)pData;
 770     if (::IsWindow(l->GetHWnd()))
 771     {
 772         result = l->IsItemSelected(index);
 773     }
 774 ret:
 775     env->DeleteGlobalRef(self);
 776 
 777     delete ses;
 778 
 779     return result;
 780 }
 781 
 782 void AwtList::_SetMultipleSelections(void *param)
 783 {
 784     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 785 
 786     SetMultipleSelectionsStruct *sms = (SetMultipleSelectionsStruct *)param;
 787     jobject self = sms->list;
 788     jboolean on = sms->on;
 789 
 790     AwtList *l = NULL;
 791 
 792     PDATA pData;
 793     JNI_CHECK_PEER_GOTO(self, ret);
 794     l = (AwtList*)pData;
 795     if (::IsWindow(l->GetHWnd()))
 796     {
 797         AwtToolkit::GetInstance().SendMessage(WM_AWT_LIST_SETMULTISELECT,
 798                                               (WPARAM)self, on);
 799     }
 800 ret:
 801     env->DeleteGlobalRef(self);
 802 
 803     delete sms;
 804 }
 805 
 806 /************************************************************************
 807  * WListPeer native methods
 808  *
 809  * This class seems to have numerous bugs in it, but they are all bugs
 810  * which were present before conversion to JNI. -br.
 811  */
 812 
 813 extern "C" {
 814 
 815 /*
 816  * Class:     sun_awt_windows_WListPeer
 817  * Method:    getMaxWidth
 818  * Signature: ()I
 819  */
 820 JNIEXPORT jint JNICALL
 821 Java_sun_awt_windows_WListPeer_getMaxWidth(JNIEnv *env, jobject self)
 822 {
 823     TRY;
 824 
 825     jobject selfGlobalRef = env->NewGlobalRef(self);
 826 
 827     return (jint)AwtToolkit::GetInstance().SyncCall(
 828         (void *(*)(void *))AwtList::_GetMaxWidth,
 829         (void *)selfGlobalRef);
 830     // selfGlobalRef is deleted in _GetMaxWidth
 831 
 832     CATCH_BAD_ALLOC_RET(0);
 833 }
 834 
 835 /*
 836  * Class:     sun_awt_windows_WListPeer
 837  * Method:    updateMaxItemWidth
 838  * Signature: ()V
 839  */
 840 JNIEXPORT void JNICALL
 841 Java_sun_awt_windows_WListPeer_updateMaxItemWidth(JNIEnv *env, jobject self)
 842 {
 843     TRY;
 844 
 845     jobject selfGlobalRef = env->NewGlobalRef(self);
 846 
 847     AwtToolkit::GetInstance().SyncCall(AwtList::_UpdateMaxItemWidth,
 848         (void *)selfGlobalRef);
 849     // selfGlobalRef is deleted in _UpdateMaxItemWidth
 850 
 851     CATCH_BAD_ALLOC;
 852 }
 853 
 854 /*
 855  * Class:     sun_awt_windows_WListPeer
 856  * Method:    addItems
 857  * Signature: ([Ljava/lang/String;II)V
 858  */
 859 JNIEXPORT void JNICALL
 860 Java_sun_awt_windows_WListPeer_addItems(JNIEnv *env, jobject self,
 861                                         jobjectArray items, jint index, jint width)
 862 {
 863     TRY;
 864 
 865     AddItemsStruct *ais = new AddItemsStruct;
 866     ais->list = env->NewGlobalRef(self);
 867     ais->items = (jobjectArray)env->NewGlobalRef(items);
 868     ais->index = index;
 869     ais->width = width;
 870 
 871     AwtToolkit::GetInstance().SyncCall(AwtList::_AddItems, ais);
 872     // global refs and ais are deleted in _AddItems()
 873 
 874     CATCH_BAD_ALLOC;
 875 }
 876 
 877 /*
 878  * Class:     sun_awt_windows_WListPeer
 879  * Method:    delItems
 880  * Signature: (II)V
 881  */
 882 JNIEXPORT void JNICALL
 883 Java_sun_awt_windows_WListPeer_delItems(JNIEnv *env, jobject self,
 884                                         jint start, jint end)
 885 {
 886     TRY;
 887 
 888     DelItemsStruct *dis = new DelItemsStruct;
 889     dis->list = env->NewGlobalRef(self);
 890     dis->start = start;
 891     dis->end = end;
 892 
 893     AwtToolkit::GetInstance().SyncCall(AwtList::_DelItems, dis);
 894     // global ref and dis are deleted in _DelItems
 895 
 896     CATCH_BAD_ALLOC;
 897 }
 898 
 899 /*
 900  * Class:     sun_awt_windows_WListPeer
 901  * Method:    select
 902  * Signature: (I)V
 903  */
 904 JNIEXPORT void JNICALL
 905 Java_sun_awt_windows_WListPeer_select(JNIEnv *env, jobject self,
 906                                       jint pos)
 907 {
 908     TRY;
 909 
 910     SelectElementStruct *ses = new SelectElementStruct;
 911     ses->list = env->NewGlobalRef(self);
 912     ses->index = pos;
 913 
 914     AwtToolkit::GetInstance().SyncCall(AwtList::_Select, ses);
 915     // global ref and ses are deleted in _Select
 916 
 917     CATCH_BAD_ALLOC;
 918 }
 919 
 920 /*
 921  * Class:     sun_awt_windows_WListPeer
 922  * Method:    deselect
 923  * Signature: (I)V
 924  */
 925 JNIEXPORT void JNICALL
 926 Java_sun_awt_windows_WListPeer_deselect(JNIEnv *env, jobject self,
 927                                         jint pos)
 928 {
 929     TRY;
 930 
 931     PDATA pData;
 932     JNI_CHECK_PEER_RETURN(self);
 933 
 934     SelectElementStruct *ses = new SelectElementStruct;
 935     ses->list = env->NewGlobalRef(self);
 936     ses->index = pos;
 937 
 938     AwtToolkit::GetInstance().SyncCall(AwtList::_Deselect, ses);
 939     // global ref and ses are deleted in _Deselect
 940 
 941     CATCH_BAD_ALLOC;
 942 }
 943 
 944 /*
 945  * Class:     sun_awt_windows_WListPeer
 946  * Method:    makeVisible
 947  * Signature: (I)V
 948  */
 949 JNIEXPORT void JNICALL
 950 Java_sun_awt_windows_WListPeer_makeVisible(JNIEnv *env, jobject self,
 951                                            jint pos)
 952 {
 953     TRY;
 954 
 955     SelectElementStruct *ses = new SelectElementStruct;
 956     ses->list = env->NewGlobalRef(self);
 957     ses->index = pos;
 958 
 959     AwtToolkit::GetInstance().SyncCall(AwtList::_MakeVisible, ses);
 960     // global ref and ses are deleted in _MakeVisible
 961 
 962     CATCH_BAD_ALLOC;
 963 }
 964 
 965 /*
 966  * Class:     sun_awt_windows_WListPeer
 967  * Method:    setMultipleSelections
 968  * Signature: (Z)V
 969  */
 970 JNIEXPORT void JNICALL
 971 Java_sun_awt_windows_WListPeer_setMultipleSelections(JNIEnv *env, jobject self,
 972                                                      jboolean on)
 973 {
 974     TRY;
 975 
 976     SetMultipleSelectionsStruct *sms = new SetMultipleSelectionsStruct;
 977     sms->list = env->NewGlobalRef(self);
 978     sms->on = on;
 979 
 980     AwtToolkit::GetInstance().SyncCall(AwtList::_SetMultipleSelections, sms);
 981     // global ref and sms are deleted in AwtList::_SetMultipleSelections
 982 
 983     CATCH_BAD_ALLOC;
 984 }
 985 
 986 /*
 987  * Class:     sun_awt_windows_WListPeer
 988  * Method:    create
 989  * Signature: (Lsun/awt/windows/WComponentPeer;)V
 990  */
 991 JNIEXPORT void JNICALL
 992 Java_sun_awt_windows_WListPeer_create(JNIEnv *env, jobject self,
 993                                       jobject parent)
 994 {
 995     TRY;
 996 
 997     PDATA pData;
 998     JNI_CHECK_PEER_RETURN(parent);
 999     AwtToolkit::CreateComponent(self, parent,
1000                                 (AwtToolkit::ComponentFactory)AwtList::Create);
1001     JNI_CHECK_PEER_CREATION_RETURN(self);
1002 
1003     CATCH_BAD_ALLOC;
1004 }
1005 
1006 /*
1007  * Class:     sun_awt_windows_WListPeer
1008  * Method:    isSelected
1009  * Signature: (I)Z
1010  */
1011 JNIEXPORT jboolean JNICALL
1012 Java_sun_awt_windows_WListPeer_isSelected(JNIEnv *env, jobject self,
1013                                           jint index)
1014 {
1015     TRY;
1016 
1017     SelectElementStruct *ses = new SelectElementStruct;
1018     ses->list = env->NewGlobalRef(self);
1019     ses->index = index;
1020 
1021     return (jboolean)AwtToolkit::GetInstance().SyncCall(
1022         (void *(*)(void *))AwtList::_IsSelected, ses);
1023     // global ref and ses are deleted in _IsSelected
1024 
1025     CATCH_BAD_ALLOC_RET(FALSE);
1026 }
1027 
1028 } /* extern "C" */