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" */