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
AwtChoice()90 AwtChoice::AwtChoice() {
91 m_hList = NULL;
92 m_listDefWindowProc = NULL;
93 }
94
GetClassName()95 LPCTSTR AwtChoice::GetClassName() {
96 return TEXT("COMBOBOX"); /* System provided combobox class */
97 }
98
Dispose()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
Create(jobject peer,jobject parent)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
GetDropDownHeight()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
GetFieldHeight()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
GetTotalHeight()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.
ResetDropDownHeight()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 */
SetDragCapture(UINT flags)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 */
ReleaseDragCapture(UINT flags)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
Reshape(int x,int y,int w,int h)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
PreferredItemSize(JNIEnv * env)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
SetFont(AwtFont * font)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
ListWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)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
WmNotify(UINT notifyCode)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
OwnerDrawItem(UINT,DRAWITEMSTRUCT & drawInfo)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
OwnerMeasureItem(UINT,MEASUREITEMSTRUCT & measureInfo)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
WmKillFocus(HWND hWndGotFocus)490 AwtChoice::WmKillFocus(HWND hWndGotFocus)
491 {
492 skipNextMouseUp = TRUE;
493 return AwtComponent::WmKillFocus(hWndGotFocus);
494 }
495
496 MsgRouting
WmMouseUp(UINT flags,int x,int y,int button)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
HandleEvent(MSG * msg,BOOL synthetic)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
InheritsNativeMouseWheelBehavior()523 BOOL AwtChoice::InheritsNativeMouseWheelBehavior() {return true;}
524
_Reshape(void * param)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
_Select(void * param)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
_AddItems(void * param)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
_Remove(void * param)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
_RemoveAll(void * param)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
_CloseList(void * param)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
Java_java_awt_Choice_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_windows_WChoicePeer_select(JNIEnv * env,jobject self,jint index)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
Java_sun_awt_windows_WChoicePeer_remove(JNIEnv * env,jobject self,jint index)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
Java_sun_awt_windows_WChoicePeer_removeAll(JNIEnv * env,jobject self)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
Java_sun_awt_windows_WChoicePeer_addItems(JNIEnv * env,jobject self,jobjectArray items,jint index)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
Java_sun_awt_windows_WChoicePeer_reshape(JNIEnv * env,jobject self,jint x,jint y,jint width,jint height)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
Java_sun_awt_windows_WChoicePeer_create(JNIEnv * env,jobject self,jobject parent)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
Java_sun_awt_windows_WChoicePeer_closeList(JNIEnv * env,jobject self)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
VerifyState()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
900