1 /*
   2  * Copyright (c) 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 package com.apple.eawt;
  27 
  28 import java.awt.Frame;
  29 import java.awt.peer.MenuComponentPeer;
  30 
  31 import javax.swing.*;
  32 import javax.swing.plaf.MenuBarUI;
  33 
  34 import com.apple.laf.ScreenMenuBar;
  35 import sun.lwawt.macosx.CMenuBar;
  36 
  37 import com.apple.laf.AquaMenuBarUI;
  38 
  39 class _AppMenuBarHandler {
  40     private static final int MENU_ABOUT = 1;
  41     private static final int MENU_PREFS = 2;
  42 
  43     private static native void nativeSetMenuState(final int menu, final boolean visible, final boolean enabled);
  44     private static native void nativeSetDefaultMenuBar(final long menuBarPeer);
  45 
  46     static final _AppMenuBarHandler instance = new _AppMenuBarHandler();
  47     static _AppMenuBarHandler getInstance() {
  48         return instance;
  49     }
  50 
  51     // callback from the native delegate -init function
  52     private static void initMenuStates(final boolean aboutMenuItemVisible, final boolean aboutMenuItemEnabled, final boolean prefsMenuItemVisible, final boolean prefsMenuItemEnabled) {
  53         synchronized (instance) {
  54             instance.aboutMenuItemVisible = aboutMenuItemVisible;
  55             instance.aboutMenuItemEnabled = aboutMenuItemEnabled;
  56             instance.prefsMenuItemVisible = prefsMenuItemVisible;
  57             instance.prefsMenuItemEnabled = prefsMenuItemEnabled;
  58         }
  59     }
  60 
  61     _AppMenuBarHandler() { }
  62 
  63     boolean aboutMenuItemVisible;
  64     boolean aboutMenuItemEnabled;
  65 
  66     boolean prefsMenuItemVisible;
  67     boolean prefsMenuItemEnabled;
  68     boolean prefsMenuItemExplicitlySet;
  69 
  70     void setDefaultMenuBar(final JMenuBar menuBar) {
  71         installDefaultMenuBar(menuBar);
  72 
  73         // scan the current frames, and see if any are foreground
  74         final Frame[] frames = Frame.getFrames();
  75         for (final Frame frame : frames) {
  76             if (frame.isVisible() && !isFrameMinimized(frame)) {
  77                 return;
  78             }
  79         }
  80 
  81         // if we have no foreground frames, then we have to "kick" the menubar
  82         final JFrame pingFrame = new JFrame();
  83         pingFrame.getRootPane().putClientProperty("Window.alpha", new Float(0.0f));
  84         pingFrame.setUndecorated(true);
  85         pingFrame.setVisible(true);
  86         pingFrame.toFront();
  87         pingFrame.setVisible(false);
  88         pingFrame.dispose();
  89     }
  90 
  91     static boolean isFrameMinimized(final Frame frame) {
  92         return (frame.getExtendedState() & Frame.ICONIFIED) != 0;
  93     }
  94 
  95     @SuppressWarnings("deprecation")
  96     static void installDefaultMenuBar(final JMenuBar menuBar) {
  97         if (menuBar == null) {
  98             // intentionally clearing the default menu
  99             nativeSetDefaultMenuBar(0);
 100             return;
 101         }
 102 
 103         final MenuBarUI ui = menuBar.getUI();
 104         if (!(ui instanceof AquaMenuBarUI)) {
 105             // Aqua was not installed
 106             throw new IllegalStateException("Application.setDefaultMenuBar() only works with the Aqua Look and Feel");
 107         }
 108 
 109         final AquaMenuBarUI aquaUI = (AquaMenuBarUI)ui;
 110         final ScreenMenuBar screenMenuBar = aquaUI.getScreenMenuBar();
 111         if (screenMenuBar == null) {
 112             // Aqua is installed, but we aren't using the screen menu bar
 113             throw new IllegalStateException("Application.setDefaultMenuBar() only works if apple.laf.useScreenMenuBar=true");
 114         }
 115 
 116         screenMenuBar.addNotify();
 117         final MenuComponentPeer peer = screenMenuBar.getPeer();
 118         if (!(peer instanceof CMenuBar)) {
 119             // such a thing should not be possible
 120             throw new IllegalStateException("Unable to determine native menu bar from provided JMenuBar");
 121         }
 122 
 123         // grab the pointer to the CMenuBar, and retain it in native
 124         nativeSetDefaultMenuBar(((CMenuBar)peer).getModel());
 125     }
 126 
 127     void setAboutMenuItemVisible(final boolean present) {
 128         synchronized (this) {
 129             if (aboutMenuItemVisible == present) return;
 130             aboutMenuItemVisible = present;
 131         }
 132 
 133         nativeSetMenuState(MENU_ABOUT, aboutMenuItemVisible, aboutMenuItemEnabled);
 134     }
 135 
 136     void setPreferencesMenuItemVisible(final boolean present) {
 137         synchronized (this) {
 138             prefsMenuItemExplicitlySet = true;
 139             if (prefsMenuItemVisible == present) return;
 140             prefsMenuItemVisible = present;
 141         }
 142         nativeSetMenuState(MENU_PREFS, prefsMenuItemVisible, prefsMenuItemEnabled);
 143     }
 144 
 145     void setAboutMenuItemEnabled(final boolean enable) {
 146         synchronized (this) {
 147             if (aboutMenuItemEnabled == enable) return;
 148             aboutMenuItemEnabled = enable;
 149         }
 150         nativeSetMenuState(MENU_ABOUT, aboutMenuItemVisible, aboutMenuItemEnabled);
 151     }
 152 
 153     void setPreferencesMenuItemEnabled(final boolean enable) {
 154         synchronized (this) {
 155             prefsMenuItemExplicitlySet = true;
 156             if (prefsMenuItemEnabled == enable) return;
 157             prefsMenuItemEnabled = enable;
 158         }
 159         nativeSetMenuState(MENU_PREFS, prefsMenuItemVisible, prefsMenuItemEnabled);
 160     }
 161 
 162     boolean isAboutMenuItemVisible() {
 163         return aboutMenuItemVisible;
 164     }
 165 
 166     boolean isPreferencesMenuItemVisible() {
 167         return prefsMenuItemVisible;
 168     }
 169 
 170     boolean isAboutMenuItemEnabled() {
 171         return aboutMenuItemEnabled;
 172     }
 173 
 174     boolean isPreferencesMenuItemEnabled() {
 175         return prefsMenuItemEnabled;
 176     }
 177 }