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