1 /*
   2  * Copyright (c) 1996, 2011, 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 "awt.h"
  27 
  28 #include "awt_Object.h"    /* wop_pDataID */
  29 #include "awt_Toolkit.h"
  30 #include "awt_Button.h"
  31 #include "awt_Canvas.h"
  32 #include "awt_Window.h"
  33 
  34 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
  35  */
  36 
  37 /***********************************************************************/
  38 // Struct for _SetLabel() method
  39 struct SetLabelStruct {
  40   jobject button;
  41   jstring label;
  42 };
  43 
  44 /************************************************************************
  45  * AwtButton fields
  46  */
  47 
  48 /* java.awt.Button fields */
  49 jfieldID AwtButton::labelID;
  50 
  51 
  52 /************************************************************************
  53  * AwtButton methods
  54  */
  55 
  56 AwtButton::AwtButton() {
  57     leftButtonDown = FALSE;
  58 }
  59 
  60 /* System provided button class */
  61 LPCTSTR AwtButton::GetClassName() {
  62     return TEXT("BUTTON");
  63 }
  64 
  65 /* Create a new AwtButton object and window. */
  66 AwtButton* AwtButton::Create(jobject self, jobject parent)
  67 {
  68     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  69 
  70     /* the result */
  71     AwtButton *c = NULL;
  72 
  73     jobject target = NULL;
  74     jstring label = NULL;
  75 
  76     try {
  77         LPCWSTR labelStr;
  78         DWORD style;
  79         DWORD exStyle = 0;
  80         jint x, y, height, width;
  81 
  82         if (env->EnsureLocalCapacity(2) < 0) {
  83             return NULL;
  84         }
  85 
  86         PDATA pData;
  87         AwtCanvas* awtParent;
  88 
  89         JNI_CHECK_PEER_GOTO(parent, done);
  90         awtParent = (AwtCanvas*)pData;
  91         JNI_CHECK_NULL_GOTO(awtParent, "awtParent", done);
  92 
  93         target = env->GetObjectField(self, AwtObject::targetID);
  94         JNI_CHECK_NULL_GOTO(target, "target", done);
  95 
  96         c = new AwtButton();
  97 
  98         label = (jstring)env->GetObjectField(target, AwtButton::labelID);
  99 
 100         x = env->GetIntField(target, AwtComponent::xID);
 101         y = env->GetIntField(target, AwtComponent::yID);
 102         width = env->GetIntField(target, AwtComponent::widthID);
 103         height = env->GetIntField(target, AwtComponent::heightID);
 104 
 105         if (label == NULL) {
 106             labelStr = L"";
 107         } else {
 108             labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE);
 109         }
 110         style = 0;
 111 
 112         if (labelStr == NULL) {
 113             throw std::bad_alloc();
 114         }
 115 
 116         style = WS_CHILD | WS_CLIPSIBLINGS | BS_PUSHBUTTON | BS_OWNERDRAW;
 117         if (GetRTLReadingOrder())
 118             exStyle |= WS_EX_RTLREADING;
 119 
 120         c->CreateHWnd(env, labelStr, style, exStyle, x, y, width, height,
 121                       awtParent->GetHWnd(),
 122                       reinterpret_cast<HMENU>(static_cast<INT_PTR>(
 123                   awtParent->CreateControlID())),
 124                       ::GetSysColor(COLOR_BTNTEXT),
 125                       ::GetSysColor(COLOR_BTNFACE),
 126                       self);
 127         c->m_backgroundColorSet = TRUE;  // suppress inheriting parent's color
 128         c->UpdateBackground(env, target);
 129         if (label != NULL)
 130             JNU_ReleaseStringPlatformChars(env, label, labelStr);
 131     } catch (...) {
 132         env->DeleteLocalRef(target);
 133         if (label != NULL)
 134             env->DeleteLocalRef(label);
 135         throw;
 136     }
 137 
 138 done:
 139     env->DeleteLocalRef(target);
 140     if (label != NULL)
 141         env->DeleteLocalRef(label);
 142     return c;
 143 }
 144 
 145 MsgRouting
 146 AwtButton::WmMouseDown(UINT flags, int x, int y, int button)
 147 {
 148     // 4530087: keep track of the when the left mouse button is pressed
 149     if (button == LEFT_BUTTON) {
 150         leftButtonDown = TRUE;
 151     }
 152     return AwtComponent::WmMouseDown(flags, x, y, button);
 153 }
 154 
 155 MsgRouting
 156 AwtButton::WmMouseUp(UINT flags, int x, int y, int button)
 157 {
 158     MsgRouting mrResult = AwtComponent::WmMouseUp(flags, x, y, button);
 159 
 160     if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd()))))
 161     {
 162         return mrConsume;
 163     }
 164 
 165     // 4530087: It is possible that a left mouse press happened on a Window
 166     // obscuring this AwtButton, and during event handling the Window was
 167     // removed.  This causes a WmMouseUp call to this AwtButton, even though
 168     // there was no accompanying WmMouseDown.  ActionEvents should ONLY be
 169     // notified (via NotifyListeners()) if the left button press happened on
 170     // this AwtButton.  --bchristi
 171     if (button == LEFT_BUTTON && leftButtonDown) {
 172         leftButtonDown = FALSE;
 173 
 174         POINT p = {x, y};
 175         RECT rect;
 176         ::GetClientRect(GetHWnd(), &rect);
 177 
 178         if (::PtInRect(&rect, p)) {
 179             NotifyListeners();
 180         }
 181     }
 182 
 183     return mrResult;
 184 }
 185 
 186 void
 187 AwtButton::NotifyListeners()
 188 {
 189     DoCallback("handleAction", "(JI)V", ::JVM_CurrentTimeMillis(NULL, 0),
 190                (jint)AwtComponent::GetJavaModifiers());
 191 }
 192 
 193 MsgRouting
 194 AwtButton::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo)
 195 {
 196     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 197 
 198     if (env->EnsureLocalCapacity(3) < 0) {
 199         /* is this OK? */
 200         return mrConsume;
 201     }
 202 
 203     jobject self = GetPeer(env);
 204     jobject target = env->GetObjectField(self, AwtObject::targetID);
 205 
 206     HDC hDC = drawInfo.hDC;
 207     RECT rect = drawInfo.rcItem;
 208     UINT nState;
 209     SIZE size;
 210 
 211     /* Draw Button */
 212     nState = DFCS_BUTTONPUSH;
 213     if (drawInfo.itemState & ODS_SELECTED)
 214         nState |= DFCS_PUSHED;
 215 
 216     ::FillRect(hDC, &rect, GetBackgroundBrush());
 217     UINT edgeType = (nState & DFCS_PUSHED) ? EDGE_SUNKEN : EDGE_RAISED;
 218     ::DrawEdge(hDC, &rect, edgeType, BF_RECT | BF_SOFT);
 219 
 220     /* Draw WindowText */
 221     jobject font = GET_FONT(target, self);
 222     jstring str = (jstring)env->GetObjectField(target, AwtButton::labelID);
 223 
 224     size = AwtFont::getMFStringSize(hDC, font, str);
 225 
 226     /* Check whether the button is disabled. */
 227     BOOL bEnabled = isEnabled();
 228 
 229     int adjust = (nState & DFCS_PUSHED) ? 1 : 0;
 230     int x = (rect.left + rect.right-size.cx) / 2 + adjust;
 231     int y = (rect.top + rect.bottom-size.cy) / 2 + adjust;
 232 
 233     if (bEnabled) {
 234         AwtComponent::DrawWindowText(hDC, font, str, x, y);
 235     } else {
 236         AwtComponent::DrawGrayText(hDC, font, str, x, y);
 237     }
 238 
 239     /* Draw focus rect */
 240     if (drawInfo.itemState & ODS_FOCUS){
 241         const int inf = 3; /* heuristic decision */
 242         RECT focusRect;
 243         VERIFY(::CopyRect(&focusRect, &rect));
 244         VERIFY(::InflateRect(&focusRect,-inf,-inf));
 245         VERIFY(::DrawFocusRect(hDC, &focusRect));
 246     }
 247 
 248     /* Notify any subclasses */
 249     DoCallback("handlePaint", "(IIII)V", rect.left, rect.top,
 250                rect.right-rect.left, rect.bottom-rect.top);
 251 
 252     env->DeleteLocalRef(target);
 253     env->DeleteLocalRef(font);
 254     env->DeleteLocalRef(str);
 255 
 256     return mrConsume;
 257 }
 258 
 259 MsgRouting AwtButton::WmPaint(HDC)
 260 {
 261     /* Suppress peer notification, because it's handled in WmDrawItem. */
 262     return mrDoDefault;
 263 }
 264 
 265 BOOL AwtButton::IsFocusingMouseMessage(MSG *pMsg) {
 266     return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP;
 267 }
 268 
 269 BOOL AwtButton::IsFocusingKeyMessage(MSG *pMsg) {
 270     return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) &&
 271             pMsg->wParam == VK_SPACE;
 272 }
 273 
 274 MsgRouting AwtButton::HandleEvent(MSG *msg, BOOL synthetic)
 275 {
 276     if (IsFocusingMouseMessage(msg)) {
 277         SendMessage(BM_SETSTATE, msg->message == WM_LBUTTONDOWN ? TRUE : FALSE, 0);
 278         delete msg;
 279         return mrConsume;
 280     }
 281     if (IsFocusingKeyMessage(msg)) {
 282         SendMessage(BM_SETSTATE, msg->message == WM_KEYDOWN ? TRUE : FALSE, 0);
 283         delete msg;
 284         return mrConsume;
 285     }
 286     return AwtComponent::HandleEvent(msg, synthetic);
 287 }
 288 
 289 void AwtButton::_SetLabel(void *param)
 290 {
 291     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 292 
 293     SetLabelStruct *sls = (SetLabelStruct *)param;
 294 
 295     jobject button = sls->button;
 296     jstring label = sls->label;
 297 
 298     int badAlloc = 0;
 299     AwtComponent *c = NULL;
 300 
 301     PDATA pData;
 302     JNI_CHECK_PEER_GOTO(button, done);
 303 
 304     c = (AwtComponent*)pData;
 305     if (::IsWindow(c->GetHWnd()))
 306     {
 307         LPCTSTR labelStr = NULL;
 308 
 309         // By convension null label means empty string
 310         if (label == NULL) {
 311             labelStr = TEXT("");
 312         } else {
 313             labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE);
 314         }
 315 
 316         if (labelStr == NULL) {
 317             badAlloc = 1;
 318         } else {
 319             c->SetText(labelStr);
 320             if (label != NULL) {
 321                 JNU_ReleaseStringPlatformChars(env, label, labelStr);
 322             }
 323         }
 324     }
 325 
 326 done:
 327     env->DeleteGlobalRef(button);
 328     if (label != NULL)
 329     {
 330         env->DeleteGlobalRef(label);
 331     }
 332 
 333     delete sls;
 334 
 335     if (badAlloc) {
 336         throw std::bad_alloc();
 337     }
 338 }
 339 
 340 /************************************************************************
 341  * WButtonPeer native methods
 342  */
 343 
 344 extern "C" {
 345 
 346 /*
 347  * Class:     sun_awt_windows_WButtonPeer
 348  * Method:    initIDs
 349  * Signature: ()V
 350  */
 351 JNIEXPORT void JNICALL
 352 Java_sun_awt_windows_WButtonPeer_initIDs(JNIEnv *env, jclass cls)
 353 {
 354     TRY;
 355 
 356     cls = env->FindClass("java/awt/Button");
 357     if (cls == NULL) {
 358         return;
 359     }
 360     AwtButton::labelID = env->GetFieldID(cls, "label", "Ljava/lang/String;");
 361     DASSERT(AwtButton::labelID != NULL);
 362 
 363     CATCH_BAD_ALLOC;
 364 }
 365 
 366 /*
 367  * Class:     sun_awt_windows_WButtonPeer
 368  * Method:    setLabel
 369  * Signature: (Ljava/lang/String;)V
 370  */
 371 JNIEXPORT void JNICALL
 372 Java_sun_awt_windows_WButtonPeer_setLabel(JNIEnv *env, jobject self,
 373                                           jstring label)
 374 {
 375     TRY;
 376 
 377     PDATA pData;
 378     JNI_CHECK_PEER_RETURN(self);
 379 
 380     SetLabelStruct *sls = new SetLabelStruct;
 381     sls->button = env->NewGlobalRef(self);
 382     sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL;
 383 
 384     AwtToolkit::GetInstance().SyncCall(AwtButton::_SetLabel, sls);
 385     // global refs and sls are deleted in _SetLabel()
 386 
 387     CATCH_BAD_ALLOC;
 388 }
 389 
 390 /*
 391  * Class:     sun_awt_windows_WButtonPeer
 392  * Method:    create
 393  * Signature: (Lsun/awt/windows/WComponentPeer;)V
 394  */
 395 JNIEXPORT void JNICALL
 396 Java_sun_awt_windows_WButtonPeer_create(JNIEnv *env, jobject self,
 397                                         jobject parent)
 398 {
 399     TRY;
 400 
 401     PDATA pData;
 402     JNI_CHECK_PEER_RETURN(parent);
 403 
 404     AwtToolkit::CreateComponent(
 405         self, parent, (AwtToolkit::ComponentFactory)AwtButton::Create);
 406 
 407     JNI_CHECK_PEER_CREATION_RETURN(self);
 408 
 409     CATCH_BAD_ALLOC;
 410 }
 411 
 412 }  /* extern "C" */