1/* 2 * Copyright (c) 1996, 2016, 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_PopupMenu.h" 27 28#include "awt_Event.h" 29#include "awt_Window.h" 30 31#include <sun_awt_windows_WPopupMenuPeer.h> 32#include <java_awt_Event.h> 33 34/* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 35 */ 36 37/***********************************************************************/ 38// struct for _Show method 39struct ShowStruct { 40 jobject self; 41 jobject event; 42}; 43 44/************************************************************************ 45 * AwtPopupMenu class methods 46 */ 47 48AwtPopupMenu::AwtPopupMenu() { 49 m_parent = NULL; 50} 51 52AwtPopupMenu::~AwtPopupMenu() 53{ 54} 55 56void AwtPopupMenu::Dispose() 57{ 58 m_parent = NULL; 59 60 AwtMenu::Dispose(); 61} 62 63LPCTSTR AwtPopupMenu::GetClassName() { 64 return TEXT("SunAwtPopupMenu"); 65} 66 67/* Create a new AwtPopupMenu object and menu. */ 68AwtPopupMenu* AwtPopupMenu::Create(jobject self, jobject parent) 69{ 70 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 71 72 jobject target = NULL; 73 AwtPopupMenu* popupMenu = NULL; 74 75 try { 76 if (env->EnsureLocalCapacity(1) < 0) { 77 return NULL; 78 } 79 80 JNI_CHECK_NULL_GOTO(parent, "peer", done); 81 AwtComponent* awtParent = (AwtComponent*) JNI_GET_PDATA(parent); 82 83 target = env->GetObjectField(self, AwtObject::targetID); 84 JNI_CHECK_NULL_GOTO(target, "null target", done); 85 86 popupMenu = new AwtPopupMenu(); 87 88 SetLastError(0); 89 HMENU hMenu = ::CreatePopupMenu(); 90 // fix for 5088782 91 if (!CheckMenuCreation(env, self, hMenu)) 92 { 93 env->DeleteLocalRef(target); 94 return NULL; 95 } 96 97 popupMenu->SetHMenu(hMenu); 98 99 popupMenu->LinkObjects(env, self); 100 popupMenu->SetParent(awtParent); 101 } catch (...) { 102 env->DeleteLocalRef(target); 103 throw; 104 } 105 106done: 107 env->DeleteLocalRef(target); 108 return popupMenu; 109} 110 111void AwtPopupMenu::Show(JNIEnv *env, jobject event, BOOL isTrayIconPopup) 112{ 113 /* 114 * For not TrayIcon popup. 115 * Convert the event's XY to absolute coordinates. The XY is 116 * relative to the origin component, which is passed by PopupMenu 117 * as the event's target. 118 */ 119 if (env->EnsureLocalCapacity(2) < 0) { 120 return; 121 } 122 jobject origin = (env)->GetObjectField(event, AwtEvent::targetID); 123 jobject peerOrigin = GetPeerForTarget(env, origin); 124 PDATA pData; 125 JNI_CHECK_PEER_GOTO(peerOrigin, done); 126 { 127 AwtComponent* awtOrigin = (AwtComponent*)pData; 128 POINT pt; 129 UINT flags = 0; 130 pt.x = (env)->GetIntField(event, AwtEvent::xID); 131 pt.y = (env)->GetIntField(event, AwtEvent::yID); 132 133 if (!isTrayIconPopup) { 134 ::MapWindowPoints(awtOrigin->GetHWnd(), 0, (LPPOINT)&pt, 1); 135 136 // Adjust to account for the Inset values 137 RECT rctInsets; 138 awtOrigin->GetInsets(&rctInsets); 139 pt.x -= rctInsets.left; 140 pt.y -= rctInsets.top; 141 142 flags = TPM_LEFTALIGN | TPM_RIGHTBUTTON; 143 144 } else { 145 ::SetForegroundWindow(awtOrigin->GetHWnd()); 146 147 flags = TPM_NONOTIFY | TPM_RIGHTALIGN | TPM_RIGHTBUTTON | TPM_BOTTOMALIGN; 148 } 149 150 /* Invoke the popup. */ 151 ::TrackPopupMenu(GetHMenu(), flags, pt.x, pt.y, 0, awtOrigin->GetHWnd(), NULL); 152 153 if (isTrayIconPopup) { 154 ::PostMessage(awtOrigin->GetHWnd(), WM_NULL, 0, 0); 155 } 156 } 157 done: 158 env->DeleteLocalRef(origin); 159 env->DeleteLocalRef(peerOrigin); 160} 161 162void AwtPopupMenu::_Show(void *param) 163{ 164 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 165 166 static jclass popupMenuCls; 167 if (popupMenuCls == NULL) { 168 jclass popupMenuClsLocal = env->FindClass("java/awt/PopupMenu"); 169 if (popupMenuClsLocal != NULL) { 170 popupMenuCls = (jclass)env->NewGlobalRef(popupMenuClsLocal); 171 env->DeleteLocalRef(popupMenuClsLocal); 172 } 173 } 174 175 static jfieldID isTrayIconPopupID; 176 if (popupMenuCls != NULL && isTrayIconPopupID == NULL) { 177 isTrayIconPopupID = env->GetFieldID(popupMenuCls, "isTrayIconPopup", "Z"); 178 DASSERT(isTrayIconPopupID); 179 } 180 181 ShowStruct *ss = (ShowStruct*)param; 182 if (ss->self != NULL && isTrayIconPopupID != NULL) { 183 PDATA pData = JNI_GET_PDATA(ss->self); 184 if (pData) { 185 AwtPopupMenu *p = (AwtPopupMenu *)pData; 186 jobject target = p->GetTarget(env); 187 BOOL isTrayIconPopup = env->GetBooleanField(target, isTrayIconPopupID); 188 env->DeleteLocalRef(target); 189 p->Show(env, ss->event, isTrayIconPopup); 190 } 191 } 192 if (ss->self != NULL) { 193 env->DeleteGlobalRef(ss->self); 194 } 195 if (ss->event != NULL) { 196 env->DeleteGlobalRef(ss->event); 197 } 198 delete ss; 199 if (isTrayIconPopupID == NULL) { 200 throw std::bad_alloc(); 201 } 202} 203 204void AwtPopupMenu::AddItem(AwtMenuItem *item) 205{ 206 AwtMenu::AddItem(item); 207 if (GetMenuContainer() != NULL) return; 208 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 209 if (env->EnsureLocalCapacity(1) < 0) { 210 return; 211 } 212 jobject target = GetTarget(env); 213 if (!(jboolean)env->GetBooleanField(target, AwtMenuItem::enabledID)) { 214 item->Enable(FALSE); 215 } 216 env->DeleteLocalRef(target); 217} 218 219void AwtPopupMenu::Enable(BOOL isEnabled) 220{ 221 AwtMenu *menu = GetMenuContainer(); 222 if (menu != NULL) { 223 AwtMenu::Enable(isEnabled); 224 return; 225 } 226 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 227 if (env->EnsureLocalCapacity(1) < 0) { 228 return; 229 } 230 jobject target = GetTarget(env); 231 int nCount = CountItem(target); 232 for (int i = 0; i < nCount; ++i) { 233 AwtMenuItem *item = GetItem(target,i); 234 jobject jitem = item->GetTarget(env); 235 BOOL bItemEnabled = isEnabled && (jboolean)env->GetBooleanField(jitem, 236 AwtMenuItem::enabledID); 237 jstring labelStr = static_cast<jstring>(env->GetObjectField(jitem, AwtMenuItem::labelID)); 238 LPCWSTR labelStrW = JNU_GetStringPlatformChars(env, labelStr, NULL); 239 if (labelStrW && wcscmp(labelStrW, L"-") != 0) { 240 item->Enable(bItemEnabled); 241 } 242 JNU_ReleaseStringPlatformChars(env, labelStr, labelStrW); 243 env->DeleteLocalRef(labelStr); 244 env->DeleteLocalRef(jitem); 245 } 246 env->DeleteLocalRef(target); 247} 248 249BOOL AwtPopupMenu::IsDisabledAndPopup() 250{ 251 if (GetMenuContainer() != NULL) return FALSE; 252 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 253 if (env->EnsureLocalCapacity(1) < 0) { 254 return FALSE; 255 } 256 jobject target = GetTarget(env); 257 BOOL bEnabled = (jboolean)env->GetBooleanField(target, 258 AwtMenuItem::enabledID); 259 env->DeleteLocalRef(target); 260 return !bEnabled; 261} 262 263/************************************************************************ 264 * WPopupMenuPeer native methods 265 */ 266 267extern "C" { 268 269/* 270 * Class: sun_awt_windows_WPopupMenuPeer 271 * Method: createMenu 272 * Signature: (Lsun/awt/windows/WComponentPeer;)V 273 */ 274JNIEXPORT void JNICALL 275Java_sun_awt_windows_WPopupMenuPeer_createMenu(JNIEnv *env, jobject self, 276 jobject parent) 277{ 278 TRY; 279 280 AwtToolkit::CreateComponent( 281 self, parent, (AwtToolkit::ComponentFactory)AwtPopupMenu::Create); 282 283 CATCH_BAD_ALLOC; 284} 285 286/* 287 * Class: sun_awt_windows_WPopupMenuPeer 288 * Method: _show 289 * Signature: (Ljava/awt/Event;)V 290 */ 291JNIEXPORT void JNICALL 292Java_sun_awt_windows_WPopupMenuPeer__1show(JNIEnv *env, jobject self, 293 jobject event) 294{ 295 TRY; 296 297 ShowStruct *ss = new ShowStruct; 298 ss->self = env->NewGlobalRef(self); 299 ss->event = env->NewGlobalRef(event); 300 301 // fix for 6268046: invoke the function without CriticalSection's synchronization 302 AwtToolkit::GetInstance().InvokeFunction(AwtPopupMenu::_Show, ss); 303 // global ref and ss are deleted in _Show() 304 305 CATCH_BAD_ALLOC; 306} 307 308} /* extern "C" */ 309