blob: 672d3540c1d03e87b35ae68c53d12680c5fcbaf4 [file] [log] [blame]
/*
* Copyright (c) 1996, 2009, 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 "awt.h"
#include "awt_Object.h" /* wop_pDataID */
#include "awt_Toolkit.h"
#include "awt_Button.h"
#include "awt_Canvas.h"
#include "awt_Window.h"
/* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
*/
/***********************************************************************/
// Struct for _SetLabel() method
struct SetLabelStruct {
jobject button;
jstring label;
};
/************************************************************************
* AwtButton fields
*/
/* java.awt.Button fields */
jfieldID AwtButton::labelID;
/************************************************************************
* AwtButton methods
*/
AwtButton::AwtButton() {
leftButtonDown = FALSE;
}
/* System provided button class */
LPCTSTR AwtButton::GetClassName() {
return TEXT("BUTTON");
}
/* Create a new AwtButton object and window. */
AwtButton* AwtButton::Create(jobject self, jobject parent)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
/* the result */
AwtButton *c = NULL;
jobject target = NULL;
jstring label = NULL;
try {
LPCWSTR labelStr;
DWORD style;
DWORD exStyle = 0;
jint x, y, height, width;
if (env->EnsureLocalCapacity(2) < 0) {
return NULL;
}
PDATA pData;
AwtCanvas* awtParent;
JNI_CHECK_PEER_GOTO(parent, done);
awtParent = (AwtCanvas*)pData;
JNI_CHECK_NULL_GOTO(awtParent, "awtParent", done);
target = env->GetObjectField(self, AwtObject::targetID);
JNI_CHECK_NULL_GOTO(target, "target", done);
c = new AwtButton();
label = (jstring)env->GetObjectField(target, AwtButton::labelID);
x = env->GetIntField(target, AwtComponent::xID);
y = env->GetIntField(target, AwtComponent::yID);
width = env->GetIntField(target, AwtComponent::widthID);
height = env->GetIntField(target, AwtComponent::heightID);
if (label == NULL) {
labelStr = L"";
} else {
labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE);
}
style = 0;
if (labelStr == NULL) {
throw std::bad_alloc();
}
style = WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON | BS_OWNERDRAW;
if (GetRTLReadingOrder())
exStyle |= WS_EX_RTLREADING;
c->CreateHWnd(env, labelStr, style, exStyle, x, y, width, height,
awtParent->GetHWnd(),
reinterpret_cast<HMENU>(static_cast<INT_PTR>(
awtParent->CreateControlID())),
::GetSysColor(COLOR_BTNTEXT),
::GetSysColor(COLOR_BTNFACE),
self);
c->m_backgroundColorSet = TRUE; // suppress inheriting parent's color
c->UpdateBackground(env, target);
if (label != NULL)
JNU_ReleaseStringPlatformChars(env, label, labelStr);
} catch (...) {
env->DeleteLocalRef(target);
if (label != NULL)
env->DeleteLocalRef(label);
throw;
}
done:
env->DeleteLocalRef(target);
if (label != NULL)
env->DeleteLocalRef(label);
return c;
}
MsgRouting
AwtButton::WmMouseDown(UINT flags, int x, int y, int button)
{
// 4530087: keep track of the when the left mouse button is pressed
if (button == LEFT_BUTTON) {
leftButtonDown = TRUE;
}
return AwtComponent::WmMouseDown(flags, x, y, button);
}
MsgRouting
AwtButton::WmMouseUp(UINT flags, int x, int y, int button)
{
MsgRouting mrResult = AwtComponent::WmMouseUp(flags, x, y, button);
if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd()))))
{
return mrConsume;
}
// 4530087: It is possible that a left mouse press happened on a Window
// obscuring this AwtButton, and during event handling the Window was
// removed. This causes a WmMouseUp call to this AwtButton, even though
// there was no accompanying WmMouseDown. ActionEvents should ONLY be
// notified (via NotifyListeners()) if the left button press happened on
// this AwtButton. --bchristi
if (button == LEFT_BUTTON && leftButtonDown) {
leftButtonDown = FALSE;
POINT p = {x, y};
RECT rect;
::GetClientRect(GetHWnd(), &rect);
if (::PtInRect(&rect, p)) {
NotifyListeners();
}
}
return mrResult;
}
void
AwtButton::NotifyListeners()
{
DoCallback("handleAction", "(JI)V", TimeHelper::getMessageTimeUTC(),
(jint)AwtComponent::GetJavaModifiers());
}
MsgRouting
AwtButton::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(3) < 0) {
/* is this OK? */
return mrConsume;
}
jobject self = GetPeer(env);
jobject target = env->GetObjectField(self, AwtObject::targetID);
HDC hDC = drawInfo.hDC;
RECT rect = drawInfo.rcItem;
UINT nState;
SIZE size;
/* Draw Button */
nState = DFCS_BUTTONPUSH;
if (drawInfo.itemState & ODS_SELECTED)
nState |= DFCS_PUSHED;
::FillRect(hDC, &rect, GetBackgroundBrush());
UINT edgeType = (nState & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED;
::DrawEdge(hDC, &rect, edgeType, BF_RECT | BF_SOFT);
/* Draw WindowText */
jobject font = GET_FONT(target, self);
jstring str = (jstring)env->GetObjectField(target, AwtButton::labelID);
size = AwtFont::getMFStringSize(hDC, font, str);
/* Check whether the button is disabled. */
BOOL bEnabled = isEnabled();
int adjust = (nState & DFCS_PUSHED) ? 1 : 0;
int x = (rect.left + rect.right-size.cx) / 2 + adjust;
int y = (rect.top + rect.bottom-size.cy) / 2 + adjust;
if (bEnabled) {
AwtComponent::DrawWindowText(hDC, font, str, x, y);
} else {
AwtComponent::DrawGrayText(hDC, font, str, x, y);
}
/* Draw focus rect */
if (drawInfo.itemState & ODS_FOCUS){
const int inf = 3; /* heuristic decision */
RECT focusRect;
VERIFY(::CopyRect(&focusRect, &rect));
VERIFY(::InflateRect(&focusRect,-inf,-inf));
VERIFY(::DrawFocusRect(hDC, &focusRect));
}
/* Notify any subclasses */
DoCallback("handlePaint", "(IIII)V", rect.left, rect.top,
rect.right-rect.left, rect.bottom-rect.top);
env->DeleteLocalRef(target);
env->DeleteLocalRef(font);
env->DeleteLocalRef(str);
return mrConsume;
}
MsgRouting AwtButton::WmPaint(HDC)
{
/* Suppress peer notification, because it's handled in WmDrawItem. */
return mrDoDefault;
}
BOOL AwtButton::IsFocusingMouseMessage(MSG *pMsg) {
return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP;
}
BOOL AwtButton::IsFocusingKeyMessage(MSG *pMsg) {
return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) &&
pMsg->wParam == VK_SPACE;
}
MsgRouting AwtButton::HandleEvent(MSG *msg, BOOL synthetic)
{
if (IsFocusingMouseMessage(msg)) {
SendMessage(BM_SETSTATE, msg->message == WM_LBUTTONDOWN ? TRUE : FALSE, 0);
delete msg;
return mrConsume;
}
if (IsFocusingKeyMessage(msg)) {
SendMessage(BM_SETSTATE, msg->message == WM_KEYDOWN ? TRUE : FALSE, 0);
delete msg;
return mrConsume;
}
return AwtComponent::HandleEvent(msg, synthetic);
}
void AwtButton::_SetLabel(void *param)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
SetLabelStruct *sls = (SetLabelStruct *)param;
jobject button = sls->button;
jstring label = sls->label;
int badAlloc = 0;
AwtComponent *c = NULL;
PDATA pData;
JNI_CHECK_PEER_GOTO(button, done);
c = (AwtComponent*)pData;
if (::IsWindow(c->GetHWnd()))
{
LPCTSTR labelStr = NULL;
// By convension null label means empty string
if (label == NULL) {
labelStr = TEXT("");
} else {
labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE);
}
if (labelStr == NULL) {
badAlloc = 1;
} else {
c->SetText(labelStr);
if (label != NULL) {
JNU_ReleaseStringPlatformChars(env, label, labelStr);
}
}
}
done:
env->DeleteGlobalRef(button);
if (label != NULL)
{
env->DeleteGlobalRef(label);
}
delete sls;
if (badAlloc) {
throw std::bad_alloc();
}
}
/************************************************************************
* WButtonPeer native methods
*/
extern "C" {
/*
* Class: sun_awt_windows_WButtonPeer
* Method: initIDs
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WButtonPeer_initIDs(JNIEnv *env, jclass cls)
{
TRY;
cls = env->FindClass("java/awt/Button");
if (cls == NULL) {
return;
}
AwtButton::labelID = env->GetFieldID(cls, "label", "Ljava/lang/String;");
DASSERT(AwtButton::labelID != NULL);
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WButtonPeer
* Method: setLabel
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WButtonPeer_setLabel(JNIEnv *env, jobject self,
jstring label)
{
TRY;
PDATA pData;
JNI_CHECK_PEER_RETURN(self);
SetLabelStruct *sls = new SetLabelStruct;
sls->button = env->NewGlobalRef(self);
sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL;
AwtToolkit::GetInstance().SyncCall(AwtButton::_SetLabel, sls);
// global refs and sls are deleted in _SetLabel()
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WButtonPeer
* Method: create
* Signature: (Lsun/awt/windows/WComponentPeer;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WButtonPeer_create(JNIEnv *env, jobject self,
jobject parent)
{
TRY;
PDATA pData;
JNI_CHECK_PEER_RETURN(parent);
AwtToolkit::CreateComponent(
self, parent, (AwtToolkit::ComponentFactory)AwtButton::Create);
JNI_CHECK_PEER_CREATION_RETURN(self);
CATCH_BAD_ALLOC;
}
} /* extern "C" */