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