1 /*
   2  * Copyright (c) 2018, 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 /**
  27  * @test
  28  * @key headful
  29  * @bug 8146310
  30  * @summary [macosx] setDefaultMenuBar does not initialize screen menu bar
  31  * @author Alan Snyder
  32  * @run main/othervm TestNoScreenMenuBar
  33  * @requires (os.family == "mac")
  34  */
  35 
  36 import java.awt.AWTException;
  37 import java.awt.Desktop;
  38 import java.awt.Robot;
  39 import java.awt.event.InputEvent;
  40 import java.io.IOException;
  41 import java.lang.reflect.InvocationTargetException;
  42 import javax.swing.JMenu;
  43 import javax.swing.JMenuBar;
  44 import javax.swing.JMenuItem;
  45 import javax.swing.SwingUtilities;
  46 
  47 public class TestNoScreenMenuBar
  48 {
  49     static TestNoScreenMenuBar theTest;
  50     private Robot robot;
  51     private boolean isApplicationOpened;
  52     private boolean isActionPerformed;
  53 
  54         public TestNoScreenMenuBar(String[] args)
  55         {
  56         try {
  57             robot = new Robot();
  58             robot.setAutoDelay(50);
  59         } catch (AWTException ex) {
  60             throw new RuntimeException(ex);
  61         }
  62 
  63         if (!(args.length > 0 && args[0].equals("baseline"))) {
  64             // activate another application
  65             openOtherApplication();
  66             robot.delay(500);
  67         }
  68 
  69         // The failure mode is installing the default menu bar while the application is inactive
  70         Desktop desktop = Desktop.getDesktop();
  71         desktop.setDefaultMenuBar(createMenuBar());
  72 
  73         robot.delay(500);
  74         desktop.requestForeground(true);
  75         robot.delay(500);
  76         }
  77 
  78     JMenuBar createMenuBar()
  79     {
  80         JMenuBar mb = new JMenuBar();
  81         // A very long name makes it more likely that the robot will hit the menu
  82         JMenu menu = new JMenu("TestTestTestTestTestTestTestTestTestTest");
  83         mb.add(menu);
  84         JMenuItem item = new JMenuItem("TestTestTestTestTestTestTestTestTestTest");
  85         item.addActionListener(ev -> {
  86             isActionPerformed = true;
  87         });
  88         menu.add(item);
  89         return mb;
  90     }
  91 
  92     void dispose()
  93     {
  94         closeOtherApplication();
  95         Desktop.getDesktop().setDefaultMenuBar(null);
  96     }
  97 
  98     private void performMenuItemTest()
  99     {
 100         // Find the menu on the screen menu bar
 101         // The location depends upon the application name which is the name of the first menu.
 102         // Unfortunately, the application name can vary based on how the application is run.
 103         // The work around is to make the menu and the menu item names very long.
 104 
 105         int menuBarX = 250;
 106         int menuBarY = 11;
 107         int menuItemX = menuBarX;
 108         int menuItemY = 34;
 109 
 110         robot.mouseMove(menuBarX, menuBarY);
 111         robot.delay(100);
 112         robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
 113         robot.delay(100);
 114         robot.mouseMove(menuItemX, menuItemY);
 115         robot.delay(100);
 116         robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
 117         robot.waitForIdle();
 118 
 119         waitForAction();
 120     }
 121 
 122     private synchronized void waitForAction()
 123     {
 124         try {
 125             for (int i = 0; i < 10; i++) {
 126                 if (isActionPerformed) {
 127                     return;
 128                 }
 129                 wait(100);
 130             }
 131         } catch (InterruptedException ex) {
 132         }
 133         throw new RuntimeException("Test failed: menu item action was not performed");
 134     }
 135 
 136     private void openOtherApplication() {
 137         String[] cmd = { "/usr/bin/open", "/Applications/System Preferences.app" };
 138         execute(cmd);
 139         isApplicationOpened = true;
 140     }
 141 
 142     private void closeOtherApplication() {
 143         if (isApplicationOpened) {
 144             String[] cmd = { "/usr/bin/osascript", "-e", "tell application \"System Preferences\" to close window 1" };
 145             execute(cmd);
 146         }
 147     }
 148 
 149     private void execute(String[] cmd) {
 150         try {
 151             Process p = Runtime.getRuntime().exec(cmd);
 152             p.waitFor();
 153         } catch (IOException | InterruptedException ex) {
 154             throw new RuntimeException("Unable to execute command");
 155         }
 156     }
 157 
 158     private static void runSwing(Runnable r)
 159     {
 160         try {
 161             SwingUtilities.invokeAndWait(r);
 162         } catch (InterruptedException e) {
 163         } catch (InvocationTargetException e) {
 164             throw new RuntimeException(e);
 165         }
 166     }
 167 
 168         public static void main(String[] args)
 169         {
 170         if (!System.getProperty("os.name").contains("OS X")) {
 171             System.out.println("This test is for MacOS only. Automatically passed on other platforms.");
 172             return;
 173         }
 174 
 175         System.setProperty("apple.laf.useScreenMenuBar", "true");
 176         try {
 177             runSwing(() -> theTest = new TestNoScreenMenuBar(args));
 178             theTest.performMenuItemTest();
 179         } finally {
 180             if (theTest != null) {
 181                 runSwing(() -> theTest.dispose());
 182             }
 183         }
 184         }
 185 }