Path: blob/master/src/java.desktop/windows/native/libawt/windows/awt_Checkbox.cpp
41153 views
/*1* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "awt.h"26#include "awt_Toolkit.h"27#include "awt_Checkbox.h"28#include "awt_Canvas.h"29#include "awt_Window.h"3031/* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.32*/3334/***********************************************************************/35// Struct for _SetLabel() method36struct SetLabelStruct {37jobject checkbox;38jstring label;39};40// Struct for _SetState() method41struct SetStateStruct {42jobject checkbox;43jboolean state;44};4546/************************************************************************47* AwtCheckbox fields48*/4950/* java.awt.Checkbox field IDs */51jfieldID AwtCheckbox::labelID;52jfieldID AwtCheckbox::groupID;53jfieldID AwtCheckbox::stateID;5455const int AwtCheckbox::CHECK_SIZE = 13;5657/************************************************************************58* AwtCheckbox methods59*/6061AwtCheckbox::AwtCheckbox() {6263m_fLButtonDowned = FALSE;64}6566LPCTSTR AwtCheckbox::GetClassName() {67return TEXT("BUTTON"); /* System provided checkbox class (a type of button) */68}6970AwtCheckbox* AwtCheckbox::Create(jobject peer, jobject parent)71{72DASSERT(AwtToolkit::IsMainThread());73JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);7475jstring label = NULL;76jobject target = NULL;77AwtCheckbox *checkbox = NULL;7879try {80if (env->EnsureLocalCapacity(2) < 0) {81return NULL;82}8384PDATA pData;85AwtComponent* awtParent;86JNI_CHECK_PEER_GOTO(parent, done);87awtParent = (AwtCanvas*)pData;8889target = env->GetObjectField(peer, AwtObject::targetID);90JNI_CHECK_NULL_GOTO(target, "null target", done);9192checkbox = new AwtCheckbox();9394{95DWORD style = WS_CHILD | WS_CLIPSIBLINGS | BS_OWNERDRAW;96LPCWSTR defaultLabelStr = L"";97LPCWSTR labelStr = defaultLabelStr;98DWORD exStyle = 0;99100if (GetRTL()) {101exStyle |= WS_EX_RIGHT;102if (GetRTLReadingOrder())103exStyle |= WS_EX_RTLREADING;104}105106label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID);107if (label != NULL) {108labelStr = JNU_GetStringPlatformChars(env, label, 0);109}110if (labelStr != 0) {111jint x = env->GetIntField(target, AwtComponent::xID);112jint y = env->GetIntField(target, AwtComponent::yID);113jint width = env->GetIntField(target, AwtComponent::widthID);114jint height = env->GetIntField(target, AwtComponent::heightID);115checkbox->CreateHWnd(env, labelStr, style, exStyle,116x, y, width, height,117awtParent->GetHWnd(),118reinterpret_cast<HMENU>(static_cast<INT_PTR>(119awtParent->CreateControlID())),120::GetSysColor(COLOR_WINDOWTEXT),121::GetSysColor(COLOR_BTNFACE),122peer);123124if (labelStr != defaultLabelStr) {125JNU_ReleaseStringPlatformChars(env, label, labelStr);126}127} else {128throw std::bad_alloc();129}130}131} catch (...) {132env->DeleteLocalRef(label);133env->DeleteLocalRef(target);134throw;135}136137done:138env->DeleteLocalRef(label);139env->DeleteLocalRef(target);140141return checkbox;142}143144MsgRouting145AwtCheckbox::WmMouseUp(UINT flags, int x, int y, int button)146{147MsgRouting mrResult = AwtComponent::WmMouseUp(flags, x, y, button);148149if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd()))))150{151return mrConsume;152}153154POINT p = {x, y};155RECT rect;156::GetClientRect(GetHWnd(), &rect);157158if (::PtInRect(&rect, p) && button == LEFT_BUTTON && m_fLButtonDowned) {159WmNotify(BN_CLICKED);160}161m_fLButtonDowned = FALSE;162return mrResult;163}164165MsgRouting166AwtCheckbox::WmMouseDown(UINT flags, int x, int y, int button)167{168m_fLButtonDowned = TRUE;169return AwtComponent::WmMouseDown(flags, x, y, button);170}171172MsgRouting173AwtCheckbox::WmNotify(UINT notifyCode)174{175if (notifyCode == BN_CLICKED) {176BOOL fChecked = !GetState();177DoCallback("handleAction", "(Z)V", fChecked);178}179return mrDoDefault;180}181182BOOL AwtCheckbox::GetState()183{184JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);185186if (env->EnsureLocalCapacity(2) < 0) {187return NULL;188}189jobject target = GetTarget(env);190jboolean result = JNI_FALSE;191if (target != NULL) {192result = env->GetBooleanField(target, AwtCheckbox::stateID);193}194195env->DeleteLocalRef(target);196197return (BOOL)result;198}199200int AwtCheckbox::GetCheckSize()201{202/* using height of small icon for check mark size */203return CHECK_SIZE;204}205206MsgRouting207AwtCheckbox::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo)208{209JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);210211if (env->EnsureLocalCapacity(4) < 0) {212return mrConsume;213}214215jobject self = GetPeer(env);216jobject target = env->GetObjectField(self, AwtObject::targetID);217218HDC hDC = drawInfo.hDC;219RECT rect = drawInfo.rcItem;220int checkSize;221UINT nState;222SIZE size;223224jobject font = GET_FONT(target, self);225jstring str = (jstring)env->GetObjectField(target, AwtCheckbox::labelID);226size = AwtFont::getMFStringSize(hDC, font, str);227228jobject group = env->GetObjectField(target, AwtCheckbox::groupID);229if (group != NULL)230nState = DFCS_BUTTONRADIO;231else232nState = DFCS_BUTTONCHECK;233234if (GetState())235nState |= DFCS_CHECKED;236else237nState &= ~DFCS_CHECKED;238239if (drawInfo.itemState & ODS_SELECTED)240nState |= DFCS_PUSHED;241242if (drawInfo.itemAction & ODA_DRAWENTIRE) {243VERIFY(::FillRect (hDC, &rect, GetBackgroundBrush()));244}245246/* draw check mark */247checkSize = GetCheckSize();248RECT boxRect;249250boxRect.left = (GetRTL()) ? rect.right - checkSize : rect.left;251boxRect.top = (rect.bottom - rect.top - checkSize)/2;252boxRect.right = boxRect.left + checkSize;253boxRect.bottom = boxRect.top + checkSize;254::DrawFrameControl(hDC, &boxRect, DFC_BUTTON, nState);255256/*257* draw string258*259* 4 is a heuristic number260*/261rect.left = rect.left + checkSize + checkSize/4;262if (drawInfo.itemAction & ODA_DRAWENTIRE) {263BOOL bEnabled = isEnabled();264265int x = (GetRTL()) ? rect.right - (checkSize + checkSize / 4 + size.cx)266: rect.left;267int y = (rect.top + rect.bottom - size.cy) / 2;268if (bEnabled) {269AwtComponent::DrawWindowText(hDC, font, str, x, y);270} else {271AwtComponent::DrawGrayText(hDC, font, str, x, y);272}273}274275/* Draw focus rect */276RECT focusRect;277const int margin = 2; /* 2 is a heuristic number */278279focusRect.left = (GetRTL()) ? rect.right - checkSize - checkSize / 4 -2802 * margin - size.cx281: rect.left - margin;282focusRect.top = (rect.top+rect.bottom-size.cy)/2;283focusRect.right = (GetRTL()) ? rect.right - checkSize - checkSize / 4 +284margin285: focusRect.left + size.cx + 2 * margin;286focusRect.bottom = focusRect.top + size.cy;287288/* draw focus rect */289if ((drawInfo.itemState & ODS_FOCUS) &&290((drawInfo.itemAction & ODA_FOCUS)||291(drawInfo.itemAction &ODA_DRAWENTIRE))) {292if(::DrawFocusRect(hDC, &focusRect) == 0)293VERIFY(::GetLastError() == 0);294}295/* erase focus rect */296else if (!(drawInfo.itemState & ODS_FOCUS) &&297(drawInfo.itemAction & ODA_FOCUS)) {298if(::DrawFocusRect(hDC, &focusRect) == 0)299VERIFY(::GetLastError() == 0);300}301302/* Notify any subclasses */303rect = drawInfo.rcItem;304DoCallback("handlePaint", "(IIII)V", rect.left, rect.top,305rect.right-rect.left, rect.bottom-rect.top);306307env->DeleteLocalRef(target);308env->DeleteLocalRef(font);309env->DeleteLocalRef(str);310env->DeleteLocalRef(group);311312return mrConsume;313}314315MsgRouting AwtCheckbox::WmPaint(HDC)316{317/* Suppress peer notification, because it's handled in WmDrawItem. */318return mrDoDefault;319}320321BOOL AwtCheckbox::IsFocusingMouseMessage(MSG *pMsg) {322return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP;323}324325BOOL AwtCheckbox::IsFocusingKeyMessage(MSG *pMsg) {326return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) &&327pMsg->wParam == VK_SPACE;328}329330MsgRouting AwtCheckbox::HandleEvent(MSG *msg, BOOL synthetic)331{332if (IsFocusingMouseMessage(msg)) {333SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_LBUTTONDOWN ? TRUE : FALSE));334delete msg;335return mrConsume;336}337if (IsFocusingKeyMessage(msg)) {338SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_KEYDOWN ? TRUE : FALSE));339if (msg->message == WM_KEYDOWN) {340m_fLButtonDowned = TRUE;341} else if (m_fLButtonDowned == TRUE) {342WmNotify(BN_CLICKED);343m_fLButtonDowned = TRUE;344}345delete msg;346return mrConsume;347}348return AwtComponent::HandleEvent(msg, synthetic);349}350351void AwtCheckbox::_SetLabel(void *param)352{353JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);354355SetLabelStruct *sls = (SetLabelStruct *)param;356jobject checkbox = sls->checkbox;357jstring label = sls->label;358359int badAlloc = 0;360AwtCheckbox *c = NULL;361362PDATA pData;363JNI_CHECK_PEER_GOTO(checkbox, done);364365c = (AwtCheckbox *)pData;366if (::IsWindow(c->GetHWnd()))367{368LPCTSTR labelStr = NULL;369370// By convension null label means empty string371if (label == NULL)372{373labelStr = TEXT("");374}375else376{377labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE);378}379380if (labelStr == NULL)381{382badAlloc = 1;383}384else385{386c->SetText(labelStr);387c->VerifyState();388if (label != NULL) {389JNU_ReleaseStringPlatformChars(env, label, labelStr);390}391}392}393394done:395env->DeleteGlobalRef(checkbox);396if (label != NULL)397{398env->DeleteGlobalRef(label);399}400401delete sls;402403if (badAlloc) {404throw std::bad_alloc();405}406}407408void AwtCheckbox::_SetCheckboxGroup(void *param)409{410JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);411412jobject *jos = (jobject *)param;413jobject checkbox = jos[0];414jobject group = jos[1];415416AwtCheckbox *c = NULL;417418PDATA pData;419JNI_CHECK_PEER_GOTO(checkbox, done);420421c = (AwtCheckbox *)pData;422if (::IsWindow(c->GetHWnd()))423{424/*425#ifdef DEBUG426if (group != NULL) {427DASSERT(IsInstanceOf((HObject*)group, "java/awt/CheckboxGroup"));428}429#endif430*/431long style = c->GetStyle();432if (group == NULL) {433style = style & ~BS_AUTORADIOBUTTON;434style = style | BS_AUTOCHECKBOX;435} else {436style = style & ~BS_AUTOCHECKBOX;437style = style | BS_AUTORADIOBUTTON;438}439c->SetStyle(style);440c->SendMessage(BM_SETSTYLE, (WPARAM)BS_OWNERDRAW, (LPARAM)TRUE);441c->VerifyState();442}443444done:445env->DeleteGlobalRef(checkbox);446if (group != NULL) {447env->DeleteGlobalRef(group);448}449450delete[] jos;451}452453void AwtCheckbox::_SetState(void *param)454{455JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);456457SetStateStruct *sss = (SetStateStruct *)param;458jobject checkbox = sss->checkbox;459jboolean state = sss->state;460461AwtCheckbox *c = NULL;462463PDATA pData;464JNI_CHECK_PEER_GOTO(checkbox, done);465466c = (AwtCheckbox *)pData;467if (::IsWindow(c->GetHWnd()))468{469/*470* when multifont and group checkbox receive setState native471* method, it must be redraw to display correct check mark472*/473jobject target = env->GetObjectField(checkbox, AwtObject::targetID);474jobject group = env->GetObjectField(target, AwtCheckbox::groupID);475HWND hWnd = c->GetHWnd();476if (group != NULL) {477RECT rect;478VERIFY(::GetWindowRect(hWnd, &rect));479VERIFY(::ScreenToClient(hWnd, (LPPOINT)&rect));480VERIFY(::ScreenToClient(hWnd, ((LPPOINT)&rect) + 1));481VERIFY(::InvalidateRect(hWnd, &rect,TRUE));482VERIFY(::UpdateWindow(hWnd));483} else {484c->SendMessage(BM_SETCHECK, (WPARAM)(state ? BST_CHECKED : BST_UNCHECKED));485VERIFY(::InvalidateRect(hWnd, NULL, FALSE));486}487c->VerifyState();488env->DeleteLocalRef(target);489env->DeleteLocalRef(group);490}491492done:493env->DeleteGlobalRef(checkbox);494495delete sss;496}497498#ifdef DEBUG499void AwtCheckbox::VerifyState()500{501if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) {502return;503}504505if (m_callbacksEnabled == FALSE) {506/* Component is not fully setup yet. */507return;508}509510AwtComponent::VerifyState();511JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);512513if (env->EnsureLocalCapacity(2) < 0) {514return;515}516517jobject target = GetTarget(env);518519/* Check button style */520DWORD style = ::GetWindowLong(GetHWnd(), GWL_STYLE);521DASSERT(style & BS_OWNERDRAW);522523/* Check label */524int len = ::GetWindowTextLength(GetHWnd());525LPTSTR peerStr;526try {527peerStr = new TCHAR[len+1];528} catch (std::bad_alloc&) {529env->DeleteLocalRef(target);530throw;531}532533GetText(peerStr, len+1);534jstring label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID);535DASSERT(_tcscmp(peerStr, JavaStringBuffer(env, label)) == 0);536delete [] peerStr;537538env->DeleteLocalRef(target);539env->DeleteLocalRef(label);540}541#endif542543544/************************************************************************545* Checkbox native methods546*/547548extern "C" {549550/*551* Class: sun_awt_windows_WButtonPeer552* Method: initIDs553* Signature: ()V554*/555JNIEXPORT void JNICALL556Java_java_awt_Checkbox_initIDs(JNIEnv *env, jclass cls)557{558TRY;559560AwtCheckbox::labelID =561env->GetFieldID(cls, "label", "Ljava/lang/String;");562DASSERT(AwtCheckbox::labelID != NULL);563CHECK_NULL(AwtCheckbox::labelID);564565AwtCheckbox::groupID =566env->GetFieldID(cls, "group", "Ljava/awt/CheckboxGroup;");567DASSERT(AwtCheckbox::groupID != NULL);568CHECK_NULL(AwtCheckbox::groupID);569570AwtCheckbox::stateID = env->GetFieldID(cls, "state", "Z");571DASSERT(AwtCheckbox::stateID != NULL);572573CATCH_BAD_ALLOC;574}575576} /* extern "C" */577578579/************************************************************************580* WCheckboxPeer native methods581*/582583extern "C" {584585/*586* Class: sun_awt_windows_WCheckboxPeer587* Method: getCheckMarkSize588* Signature: ()I589*/590JNIEXPORT jint JNICALL591Java_sun_awt_windows_WCheckboxPeer_getCheckMarkSize(JNIEnv *env,592jclass cls)593{594return (jint)AwtCheckbox::GetCheckSize();595}596597/*598* Class: sun_awt_windows_WCheckboxPeer599* Method: setState600* Signature: (Z)V601*/602JNIEXPORT void JNICALL603Java_sun_awt_windows_WCheckboxPeer_setState(JNIEnv *env, jobject self,604jboolean state)605{606TRY;607608SetStateStruct *sss = new SetStateStruct;609sss->checkbox = env->NewGlobalRef(self);610sss->state = state;611612AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetState, sss);613// global refs and sss are deleted in _SetState()614615CATCH_BAD_ALLOC;616}617618/*619* Class: sun_awt_windows_WCheckboxPeer620* Method: setCheckboxGroup621* Signature: (Ljava/awt/CheckboxGroup;)V622*/623JNIEXPORT void JNICALL624Java_sun_awt_windows_WCheckboxPeer_setCheckboxGroup(JNIEnv *env, jobject self,625jobject group)626{627TRY;628629jobject *jos = new jobject[2];630jos[0] = env->NewGlobalRef(self);631jos[1] = env->NewGlobalRef(group);632633AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetCheckboxGroup, jos);634// global refs and jos are deleted in _SetLabel()635636CATCH_BAD_ALLOC;637}638639/*640* Class: sun_awt_windows_WCheckboxPeer641* Method: setLabel642* Signature: (Ljava/lang/String;)V643*/644JNIEXPORT void JNICALL645Java_sun_awt_windows_WCheckboxPeer_setLabel(JNIEnv *env, jobject self,646jstring label)647{648TRY;649650SetLabelStruct *sls = new SetLabelStruct;651sls->checkbox = env->NewGlobalRef(self);652sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL;653654AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetLabel, sls);655// global refs and sls are deleted in _SetLabel()656657CATCH_BAD_ALLOC;658}659660/*661* Class: sun_awt_windows_WCheckboxPeer662* Method: create663* Signature: (Lsun/awt/windows/WComponentPeer;)V664*/665JNIEXPORT void JNICALL666Java_sun_awt_windows_WCheckboxPeer_create(JNIEnv *env, jobject self,667jobject parent)668{669TRY;670671AwtToolkit::CreateComponent(self, parent,672(AwtToolkit::ComponentFactory)673AwtCheckbox::Create);674PDATA pData;675JNI_CHECK_PEER_CREATION_RETURN(self);676677#ifdef DEBUG678((AwtComponent*)JNI_GET_PDATA(self))->VerifyState();679#endif680681CATCH_BAD_ALLOC;682}683684} /* extern "C" */685686687