8007267: [macosx] com.apple.eawt.Application.setDefaultMenuBar is not working
authorleonidr
Fri, 26 Jul 2013 16:22:29 +0400
changeset 19022 4d36c6935abb
parent 19021 8a5340b88ee5
child 19023 0f75f2d09f6e
8007267: [macosx] com.apple.eawt.Application.setDefaultMenuBar is not working Reviewed-by: anthony, serb
jdk/src/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java
jdk/src/macosx/classes/sun/lwawt/macosx/CMenuComponent.java
jdk/src/macosx/native/sun/awt/AWTWindow.m
jdk/src/macosx/native/sun/awt/CMenuItem.m
--- a/jdk/src/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java	Wed Jul 24 17:14:45 2013 +0400
+++ b/jdk/src/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java	Fri Jul 26 16:22:29 2013 +0400
@@ -31,6 +31,7 @@
 import javax.swing.*;
 import javax.swing.plaf.MenuBarUI;
 
+import com.apple.laf.ScreenMenuBar;
 import sun.lwawt.macosx.CMenuBar;
 
 import com.apple.laf.AquaMenuBarUI;
@@ -72,12 +73,15 @@
         // scan the current frames, and see if any are foreground
         final Frame[] frames = Frame.getFrames();
         for (final Frame frame : frames) {
-            if (frame.isVisible() && !isFrameMinimized(frame)) return;
+            if (frame.isVisible() && !isFrameMinimized(frame)) {
+                return;
+            }
         }
 
         // if we have no foreground frames, then we have to "kick" the menubar
         final JFrame pingFrame = new JFrame();
         pingFrame.getRootPane().putClientProperty("Window.alpha", new Float(0.0f));
+        pingFrame.setUndecorated(true);
         pingFrame.setVisible(true);
         pingFrame.toFront();
         pingFrame.setVisible(false);
@@ -101,7 +105,6 @@
             // Aqua was not installed
             throw new IllegalStateException("Application.setDefaultMenuBar() only works with the Aqua Look and Feel");
         }
-/* TODO: disabled until ScreenMenuBar is working
 
         final AquaMenuBarUI aquaUI = (AquaMenuBarUI)ui;
         final ScreenMenuBar screenMenuBar = aquaUI.getScreenMenuBar();
@@ -118,8 +121,7 @@
         }
 
         // grab the pointer to the CMenuBar, and retain it in native
-        nativeSetDefaultMenuBar(((CMenuBar)peer).getNativeMenuBarPeer());
-*/
+        nativeSetDefaultMenuBar(((CMenuBar)peer).getModel());
     }
 
     void setAboutMenuItemVisible(final boolean present) {
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CMenuComponent.java	Wed Jul 24 17:14:45 2013 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CMenuComponent.java	Fri Jul 26 16:22:29 2013 +0400
@@ -43,7 +43,7 @@
         return target;
     }
 
-    long getModel() {
+    public long getModel() {
         return modelPtr;
     }
 
--- a/jdk/src/macosx/native/sun/awt/AWTWindow.m	Wed Jul 24 17:14:45 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m	Fri Jul 26 16:22:29 2013 +0400
@@ -30,6 +30,7 @@
 #import "sun_lwawt_macosx_CPlatformWindow.h"
 #import "com_apple_eawt_event_GestureHandler.h"
 #import "com_apple_eawt_FullScreenHandler.h"
+#import "ApplicationDelegate.h"
 
 #import "AWTWindow.h"
 #import "AWTView.h"
@@ -55,7 +56,7 @@
 // doesn't provide information about "opposite" window, so we
 // have to do a bit of tracking. This variable points to a window
 // which had been the key window just before a new key window
-// was set. It would be nil if the new key window isn't an AWT 
+// was set. It would be nil if the new key window isn't an AWT
 // window or the app currently has no key window.
 static AWTWindow* lastKeyWindow = nil;
 
@@ -542,17 +543,26 @@
 AWT_ASSERT_APPKIT_THREAD;
     [AWTToolkit eventCountPlusPlus];
     AWTWindow *opposite = [AWTWindow lastKeyWindow];
-    
+
     // Finds appropriate menubar in our hierarchy,
     AWTWindow *awtWindow = self;
     while (awtWindow.ownerWindow != nil) {
         awtWindow = awtWindow.ownerWindow;
     }
+
     CMenuBar *menuBar = nil;
+    BOOL isDisabled = NO;
     if ([awtWindow.nsWindow isVisible]){
         menuBar = awtWindow.javaMenuBar;
+        isDisabled = !awtWindow.isEnabled;
     }
-    [CMenuBar activate:menuBar modallyDisabled:!awtWindow.isEnabled];
+
+    if (menuBar == nil) {
+        menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
+        isDisabled = NO;
+    }
+
+    [CMenuBar activate:menuBar modallyDisabled:isDisabled];
 
     [AWTWindow setLastKeyWindow:nil];
 
@@ -565,6 +575,14 @@
     [AWTToolkit eventCountPlusPlus];
     [self.javaMenuBar deactivate];
 
+    // In theory, this might cause flickering if the window gaining focus
+    // has its own menu. However, I couldn't reproduce it on practice, so
+    // perhaps this is a non issue.
+    CMenuBar* defaultMenu = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
+    if (defaultMenu != nil) {
+        [CMenuBar activate:defaultMenu modallyDisabled:NO];
+    }
+
     // the new key window
     NSWindow *keyWindow = [NSApp keyWindow];
     AWTWindow *opposite = nil;
@@ -829,11 +847,19 @@
 
         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 
-        if ([nsWindow isKeyWindow]) [window.javaMenuBar deactivate];
+        if ([nsWindow isKeyWindow]) {
+            [window.javaMenuBar deactivate];
+        }
+
         window.javaMenuBar = menuBar;
 
+        CMenuBar* actualMenuBar = menuBar;
+        if (actualMenuBar == nil) {
+            actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
+        }
+
         if ([nsWindow isKeyWindow]) {
-            [CMenuBar activate:window.javaMenuBar modallyDisabled:NO];
+            [CMenuBar activate:actualMenuBar modallyDisabled:NO];
         }
     }];
 
--- a/jdk/src/macosx/native/sun/awt/CMenuItem.m	Wed Jul 24 17:14:45 2013 +0400
+++ b/jdk/src/macosx/native/sun/awt/CMenuItem.m	Fri Jul 26 16:22:29 2013 +0400
@@ -70,9 +70,15 @@
     JNIEnv *env = [ThreadUtilities getJNIEnv];
 JNF_COCOA_ENTER(env);
 
-    // If we are called as a result of user pressing a shorcut, do nothing,
+    // If we are called as a result of user pressing a shortcut, do nothing,
     // because AVTView has already sent corresponding key event to the Java
-    // layer from performKeyEquivalent
+    // layer from performKeyEquivalent.
+    // There is an exception from the rule above, though: if a window with
+    // a menu gets minimized by user and there are no other windows to take
+    // focus, the window's menu won't be removed from the global menu bar.
+    // However, the Java layer won't handle invocation by a shortcut coming
+    // from this "frameless" menu, because there are no active windows. This
+    // means we have to handle it here.
     NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent];
     if ([currEvent type] == NSKeyDown) {
         NSString *menuKey = [sender keyEquivalent];
@@ -91,7 +97,8 @@
             eventKey = [NSString stringWithCharacters: &newChar length: 1];
         }
 
-        if ([menuKey isEqualToString:eventKey]) {
+        NSWindow *keyWindow = [NSApp keyWindow];
+        if ([menuKey isEqualToString:eventKey] && keyWindow != nil) {
             return;
         }
     }