| /* |
| * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #include <windowsx.h> |
| |
| #include "awt_Toolkit.h" |
| #include "awt_Choice.h" |
| #include "awt_Canvas.h" |
| |
| #include "awt_Dimension.h" |
| #include "awt_Container.h" |
| |
| #include "ComCtl32Util.h" |
| |
| #include <java_awt_Toolkit.h> |
| #include <java_awt_FontMetrics.h> |
| #include <java_awt_event_InputEvent.h> |
| |
| /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. |
| */ |
| |
| /************************************************************************/ |
| // Struct for _Reshape() method |
| struct ReshapeStruct { |
| jobject choice; |
| jint x, y; |
| jint width, height; |
| }; |
| // Struct for _Select() method |
| struct SelectStruct { |
| jobject choice; |
| jint index; |
| }; |
| // Struct for _AddItems() method |
| struct AddItemsStruct { |
| jobject choice; |
| jobjectArray items; |
| jint index; |
| }; |
| // Struct for _Remove() method |
| struct RemoveStruct { |
| jobject choice; |
| jint index; |
| }; |
| |
| /************************************************************************/ |
| |
| /* Bug #4509045: set if SetDragCapture captured mouse */ |
| |
| BOOL AwtChoice::mouseCapture = FALSE; |
| |
| /* Bug #4338368: consume the spurious MouseUp when the choice loses focus */ |
| |
| BOOL AwtChoice::skipNextMouseUp = FALSE; |
| |
| BOOL AwtChoice::sm_isMouseMoveInList = FALSE; |
| |
| static const UINT MINIMUM_NUMBER_OF_VISIBLE_ITEMS = 8; |
| |
| /************************************************************************* |
| * AwtChoice class methods |
| */ |
| |
| AwtChoice::AwtChoice() { |
| m_hList = NULL; |
| m_listDefWindowProc = NULL; |
| } |
| |
| LPCTSTR AwtChoice::GetClassName() { |
| return TEXT("COMBOBOX"); /* System provided combobox class */ |
| } |
| |
| void AwtChoice::Dispose() { |
| if (m_hList != NULL && m_listDefWindowProc != NULL) { |
| ComCtl32Util::GetInstance().UnsubclassHWND(m_hList, ListWindowProc, m_listDefWindowProc); |
| } |
| AwtComponent::Dispose(); |
| } |
| |
| AwtChoice* AwtChoice::Create(jobject peer, jobject parent) { |
| |
| |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| jobject target = NULL; |
| AwtChoice* c = NULL; |
| RECT rc; |
| |
| try { |
| if (env->EnsureLocalCapacity(1) < 0) { |
| return NULL; |
| } |
| AwtCanvas* awtParent; |
| |
| JNI_CHECK_NULL_GOTO(parent, "null parent", done); |
| |
| awtParent = (AwtCanvas*)JNI_GET_PDATA(parent); |
| JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done); |
| |
| target = env->GetObjectField(peer, AwtObject::targetID); |
| JNI_CHECK_NULL_GOTO(target, "null target", done); |
| |
| c = new AwtChoice(); |
| |
| { |
| DWORD style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | |
| CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED; |
| DWORD exStyle = 0; |
| if (GetRTL()) { |
| exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR; |
| if (GetRTLReadingOrder()) |
| exStyle |= WS_EX_RTLREADING; |
| } |
| |
| /* |
| * In OWNER_DRAW, the size of the edit control part of the |
| * choice must be determinded in its creation, when the parent |
| * cannot get the choice's instance from its handle. So |
| * record the pair of the ID and the instance of the choice. |
| */ |
| UINT myId = awtParent->CreateControlID(); |
| DASSERT(myId > 0); |
| c->m_myControlID = myId; |
| awtParent->PushChild(myId, c); |
| |
| jint x = env->GetIntField(target, AwtComponent::xID); |
| jint y = env->GetIntField(target, AwtComponent::yID); |
| jint width = env->GetIntField(target, AwtComponent::widthID); |
| jint height = env->GetIntField(target, AwtComponent::heightID); |
| |
| jobject dimension = JNU_CallMethodByName(env, NULL, peer, |
| "preferredSize", |
| "()Ljava/awt/Dimension;").l; |
| DASSERT(!safe_ExceptionOccurred(env)); |
| |
| if (dimension != NULL && width == 0) { |
| width = env->GetIntField(dimension, AwtDimension::widthID); |
| } |
| c->CreateHWnd(env, L"", style, exStyle, |
| x, y, width, height, |
| awtParent->GetHWnd(), |
| reinterpret_cast<HMENU>(static_cast<INT_PTR>(myId)), |
| ::GetSysColor(COLOR_WINDOWTEXT), |
| ::GetSysColor(COLOR_WINDOW), |
| peer); |
| |
| /* suppress inheriting parent's color. */ |
| c->m_backgroundColorSet = TRUE; |
| c->UpdateBackground(env, target); |
| |
| /* Bug 4255631 Solaris: Size returned by Choice.getSize() does not match |
| * actual size |
| * Fix: Set the Choice to its actual size in the component. |
| */ |
| ::GetClientRect(c->GetHWnd(), &rc); |
| env->SetIntField(target, AwtComponent::widthID, (jint) rc.right); |
| env->SetIntField(target, AwtComponent::heightID, (jint) rc.bottom); |
| |
| if (IS_WINXP) { |
| ::SendMessage(c->GetHWnd(), CB_SETMINVISIBLE, (WPARAM) MINIMUM_NUMBER_OF_VISIBLE_ITEMS, 0); |
| } |
| |
| env->DeleteLocalRef(dimension); |
| } |
| } catch (...) { |
| env->DeleteLocalRef(target); |
| throw; |
| } |
| |
| done: |
| env->DeleteLocalRef(target); |
| |
| return c; |
| } |
| |
| // calculate height of drop-down list part of the combobox |
| // to show all the items up to a maximum of eight |
| int AwtChoice::GetDropDownHeight() |
| { |
| int itemHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)0,0); |
| int numItemsToShow = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0,0); |
| numItemsToShow = min(MINIMUM_NUMBER_OF_VISIBLE_ITEMS, numItemsToShow); |
| // drop-down height snaps to nearest line, so add a |
| // fudge factor of 1/2 line to ensure last line shows |
| return itemHeight*numItemsToShow + itemHeight/2; |
| } |
| |
| // get the height of the field portion of the combobox |
| int AwtChoice::GetFieldHeight() |
| { |
| int fieldHeight; |
| int borderHeight; |
| fieldHeight =(int)::SendMessage(GetHWnd(), CB_GETITEMHEIGHT, (UINT)-1, 0); |
| // add top and bottom border lines; border size is different for |
| // Win 4.x (3d edge) vs 3.x (1 pixel line) |
| borderHeight = ::GetSystemMetrics(SM_CYEDGE); |
| fieldHeight += borderHeight*2; |
| return fieldHeight; |
| } |
| |
| // gets the total height of the combobox, including drop down |
| int AwtChoice::GetTotalHeight() |
| { |
| int dropHeight = GetDropDownHeight(); |
| int fieldHeight = GetFieldHeight(); |
| int totalHeight; |
| |
| // border on drop-down portion is always non-3d (so don't use SM_CYEDGE) |
| int borderHeight = ::GetSystemMetrics(SM_CYBORDER); |
| // total height = drop down height + field height + top+bottom drop down border lines |
| totalHeight = dropHeight + fieldHeight +borderHeight*2; |
| return totalHeight; |
| } |
| |
| // Recalculate and set the drop-down height for the Choice. |
| void AwtChoice::ResetDropDownHeight() |
| { |
| RECT rcWindow; |
| |
| ::GetWindowRect(GetHWnd(), &rcWindow); |
| // resize the drop down to accomodate added/removed items |
| int totalHeight = GetTotalHeight(); |
| ::SetWindowPos(GetHWnd(), NULL, |
| 0, 0, rcWindow.right - rcWindow.left, totalHeight, |
| SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); |
| } |
| |
| /* Fix for the bug 4327666: set the capture for middle |
| and right mouse buttons, but leave left button alone */ |
| void AwtChoice::SetDragCapture(UINT flags) |
| { |
| if ((flags & MK_LBUTTON) != 0) { |
| if ((::GetCapture() == GetHWnd()) && mouseCapture) { |
| /* On MK_LBUTTON ComboBox captures mouse itself |
| so we should release capture and clear flag to |
| prevent releasing capture by ReleaseDragCapture |
| */ |
| ::ReleaseCapture(); |
| mouseCapture = FALSE; |
| } |
| return; |
| } |
| |
| // don't want to interfere with other controls |
| if (::GetCapture() == NULL) { |
| ::SetCapture(GetHWnd()); |
| mouseCapture = TRUE; |
| } |
| } |
| |
| /* Fix for Bug 4509045: should release capture only if it is set by SetDragCapture */ |
| void AwtChoice::ReleaseDragCapture(UINT flags) |
| { |
| if ((::GetCapture() == GetHWnd()) && ((flags & ALL_MK_BUTTONS) == 0) && mouseCapture) { |
| ::ReleaseCapture(); |
| mouseCapture = FALSE; |
| } |
| } |
| |
| void AwtChoice::Reshape(int x, int y, int w, int h) |
| { |
| // Choice component height is fixed (when rolled up) |
| // so vertically center the choice in it's bounding box |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject target = GetTarget(env); |
| jobject parent = env->GetObjectField(target, AwtComponent::parentID); |
| RECT rc; |
| |
| int fieldHeight = GetFieldHeight(); |
| if ((parent != NULL && env->GetObjectField(parent, AwtContainer::layoutMgrID) != NULL) && |
| fieldHeight > 0 && fieldHeight < h) { |
| y += (h - fieldHeight) / 2; |
| } |
| |
| /* Fix for 4783342 |
| * Choice should ignore reshape on height changes, |
| * as height is dependent on Font size only. |
| */ |
| AwtComponent* awtParent = GetParent(); |
| BOOL bReshape = true; |
| if (awtParent != NULL) { |
| ::GetWindowRect(GetHWnd(), &rc); |
| int oldW = rc.right - rc.left; |
| RECT parentRc; |
| ::GetWindowRect(awtParent->GetHWnd(), &parentRc); |
| int oldX = rc.left - parentRc.left; |
| int oldY = rc.top - parentRc.top; |
| bReshape = (x != oldX || y != oldY || w != oldW); |
| } |
| |
| if (bReshape) |
| { |
| int totalHeight = GetTotalHeight(); |
| AwtComponent::Reshape(x, y, w, totalHeight); |
| } |
| |
| /* Bug 4255631 Solaris: Size returned by Choice.getSize() does not match |
| * actual size |
| * Fix: Set the Choice to its actual size in the component. |
| */ |
| ::GetClientRect(GetHWnd(), &rc); |
| env->SetIntField(target, AwtComponent::widthID, (jint)rc.right); |
| env->SetIntField(target, AwtComponent::heightID, (jint)rc.bottom); |
| |
| env->DeleteLocalRef(target); |
| env->DeleteLocalRef(parent); |
| } |
| |
| jobject AwtChoice::PreferredItemSize(JNIEnv *env) |
| { |
| jobject dimension = JNU_CallMethodByName(env, NULL, GetPeer(env), |
| "preferredSize", |
| "()Ljava/awt/Dimension;").l; |
| DASSERT(!safe_ExceptionOccurred(env)); |
| if (dimension == NULL) { |
| return NULL; |
| } |
| /* This size is window size of choice and it's too big for each |
| * drop down item height. |
| */ |
| env->SetIntField(dimension, AwtDimension::heightID, |
| GetFontHeight(env)); |
| return dimension; |
| } |
| |
| void AwtChoice::SetFont(AwtFont* font) |
| { |
| AwtComponent::SetFont(font); |
| |
| //Get the text metrics and change the height of each item. |
| HDC hDC = ::GetDC(GetHWnd()); |
| DASSERT(hDC != NULL); |
| TEXTMETRIC tm; |
| |
| HANDLE hFont = font->GetHFont(); |
| VERIFY(::SelectObject(hDC, hFont) != NULL); |
| VERIFY(::GetTextMetrics(hDC, &tm)); |
| long h = tm.tmHeight + tm.tmExternalLeading; |
| VERIFY(::ReleaseDC(GetHWnd(), hDC) != 0); |
| |
| int nCount = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0, 0); |
| for(int i = 0; i < nCount; ++i) { |
| VERIFY(::SendMessage(GetHWnd(), CB_SETITEMHEIGHT, i, MAKELPARAM(h, 0)) != CB_ERR); |
| } |
| //Change the height of the Edit Box. |
| VERIFY(::SendMessage(GetHWnd(), CB_SETITEMHEIGHT, (UINT)-1, |
| MAKELPARAM(h, 0)) != CB_ERR); |
| |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| jobject target = GetTarget(env); |
| jint height = env->GetIntField(target, AwtComponent::heightID); |
| |
| Reshape(env->GetIntField(target, AwtComponent::xID), |
| env->GetIntField(target, AwtComponent::yID), |
| env->GetIntField(target, AwtComponent::widthID), |
| h); |
| |
| env->DeleteLocalRef(target); |
| } |
| |
| static int lastClickX = -1; |
| static int lastClickY = -1; |
| |
| LRESULT CALLBACK AwtChoice::ListWindowProc(HWND hwnd, UINT message, |
| WPARAM wParam, LPARAM lParam) |
| { |
| /* |
| * We don't pass the choice WM_LBUTTONDOWN message. As the result the choice's list |
| * doesn't forward mouse messages it captures. Below we do forward what we need. |
| */ |
| |
| TRY; |
| |
| DASSERT(::IsWindow(hwnd)); |
| |
| switch (message) { |
| case WM_LBUTTONDOWN: { |
| DWORD curPos = ::GetMessagePos(); |
| lastClickX = GET_X_LPARAM(curPos); |
| lastClickY = GET_Y_LPARAM(curPos); |
| break; |
| } |
| case WM_MOUSEMOVE: { |
| RECT rect; |
| ::GetClientRect(hwnd, &rect); |
| |
| POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; |
| if (::PtInRect(&rect, pt)) { |
| sm_isMouseMoveInList = TRUE; |
| } |
| |
| POINT lastPt = {lastClickX, lastClickY}; |
| ::ScreenToClient(hwnd, &lastPt); |
| if (::PtInRect(&rect, lastPt)) { |
| break; // ignore when dragging inside the list |
| } |
| } |
| case WM_LBUTTONUP: { |
| lastClickX = -1; |
| lastClickY = -1; |
| |
| AwtChoice *c = (AwtChoice *)::GetWindowLongPtr(hwnd, GWLP_USERDATA); |
| if (c != NULL) { |
| // forward the msg to the choice |
| c->WindowProc(message, wParam, lParam); |
| } |
| } |
| } |
| return ComCtl32Util::GetInstance().DefWindowProc(NULL, hwnd, message, wParam, lParam); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| |
| MsgRouting AwtChoice::WmNotify(UINT notifyCode) |
| { |
| if (notifyCode == CBN_SELCHANGE) { |
| int itemSelect = (int)SendMessage(CB_GETCURSEL); |
| if (itemSelect != CB_ERR){ |
| DoCallback("handleAction", "(I)V", itemSelect); |
| } |
| } else if (notifyCode == CBN_DROPDOWN) { |
| |
| if (m_hList == NULL) { |
| COMBOBOXINFO cbi; |
| cbi.cbSize = sizeof(COMBOBOXINFO); |
| ::GetComboBoxInfo(GetHWnd(), &cbi); |
| m_hList = cbi.hwndList; |
| m_listDefWindowProc = ComCtl32Util::GetInstance().SubclassHWND(m_hList, ListWindowProc); |
| DASSERT(::GetWindowLongPtr(m_hList, GWLP_USERDATA) == NULL); |
| ::SetWindowLongPtr(m_hList, GWLP_USERDATA, (LONG_PTR)this); |
| } |
| sm_isMouseMoveInList = FALSE; |
| |
| // Clicking in the dropdown list steals focus from the proxy. |
| // So, set the focus-restore flag up. |
| SetRestoreFocus(TRUE); |
| } else if (notifyCode == CBN_CLOSEUP) { |
| SetRestoreFocus(FALSE); |
| } |
| return mrDoDefault; |
| } |
| |
| MsgRouting |
| AwtChoice::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo) |
| { |
| DrawListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), drawInfo); |
| return mrConsume; |
| } |
| |
| MsgRouting |
| AwtChoice::OwnerMeasureItem(UINT /*ctrlId*/, MEASUREITEMSTRUCT& measureInfo) |
| { |
| MeasureListItem((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), measureInfo); |
| return mrConsume; |
| } |
| |
| /* Bug #4338368: when a choice loses focus, it triggers spurious MouseUp event, |
| * even if the focus was lost due to TAB key pressing |
| */ |
| |
| MsgRouting |
| AwtChoice::WmKillFocus(HWND hWndGotFocus) |
| { |
| skipNextMouseUp = TRUE; |
| return AwtComponent::WmKillFocus(hWndGotFocus); |
| } |
| |
| MsgRouting |
| AwtChoice::WmMouseUp(UINT flags, int x, int y, int button) |
| { |
| if (skipNextMouseUp) { |
| skipNextMouseUp = FALSE; |
| return mrDoDefault; |
| } |
| return AwtComponent::WmMouseUp(flags, x, y, button); |
| } |
| |
| MsgRouting AwtChoice::HandleEvent(MSG *msg, BOOL synthetic) |
| { |
| if (IsFocusingMouseMessage(msg)) { |
| SendMessage(CB_SHOWDROPDOWN, ~SendMessage(CB_GETDROPPEDSTATE, 0, 0), 0); |
| delete msg; |
| return mrConsume; |
| } |
| // To simulate the native behavior, we close the list on WM_LBUTTONUP if |
| // WM_MOUSEMOVE has been dedected on the list since it has been dropped down. |
| if (msg->message == WM_LBUTTONUP && SendMessage(CB_GETDROPPEDSTATE, 0, 0) && |
| sm_isMouseMoveInList) |
| { |
| SendMessage(CB_SHOWDROPDOWN, FALSE, 0); |
| } |
| return AwtComponent::HandleEvent(msg, synthetic); |
| } |
| |
| BOOL AwtChoice::InheritsNativeMouseWheelBehavior() {return true;} |
| |
| void AwtChoice::_Reshape(void *param) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| ReshapeStruct *rs = (ReshapeStruct *)param; |
| jobject choice = rs->choice; |
| jint x = rs->x; |
| jint y = rs->y; |
| jint width = rs->width; |
| jint height = rs->height; |
| |
| AwtChoice *c = NULL; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_GOTO(choice, done); |
| |
| c = (AwtChoice *)pData; |
| if (::IsWindow(c->GetHWnd())) |
| { |
| c->Reshape(x, y, width, height); |
| c->VerifyState(); |
| } |
| |
| done: |
| env->DeleteGlobalRef(choice); |
| |
| delete rs; |
| } |
| |
| void AwtChoice::_Select(void *param) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| SelectStruct *ss = (SelectStruct *)param; |
| jobject choice = ss->choice; |
| jint index = ss->index; |
| |
| AwtChoice *c = NULL; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_GOTO(choice, done); |
| |
| c = (AwtChoice *)pData; |
| if (::IsWindow(c->GetHWnd())) |
| { |
| c->SendMessage(CB_SETCURSEL, index); |
| // c->VerifyState(); |
| } |
| |
| done: |
| env->DeleteGlobalRef(choice); |
| |
| delete ss; |
| } |
| |
| void AwtChoice::_AddItems(void *param) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| AddItemsStruct *ais = (AddItemsStruct *)param; |
| jobject choice = ais->choice; |
| jobjectArray items = ais->items; |
| jint index = ais->index; |
| |
| AwtChoice *c = NULL; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_GOTO(choice, done); |
| JNI_CHECK_NULL_GOTO(items, "null items", done); |
| |
| c = (AwtChoice *)pData; |
| if (::IsWindow(c->GetHWnd())) |
| { |
| jsize i; |
| int itemCount = env->GetArrayLength(items); |
| if (itemCount > 0) { |
| c->SendMessage(WM_SETREDRAW, (WPARAM)FALSE, 0); |
| for (i = 0; i < itemCount; i++) |
| { |
| jstring item = (jstring)env->GetObjectArrayElement(items, i); |
| JNI_CHECK_NULL_GOTO(item, "null item", next_elem); |
| c->SendMessage(CB_INSERTSTRING, index + i, JavaStringBuffer(env, item)); |
| env->DeleteLocalRef(item); |
| next_elem: |
| ; |
| } |
| c->SendMessage(WM_SETREDRAW, (WPARAM)TRUE, 0); |
| InvalidateRect(c->GetHWnd(), NULL, TRUE); |
| c->ResetDropDownHeight(); |
| c->VerifyState(); |
| } |
| } |
| |
| done: |
| env->DeleteGlobalRef(choice); |
| env->DeleteGlobalRef(items); |
| |
| delete ais; |
| } |
| |
| void AwtChoice::_Remove(void *param) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| RemoveStruct *rs = (RemoveStruct *)param; |
| jobject choice = rs->choice; |
| jint index = rs->index; |
| |
| AwtChoice *c = NULL; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_GOTO(choice, done); |
| |
| c = (AwtChoice *)pData; |
| if (::IsWindow(c->GetHWnd())) |
| { |
| c->SendMessage(CB_DELETESTRING, index, 0); |
| c->ResetDropDownHeight(); |
| c->VerifyState(); |
| } |
| |
| done: |
| env->DeleteGlobalRef(choice); |
| |
| delete rs; |
| } |
| |
| void AwtChoice::_RemoveAll(void *param) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| jobject choice = (jobject)param; |
| |
| AwtChoice *c = NULL; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_GOTO(choice, done); |
| |
| c = (AwtChoice *)pData; |
| if (::IsWindow(c->GetHWnd())) |
| { |
| c->SendMessage(CB_RESETCONTENT, 0, 0); |
| c->ResetDropDownHeight(); |
| c->VerifyState(); |
| } |
| |
| done: |
| env->DeleteGlobalRef(choice); |
| } |
| |
| void AwtChoice::_CloseList(void *param) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| jobject choice = (jobject)param; |
| |
| AwtChoice *c = NULL; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_GOTO(choice, done); |
| |
| c = (AwtChoice *)pData; |
| if (::IsWindow(c->GetHWnd()) && c->SendMessage(CB_GETDROPPEDSTATE, 0, 0)) { |
| c->SendMessage(CB_SHOWDROPDOWN, FALSE, 0); |
| } |
| |
| done: |
| env->DeleteGlobalRef(choice); |
| } |
| |
| /************************************************************************ |
| * WChoicePeer native methods |
| */ |
| |
| extern "C" { |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: select |
| * Signature: (I)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_select(JNIEnv *env, jobject self, |
| jint index) |
| { |
| TRY; |
| |
| SelectStruct *ss = new SelectStruct; |
| ss->choice = env->NewGlobalRef(self); |
| ss->index = index; |
| |
| AwtToolkit::GetInstance().SyncCall(AwtChoice::_Select, ss); |
| // global refs and ss are removed in _Select |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: remove |
| * Signature: (I)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_remove(JNIEnv *env, jobject self, |
| jint index) |
| { |
| TRY; |
| |
| RemoveStruct *rs = new RemoveStruct; |
| rs->choice = env->NewGlobalRef(self); |
| rs->index = index; |
| |
| AwtToolkit::GetInstance().SyncCall(AwtChoice::_Remove, rs); |
| // global ref and rs are deleted in _Remove |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: removeAll |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_removeAll(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| jobject selfGlobalRef = env->NewGlobalRef(self); |
| |
| AwtToolkit::GetInstance().SyncCall(AwtChoice::_RemoveAll, (void *)selfGlobalRef); |
| // selfGlobalRef is deleted in _RemoveAll |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: addItems |
| * Signature: ([Ljava/lang/String;I)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_addItems(JNIEnv *env, jobject self, |
| jobjectArray items, jint index) |
| { |
| TRY; |
| |
| AddItemsStruct *ais = new AddItemsStruct; |
| ais->choice = env->NewGlobalRef(self); |
| ais->items = (jobjectArray)env->NewGlobalRef(items); |
| ais->index = index; |
| |
| AwtToolkit::GetInstance().SyncCall(AwtChoice::_AddItems, ais); |
| // global refs and ais are deleted in _AddItems |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: reshape |
| * Signature: (IIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_reshape(JNIEnv *env, jobject self, |
| jint x, jint y, |
| jint width, jint height) |
| { |
| TRY; |
| |
| ReshapeStruct *rs = new ReshapeStruct; |
| rs->choice = env->NewGlobalRef(self); |
| rs->x = x; |
| rs->y = y; |
| rs->width = width; |
| rs->height = height; |
| |
| AwtToolkit::GetInstance().SyncCall(AwtChoice::_Reshape, rs); |
| // global ref and rs are deleted in _Reshape |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: create |
| * Signature: (Lsun/awt/windows/WComponentPeer;)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_create(JNIEnv *env, jobject self, |
| jobject parent) |
| { |
| TRY; |
| |
| PDATA pData; |
| JNI_CHECK_PEER_RETURN(parent); |
| AwtToolkit::CreateComponent(self, parent, |
| (AwtToolkit::ComponentFactory) |
| AwtChoice::Create); |
| JNI_CHECK_PEER_CREATION_RETURN(self); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WChoicePeer |
| * Method: closeList |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WChoicePeer_closeList(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| jobject selfGlobalRef = env->NewGlobalRef(self); |
| |
| AwtToolkit::GetInstance().SyncCall(AwtChoice::_CloseList, (void *)selfGlobalRef); |
| // global ref is deleted in _CloseList |
| |
| CATCH_BAD_ALLOC; |
| } |
| } /* extern "C" */ |
| |
| |
| /************************************************************************ |
| * Diagnostic routines |
| */ |
| |
| #ifdef DEBUG |
| |
| void AwtChoice::VerifyState() |
| { |
| if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) { |
| return; |
| } |
| |
| if (m_callbacksEnabled == FALSE) { |
| /* Component is not fully setup yet. */ |
| return; |
| } |
| |
| AwtComponent::VerifyState(); |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| if (env->PushLocalFrame(1) < 0) |
| return; |
| |
| jobject target = GetTarget(env); |
| |
| // To avoid possibly running client code on the toolkit thread, don't |
| // do the following checks if we're running on the toolkit thread. |
| if (AwtToolkit::MainThread() != ::GetCurrentThreadId()) { |
| // Compare number of items. |
| int nTargetItems = JNU_CallMethodByName(env, NULL, target, |
| "countItems", "()I").i; |
| DASSERT(!safe_ExceptionOccurred(env)); |
| int nPeerItems = (int)::SendMessage(GetHWnd(), CB_GETCOUNT, 0, 0); |
| DASSERT(nTargetItems == nPeerItems); |
| |
| // Compare selection |
| int targetIndex = JNU_CallMethodByName(env, NULL, target, |
| "getSelectedIndex", "()I").i; |
| DASSERT(!safe_ExceptionOccurred(env)); |
| int peerCurSel = (int)::SendMessage(GetHWnd(), CB_GETCURSEL, 0, 0); |
| DASSERT(targetIndex == peerCurSel); |
| } |
| env->PopLocalFrame(0); |
| } |
| #endif //DEBUG |