1 /* 2 * Copyright (c) 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 @test 25 @bug 6236247 26 @summary Test that setting of always-on-top flags before showing window works 27 @author dom@sparc.spb.su: area=awt.toplevel 28 @run main TestAlwaysOnTopBeforeShow 29 */ 30 31 /** 32 * TestAlwaysOnTopBeforeShow.java 33 * 34 * summary: Test that always-on-top works in the following situations: 35 * - when set on a window before showing 36 * - when set on a child dialog 37 * - that it doesn't generate focus event when set on an invisible window 38 */ 39 40 import java.awt.*; 41 import java.awt.event.*; 42 import java.util.concurrent.atomic.AtomicBoolean; 43 44 45 //*** global search and replace TestAlwaysOnTopBeforeShow with name of the test *** 46 47 public class TestAlwaysOnTopBeforeShow 48 { 49 50 //*** test-writer defined static variables go here *** 51 52 private static AtomicBoolean focused = new AtomicBoolean(); 53 private static AtomicBoolean pressed = new AtomicBoolean(); 54 private static volatile Object pressedTarget; 55 private static Robot robot = null; 56 private static void init() 57 { 58 //*** Create instructions for the user here *** 59 60 Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { 61 public void eventDispatched(AWTEvent e) { 62 if (e.getID() == MouseEvent.MOUSE_PRESSED) { 63 synchronized(pressed) { 64 pressed.set(true); 65 pressedTarget = e.getSource(); 66 pressed.notifyAll(); 67 } 68 } 69 } 70 }, AWTEvent.MOUSE_EVENT_MASK); 71 72 Frame f = new Frame("always-on-top"); 73 f.setBounds(0, 0, 200, 200); 74 f.addFocusListener(new FocusAdapter() { 75 public void focusGained(FocusEvent e) { 76 synchronized(focused) { 77 focused.set(true); 78 focused.notifyAll(); 79 } 80 } 81 }); 82 83 f.setAlwaysOnTop(true); 84 85 waitForIdle(1000); 86 if (focused.get()) { 87 throw new RuntimeException("Always-on-top generated focus event"); 88 } 89 90 f.setVisible(true); 91 92 waitFocused(f, focused); 93 focused.set(false); 94 95 Frame f2 = new Frame("auxilary"); 96 f2.setBounds(100, 0, 200, 100); 97 f2.setVisible(true); 98 f2.toFront(); 99 waitForIdle(1000); 100 101 Point location = f.getLocationOnScreen(); 102 Dimension size = f.getSize(); 103 checkOnTop(f, f2, location.x + size.width / 2, location.y + size.height / 2); 104 105 Dialog d = new Dialog(f, "Always-on-top"); 106 d.pack(); 107 d.setBounds(0, 0, 100, 100); 108 109 waitForIdle(1000); 110 checkOnTop(f, f2, location.x + size.width / 2, location.y + size.height / 2); 111 waitForIdle(1000); 112 113 focused.set(false); 114 f.setVisible(false); 115 f.setAlwaysOnTop(false); 116 waitForIdle(1000); 117 if (focused.get()) { 118 throw new RuntimeException("Always-on-top generated focus event"); 119 } 120 121 TestAlwaysOnTopBeforeShow.pass(); 122 123 }//End init() 124 125 private static void waitForIdle(int mls) { 126 try { 127 if(robot == null) { 128 robot = new Robot(); 129 } 130 robot.waitForIdle(); 131 Thread.sleep(mls); 132 } catch (Exception e) { 133 e.printStackTrace(); 134 } 135 } 136 137 static void waitFocused(Window w, AtomicBoolean b) { 138 try { 139 synchronized(b) { 140 if (w.isFocusOwner()) { 141 return; 142 } 143 b.wait(3000); 144 } 145 } catch (Exception e) { 146 throw new RuntimeException(e); 147 } 148 if (!w.isFocusOwner()) { 149 throw new RuntimeException("Can't make " + w + " focus owner"); 150 } 151 } 152 153 static void checkOnTop(Window ontop, Window under, int x, int y) { 154 under.toFront(); 155 try { 156 Robot robot = new Robot(); 157 robot.mouseMove(x, y); 158 robot.mousePress(InputEvent.BUTTON1_MASK); 159 robot.mouseRelease(InputEvent.BUTTON1_MASK); 160 synchronized(pressed) { 161 if (pressed.get()) { 162 if (pressedTarget != ontop) { 163 throw new RuntimeException("Pressed at wrong location: " + pressedTarget); 164 } 165 } else { 166 pressed.wait(5000); 167 } 168 } 169 if (!pressed.get() || pressedTarget != ontop) { 170 throw new RuntimeException("Pressed at wrong location: " + pressedTarget); 171 } 172 } catch (Exception e) { 173 throw new RuntimeException(e); 174 } 175 } 176 177 /***************************************************** 178 * Standard Test Machinery Section 179 * DO NOT modify anything in this section -- it's a 180 * standard chunk of code which has all of the 181 * synchronisation necessary for the test harness. 182 * By keeping it the same in all tests, it is easier 183 * to read and understand someone else's test, as 184 * well as insuring that all tests behave correctly 185 * with the test harness. 186 * There is a section following this for test- 187 * classes 188 ******************************************************/ 189 private static boolean theTestPassed = false; 190 private static boolean testGeneratedInterrupt = false; 191 private static String failureMessage = ""; 192 193 private static Thread mainThread = null; 194 195 private static int sleepTime = 300000; 196 197 // Not sure about what happens if multiple of this test are 198 // instantiated in the same VM. Being static (and using 199 // static vars), it aint gonna work. Not worrying about 200 // it for now. 201 public static void main( String args[] ) throws InterruptedException 202 { 203 mainThread = Thread.currentThread(); 204 try 205 { 206 init(); 207 } 208 catch( TestPassedException e ) 209 { 210 //The test passed, so just return from main and harness will 211 // interepret this return as a pass 212 return; 213 } 214 //At this point, neither test pass nor test fail has been 215 // called -- either would have thrown an exception and ended the 216 // test, so we know we have multiple threads. 217 218 //Test involves other threads, so sleep and wait for them to 219 // called pass() or fail() 220 try 221 { 222 Thread.sleep( sleepTime ); 223 //Timed out, so fail the test 224 throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); 225 } 226 catch (InterruptedException e) 227 { 228 //The test harness may have interrupted the test. If so, rethrow the exception 229 // so that the harness gets it and deals with it. 230 if( ! testGeneratedInterrupt ) throw e; 231 232 //reset flag in case hit this code more than once for some reason (just safety) 233 testGeneratedInterrupt = false; 234 235 if ( theTestPassed == false ) 236 { 237 throw new RuntimeException( failureMessage ); 238 } 239 } 240 241 }//main 242 243 public static synchronized void setTimeoutTo( int seconds ) 244 { 245 sleepTime = seconds * 1000; 246 } 247 248 public static synchronized void pass() 249 { 250 Sysout.println( "The test passed." ); 251 Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); 252 //first check if this is executing in main thread 253 if ( mainThread == Thread.currentThread() ) 254 { 255 //Still in the main thread, so set the flag just for kicks, 256 // and throw a test passed exception which will be caught 257 // and end the test. 258 theTestPassed = true; 259 throw new TestPassedException(); 260 } 261 theTestPassed = true; 262 testGeneratedInterrupt = true; 263 mainThread.interrupt(); 264 }//pass() 265 266 public static synchronized void fail() 267 { 268 //test writer didn't specify why test failed, so give generic 269 fail( "it just plain failed! :-)" ); 270 } 271 272 public static synchronized void fail( String whyFailed ) 273 { 274 Sysout.println( "The test failed: " + whyFailed ); 275 Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); 276 //check if this called from main thread 277 if ( mainThread == Thread.currentThread() ) 278 { 279 //If main thread, fail now 'cause not sleeping 280 throw new RuntimeException( whyFailed ); 281 } 282 theTestPassed = false; 283 testGeneratedInterrupt = true; 284 failureMessage = whyFailed; 285 mainThread.interrupt(); 286 }//fail() 287 288 }// class TestAlwaysOnTopBeforeShow 289 290 //This exception is used to exit from any level of call nesting 291 // when it's determined that the test has passed, and immediately 292 // end the test. 293 class TestPassedException extends RuntimeException 294 { 295 } 296 297 //*********** End Standard Test Machinery Section ********** 298 299 300 //************ Begin classes defined for the test **************** 301 302 // if want to make listeners, here is the recommended place for them, then instantiate 303 // them in init() 304 305 /* Example of a class which may be written as part of a test 306 class NewClass implements anInterface 307 { 308 static int newVar = 0; 309 310 public void eventDispatched(AWTEvent e) 311 { 312 //Counting events to see if we get enough 313 eventCount++; 314 315 if( eventCount == 20 ) 316 { 317 //got enough events, so pass 318 319 TestAlwaysOnTopBeforeShow.pass(); 320 } 321 else if( tries == 20 ) 322 { 323 //tried too many times without getting enough events so fail 324 325 TestAlwaysOnTopBeforeShow.fail(); 326 } 327 328 }// eventDispatched() 329 330 }// NewClass class 331 332 */ 333 334 335 //************** End classes defined for the test ******************* 336 337 338 339 340 /**************************************************** 341 Standard Test Machinery 342 DO NOT modify anything below -- it's a standard 343 chunk of code whose purpose is to make user 344 interaction uniform, and thereby make it simpler 345 to read and understand someone else's test. 346 ****************************************************/ 347 348 /** 349 This is part of the standard test machinery. 350 It creates a dialog (with the instructions), and is the interface 351 for sending text messages to the user. 352 To print the instructions, send an array of strings to Sysout.createDialog 353 WithInstructions method. Put one line of instructions per array entry. 354 To display a message for the tester to see, simply call Sysout.println 355 with the string to be displayed. 356 This mimics System.out.println but works within the test harness as well 357 as standalone. 358 */ 359 360 class Sysout 361 { 362 private static TestDialog dialog; 363 364 public static void createDialogWithInstructions( String[] instructions ) 365 { 366 dialog = new TestDialog( new Frame(), "Instructions" ); 367 dialog.printInstructions( instructions ); 368 dialog.setVisible(true); 369 println( "Any messages for the tester will display here." ); 370 } 371 372 public static void createDialog( ) 373 { 374 dialog = new TestDialog( new Frame(), "Instructions" ); 375 String[] defInstr = { "Instructions will appear here. ", "" } ; 376 dialog.printInstructions( defInstr ); 377 dialog.setVisible(true); 378 println( "Any messages for the tester will display here." ); 379 } 380 381 382 public static void printInstructions( String[] instructions ) 383 { 384 dialog.printInstructions( instructions ); 385 } 386 387 388 public static void println( String messageIn ) 389 { 390 System.out.println(messageIn); 391 } 392 393 }// Sysout class 394 395 /** 396 This is part of the standard test machinery. It provides a place for the 397 test instructions to be displayed, and a place for interactive messages 398 to the user to be displayed. 399 To have the test instructions displayed, see Sysout. 400 To have a message to the user be displayed, see Sysout. 401 Do not call anything in this dialog directly. 402 */ 403 class TestDialog extends Dialog 404 { 405 406 TextArea instructionsText; 407 TextArea messageText; 408 int maxStringLength = 80; 409 410 //DO NOT call this directly, go through Sysout 411 public TestDialog( Frame frame, String name ) 412 { 413 super( frame, name ); 414 int scrollBoth = TextArea.SCROLLBARS_BOTH; 415 instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); 416 add( "North", instructionsText ); 417 418 messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); 419 add("Center", messageText); 420 421 pack(); 422 423 setVisible(true); 424 }// TestDialog() 425 426 //DO NOT call this directly, go through Sysout 427 public void printInstructions( String[] instructions ) 428 { 429 //Clear out any current instructions 430 instructionsText.setText( "" ); 431 432 //Go down array of instruction strings 433 434 String printStr, remainingStr; 435 for( int i=0; i < instructions.length; i++ ) 436 { 437 //chop up each into pieces maxSringLength long 438 remainingStr = instructions[ i ]; 439 while( remainingStr.length() > 0 ) 440 { 441 //if longer than max then chop off first max chars to print 442 if( remainingStr.length() >= maxStringLength ) 443 { 444 //Try to chop on a word boundary 445 int posOfSpace = remainingStr. 446 lastIndexOf( ' ', maxStringLength - 1 ); 447 448 if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; 449 450 printStr = remainingStr.substring( 0, posOfSpace + 1 ); 451 remainingStr = remainingStr.substring( posOfSpace + 1 ); 452 } 453 //else just print 454 else 455 { 456 printStr = remainingStr; 457 remainingStr = ""; 458 } 459 460 instructionsText.append( printStr + "\n" ); 461 462 }// while 463 464 }// for 465 466 }//printInstructions() 467 468 //DO NOT call this directly, go through Sysout 469 public void displayMessage( String messageIn ) 470 { 471 messageText.append( messageIn + "\n" ); 472 System.out.println(messageIn); 473 } 474 475 }// TestDialog class