1 /* 2 * Copyright (c) 1996, 2007, 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 <java_awt_PopupMenu.h> 32 #include <sun_awt_windows_WPopupMenuPeer.h> 33 #include <java_awt_Event.h> 34 35 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 36 */ 37 38 /***********************************************************************/ 39 // struct for _Show method 40 struct ShowStruct { 41 jobject self; 42 jobject event; 43 }; 44 45 /************************************************************************ 46 * AwtPopupMenu class methods 47 */ 48 49 AwtPopupMenu::AwtPopupMenu() { 50 m_parent = NULL; 51 } 52 53 AwtPopupMenu::~AwtPopupMenu() 54 { 55 } 56 57 void AwtPopupMenu::Dispose() 58 { 59 m_parent = NULL; 60 61 AwtMenu::Dispose(); 62 } 63 64 LPCTSTR AwtPopupMenu::GetClassName() { 65 return TEXT("SunAwtPopupMenu"); 66 } 67 68 /* Create a new AwtPopupMenu object and menu. */ 69 AwtPopupMenu* AwtPopupMenu::Create(jobject self, AwtComponent* parent) 70 { 71 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 72 73 jobject target = NULL; 74 AwtPopupMenu* popupMenu = NULL; 75 76 try { 77 if (env->EnsureLocalCapacity(1) < 0) { 78 return NULL; 79 } 80 81 target = env->GetObjectField(self, AwtObject::targetID); 82 JNI_CHECK_NULL_GOTO(target, "null target", done); 83 84 popupMenu = new AwtPopupMenu(); 85 86 SetLastError(0); 87 HMENU hMenu = ::CreatePopupMenu(); 88 // fix for 5088782 89 if (!CheckMenuCreation(env, self, hMenu)) 90 { 91 env->DeleteLocalRef(target); 92 return NULL; 93 } 94 95 popupMenu->SetHMenu(hMenu); 96 97 popupMenu->LinkObjects(env, self); 98 popupMenu->SetParent(parent); 99 } catch (...) { 100 env->DeleteLocalRef(target); 101 throw; 102 } 103 104 done: 105 env->DeleteLocalRef(target); 106 return popupMenu; 107 } 108 109 void AwtPopupMenu::Show(JNIEnv *env, jobject event, BOOL isTrayIconPopup) 110 { 111 /* 112 * For not TrayIcon popup. 113 * Convert the event's XY to absolute coordinates. The XY is 114 * relative to the origin component, which is passed by PopupMenu 115 * as the event's target. 116 */ 117 if (env->EnsureLocalCapacity(2) < 0) { 118 env->DeleteGlobalRef(event); 119 return; 120 } 121 jobject origin = (env)->GetObjectField(event, AwtEvent::targetID); 122 jobject peerOrigin = GetPeerForTarget(env, origin); 123 PDATA pData; 124 JNI_CHECK_PEER_GOTO(peerOrigin, done); 125 { 126 AwtComponent* awtOrigin = (AwtComponent*)pData; 127 POINT pt; 128 UINT flags = 0; 129 pt.x = (env)->GetIntField(event, AwtEvent::xID); 130 pt.y = (env)->GetIntField(event, AwtEvent::yID); 131 132 if (!isTrayIconPopup) { 133 ::MapWindowPoints(awtOrigin->GetHWnd(), 0, (LPPOINT)&pt, 1); 134 135 // Adjust to account for the Inset values 136 RECT rctInsets; 137 awtOrigin->GetInsets(&rctInsets); 138 pt.x -= rctInsets.left; 139 pt.y -= rctInsets.top; 140 141 flags = TPM_LEFTALIGN | TPM_RIGHTBUTTON; 142 143 } else { 144 ::SetForegroundWindow(awtOrigin->GetHWnd()); 145 146 flags = TPM_NONOTIFY | TPM_RIGHTALIGN | TPM_RIGHTBUTTON | TPM_BOTTOMALIGN; 147 } 148 149 /* Invoke the popup. */ 150 ::TrackPopupMenu(GetHMenu(), flags, pt.x, pt.y, 0, awtOrigin->GetHWnd(), NULL); 151 152 if (isTrayIconPopup) { 153 ::PostMessage(awtOrigin->GetHWnd(), WM_NULL, 0, 0); 154 } 155 } 156 done: 157 env->DeleteLocalRef(origin); 158 env->DeleteLocalRef(peerOrigin); 159 env->DeleteGlobalRef(event); 160 } 161 162 void 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 = 169 env->FindClass("java/awt/PopupMenu"); 170 if (!popupMenuClsLocal) { 171 /* exception already thrown */ 172 ShowStruct *ss = (ShowStruct*)param; 173 if (ss->self != NULL) { 174 env->DeleteGlobalRef(ss->self); 175 } 176 delete ss; 177 return; 178 } 179 popupMenuCls = (jclass)env->NewGlobalRef(popupMenuClsLocal); 180 env->DeleteLocalRef(popupMenuClsLocal); 181 } 182 183 static jfieldID isTrayIconPopupID; 184 if (isTrayIconPopupID == NULL) { 185 isTrayIconPopupID = env->GetFieldID(popupMenuCls, "isTrayIconPopup", "Z"); 186 DASSERT(isTrayIconPopupID); 187 } 188 189 ShowStruct *ss = (ShowStruct*)param; 190 if (ss->self != NULL) { 191 PDATA pData = JNI_GET_PDATA(ss->self); 192 if (pData) { 193 AwtPopupMenu *p = (AwtPopupMenu *)pData; 194 jobject target = p->GetTarget(env); 195 BOOL isTrayIconPopup = env->GetBooleanField(target, isTrayIconPopupID); 196 env->DeleteLocalRef(target); 197 p->Show(env, ss->event, isTrayIconPopup); 198 } 199 env->DeleteGlobalRef(ss->self); 200 } 201 delete ss; 202 } 203 204 void 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 219 void 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 249 BOOL 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 267 extern "C" { 268 269 /* 270 * Class: sun_awt_windows_WPopupMenuPeer 271 * Method: createMenu 272 * Signature: (Lsun/awt/windows/WComponentPeer;)V 273 */ 274 JNIEXPORT void JNICALL 275 Java_sun_awt_windows_WPopupMenuPeer_createMenu(JNIEnv *env, jobject self, 276 jobject parent) 277 { 278 TRY; 279 280 PDATA pData; 281 JNI_CHECK_PEER_RETURN(parent); 282 AwtComponent* awtParent = (AwtComponent *)pData; 283 AwtToolkit::CreateComponent( 284 self, awtParent, (AwtToolkit::ComponentFactory)AwtPopupMenu::Create, FALSE); 285 JNI_CHECK_PEER_CREATION_RETURN(self); 286 287 CATCH_BAD_ALLOC; 288 } 289 290 /* 291 * Class: sun_awt_windows_WPopupMenuPeer 292 * Method: _show 293 * Signature: (Ljava/awt/Event;)V 294 */ 295 JNIEXPORT void JNICALL 296 Java_sun_awt_windows_WPopupMenuPeer__1show(JNIEnv *env, jobject self, 297 jobject event) 298 { 299 TRY; 300 301 ShowStruct *ss = new ShowStruct; 302 ss->self = env->NewGlobalRef(self); 303 ss->event = env->NewGlobalRef(event); 304 305 // fix for 6268046: invoke the function without CriticalSection's synchronization 306 AwtToolkit::GetInstance().InvokeFunction(AwtPopupMenu::_Show, ss); 307 // global ref is deleted in _Show() and ss is deleted in Show() 308 309 CATCH_BAD_ALLOC; 310 } 311 312 } /* extern "C" */