1 /*
   2   test
   3   @bug       5028014
   4   @summary   Focus request & mouse click performed nearly synchronously shouldn't lead to a focus race.
   5   @author    anton.tarasov@sun.com: area=awt-focus
   6   @run       applet MouseClickRequestFocusRaceTest.html
   7 */
   8 
   9 import java.awt.*;
  10 import javax.swing.*;
  11 import java.awt.event.*;
  12 import java.applet.Applet;
  13 
  14 public class MouseClickRequestFocusRaceTest extends Applet {
  15     Robot robot;
  16     JFrame frame1 = new JFrame("Frame-1") {
  17             public String toString() { return "Frame-1";}
  18         };
  19     JFrame frame2 = new JFrame("Frame-2") {
  20             public String toString() { return "Frame-2";}
  21         };
  22     JButton button1 = new JButton("button-1") {
  23             public String toString() { return "button-1";}
  24         };
  25     JButton button2 = new JButton("button-2") {
  26             public String toString() { return "button-2";}
  27         };
  28     JPopupMenu popup = new JPopupMenu();
  29 
  30     public static void main(String[] args) {
  31         MouseClickRequestFocusRaceTest app = new MouseClickRequestFocusRaceTest();
  32         app.init();
  33         app.start();
  34     }
  35 
  36     public void init() {
  37         try {
  38             robot = new Robot();
  39         } catch (AWTException e) {
  40             throw new RuntimeException("Error: unable to create robot", e);
  41         }
  42         // Create instructions for the user here, as well as set up
  43         // the environment -- set the layout manager, add buttons,
  44         // etc.
  45         this.setLayout (new BorderLayout ());
  46         Sysout.createDialogWithInstructions(new String[]
  47             {"Automatic test. Simply wait until it is done."
  48             });
  49     }
  50 
  51     public void start() {
  52         frame1.add(button1);
  53         frame2.add(button2);
  54         frame1.setBounds(0, 0, 200, 300);
  55         frame2.setBounds(300, 0, 200, 300);
  56         frame1.setLayout(new FlowLayout());
  57         frame2.setLayout(new FlowLayout());
  58 
  59         popup.add(new JMenuItem("black"));
  60         popup.add(new JMenuItem("yellow"));
  61         popup.add(new JMenuItem("white"));
  62 
  63         frame1.add(popup);
  64 
  65         frame1.addMouseListener(new MouseAdapter() {
  66                 void popup(MouseEvent e) {
  67                     if (e.isPopupTrigger()) {
  68                         Point loc = button1.getLocation();
  69                         popup.show(button1, e.getX() - loc.x, e.getY() - loc.y);
  70                     }
  71                 }
  72                 public void mousePressed(MouseEvent e) {
  73                     popup(e);
  74                 }
  75                 public void mouseReleased(MouseEvent e) {
  76                     popup(e);
  77                 }
  78             });
  79 
  80         frame2.addMouseListener(new MouseAdapter() {
  81                 public void mousePressed(MouseEvent e) {
  82                     button1.requestFocusInWindow();
  83                 }
  84             });
  85 
  86         frame2.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
  87 
  88         frame1.setVisible(true);
  89         frame2.setVisible(true);
  90 //        ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
  91         robot.delay(1000);
  92 
  93         test();
  94     }
  95 
  96     public void test() {
  97         // Right click Frame-1
  98         robot.mouseMove(frame1.getLocation().x + 100, frame1.getLocation().y + 200);
  99         robot.mousePress(InputEvent.BUTTON3_MASK);
 100         robot.delay(100);
 101         robot.mouseRelease(InputEvent.BUTTON3_MASK);
 102 
 103 //        ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
 104         robot.delay(1000);
 105 
 106         // Left click Frame-2
 107         robot.mouseMove(frame2.getLocation().x + 100, frame1.getLocation().y + 200);
 108         robot.mousePress(InputEvent.BUTTON1_MASK);
 109         robot.delay(100);
 110         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 111 
 112 //        ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
 113         robot.delay(1000);
 114 
 115         JComponent focusOwner = (JComponent)KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
 116         JFrame focusedWindow = (JFrame)KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
 117 
 118         Sysout.println("focus owner: " + focusOwner);
 119         Sysout.println("focused window: " + focusedWindow);
 120 
 121         // Verify that the focused window is the ancestor of the focus owner
 122         if (!focusedWindow.isAncestorOf(focusOwner)) {
 123             throw new TestFailedException("The focus owner is not in the focused window!");
 124         }
 125 
 126         // Try to close native focused window
 127         robot.keyPress(KeyEvent.VK_ALT);
 128         robot.keyPress(KeyEvent.VK_F4);
 129         robot.keyRelease(KeyEvent.VK_F4);
 130         robot.keyRelease(KeyEvent.VK_ALT);
 131 
 132 //        ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
 133         robot.delay(1000);
 134 
 135         // Verify that the Java focused window really mapped the native focused window.
 136         if (focusedWindow.isVisible()) {
 137             throw new TestFailedException("The focused window is different on Java and on the native level.");
 138         }
 139     }
 140 
 141     class TestFailedException extends RuntimeException {
 142         public TestFailedException(String cause) {
 143             super("Test failed.");
 144             Sysout.println(cause);
 145         }
 146     }
 147 }
 148 
 149 /****************************************************
 150  Standard Test Machinery
 151  DO NOT modify anything below -- it's a standard
 152   chunk of code whose purpose is to make user
 153   interaction uniform, and thereby make it simpler
 154   to read and understand someone else's test.
 155  ****************************************************/
 156 
 157 /**
 158  This is part of the standard test machinery.
 159  It creates a dialog (with the instructions), and is the interface
 160   for sending text messages to the user.
 161  To print the instructions, send an array of strings to Sysout.createDialog
 162   WithInstructions method.  Put one line of instructions per array entry.
 163  To display a message for the tester to see, simply call Sysout.println
 164   with the string to be displayed.
 165  This mimics System.out.println but works within the test harness as well
 166   as standalone.
 167  */
 168 
 169 class Sysout
 170 {
 171     static TestDialog dialog;
 172 
 173     public static void createDialogWithInstructions( String[] instructions )
 174     {
 175         dialog = new TestDialog( new Frame(), "Instructions" );
 176         dialog.printInstructions( instructions );
 177 //        dialog.setVisible(true);
 178         println( "Any messages for the tester will display here." );
 179     }
 180 
 181     public static void createDialog( )
 182     {
 183         dialog = new TestDialog( new Frame(), "Instructions" );
 184         String[] defInstr = { "Instructions will appear here. ", "" } ;
 185         dialog.printInstructions( defInstr );
 186 //        dialog.setVisible(true);
 187         println( "Any messages for the tester will display here." );
 188     }
 189 
 190 
 191     public static void printInstructions( String[] instructions )
 192     {
 193         dialog.printInstructions( instructions );
 194     }
 195 
 196 
 197     public static void println( String messageIn )
 198     {
 199         dialog.displayMessage( messageIn );
 200     }
 201 
 202 }// Sysout  class
 203 
 204 /**
 205   This is part of the standard test machinery.  It provides a place for the
 206    test instructions to be displayed, and a place for interactive messages
 207    to the user to be displayed.
 208   To have the test instructions displayed, see Sysout.
 209   To have a message to the user be displayed, see Sysout.
 210   Do not call anything in this dialog directly.
 211   */
 212 class TestDialog extends Dialog
 213 {
 214 
 215     TextArea instructionsText;
 216     TextArea messageText;
 217     int maxStringLength = 80;
 218 
 219     //DO NOT call this directly, go through Sysout
 220     public TestDialog( Frame frame, String name )
 221     {
 222         super( frame, name );
 223         int scrollBoth = TextArea.SCROLLBARS_BOTH;
 224         instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
 225         add( "North", instructionsText );
 226 
 227         messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
 228         add("Center", messageText);
 229 
 230         pack();
 231 
 232 //        setVisible(true);
 233     }// TestDialog()
 234 
 235     //DO NOT call this directly, go through Sysout
 236     public void printInstructions( String[] instructions )
 237     {
 238         //Clear out any current instructions
 239         instructionsText.setText( "" );
 240 
 241         //Go down array of instruction strings
 242 
 243         String printStr, remainingStr;
 244         for( int i=0; i < instructions.length; i++ )
 245         {
 246             //chop up each into pieces maxSringLength long
 247             remainingStr = instructions[ i ];
 248             while( remainingStr.length() > 0 )
 249             {
 250                 //if longer than max then chop off first max chars to print
 251                 if( remainingStr.length() >= maxStringLength )
 252                 {
 253                     //Try to chop on a word boundary
 254                     int posOfSpace = remainingStr.
 255                         lastIndexOf( ' ', maxStringLength - 1 );
 256 
 257                     if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
 258 
 259                     printStr = remainingStr.substring( 0, posOfSpace + 1 );
 260                     remainingStr = remainingStr.substring( posOfSpace + 1 );
 261                 }
 262                 //else just print
 263                 else
 264                 {
 265                     printStr = remainingStr;
 266                     remainingStr = "";
 267                 }
 268 
 269                 instructionsText.append( printStr + "\n" );
 270 
 271             }// while
 272 
 273         }// for
 274 
 275     }//printInstructions()
 276 
 277     //DO NOT call this directly, go through Sysout
 278     public void displayMessage( String messageIn )
 279     {
 280         messageText.append( messageIn + "\n" );
 281         System.out.println(messageIn);
 282     }
 283 
 284 }// TestDialog  class