1 /*
   2  * Copyright (c) 1996, 2010, 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 <windowsx.h>
  27 
  28 #include "awt_Toolkit.h"
  29 #include "awt_Choice.h"
  30 #include "awt_Canvas.h"
  31 
  32 #include "awt_Dimension.h"
  33 #include "awt_Container.h"
  34 
  35 #include "ComCtl32Util.h"
  36 
  37 #include <java_awt_Toolkit.h>
  38 #include <java_awt_FontMetrics.h>
  39 #include <java_awt_event_InputEvent.h>
  40 
  41 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
  42  */
  43 
  44 /************************************************************************/
  45 // Struct for _Reshape() method
  46 struct ReshapeStruct {
  47     jobject choice;
  48     jint x, y;
  49     jint width, height;
  50 };
  51 // Struct for _Select() method
  52 struct SelectStruct {
  53     jobject choice;
  54     jint index;
  55 };
  56 // Struct for _AddItems() method
  57 struct AddItemsStruct {
  58     jobject choice;
  59     jobjectArray items;
  60     jint index;
  61 };
  62 // Struct for _Remove() method
  63 struct RemoveStruct {
  64     jobject choice;
  65     jint index;
  66 };
  67 
  68 /************************************************************************/
  69 
  70 /* Bug #4509045: set if SetDragCapture captured mouse */
  71 
  72 BOOL AwtChoice::mouseCapture = FALSE;
  73 
  74 /* Bug #4338368: consume the spurious MouseUp when the choice loses focus */
  75 
  76 BOOL AwtChoice::skipNextMouseUp = FALSE;
  77 
  78 BOOL AwtChoice::sm_isMouseMoveInList = FALSE;
  79 
  80 static const UINT MINIMUM_NUMBER_OF_VISIBLE_ITEMS = 8;
  81 
  82 /*************************************************************************
  83  * AwtChoice class methods
  84  */
  85 
  86 AwtChoice::AwtChoice() {
  87     m_hList = NULL;
  88     m_listDefWindowProc = NULL;
  89     m_selectedItem = -1;
  90 }
  91 
  92 LPCTSTR AwtChoice::GetClassName() {
  93     return TEXT("COMBOBOX");  /* System provided combobox class */
  94 }
  95 
  96 void AwtChoice::Dispose() {
  97     if (m_hList != NULL && m_listDefWindowProc != NULL) {
  98         ComCtl32Util::GetInstance().UnsubclassHWND(m_hList, ListWindowProc, m_listDefWindowProc);
  99     }
 100     AwtComponent::Dispose();
 101 }
 102 
 103 AwtChoice* AwtChoice::Create(jobject peer, jobject parent) {
 104 
 105 
 106     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 107 
 108     jobject target = NULL;
 109     AwtChoice* c = NULL;
 110     RECT rc;
 111 
 112     try {
 113         if (env->EnsureLocalCapacity(1) < 0) {
 114             return NULL;
 115         }
 116         AwtCanvas* awtParent;
 117 
 118         JNI_CHECK_NULL_GOTO(parent, "null parent", done);
 119 
 120         awtParent = (AwtCanvas*)JNI_GET_PDATA(parent);
 121         JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done);
 122 
 123         target = env->GetObjectField(peer, AwtObject::targetID);
 124         JNI_CHECK_NULL_GOTO(target, "null target", done);
 125 
 126         c = new AwtChoice();
 127 
 128         {
 129             DWORD style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL |
 130                           CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED;
 131             DWORD exStyle = 0;
 132             if (GetRTL()) {
 133                 exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
 134                 if (GetRTLReadingOrder())
 135                     exStyle |= WS_EX_RTLREADING;
 136             }
 137 
 138             /*
 139              * In OWNER_DRAW, the size of the edit control part of the
 140              * choice must be determinded in its creation, when the parent
 141              * cannot get the choice's instance from its handle.  So
 142              * record the pair of the ID and the instance of the choice.
 143              */
 144             UINT myId = awtParent->CreateControlID();
 145             DASSERT(myId > 0);
 146             c->m_myControlID = myId;
 147             awtParent->PushChild(myId, c);
 148 
 149             jint x = env->GetIntField(target, AwtComponent::xID);
 150             jint y = env->GetIntField(target, AwtComponent::yID);
 151             jint width = env->GetIntField(target, AwtComponent::widthID);
 152             jint height = env->GetIntField(target, AwtComponent::heightID);
 153 
 154             jobject dimension = JNU_CallMethodByName(env, NULL, peer,
 155                                                      "preferredSize",
 156                                                      "()Ljava/awt/Dimension;").l;
 157             DASSERT(!safe_ExceptionOccurred(env));
 158 
 159             if (dimension != NULL && width == 0) {
 160                 width = env->GetIntField(dimension, AwtDimension::widthID);
 161             }
 162             c->CreateHWnd(env, L"", style, exStyle,
 163                           x, y, width, height,
 164                           awtParent->GetHWnd(),
 165                           reinterpret_cast<HMENU>(static_cast<INT_PTR>(myId)),
 166                           ::GetSysColor(COLOR_WINDOWTEXT),
 167                           ::GetSysColor(COLOR_WINDOW),
 168                           peer);
 169 
 170             /* suppress inheriting parent's color. */
 171             c->m_backgroundColorSet = TRUE;
 172             c->UpdateBackground(env, target);
 173 
 174             /* Bug 4255631 Solaris: Size returned by Choice.getSize() does not match
 175              * actual size
 176              * Fix: Set the Choice to its actual size in the component.
 177              */
 178             ::GetClientRect(c->GetHWnd(), &rc);
 179             env->SetIntField(target, AwtComponent::widthID,  (jint) rc.right);
 180             env->SetIntField(target, AwtComponent::heightID, (jint) rc.bottom);
 181 
 182             if (IS_WINXP) {
 183                 ::SendMessage(c->GetHWnd(), CB_SETMINVISIBLE, (WPARAM) MINIMUM_NUMBER_OF_VISIBLE_ITEMS, 0);
 184             }
 185 
 186             env->DeleteLocalRef(dimension);
 187         }
 188     } catch (...) {
 189         env->DeleteLocalRef(target);
 190         throw;
 191     }
 192 
 193 done:
 194     env->DeleteLocalRef(target);
 195 
 196     return c;
 197 }
 198 
 199 // calculate height of drop-down list part of the combobox
 200 // to show all the items up to a maximum of eight
 201 int AwtChoice::GetDropDownHeight()
 202 {
 203     int itemHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)0,0);
 204     int numItemsToShow = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0,0);
 205     numItemsToShow = min(MINIMUM_NUMBER_OF_VISIBLE_ITEMS, numItemsToShow);
 206     // drop-down height snaps to nearest line, so add a
 207     // fudge factor of 1/2 line to ensure last line shows
 208     return itemHeight*numItemsToShow + itemHeight/2;
 209 }
 210 
 211 // get the height of the field portion of the combobox
 212 int AwtChoice::GetFieldHeight()
 213 {
 214     int fieldHeight;
 215     int borderHeight;
 216     fieldHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)-1, 0);
 217     // add top and bottom border lines; border size is different for
 218     // Win 4.x (3d edge) vs 3.x (1 pixel line)
 219     borderHeight = ::GetSystemMetrics(SM_CYEDGE);
 220     fieldHeight += borderHeight*2;
 221     return fieldHeight;
 222 }
 223 
 224 // gets the total height of the combobox, including drop down
 225 int AwtChoice::GetTotalHeight()
 226 {
 227     int dropHeight = GetDropDownHeight();
 228     int fieldHeight = GetFieldHeight();
 229     int totalHeight;
 230 
 231     // border on drop-down portion is always non-3d (so don't use SM_CYEDGE)
 232     int borderHeight = ::GetSystemMetrics(SM_CYBORDER);
 233     // total height = drop down height + field height + top+bottom drop down border lines
 234     totalHeight = dropHeight + fieldHeight +borderHeight*2;
 235     return totalHeight;
 236 }
 237 
 238 // Recalculate and set the drop-down height for the Choice.
 239 void AwtChoice::ResetDropDownHeight()
 240 {
 241     RECT    rcWindow;
 242 
 243     ::GetWindowRect(GetHWnd(), &rcWindow);
 244     // resize the drop down to accomodate added/removed items
 245     int     totalHeight = GetTotalHeight();
 246     ::SetWindowPos(GetHWnd(), NULL,
 247                     0, 0, rcWindow.right - rcWindow.left, totalHeight,
 248                     SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
 249 }
 250 
 251 /* Fix for the bug 4327666: set the capture for middle
 252    and right mouse buttons, but leave left button alone */
 253 void AwtChoice::SetDragCapture(UINT flags)
 254 {
 255     if ((flags & MK_LBUTTON) != 0) {
 256         if ((::GetCapture() == GetHWnd()) && mouseCapture) {
 257             /* On MK_LBUTTON ComboBox captures mouse itself
 258                so we should release capture and clear flag to
 259                prevent releasing capture by ReleaseDragCapture
 260              */
 261             ::ReleaseCapture();
 262             mouseCapture = FALSE;
 263         }
 264         return;
 265     }
 266 
 267     // don't want to interfere with other controls
 268     if (::GetCapture() == NULL) {
 269         ::SetCapture(GetHWnd());
 270         mouseCapture = TRUE;
 271     }
 272 }
 273 
 274 /* Fix for Bug 4509045: should release capture only if it is set by SetDragCapture */
 275 void AwtChoice::ReleaseDragCapture(UINT flags)
 276 {
 277     if ((::GetCapture() == GetHWnd()) && ((flags & ALL_MK_BUTTONS) == 0) && mouseCapture) {
 278         ::ReleaseCapture();
 279         mouseCapture = FALSE;
 280     }
 281 }
 282 
 283 void AwtChoice::Reshape(int x, int y, int w, int h)
 284 {
 285     // Choice component height is fixed (when rolled up)
 286     // so vertically center the choice in it's bounding box
 287     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 288     jobject target = GetTarget(env);
 289     jobject parent = env->GetObjectField(target, AwtComponent::parentID);
 290     RECT rc;
 291 
 292     int fieldHeight = GetFieldHeight();
 293     if ((parent != NULL && env->GetObjectField(parent, AwtContainer::layoutMgrID) != NULL) &&
 294         fieldHeight > 0 && fieldHeight < h) {
 295         y += (h - fieldHeight) / 2;
 296     }
 297 
 298     /* Fix for 4783342
 299      * Choice should ignore reshape on height changes,
 300      * as height is dependent on Font size only.
 301      */
 302     AwtComponent* awtParent = GetParent();
 303     BOOL bReshape = true;
 304     if (awtParent != NULL) {
 305         ::GetWindowRect(GetHWnd(), &rc);
 306         int oldW = rc.right - rc.left;
 307         RECT parentRc;
 308         ::GetWindowRect(awtParent->GetHWnd(), &parentRc);
 309         int oldX = rc.left - parentRc.left;
 310         int oldY = rc.top - parentRc.top;
 311         bReshape = (x != oldX || y != oldY || w != oldW);
 312     }
 313 
 314     if (bReshape)
 315     {
 316         int totalHeight = GetTotalHeight();
 317         AwtComponent::Reshape(x, y, w, totalHeight);
 318     }
 319 
 320     /* Bug 4255631 Solaris: Size returned by Choice.getSize() does not match
 321      * actual size
 322      * Fix: Set the Choice to its actual size in the component.
 323      */
 324     ::GetClientRect(GetHWnd(), &rc);
 325     env->SetIntField(target, AwtComponent::widthID,  (jint)rc.right);
 326     env->SetIntField(target, AwtComponent::heightID, (jint)rc.bottom);
 327 
 328     env->DeleteLocalRef(target);
 329     env->DeleteLocalRef(parent);
 330 }
 331 
 332 jobject AwtChoice::PreferredItemSize(JNIEnv *env)
 333 {
 334     jobject dimension = JNU_CallMethodByName(env, NULL, GetPeer(env),
 335                                              "preferredSize",
 336                                              "()Ljava/awt/Dimension;").l;
 337     DASSERT(!safe_ExceptionOccurred(env));
 338     if (dimension == NULL) {
 339         return NULL;
 340     }
 341     /* This size is window size of choice and it's too big for each
 342      * drop down item height.
 343      */
 344     env->SetIntField(dimension, AwtDimension::heightID,
 345                        GetFontHeight(env));
 346     return dimension;
 347 }
 348 
 349 void AwtChoice::SetFont(AwtFont* font)
 350 {
 351     AwtComponent::SetFont(font);
 352 
 353     //Get the text metrics and change the height of each item.
 354     HDC hDC = ::GetDC(GetHWnd());
 355     DASSERT(hDC != NULL);
 356     TEXTMETRIC tm;
 357 
 358     HANDLE hFont = font->GetHFont();
 359     VERIFY(::SelectObject(hDC, hFont) != NULL);
 360     VERIFY(::GetTextMetrics(hDC, &tm));
 361     long h = tm.tmHeight + tm.tmExternalLeading;
 362     VERIFY(::ReleaseDC(GetHWnd(), hDC) != 0);
 363 
 364     int nCount = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0, 0);
 365     for(int i = 0; i < nCount; ++i) {
 366         VERIFY(::SendMessage(GetHWnd(), CB_SETITEMHEIGHT, i, MAKELPARAM(h, 0)) != CB_ERR);
 367     }
 368     //Change the height of the Edit Box.
 369     VERIFY(::SendMessage(GetHWnd(), CB_SETITEMHEIGHT, (UINT)-1,
 370                          MAKELPARAM(h, 0)) != CB_ERR);
 371 
 372     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 373     jobject target = GetTarget(env);
 374     jint height = env->GetIntField(target, AwtComponent::heightID);
 375 
 376     Reshape(env->GetIntField(target, AwtComponent::xID),
 377             env->GetIntField(target, AwtComponent::yID),
 378             env->GetIntField(target, AwtComponent::widthID),
 379             h);
 380 
 381     env->DeleteLocalRef(target);
 382 }
 383 
 384 static int lastClickX = -1;
 385 static int lastClickY = -1;
 386 
 387 LRESULT CALLBACK AwtChoice::ListWindowProc(HWND hwnd, UINT message,
 388                                            WPARAM wParam, LPARAM lParam)
 389 {
 390     /*
 391      * We don't pass the choice WM_LBUTTONDOWN message. As the result the choice's list
 392      * doesn't forward mouse messages it captures. Below we do forward what we need.
 393      */
 394 
 395     TRY;
 396 
 397     DASSERT(::IsWindow(hwnd));
 398 
 399     switch (message) {
 400         case WM_LBUTTONDOWN: {
 401             DWORD curPos = ::GetMessagePos();
 402             lastClickX = GET_X_LPARAM(curPos);
 403             lastClickY = GET_Y_LPARAM(curPos);
 404             break;
 405         }
 406         case WM_MOUSEMOVE: {
 407             RECT rect;
 408             ::GetClientRect(hwnd, &rect);
 409 
 410             POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
 411             if (::PtInRect(&rect, pt)) {
 412                 sm_isMouseMoveInList = TRUE;
 413             }
 414 
 415             POINT lastPt = {lastClickX, lastClickY};
 416             ::ScreenToClient(hwnd, &lastPt);
 417             if (::PtInRect(&rect, lastPt)) {
 418                 break; // ignore when dragging inside the list
 419             }
 420         }
 421         case WM_LBUTTONUP: {
 422             lastClickX = -1;
 423             lastClickY = -1;
 424 
 425             AwtChoice *c = (AwtChoice *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
 426             if (c != NULL) {
 427                 // forward the msg to the choice
 428                 c->WindowProc(message, wParam, lParam);
 429             }
 430         }
 431     }
 432     return ComCtl32Util::GetInstance().DefWindowProc(NULL, hwnd, message, wParam, lParam);
 433 
 434     CATCH_BAD_ALLOC_RET(0);
 435 }
 436 
 437 
 438 MsgRouting AwtChoice::WmNotify(UINT notifyCode)
 439 {
 440     if (notifyCode == CBN_SELCHANGE) {
 441         int selectedItem = (int)SendMessage(CB_GETCURSEL);
 442         if (selectedItem != CB_ERR && m_selectedItem != selectedItem){
 443             m_selectedItem = selectedItem;
 444             DoCallback("handleAction", "(I)V", selectedItem);
 445         }
 446     } else if (notifyCode == CBN_DROPDOWN) {
 447 
 448         if (m_hList == NULL) {
 449             COMBOBOXINFO cbi;
 450             cbi.cbSize = sizeof(COMBOBOXINFO);
 451             ::GetComboBoxInfo(GetHWnd(), &cbi);
 452             m_hList = cbi.hwndList;
 453             m_listDefWindowProc = ComCtl32Util::GetInstance().SubclassHWND(m_hList, ListWindowProc);
 454             DASSERT(::GetWindowLongPtr(m_hList, GWLP_USERDATA) == NULL);
 455             ::SetWindowLongPtr(m_hList, GWLP_USERDATA, (LONG_PTR)this);
 456         }
 457         sm_isMouseMoveInList = FALSE;
 458 
 459         // Clicking in the dropdown list steals focus from the proxy.
 460         // So, set the focus-restore flag up.
 461         SetRestoreFocus(TRUE);
 462     } else if (notifyCode == CBN_CLOSEUP) {
 463         SetRestoreFocus(FALSE);
 464     }
 465     return mrDoDefault;
 466 }
 467 
 468 MsgRouting
 469 AwtChoice::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo)
 470 {
 471     DrawListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), drawInfo);
 472     return mrConsume;
 473 }
 474 
 475 MsgRouting
 476 AwtChoice::OwnerMeasureItem(UINT /*ctrlId*/, MEASUREITEMSTRUCT& measureInfo)
 477 {
 478     MeasureListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), measureInfo);
 479     return mrConsume;
 480 }
 481 
 482 /* Bug #4338368: when a choice loses focus, it triggers spurious MouseUp event,
 483  * even if the focus was lost due to TAB key pressing
 484  */
 485 
 486 MsgRouting
 487 AwtChoice::WmKillFocus(HWND hWndGotFocus)
 488 {
 489     skipNextMouseUp = TRUE;
 490     return AwtComponent::WmKillFocus(hWndGotFocus);
 491 }
 492 
 493 MsgRouting
 494 AwtChoice::WmMouseUp(UINT flags, int x, int y, int button)
 495 {
 496     if (skipNextMouseUp) {
 497         skipNextMouseUp = FALSE;
 498         return mrDoDefault;
 499     }
 500     return AwtComponent::WmMouseUp(flags, x, y, button);
 501 }
 502 
 503 MsgRouting AwtChoice::HandleEvent(MSG *msg, BOOL synthetic)
 504 {
 505     if (IsFocusingMouseMessage(msg)) {
 506         SendMessage(CB_SHOWDROPDOWN, ~SendMessage(CB_GETDROPPEDSTATE, 0, 0), 0);
 507         delete msg;
 508         return mrConsume;
 509     }
 510     // To simulate the native behavior, we close the list on WM_LBUTTONUP if
 511     // WM_MOUSEMOVE has been dedected on the list since it has been dropped down.
 512     if (msg->message == WM_LBUTTONUP && SendMessage(CB_GETDROPPEDSTATE, 0, 0) &&
 513         sm_isMouseMoveInList)
 514     {
 515         SendMessage(CB_SHOWDROPDOWN, FALSE, 0);
 516     }
 517     return AwtComponent::HandleEvent(msg, synthetic);
 518 }
 519 
 520 BOOL AwtChoice::InheritsNativeMouseWheelBehavior() {return true;}
 521 
 522 void AwtChoice::_Reshape(void *param)
 523 {
 524     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 525 
 526     ReshapeStruct *rs = (ReshapeStruct *)param;
 527     jobject choice = rs->choice;
 528     jint x = rs->x;
 529     jint y = rs->y;
 530     jint width = rs->width;
 531     jint height = rs->height;
 532 
 533     AwtChoice *c = NULL;
 534 
 535     PDATA pData;
 536     JNI_CHECK_PEER_GOTO(choice, done);
 537 
 538     c = (AwtChoice *)pData;
 539     if (::IsWindow(c->GetHWnd()))
 540     {
 541         c->Reshape(x, y, width, height);
 542         c->VerifyState();
 543     }
 544 
 545 done:
 546     env->DeleteGlobalRef(choice);
 547 
 548     delete rs;
 549 }
 550 
 551 void AwtChoice::_Select(void *param)
 552 {
 553     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 554 
 555     SelectStruct *ss = (SelectStruct *)param;
 556     jobject choice = ss->choice;
 557     jint index = ss->index;
 558 
 559     AwtChoice *c = NULL;
 560 
 561     PDATA pData;
 562     JNI_CHECK_PEER_GOTO(choice, done);
 563 
 564     c = (AwtChoice *)pData;
 565     if (::IsWindow(c->GetHWnd()))
 566     {
 567         c->SendMessage(CB_SETCURSEL, index);
 568 //        c->VerifyState();
 569     }
 570 
 571 done:
 572     env->DeleteGlobalRef(choice);
 573 
 574     delete ss;
 575 }
 576 
 577 void AwtChoice::_AddItems(void *param)
 578 {
 579     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 580 
 581     AddItemsStruct *ais = (AddItemsStruct *)param;
 582     jobject choice = ais->choice;
 583     jobjectArray items = ais->items;
 584     jint index = ais->index;
 585 
 586     AwtChoice *c = NULL;
 587 
 588     PDATA pData;
 589     JNI_CHECK_PEER_GOTO(choice, done);
 590     JNI_CHECK_NULL_GOTO(items, "null items", done);
 591 
 592     c = (AwtChoice *)pData;
 593     if (::IsWindow(c->GetHWnd()))
 594     {
 595         jsize i;
 596         int itemCount = env->GetArrayLength(items);
 597         if (itemCount > 0) {
 598            c->SendMessage(WM_SETREDRAW, (WPARAM)FALSE, 0);
 599            for (i = 0; i < itemCount; i++)
 600            {
 601                jstring item = (jstring)env->GetObjectArrayElement(items, i);
 602                JNI_CHECK_NULL_GOTO(item, "null item", next_elem);
 603                c->SendMessage(CB_INSERTSTRING, index + i, JavaStringBuffer(env, item));
 604                env->DeleteLocalRef(item);
 605 next_elem:
 606                ;
 607            }
 608            c->SendMessage(WM_SETREDRAW, (WPARAM)TRUE, 0);
 609            InvalidateRect(c->GetHWnd(), NULL, TRUE);
 610            c->ResetDropDownHeight();
 611            c->VerifyState();
 612         }
 613     }
 614 
 615 done:
 616     env->DeleteGlobalRef(choice);
 617     env->DeleteGlobalRef(items);
 618 
 619     delete ais;
 620 }
 621 
 622 void AwtChoice::_Remove(void *param)
 623 {
 624     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 625 
 626     RemoveStruct *rs = (RemoveStruct *)param;
 627     jobject choice = rs->choice;
 628     jint index = rs->index;
 629 
 630     AwtChoice *c = NULL;
 631 
 632     PDATA pData;
 633     JNI_CHECK_PEER_GOTO(choice, done);
 634 
 635     c = (AwtChoice *)pData;
 636     if (::IsWindow(c->GetHWnd()))
 637     {
 638         c->SendMessage(CB_DELETESTRING, index, 0);
 639         c->ResetDropDownHeight();
 640         c->VerifyState();
 641     }
 642 
 643 done:
 644     env->DeleteGlobalRef(choice);
 645 
 646     delete rs;
 647 }
 648 
 649 void AwtChoice::_RemoveAll(void *param)
 650 {
 651     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 652 
 653     jobject choice = (jobject)param;
 654 
 655     AwtChoice *c = NULL;
 656 
 657     PDATA pData;
 658     JNI_CHECK_PEER_GOTO(choice, done);
 659 
 660     c = (AwtChoice *)pData;
 661     if (::IsWindow(c->GetHWnd()))
 662     {
 663         c->SendMessage(CB_RESETCONTENT, 0, 0);
 664         c->ResetDropDownHeight();
 665         c->VerifyState();
 666     }
 667 
 668 done:
 669     env->DeleteGlobalRef(choice);
 670 }
 671 
 672 void AwtChoice::_CloseList(void *param)
 673 {
 674     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 675 
 676     jobject choice = (jobject)param;
 677 
 678     AwtChoice *c = NULL;
 679 
 680     PDATA pData;
 681     JNI_CHECK_PEER_GOTO(choice, done);
 682 
 683     c = (AwtChoice *)pData;
 684     if (::IsWindow(c->GetHWnd()) && c->SendMessage(CB_GETDROPPEDSTATE, 0, 0)) {
 685         c->SendMessage(CB_SHOWDROPDOWN, FALSE, 0);
 686     }
 687 
 688 done:
 689     env->DeleteGlobalRef(choice);
 690 }
 691 
 692 /************************************************************************
 693  * WChoicePeer native methods
 694  */
 695 
 696 extern "C" {
 697 
 698 /*
 699  * Class:     sun_awt_windows_WChoicePeer
 700  * Method:    select
 701  * Signature: (I)V
 702  */
 703 JNIEXPORT void JNICALL
 704 Java_sun_awt_windows_WChoicePeer_select(JNIEnv *env, jobject self,
 705                                         jint index)
 706 {
 707     TRY;
 708 
 709     SelectStruct *ss = new SelectStruct;
 710     ss->choice = env->NewGlobalRef(self);
 711     ss->index = index;
 712 
 713     AwtToolkit::GetInstance().SyncCall(AwtChoice::_Select, ss);
 714     // global refs and ss are removed in _Select
 715 
 716     CATCH_BAD_ALLOC;
 717 }
 718 
 719 /*
 720  * Class:     sun_awt_windows_WChoicePeer
 721  * Method:    remove
 722  * Signature: (I)V
 723  */
 724 JNIEXPORT void JNICALL
 725 Java_sun_awt_windows_WChoicePeer_remove(JNIEnv *env, jobject self,
 726                                         jint index)
 727 {
 728     TRY;
 729 
 730     RemoveStruct *rs = new RemoveStruct;
 731     rs->choice = env->NewGlobalRef(self);
 732     rs->index = index;
 733 
 734     AwtToolkit::GetInstance().SyncCall(AwtChoice::_Remove, rs);
 735     // global ref and rs are deleted in _Remove
 736 
 737     CATCH_BAD_ALLOC;
 738 }
 739 
 740 /*
 741  * Class:     sun_awt_windows_WChoicePeer
 742  * Method:    removeAll
 743  * Signature: ()V
 744  */
 745 JNIEXPORT void JNICALL
 746 Java_sun_awt_windows_WChoicePeer_removeAll(JNIEnv *env, jobject self)
 747 {
 748     TRY;
 749 
 750     jobject selfGlobalRef = env->NewGlobalRef(self);
 751 
 752     AwtToolkit::GetInstance().SyncCall(AwtChoice::_RemoveAll, (void *)selfGlobalRef);
 753     // selfGlobalRef is deleted in _RemoveAll
 754 
 755     CATCH_BAD_ALLOC;
 756 }
 757 
 758 /*
 759  * Class:     sun_awt_windows_WChoicePeer
 760  * Method:    addItems
 761  * Signature: ([Ljava/lang/String;I)V
 762  */
 763 JNIEXPORT void JNICALL
 764 Java_sun_awt_windows_WChoicePeer_addItems(JNIEnv *env, jobject self,
 765                                           jobjectArray items, jint index)
 766 {
 767     TRY;
 768 
 769     AddItemsStruct *ais = new AddItemsStruct;
 770     ais->choice = env->NewGlobalRef(self);
 771     ais->items = (jobjectArray)env->NewGlobalRef(items);
 772     ais->index = index;
 773 
 774     AwtToolkit::GetInstance().SyncCall(AwtChoice::_AddItems, ais);
 775     // global refs and ais are deleted in _AddItems
 776 
 777     CATCH_BAD_ALLOC;
 778 }
 779 
 780 /*
 781  * Class:     sun_awt_windows_WChoicePeer
 782  * Method:    reshape
 783  * Signature: (IIII)V
 784  */
 785 JNIEXPORT void JNICALL
 786 Java_sun_awt_windows_WChoicePeer_reshape(JNIEnv *env, jobject self,
 787                                          jint x, jint y,
 788                                          jint width, jint height)
 789 {
 790     TRY;
 791 
 792     ReshapeStruct *rs = new ReshapeStruct;
 793     rs->choice = env->NewGlobalRef(self);
 794     rs->x = x;
 795     rs->y = y;
 796     rs->width = width;
 797     rs->height = height;
 798 
 799     AwtToolkit::GetInstance().SyncCall(AwtChoice::_Reshape, rs);
 800     // global ref and rs are deleted in _Reshape
 801 
 802     CATCH_BAD_ALLOC;
 803 }
 804 
 805 /*
 806  * Class:     sun_awt_windows_WChoicePeer
 807  * Method:    create
 808  * Signature: (Lsun/awt/windows/WComponentPeer;)V
 809  */
 810 JNIEXPORT void JNICALL
 811 Java_sun_awt_windows_WChoicePeer_create(JNIEnv *env, jobject self,
 812                                         jobject parent)
 813 {
 814     TRY;
 815 
 816     PDATA pData;
 817     JNI_CHECK_PEER_RETURN(parent);
 818     AwtToolkit::CreateComponent(self, parent,
 819                                 (AwtToolkit::ComponentFactory)
 820                                 AwtChoice::Create);
 821     JNI_CHECK_PEER_CREATION_RETURN(self);
 822 
 823     CATCH_BAD_ALLOC;
 824 }
 825 
 826 /*
 827  * Class:     sun_awt_windows_WChoicePeer
 828  * Method:    closeList
 829  * Signature: ()V
 830  */
 831 JNIEXPORT void JNICALL
 832 Java_sun_awt_windows_WChoicePeer_closeList(JNIEnv *env, jobject self)
 833 {
 834     TRY;
 835 
 836     jobject selfGlobalRef = env->NewGlobalRef(self);
 837 
 838     AwtToolkit::GetInstance().SyncCall(AwtChoice::_CloseList, (void *)selfGlobalRef);
 839     // global ref is deleted in _CloseList
 840 
 841     CATCH_BAD_ALLOC;
 842 }
 843 } /* extern "C" */
 844 
 845 
 846 /************************************************************************
 847  * Diagnostic routines
 848  */
 849 
 850 #ifdef DEBUG
 851 
 852 void AwtChoice::VerifyState()
 853 {
 854     if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) {
 855         return;
 856     }
 857 
 858     if (m_callbacksEnabled == FALSE) {
 859         /* Component is not fully setup yet. */
 860         return;
 861     }
 862 
 863     AwtComponent::VerifyState();
 864     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 865     if (env->PushLocalFrame(1) < 0)
 866         return;
 867 
 868     jobject target = GetTarget(env);
 869 
 870     // To avoid possibly running client code on the toolkit thread, don't
 871     // do the following checks if we're running on the toolkit thread.
 872     if (AwtToolkit::MainThread() != ::GetCurrentThreadId()) {
 873         // Compare number of items.
 874         int nTargetItems = JNU_CallMethodByName(env, NULL, target,
 875                                                 "countItems", "()I").i;
 876         DASSERT(!safe_ExceptionOccurred(env));
 877         int nPeerItems = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0, 0);
 878         DASSERT(nTargetItems == nPeerItems);
 879 
 880         // Compare selection
 881         int targetIndex = JNU_CallMethodByName(env, NULL, target,
 882                                                "getSelectedIndex", "()I").i;
 883         DASSERT(!safe_ExceptionOccurred(env));
 884         int peerCurSel = (int)::SendMessage(GetHWnd(), CB_GETCURSEL, 0, 0);
 885         DASSERT(targetIndex == peerCurSel);
 886     }
 887     env->PopLocalFrame(0);
 888 }
 889 #endif //DEBUG