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