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