1 /* 2 * Copyright (c) 2003, 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. 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 area=awt.focus 29 @run applet TestDialogTypeAhead.html 30 */ 31 32 // Note there is no @ in front of test above. This is so that the 33 // harness will not mistake this file as a test file. It should 34 // only see the html file as a test file. (the harness runs all 35 // valid test files, so it would run this test twice if this file 36 // were valid as well as the html file.) 37 // Also, note the area= after Your Name in the author tag. Here, you 38 // should put which functional area the test falls in. See the 39 // AWT-core home page -> test areas and/or -> AWT team for a list of 40 // areas. 41 // Note also the 'TestDialogTypeAhead.html' in the run tag. This should 42 // be changed to the name of the test. 43 44 45 /** 46 * TestDialogTypeAhead.java 47 * 48 * summary: 49 */ 50 51 import java.applet.Applet; 52 import java.awt.*; 53 import java.awt.event.*; 54 import java.lang.reflect.InvocationTargetException; 55 import test.java.awt.regtesthelpers.Util; 56 57 //Automated tests should run as applet tests if possible because they 58 // get their environments cleaned up, including AWT threads, any 59 // test created threads, and any system resources used by the test 60 // such as file descriptors. (This is normally not a problem as 61 // main tests usually run in a separate VM, however on some platforms 62 // such as the Mac, separate VMs are not possible and non-applet 63 // tests will cause problems). Also, you don't have to worry about 64 // synchronisation stuff in Applet tests they way you do in main 65 // tests... 66 67 68 public class TestDialogTypeAhead extends Applet 69 { 70 //Declare things used in the test, like buttons and labels here 71 static Frame f; 72 static Button b; 73 static Dialog d; 74 static Button ok; 75 static Semaphore pressSema = new Semaphore(); 76 static Semaphore robotSema = new Semaphore(); 77 static volatile boolean gotFocus = false; 78 static Robot robot; 79 public void init() 80 { 81 //Create instructions for the user here, as well as set up 82 // the environment -- set the layout manager, add buttons, 83 // etc. 84 85 Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { 86 public void eventDispatched(AWTEvent e) { 87 System.err.println(e.toString()); 88 } 89 }, AWTEvent.KEY_EVENT_MASK); 90 91 KeyboardFocusManager.setCurrentKeyboardFocusManager(new TestKFM()); 92 93 this.setLayout (new BorderLayout ()); 94 95 f = new Frame("frame"); 96 b = new Button("press"); 97 d = new Dialog(f, "dialog", true); 98 ok = new Button("ok"); 99 d.add(ok); 100 d.pack(); 101 102 ok.addKeyListener(new KeyAdapter() { 103 public void keyPressed(KeyEvent e) { 104 System.err.println("OK pressed"); 105 d.dispose(); 106 f.dispose(); 107 // Typed-ahead key events should only be accepted if 108 // they arrive after FOCUS_GAINED 109 if (gotFocus) { 110 pressSema.raise(); 111 } 112 } 113 }); 114 ok.addFocusListener(new FocusAdapter() { 115 public void focusGained(FocusEvent e) { 116 gotFocus = true; 117 System.err.println("Ok got focus"); 118 } 119 }); 120 f.add(b); 121 f.pack(); 122 b.addActionListener(new ActionListener() { 123 public void actionPerformed(ActionEvent e) { 124 System.err.println("B pressed"); 125 126 EventQueue.invokeLater(new Runnable() { 127 public void run() { 128 waitTillShown(d); 129 TestDialogTypeAhead.this.d.toFront(); 130 TestDialogTypeAhead.this.moveMouseOver(d); 131 } 132 }); 133 134 d.setVisible(true); 135 } 136 }); 137 138 }//End init() 139 140 public void start () 141 { 142 //Get things going. Request focus, set size, et cetera 143 setSize (200,200); 144 setVisible(true); 145 validate(); 146 try { 147 robot = new Robot(); 148 } catch (Exception e) { 149 throw new RuntimeException("Can't create robot:" + e); 150 } 151 152 f.setVisible(true); 153 waitTillShown(b); 154 System.err.println("b is shown"); 155 f.toFront(); 156 moveMouseOver(f); 157 waitForIdle(); 158 makeFocused(b); 159 waitForIdle(); 160 System.err.println("b is focused"); 161 162 robot.keyPress(KeyEvent.VK_SPACE); 163 robot.keyRelease(KeyEvent.VK_SPACE); 164 try { 165 robotSema.doWait(1000); 166 } catch (InterruptedException ie) { 167 throw new RuntimeException("Interrupted!"); 168 } 169 if (!robotSema.getState()) { 170 throw new RuntimeException("robotSema hasn't been triggered"); 171 } 172 173 System.err.println("typing ahead"); 174 robot.keyPress(KeyEvent.VK_SPACE); 175 robot.keyRelease(KeyEvent.VK_SPACE); 176 waitForIdle(); 177 try { 178 pressSema.doWait(3000); 179 } catch (InterruptedException ie) { 180 throw new RuntimeException("Interrupted!"); 181 } 182 if (!pressSema.getState()) { 183 throw new RuntimeException("Type-ahead doesn't work"); 184 } 185 186 }// start() 187 188 private void moveMouseOver(Container c) { 189 Point p = c.getLocationOnScreen(); 190 Dimension d = c.getSize(); 191 robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)(d.getHeight()/2)); 192 } 193 private void waitForIdle() { 194 try { 195 robot.waitForIdle(); 196 EventQueue.invokeAndWait( new Runnable() { 197 public void run() { 198 // dummy implementation 199 } 200 } ); 201 } catch(InterruptedException ite) { 202 System.err.println("Robot.waitForIdle, non-fatal exception caught:"); 203 ite.printStackTrace(); 204 } catch(InvocationTargetException ine) { 205 System.err.println("Robot.waitForIdle, non-fatal exception caught:"); 206 ine.printStackTrace(); 207 } 208 } 209 210 private void waitTillShown(Component c) { 211 while (true) { 212 try { 213 Thread.sleep(100); 214 c.getLocationOnScreen(); 215 break; 216 } catch (InterruptedException ie) { 217 ie.printStackTrace(); 218 break; 219 } catch (Exception e) { 220 } 221 } 222 } 223 private void makeFocused(Component comp) { 224 if (comp.isFocusOwner()) { 225 return; 226 } 227 final Semaphore sema = new Semaphore(); 228 final FocusAdapter fa = new FocusAdapter() { 229 public void focusGained(FocusEvent fe) { 230 sema.raise(); 231 } 232 }; 233 comp.addFocusListener(fa); 234 comp.requestFocusInWindow(); 235 if (comp.isFocusOwner()) { 236 return; 237 } 238 try { 239 sema.doWait(3000); 240 } catch (InterruptedException ie) { 241 ie.printStackTrace(); 242 } 243 comp.removeFocusListener(fa); 244 if (!comp.isFocusOwner()) { 245 throw new RuntimeException("Can't make " + comp + " focused, current owner is " + KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner()); 246 } 247 } 248 249 static class Semaphore { 250 boolean state = false; 251 int waiting = 0; 252 public Semaphore() { 253 } 254 public synchronized void doWait() throws InterruptedException { 255 if (state) { 256 return; 257 } 258 waiting++; 259 wait(); 260 waiting--; 261 } 262 public synchronized void doWait(int timeout) throws InterruptedException { 263 if (state) { 264 return; 265 } 266 waiting++; 267 wait(timeout); 268 waiting--; 269 } 270 public synchronized void raise() { 271 state = true; 272 if (waiting > 0) { 273 notifyAll(); 274 } 275 } 276 public synchronized boolean getState() { 277 return state; 278 } 279 } 280 281 class TestKFM extends DefaultKeyboardFocusManager { 282 protected synchronized void enqueueKeyEvents(long after, 283 Component untilFocused) 284 { 285 super.enqueueKeyEvents(after, untilFocused); 286 287 if (untilFocused == TestDialogTypeAhead.this.ok) { 288 TestDialogTypeAhead.this.robotSema.raise(); 289 } 290 } 291 } 292 }// class TestDialogTypeAhead 293