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