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