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