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