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