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