1 /* 2 * Copyright (c) 1996, 2013, 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 "preferredSize", 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, (jint) rc.right); 181 env->SetIntField(target, AwtComponent::heightID, (jint) 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 // drop-down height snaps to nearest line, so add a 208 // fudge factor of 1/2 line to ensure last line shows 209 return itemHeight*numItemsToShow + itemHeight/2; 210 } 211 212 // get the height of the field portion of the combobox 213 int AwtChoice::GetFieldHeight() 214 { 215 int fieldHeight; 216 int borderHeight; 217 fieldHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)-1, 0); 218 // add top and bottom border lines; border size is different for 219 // Win 4.x (3d edge) vs 3.x (1 pixel line) 220 borderHeight = ::GetSystemMetrics(SM_CYEDGE); 221 fieldHeight += borderHeight*2; 222 return fieldHeight; 223 } 224 225 // gets the total height of the combobox, including drop down 226 int AwtChoice::GetTotalHeight() 227 { 228 int dropHeight = GetDropDownHeight(); 229 int fieldHeight = GetFieldHeight(); 230 int totalHeight; 231 232 // border on drop-down portion is always non-3d (so don't use SM_CYEDGE) 233 int borderHeight = ::GetSystemMetrics(SM_CYBORDER); 234 // total height = drop down height + field height + top+bottom drop down border lines 235 totalHeight = dropHeight + fieldHeight +borderHeight*2; 236 return totalHeight; 237 } 238 239 // Recalculate and set the drop-down height for the Choice. 240 void AwtChoice::ResetDropDownHeight() 241 { 242 RECT rcWindow; 243 244 ::GetWindowRect(GetHWnd(), &rcWindow); 245 // resize the drop down to accommodate added/removed items 246 int totalHeight = GetTotalHeight(); 247 ::SetWindowPos(GetHWnd(), NULL, 248 0, 0, rcWindow.right - rcWindow.left, totalHeight, 249 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); 250 } 251 252 /* Fix for the bug 4327666: set the capture for middle 253 and right mouse buttons, but leave left button alone */ 254 void AwtChoice::SetDragCapture(UINT flags) 255 { 256 if ((flags & MK_LBUTTON) != 0) { 257 if ((::GetCapture() == GetHWnd()) && mouseCapture) { 258 /* On MK_LBUTTON ComboBox captures mouse itself 259 so we should release capture and clear flag to 260 prevent releasing capture by ReleaseDragCapture 261 */ 262 ::ReleaseCapture(); 263 mouseCapture = FALSE; 264 } 265 return; 266 } 267 268 // don't want to interfere with other controls 269 if (::GetCapture() == NULL) { 270 ::SetCapture(GetHWnd()); 271 mouseCapture = TRUE; 272 } 273 } 274 275 /* Fix for Bug 4509045: should release capture only if it is set by SetDragCapture */ 276 void AwtChoice::ReleaseDragCapture(UINT flags) 277 { 278 if ((::GetCapture() == GetHWnd()) && ((flags & ALL_MK_BUTTONS) == 0) && mouseCapture) { 279 ::ReleaseCapture(); 280 mouseCapture = FALSE; 281 } 282 } 283 284 void AwtChoice::Reshape(int x, int y, int w, int h) 285 { 286 // Choice component height is fixed (when rolled up) 287 // so vertically center the choice in it's bounding box 288 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 289 jobject target = GetTarget(env); 290 jobject parent = env->GetObjectField(target, AwtComponent::parentID); 291 RECT rc; 292 293 int fieldHeight = GetFieldHeight(); 294 if ((parent != NULL && env->GetObjectField(parent, AwtContainer::layoutMgrID) != NULL) && 295 fieldHeight > 0 && fieldHeight < h) { 296 y += (h - fieldHeight) / 2; 297 } 298 299 /* Fix for 4783342 300 * Choice should ignore reshape on height changes, 301 * as height is dependent on Font size only. 302 */ 303 AwtComponent* awtParent = GetParent(); 304 BOOL bReshape = true; 305 if (awtParent != NULL) { 306 ::GetWindowRect(GetHWnd(), &rc); 307 int oldW = rc.right - rc.left; 308 RECT parentRc; 309 ::GetWindowRect(awtParent->GetHWnd(), &parentRc); 310 int oldX = rc.left - parentRc.left; 311 int oldY = rc.top - parentRc.top; 312 bReshape = (x != oldX || y != oldY || w != oldW); 313 } 314 315 if (bReshape) 316 { 317 int totalHeight = GetTotalHeight(); 318 AwtComponent::Reshape(x, y, w, totalHeight); 319 } 320 321 /* Bug 4255631 Solaris: Size returned by Choice.getSize() does not match 322 * actual size 323 * Fix: Set the Choice to its actual size in the component. 324 */ 325 ::GetClientRect(GetHWnd(), &rc); 326 env->SetIntField(target, AwtComponent::widthID, (jint)rc.right); 327 env->SetIntField(target, AwtComponent::heightID, (jint)rc.bottom); 328 329 env->DeleteLocalRef(target); 330 env->DeleteLocalRef(parent); 331 } 332 333 jobject AwtChoice::PreferredItemSize(JNIEnv *env) 334 { 335 jobject dimension = JNU_CallMethodByName(env, NULL, GetPeer(env), 336 "preferredSize", 337 "()Ljava/awt/Dimension;").l; 338 DASSERT(!safe_ExceptionOccurred(env)); 339 CHECK_NULL_RETURN(dimension, 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 selectedIndex = (int)SendMessage(CB_GETCURSEL); 442 443 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 444 jobject target = GetTarget(env); 445 int previousIndex = env->GetIntField(target, selectedIndexID); 446 447 if (selectedIndex != CB_ERR && selectedIndex != previousIndex){ 448 DoCallback("handleAction", "(I)V", selectedIndex); 449 } 450 } else if (notifyCode == CBN_DROPDOWN) { 451 452 if (m_hList == NULL) { 453 COMBOBOXINFO cbi; 454 cbi.cbSize = sizeof(COMBOBOXINFO); 455 ::GetComboBoxInfo(GetHWnd(), &cbi); 456 m_hList = cbi.hwndList; 457 m_listDefWindowProc = ComCtl32Util::GetInstance().SubclassHWND(m_hList, ListWindowProc); 458 DASSERT(::GetWindowLongPtr(m_hList, GWLP_USERDATA) == NULL); 459 ::SetWindowLongPtr(m_hList, GWLP_USERDATA, (LONG_PTR)this); 460 } 461 sm_isMouseMoveInList = FALSE; 462 463 // Clicking in the dropdown list steals focus from the proxy. 464 // So, set the focus-restore flag up. 465 SetRestoreFocus(TRUE); 466 } else if (notifyCode == CBN_CLOSEUP) { 467 SetRestoreFocus(FALSE); 468 } 469 return mrDoDefault; 470 } 471 472 MsgRouting 473 AwtChoice::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo) 474 { 475 DrawListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), drawInfo); 476 return mrConsume; 477 } 478 479 MsgRouting 480 AwtChoice::OwnerMeasureItem(UINT /*ctrlId*/, MEASUREITEMSTRUCT& measureInfo) 481 { 482 MeasureListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), measureInfo); 483 return mrConsume; 484 } 485 486 /* Bug #4338368: when a choice loses focus, it triggers spurious MouseUp event, 487 * even if the focus was lost due to TAB key pressing 488 */ 489 490 MsgRouting 491 AwtChoice::WmKillFocus(HWND hWndGotFocus) 492 { 493 skipNextMouseUp = TRUE; 494 return AwtComponent::WmKillFocus(hWndGotFocus); 495 } 496 497 MsgRouting 498 AwtChoice::WmMouseUp(UINT flags, int x, int y, int button) 499 { 500 if (skipNextMouseUp) { 501 skipNextMouseUp = FALSE; 502 return mrDoDefault; 503 } 504 return AwtComponent::WmMouseUp(flags, x, y, button); 505 } 506 507 MsgRouting AwtChoice::HandleEvent(MSG *msg, BOOL synthetic) 508 { 509 if (IsFocusingMouseMessage(msg)) { 510 SendMessage(CB_SHOWDROPDOWN, ~SendMessage(CB_GETDROPPEDSTATE, 0, 0), 0); 511 delete msg; 512 return mrConsume; 513 } 514 // To simulate the native behavior, we close the list on WM_LBUTTONUP if 515 // WM_MOUSEMOVE has been dedected on the list since it has been dropped down. 516 if (msg->message == WM_LBUTTONUP && SendMessage(CB_GETDROPPEDSTATE, 0, 0) && 517 sm_isMouseMoveInList) 518 { 519 SendMessage(CB_SHOWDROPDOWN, FALSE, 0); 520 } 521 return AwtComponent::HandleEvent(msg, synthetic); 522 } 523 524 BOOL AwtChoice::InheritsNativeMouseWheelBehavior() {return true;} 525 526 void AwtChoice::_Reshape(void *param) 527 { 528 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 529 530 ReshapeStruct *rs = (ReshapeStruct *)param; 531 jobject choice = rs->choice; 532 jint x = rs->x; 533 jint y = rs->y; 534 jint width = rs->width; 535 jint height = rs->height; 536 537 AwtChoice *c = NULL; 538 539 PDATA pData; 540 JNI_CHECK_PEER_GOTO(choice, done); 541 542 c = (AwtChoice *)pData; 543 if (::IsWindow(c->GetHWnd())) 544 { 545 c->Reshape(x, y, width, height); 546 c->VerifyState(); 547 } 548 549 done: 550 env->DeleteGlobalRef(choice); 551 552 delete rs; 553 } 554 555 void AwtChoice::_Select(void *param) 556 { 557 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 558 559 SelectStruct *ss = (SelectStruct *)param; 560 jobject choice = ss->choice; 561 jint index = ss->index; 562 563 AwtChoice *c = NULL; 564 565 PDATA pData; 566 JNI_CHECK_PEER_GOTO(choice, done); 567 568 c = (AwtChoice *)pData; 569 if (::IsWindow(c->GetHWnd())) 570 { 571 c->SendMessage(CB_SETCURSEL, index); 572 // c->VerifyState(); 573 } 574 575 done: 576 env->DeleteGlobalRef(choice); 577 578 delete ss; 579 } 580 581 void AwtChoice::_AddItems(void *param) 582 { 583 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 584 585 AddItemsStruct *ais = (AddItemsStruct *)param; 586 jobject choice = ais->choice; 587 jobjectArray items = ais->items; 588 jint index = ais->index; 589 590 AwtChoice *c = NULL; 591 592 PDATA pData; 593 JNI_CHECK_PEER_GOTO(choice, done); 594 JNI_CHECK_NULL_GOTO(items, "null items", done); 595 596 c = (AwtChoice *)pData; 597 if (::IsWindow(c->GetHWnd())) 598 { 599 jsize i; 600 int itemCount = env->GetArrayLength(items); 601 if (itemCount > 0) { 602 c->SendMessage(WM_SETREDRAW, (WPARAM)FALSE, 0); 603 for (i = 0; i < itemCount; i++) 604 { 605 jstring item = (jstring)env->GetObjectArrayElement(items, i); 606 if (env->ExceptionCheck()) goto done; 607 if (item == NULL) goto next_elem; 608 c->SendMessage(CB_INSERTSTRING, index + i, JavaStringBuffer(env, item)); 609 env->DeleteLocalRef(item); 610 next_elem: 611 ; 612 } 613 c->SendMessage(WM_SETREDRAW, (WPARAM)TRUE, 0); 614 InvalidateRect(c->GetHWnd(), NULL, TRUE); 615 c->ResetDropDownHeight(); 616 c->VerifyState(); 617 } 618 } 619 620 done: 621 env->DeleteGlobalRef(choice); 622 env->DeleteGlobalRef(items); 623 624 delete ais; 625 } 626 627 void AwtChoice::_Remove(void *param) 628 { 629 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 630 631 RemoveStruct *rs = (RemoveStruct *)param; 632 jobject choice = rs->choice; 633 jint index = rs->index; 634 635 AwtChoice *c = NULL; 636 637 PDATA pData; 638 JNI_CHECK_PEER_GOTO(choice, done); 639 640 c = (AwtChoice *)pData; 641 if (::IsWindow(c->GetHWnd())) 642 { 643 c->SendMessage(CB_DELETESTRING, index, 0); 644 c->ResetDropDownHeight(); 645 c->VerifyState(); 646 } 647 648 done: 649 env->DeleteGlobalRef(choice); 650 651 delete rs; 652 } 653 654 void AwtChoice::_RemoveAll(void *param) 655 { 656 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 657 658 jobject choice = (jobject)param; 659 660 AwtChoice *c = NULL; 661 662 PDATA pData; 663 JNI_CHECK_PEER_GOTO(choice, done); 664 665 c = (AwtChoice *)pData; 666 if (::IsWindow(c->GetHWnd())) 667 { 668 c->SendMessage(CB_RESETCONTENT, 0, 0); 669 c->ResetDropDownHeight(); 670 c->VerifyState(); 671 } 672 673 done: 674 env->DeleteGlobalRef(choice); 675 } 676 677 void AwtChoice::_CloseList(void *param) 678 { 679 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 680 681 jobject choice = (jobject)param; 682 683 AwtChoice *c = NULL; 684 685 PDATA pData; 686 JNI_CHECK_PEER_GOTO(choice, done); 687 688 c = (AwtChoice *)pData; 689 if (::IsWindow(c->GetHWnd()) && c->SendMessage(CB_GETDROPPEDSTATE, 0, 0)) { 690 c->SendMessage(CB_SHOWDROPDOWN, FALSE, 0); 691 } 692 693 done: 694 env->DeleteGlobalRef(choice); 695 } 696 697 /************************************************************************ 698 * WChoicePeer native methods 699 */ 700 701 extern "C" { 702 703 JNIEXPORT void JNICALL 704 Java_java_awt_Choice_initIDs(JNIEnv *env, jclass cls) 705 { 706 TRY; 707 selectedIndexID = env->GetFieldID(cls, "selectedIndex", "I"); 708 DASSERT(selectedIndexID); 709 CATCH_BAD_ALLOC; 710 } 711 712 /* 713 * Class: sun_awt_windows_WChoicePeer 714 * Method: select 715 * Signature: (I)V 716 */ 717 JNIEXPORT void JNICALL 718 Java_sun_awt_windows_WChoicePeer_select(JNIEnv *env, jobject self, 719 jint index) 720 { 721 TRY; 722 723 SelectStruct *ss = new SelectStruct; 724 ss->choice = env->NewGlobalRef(self); 725 ss->index = index; 726 727 AwtToolkit::GetInstance().SyncCall(AwtChoice::_Select, ss); 728 // global refs and ss are removed in _Select 729 730 CATCH_BAD_ALLOC; 731 } 732 733 /* 734 * Class: sun_awt_windows_WChoicePeer 735 * Method: remove 736 * Signature: (I)V 737 */ 738 JNIEXPORT void JNICALL 739 Java_sun_awt_windows_WChoicePeer_remove(JNIEnv *env, jobject self, 740 jint index) 741 { 742 TRY; 743 744 RemoveStruct *rs = new RemoveStruct; 745 rs->choice = env->NewGlobalRef(self); 746 rs->index = index; 747 748 AwtToolkit::GetInstance().SyncCall(AwtChoice::_Remove, rs); 749 // global ref and rs are deleted in _Remove 750 751 CATCH_BAD_ALLOC; 752 } 753 754 /* 755 * Class: sun_awt_windows_WChoicePeer 756 * Method: removeAll 757 * Signature: ()V 758 */ 759 JNIEXPORT void JNICALL 760 Java_sun_awt_windows_WChoicePeer_removeAll(JNIEnv *env, jobject self) 761 { 762 TRY; 763 764 jobject selfGlobalRef = env->NewGlobalRef(self); 765 766 AwtToolkit::GetInstance().SyncCall(AwtChoice::_RemoveAll, (void *)selfGlobalRef); 767 // selfGlobalRef is deleted in _RemoveAll 768 769 CATCH_BAD_ALLOC; 770 } 771 772 /* 773 * Class: sun_awt_windows_WChoicePeer 774 * Method: addItems 775 * Signature: ([Ljava/lang/String;I)V 776 */ 777 JNIEXPORT void JNICALL 778 Java_sun_awt_windows_WChoicePeer_addItems(JNIEnv *env, jobject self, 779 jobjectArray items, jint index) 780 { 781 TRY; 782 783 AddItemsStruct *ais = new AddItemsStruct; 784 ais->choice = env->NewGlobalRef(self); 785 ais->items = (jobjectArray)env->NewGlobalRef(items); 786 ais->index = index; 787 788 AwtToolkit::GetInstance().SyncCall(AwtChoice::_AddItems, ais); 789 // global refs and ais are deleted in _AddItems 790 791 CATCH_BAD_ALLOC; 792 } 793 794 /* 795 * Class: sun_awt_windows_WChoicePeer 796 * Method: reshape 797 * Signature: (IIII)V 798 */ 799 JNIEXPORT void JNICALL 800 Java_sun_awt_windows_WChoicePeer_reshape(JNIEnv *env, jobject self, 801 jint x, jint y, 802 jint width, jint height) 803 { 804 TRY; 805 806 ReshapeStruct *rs = new ReshapeStruct; 807 rs->choice = env->NewGlobalRef(self); 808 rs->x = x; 809 rs->y = y; 810 rs->width = width; 811 rs->height = height; 812 813 AwtToolkit::GetInstance().SyncCall(AwtChoice::_Reshape, rs); 814 // global ref and rs are deleted in _Reshape 815 816 CATCH_BAD_ALLOC; 817 } 818 819 /* 820 * Class: sun_awt_windows_WChoicePeer 821 * Method: create 822 * Signature: (Lsun/awt/windows/WComponentPeer;)V 823 */ 824 JNIEXPORT void JNICALL 825 Java_sun_awt_windows_WChoicePeer_create(JNIEnv *env, jobject self, 826 jobject parent) 827 { 828 TRY; 829 830 AwtToolkit::CreateComponent(self, parent, 831 (AwtToolkit::ComponentFactory) 832 AwtChoice::Create); 833 834 CATCH_BAD_ALLOC; 835 } 836 837 /* 838 * Class: sun_awt_windows_WChoicePeer 839 * Method: closeList 840 * Signature: ()V 841 */ 842 JNIEXPORT void JNICALL 843 Java_sun_awt_windows_WChoicePeer_closeList(JNIEnv *env, jobject self) 844 { 845 TRY; 846 847 jobject selfGlobalRef = env->NewGlobalRef(self); 848 849 AwtToolkit::GetInstance().SyncCall(AwtChoice::_CloseList, (void *)selfGlobalRef); 850 // global ref is deleted in _CloseList 851 852 CATCH_BAD_ALLOC; 853 } 854 } /* extern "C" */ 855 856 857 /************************************************************************ 858 * Diagnostic routines 859 */ 860 861 #ifdef DEBUG 862 863 void AwtChoice::VerifyState() 864 { 865 if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) { 866 return; 867 } 868 869 if (m_callbacksEnabled == FALSE) { 870 /* Component is not fully setup yet. */ 871 return; 872 } 873 874 AwtComponent::VerifyState(); 875 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 876 if (env->PushLocalFrame(1) < 0) 877 return; 878 879 jobject target = GetTarget(env); 880 881 // To avoid possibly running client code on the toolkit thread, don't 882 // do the following checks if we're running on the toolkit thread. 883 if (AwtToolkit::MainThread() != ::GetCurrentThreadId()) { 884 // Compare number of items. 885 int nTargetItems = JNU_CallMethodByName(env, NULL, target, 886 "countItems", "()I").i; 887 DASSERT(!safe_ExceptionOccurred(env)); 888 int nPeerItems = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0, 0); 889 DASSERT(nTargetItems == nPeerItems); 890 891 // Compare selection 892 int targetIndex = JNU_CallMethodByName(env, NULL, target, 893 "getSelectedIndex", "()I").i; 894 DASSERT(!safe_ExceptionOccurred(env)); 895 int peerCurSel = (int)::SendMessage(GetHWnd(), CB_GETCURSEL, 0, 0); 896 DASSERT(targetIndex == peerCurSel); 897 } 898 env->PopLocalFrame(0); 899 } 900 #endif //DEBUG