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
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 "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
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 // 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
GetFieldHeight()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
GetTotalHeight()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.
ResetDropDownHeight()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 */
SetDragCapture(UINT flags)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 */
ReleaseDragCapture(UINT flags)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
Reshape(int x,int y,int w,int h)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
PreferredItemSize(JNIEnv * env)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
SetFont(AwtFont * font)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
ListWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)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
WmNotify(UINT notifyCode)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
OwnerDrawItem(UINT,DRAWITEMSTRUCT & drawInfo)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
OwnerMeasureItem(UINT,MEASUREITEMSTRUCT & measureInfo)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
WmKillFocus(HWND hWndGotFocus)491 AwtChoice::WmKillFocus(HWND hWndGotFocus)
492 {
493 skipNextMouseUp = TRUE;
494 return AwtComponent::WmKillFocus(hWndGotFocus);
495 }
496
497 MsgRouting
WmMouseUp(UINT flags,int x,int y,int button)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
HandleEvent(MSG * msg,BOOL synthetic)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
InheritsNativeMouseWheelBehavior()524 BOOL AwtChoice::InheritsNativeMouseWheelBehavior() {return true;}
525
_Reshape(void * param)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
_Select(void * param)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
_AddItems(void * param)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
_Remove(void * param)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
_RemoveAll(void * param)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
_CloseList(void * param)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
Java_java_awt_Choice_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_windows_WChoicePeer_select(JNIEnv * env,jobject self,jint index)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
Java_sun_awt_windows_WChoicePeer_remove(JNIEnv * env,jobject self,jint index)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
Java_sun_awt_windows_WChoicePeer_removeAll(JNIEnv * env,jobject self)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
Java_sun_awt_windows_WChoicePeer_addItems(JNIEnv * env,jobject self,jobjectArray items,jint index)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
Java_sun_awt_windows_WChoicePeer_reshape(JNIEnv * env,jobject self,jint x,jint y,jint width,jint height)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
Java_sun_awt_windows_WChoicePeer_create(JNIEnv * env,jobject self,jobject parent)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
Java_sun_awt_windows_WChoicePeer_closeList(JNIEnv * env,jobject self)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
VerifyState()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
901