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