1 /* 2 * Copyright (c) 1996, 2015, 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 if(::DrawFocusRect(hDC, &focusRect) == 0) 246 VERIFY(::GetLastError() == 0); 247 } 248 249 /* Notify any subclasses */ 250 DoCallback("handlePaint", "(IIII)V", rect.left, rect.top, 251 rect.right-rect.left, rect.bottom-rect.top); 252 253 env->DeleteLocalRef(target); 254 env->DeleteLocalRef(font); 255 env->DeleteLocalRef(str); 256 257 return mrConsume; 258 } 259 260 MsgRouting AwtButton::WmPaint(HDC) 261 { 262 /* Suppress peer notification, because it's handled in WmDrawItem. */ 263 return mrDoDefault; 264 } 265 266 BOOL AwtButton::IsFocusingMouseMessage(MSG *pMsg) { 267 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP; 268 } 269 270 BOOL AwtButton::IsFocusingKeyMessage(MSG *pMsg) { 271 return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) && 272 pMsg->wParam == VK_SPACE; 273 } 274 275 MsgRouting AwtButton::HandleEvent(MSG *msg, BOOL synthetic) 276 { 277 if (IsFocusingMouseMessage(msg)) { 278 SendMessage(BM_SETSTATE, msg->message == WM_LBUTTONDOWN ? TRUE : FALSE, 0); 279 delete msg; 280 return mrConsume; 281 } 282 if (IsFocusingKeyMessage(msg)) { 283 SendMessage(BM_SETSTATE, msg->message == WM_KEYDOWN ? TRUE : FALSE, 0); 284 delete msg; 285 return mrConsume; 286 } 287 return AwtComponent::HandleEvent(msg, synthetic); 288 } 289 290 void AwtButton::_SetLabel(void *param) 291 { 292 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 293 294 SetLabelStruct *sls = (SetLabelStruct *)param; 295 296 jobject button = sls->button; 297 jstring label = sls->label; 298 299 int badAlloc = 0; 300 AwtComponent *c = NULL; 301 302 PDATA pData; 303 JNI_CHECK_PEER_GOTO(button, done); 304 305 c = (AwtComponent*)pData; 306 if (::IsWindow(c->GetHWnd())) 307 { 308 LPCTSTR labelStr = NULL; 309 310 // By convension null label means empty string 311 if (label == NULL) { 312 labelStr = TEXT(""); 313 } else { 314 labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE); 315 } 316 317 if (labelStr == NULL) { 318 badAlloc = 1; 319 } else { 320 c->SetText(labelStr); 321 if (label != NULL) { 322 JNU_ReleaseStringPlatformChars(env, label, labelStr); 323 } 324 } 325 } 326 327 done: 328 env->DeleteGlobalRef(button); 329 if (label != NULL) 330 { 331 env->DeleteGlobalRef(label); 332 } 333 334 delete sls; 335 336 if (badAlloc) { 337 throw std::bad_alloc(); 338 } 339 } 340 341 /************************************************************************ 342 * WButtonPeer native methods 343 */ 344 345 extern "C" { 346 347 /* 348 * Class: sun_awt_windows_WButtonPeer 349 * Method: initIDs 350 * Signature: ()V 351 */ 352 JNIEXPORT void JNICALL 353 Java_sun_awt_windows_WButtonPeer_initIDs(JNIEnv *env, jclass cls) 354 { 355 TRY; 356 357 cls = env->FindClass("java/awt/Button"); 358 if (cls == NULL) { 359 return; 360 } 361 AwtButton::labelID = env->GetFieldID(cls, "label", "Ljava/lang/String;"); 362 DASSERT(AwtButton::labelID != NULL); 363 364 CATCH_BAD_ALLOC; 365 } 366 367 /* 368 * Class: sun_awt_windows_WButtonPeer 369 * Method: setLabel 370 * Signature: (Ljava/lang/String;)V 371 */ 372 JNIEXPORT void JNICALL 373 Java_sun_awt_windows_WButtonPeer_setLabel(JNIEnv *env, jobject self, 374 jstring label) 375 { 376 TRY; 377 378 PDATA pData; 379 JNI_CHECK_PEER_RETURN(self); 380 381 SetLabelStruct *sls = new SetLabelStruct; 382 sls->button = env->NewGlobalRef(self); 383 sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL; 384 385 AwtToolkit::GetInstance().SyncCall(AwtButton::_SetLabel, sls); 386 // global refs and sls are deleted in _SetLabel() 387 388 CATCH_BAD_ALLOC; 389 } 390 391 /* 392 * Class: sun_awt_windows_WButtonPeer 393 * Method: create 394 * Signature: (Lsun/awt/windows/WComponentPeer;)V 395 */ 396 JNIEXPORT void JNICALL 397 Java_sun_awt_windows_WButtonPeer_create(JNIEnv *env, jobject self, 398 jobject parent) 399 { 400 TRY; 401 402 PDATA pData; 403 JNI_CHECK_PEER_RETURN(parent); 404 405 AwtToolkit::CreateComponent( 406 self, parent, (AwtToolkit::ComponentFactory)AwtButton::Create); 407 408 JNI_CHECK_PEER_CREATION_RETURN(self); 409 410 CATCH_BAD_ALLOC; 411 } 412 413 } /* extern "C" */