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