1 /*
   2 test
   3 @bug 4799136
   4 @summary Tests that type-ahead for dialog works and doesn't block program
   5 @author Dmitry.Cherepanov@SUN.COM area=awt.focus
   6 @run applet EnqueueWithDialogButtonTest.html
   7 */
   8 
   9 import java.applet.Applet;
  10 import java.awt.*;
  11 import java.lang.reflect.InvocationTargetException;
  12 import java.awt.event.*;
  13 import sun.awt.SunToolkit;
  14 
  15 /*
  16  * Tests that type-ahead works correctly. That means
  17  * that the key events are not delivered until a focus
  18  * transfer is completed. This test is non-Windows
  19  * because the unexpected FOCUS_GAINED event on dialog
  20  * will cause the key event processing before the button
  21  * become the focus owner(bug 6347235). That's why another
  22  * similar regression test was written: EnqueueWithDialogTest.
  23  */
  24 
  25 public class EnqueueWithDialogButtonTest extends Applet
  26 {
  27     static Frame f;
  28     static Button b;
  29     static Dialog d;
  30     static Button ok;
  31     static Semaphore pressSema = new Semaphore();
  32     static Semaphore robotSema = new Semaphore();
  33     static volatile boolean gotFocus = false;
  34     static Robot robot;
  35     public void init()
  36     {
  37         Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
  38                 public void eventDispatched(AWTEvent e) {
  39                     if (e instanceof InputEvent){
  40                         System.err.println(e.toString()+","+((InputEvent)e).getWhen());
  41                     }else{
  42                         System.err.println(e.toString());
  43                     }
  44                  }
  45             }, AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
  46 
  47         this.setLayout (new BorderLayout ());
  48 
  49         f = new Frame("frame");
  50         b = new Button("press");
  51         d = new Dialog(f, "dialog", true);
  52         ok = new Button("ok");
  53         d.add(ok);
  54         d.pack();
  55         ok.addKeyListener(new KeyAdapter() {
  56                 public void keyPressed(KeyEvent e) {
  57                     System.err.println("OK pressed: should arrive after got focus");
  58                     d.dispose();
  59                     f.dispose();
  60                     // Typed-ahead key events should only be accepted if
  61                     // they arrive after FOCUS_GAINED
  62                     if (gotFocus) {
  63                         pressSema.raise();
  64                     }
  65                 }
  66             });
  67         ok.addFocusListener(new FocusAdapter() {
  68                 public void focusGained(FocusEvent e) {
  69                     gotFocus = true;
  70                     System.err.println("OK got focus");
  71                 }
  72             });
  73         f.add(b);
  74         f.pack();
  75         b.addActionListener(new ActionListener() {
  76                 public void actionPerformed(ActionEvent e) {
  77                     System.err.println(e.toString()+","+e.getWhen());
  78                     System.err.println("B pressed");
  79                     robotSema.raise();
  80 
  81                     EventQueue.invokeLater(new Runnable() {
  82                             public void run() {
  83                                 waitTillShown(d);
  84                                 EnqueueWithDialogButtonTest.this.d.toFront();
  85                                 EnqueueWithDialogButtonTest.this.moveMouseOver(d);
  86                             }
  87                         });
  88 
  89                     // This will cause enqueue the following key events
  90                     d.setVisible(true);
  91                 }
  92             });
  93 
  94     }//End  init()
  95 
  96     public void start ()
  97     {
  98         // This test doesn't work on Windows
  99         // because of the bug 6347235
 100         final String os = System.getProperty("os.name");
 101         final boolean isWin = os.startsWith("Win");
 102         if (isWin){
 103             System.err.println("non-Windows test");
 104             return;
 105         }
 106 
 107         //Get things going.  Request focus, set size, et cetera
 108         setSize (200,200);
 109         setVisible(true);
 110         validate();
 111         try {
 112             robot = new Robot();
 113         } catch (Exception e) {
 114             throw new RuntimeException("Can't create robot:" + e);
 115         }
 116 
 117         f.setVisible(true);
 118         waitTillShown(b);
 119         System.err.println("b is shown");
 120         f.toFront();
 121         moveMouseOver(f);
 122         ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
 123         makeFocused(b);
 124         ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
 125         System.err.println("b is focused");
 126 
 127         robot.keyPress(KeyEvent.VK_SPACE);
 128         robot.keyRelease(KeyEvent.VK_SPACE);
 129         try {
 130             robotSema.doWait(1000);
 131         } catch (InterruptedException ie) {
 132             throw new RuntimeException("Interrupted!");
 133         }
 134         robot.keyPress(KeyEvent.VK_SPACE);
 135         robot.keyRelease(KeyEvent.VK_SPACE);
 136         ((SunToolkit)Toolkit.getDefaultToolkit()).realSync();
 137         try {
 138             pressSema.doWait(3000);
 139         } catch (InterruptedException ie) {
 140             throw new RuntimeException("Interrupted!");
 141         }
 142         if (!pressSema.getState()) {
 143             throw new RuntimeException("Type-ahead doesn't work");
 144         }
 145 
 146     }// start()
 147 
 148     private void moveMouseOver(Container c) {
 149         Point p = c.getLocationOnScreen();
 150         Dimension d = c.getSize();
 151         robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)(d.getHeight()/2));
 152     }
 153 
 154     private void waitTillShown(Component c) {
 155         while (true) {
 156             try {
 157                 Thread.sleep(100);
 158                 c.getLocationOnScreen();
 159                 break;
 160             } catch (InterruptedException ie) {
 161                 ie.printStackTrace();
 162                 break;
 163             } catch (Exception e) {
 164             }
 165         }
 166     }
 167     private void makeFocused(Component comp) {
 168         if (comp.isFocusOwner()) {
 169             return;
 170         }
 171         final Semaphore sema = new Semaphore();
 172         final FocusAdapter fa = new FocusAdapter() {
 173                 public void focusGained(FocusEvent fe) {
 174                     sema.raise();
 175                 }
 176             };
 177         comp.addFocusListener(fa);
 178         comp.requestFocusInWindow();
 179         if (comp.isFocusOwner()) {
 180             return;
 181         }
 182         try {
 183             sema.doWait(3000);
 184         } catch (InterruptedException ie) {
 185             ie.printStackTrace();
 186         }
 187         comp.removeFocusListener(fa);
 188         if (!comp.isFocusOwner()) {
 189             throw new RuntimeException("Can't make " + comp + " focused, current owner is " + KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
 190         }
 191     }
 192 
 193 static class Semaphore {
 194     boolean state = false;
 195     int waiting = 0;
 196     public Semaphore() {
 197     }
 198     public synchronized void doWait() throws InterruptedException {
 199         if (state) {
 200             return;
 201         }
 202         waiting++;
 203         wait();
 204         waiting--;
 205     }
 206     public synchronized void doWait(int timeout) throws InterruptedException {
 207         if (state) {
 208             return;
 209         }
 210         waiting++;
 211         wait(timeout);
 212         waiting--;
 213     }
 214     public synchronized void raise() {
 215         state = true;
 216         if (waiting > 0) {
 217             notifyAll();
 218         }
 219     }
 220     public synchronized boolean getState() {
 221         return state;
 222     }
 223 }
 224 }// class TestDialogTypeAhead
 225 
 226 
 227 /****************************************************
 228  Standard Test Machinery
 229  DO NOT modify anything below -- it's a standard
 230   chunk of code whose purpose is to make user
 231   interaction uniform, and thereby make it simpler
 232   to read and understand someone else's test.
 233  ****************************************************/
 234 
 235 /**
 236  This is part of the standard test machinery.
 237  It creates a dialog (with the instructions), and is the interface
 238   for sending text messages to the user.
 239  To print the instructions, send an array of strings to Sysout.createDialog
 240   WithInstructions method.  Put one line of instructions per array entry.
 241  To display a message for the tester to see, simply call Sysout.println
 242   with the string to be displayed.
 243  This mimics System.out.println but works within the test harness as well
 244   as standalone.
 245  */
 246 
 247 class Sysout
 248 {
 249     private static TestDialog dialog;
 250 
 251     public static void createDialogWithInstructions( String[] instructions )
 252     {
 253         dialog = new TestDialog( new Frame(), "Instructions" );
 254         dialog.printInstructions( instructions );
 255         dialog.setVisible(true);
 256         println( "Any messages for the tester will display here." );
 257     }
 258 
 259     public static void createDialog( )
 260     {
 261         dialog = new TestDialog( new Frame(), "Instructions" );
 262         String[] defInstr = { "Instructions will appear here. ", "" } ;
 263         dialog.printInstructions( defInstr );
 264         dialog.setVisible(true);
 265         println( "Any messages for the tester will display here." );
 266     }
 267 
 268 
 269     public static void printInstructions( String[] instructions )
 270     {
 271         dialog.printInstructions( instructions );
 272     }
 273 
 274 
 275     public static void println( String messageIn )
 276     {
 277         dialog.displayMessage( messageIn );
 278     }
 279 
 280 }// Sysout  class
 281 
 282 /**
 283   This is part of the standard test machinery.  It provides a place for the
 284    test instructions to be displayed, and a place for interactive messages
 285    to the user to be displayed.
 286   To have the test instructions displayed, see Sysout.
 287   To have a message to the user be displayed, see Sysout.
 288   Do not call anything in this dialog directly.
 289   */
 290 class TestDialog extends Dialog
 291 {
 292 
 293     TextArea instructionsText;
 294     TextArea messageText;
 295     int maxStringLength = 80;
 296 
 297     //DO NOT call this directly, go through Sysout
 298     public TestDialog( Frame frame, String name )
 299     {
 300         super( frame, name );
 301         int scrollBoth = TextArea.SCROLLBARS_BOTH;
 302         instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
 303         add( "North", instructionsText );
 304 
 305         messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
 306         add("Center", messageText);
 307 
 308         pack();
 309 
 310         show();
 311     }// TestDialog()
 312 
 313     //DO NOT call this directly, go through Sysout
 314     public void printInstructions( String[] instructions )
 315     {
 316         //Clear out any current instructions
 317         instructionsText.setText( "" );
 318 
 319         //Go down array of instruction strings
 320 
 321         String printStr, remainingStr;
 322         for( int i=0; i < instructions.length; i++ )
 323         {
 324             //chop up each into pieces maxSringLength long
 325             remainingStr = instructions[ i ];
 326             while( remainingStr.length() > 0 )
 327             {
 328                 //if longer than max then chop off first max chars to print
 329                 if( remainingStr.length() >= maxStringLength )
 330                 {
 331                     //Try to chop on a word boundary
 332                     int posOfSpace = remainingStr.
 333                         lastIndexOf( ' ', maxStringLength - 1 );
 334 
 335                     if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
 336 
 337                     printStr = remainingStr.substring( 0, posOfSpace + 1 );
 338                     remainingStr = remainingStr.substring( posOfSpace + 1 );
 339                 }
 340                 //else just print
 341                 else
 342                 {
 343                     printStr = remainingStr;
 344                     remainingStr = "";
 345                 }
 346 
 347                 instructionsText.append( printStr + "\n" );
 348 
 349             }// while
 350 
 351         }// for
 352 
 353     }//printInstructions()
 354 
 355     //DO NOT call this directly, go through Sysout
 356     public void displayMessage( String messageIn )
 357     {
 358         messageText.append( messageIn + "\n" );
 359         System.out.println(messageIn);
 360     }
 361 
 362 }// TestDialog  class