1 /*
   2  * Copyright (c) 2003, 2019, 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   @key headful
  27   @bug 4632143
  28   @summary Unit test for the RFE window/frame/dialog always on top
  29   @author dom@sparc.spb.su: area=awt.toplevel
  30   @run main/othervm/timeout=600 AutoTestOnTop
  31 */
  32 
  33 import java.awt.AWTEvent;
  34 import java.awt.AWTException;
  35 import java.awt.Component;
  36 import java.awt.Dialog;
  37 import java.awt.EventQueue;
  38 import java.awt.Frame;
  39 import java.awt.IllegalComponentStateException;
  40 import java.awt.Point;
  41 import java.awt.Robot;
  42 import java.awt.Toolkit;
  43 import java.awt.Window;
  44 import java.awt.event.AWTEventListener;
  45 import java.awt.event.FocusEvent;
  46 import java.awt.event.InputEvent;
  47 import java.awt.event.MouseEvent;
  48 import java.awt.event.PaintEvent;
  49 import java.awt.event.WindowAdapter;
  50 import java.awt.event.WindowEvent;
  51 import java.lang.reflect.InvocationTargetException;
  52 import java.lang.reflect.Method;
  53 import java.util.Vector;
  54 
  55 import javax.swing.JDialog;
  56 import javax.swing.JFrame;
  57 import javax.swing.JWindow;
  58 
  59 /**
  60  * @author tav@sparc.spb.su
  61  * @author dom@sparc.spb.su
  62  * Tests that always-on-top windows combine correctly with different kinds of window in different styles and conditions.
  63  *
  64  * !!! WARNING !!!
  65  * The test fails sometimes because the toFront() method doesn't guarantee
  66  * that after its invocation the frame will be placed above all other windows.
  67  */
  68 public class AutoTestOnTop {
  69     private static final int X = 300;
  70     private static final int Y = 300;
  71 
  72     static Window topw;
  73     static Frame  parentw = new Frame();
  74     static Window f;
  75     static Frame  parentf = new Frame();
  76 
  77     static final Object  uncheckedSrc = new Object(); // used when no need to check event source
  78     static volatile Object  eventSrc = uncheckedSrc;
  79     static boolean dispatchedCond;
  80 
  81     static Semaphore STATE_SEMA = new Semaphore();
  82     static Semaphore VIS_SEMA = new Semaphore();
  83     static Vector errors = new Vector();
  84 
  85     static boolean isUnix = false;
  86 
  87     static StringBuffer msgError = new StringBuffer();
  88     static StringBuffer msgCase = new StringBuffer();
  89     static StringBuffer msgAction = new StringBuffer();
  90     static StringBuffer msgFunc = new StringBuffer();
  91     static StringBuffer msgVisibility = new StringBuffer();
  92 
  93     static volatile int stageNum;
  94     static volatile int actNum;
  95     static volatile int testResult = 0;
  96 
  97     static volatile boolean doCheckEvents;
  98     static volatile boolean eventsCheckPassed;
  99     static boolean[] eventsCheckInitVals = new boolean[] { // Whether events are checked for abcence or precence
 100         true, true, true, true, true, false, false, false, false
 101     };
 102     static String[] msgEventsChecks = new String[] {
 103         null, null, null, null, null,
 104         "expected WindowEvent.WINDOW_STATE_CHANGED hasn't been generated",
 105         "expected WindowEvent.WINDOW_STATE_CHANGED hasn't been generated",
 106         "expected WindowEvent.WINDOW_STATE_CHANGED hasn't been generated",
 107         "expected WindowEvent.WINDOW_STATE_CHANGED hasn't been generated",
 108     };
 109 
 110     static final int stagesCount = 7;
 111     static final int actionsCount = 9;
 112 
 113     static Method[] preActions = new Method[actionsCount];
 114     static Method[] postActions = new Method[actionsCount];
 115     static Method[] isActionsAllowed = new Method[actionsCount];
 116     static Method[] checksActionEvents = new Method[actionsCount];
 117 
 118     static Robot robot;
 119 
 120     static boolean doStartTest;
 121     static String osName = System.getProperty("os.name");
 122 
 123 
 124     public static void main(String[] args) {
 125         checkTesting();
 126 
 127     }
 128 
 129     public static void performTesting() {
 130         isUnix = osName.equals("Linux") || osName.equals("SunOS");
 131 
 132         Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
 133                 public void eventDispatched(AWTEvent e) {
 134                     if (e.getID() == MouseEvent.MOUSE_CLICKED) {
 135                         if (eventSrc != null & eventSrc != uncheckedSrc && e.getSource() != eventSrc) {
 136                             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": " + msgError);
 137                             testResult = -1;
 138                         }
 139                         if (eventSrc != null){
 140                             synchronized (eventSrc) {
 141                                 dispatchedCond = true;
 142                                 eventSrc.notify();
 143                             }
 144                         }
 145                     }
 146 
 147                     if (doCheckEvents && (e.getSource() == topw || e.getSource() == f)) {
 148 
 149                         //System.err.println("AWTEventListener: catched the event " + e);
 150 
 151                         try {
 152                             checksActionEvents[actNum].invoke(null, new Object[] {e});
 153                         } catch (InvocationTargetException ite) {
 154                             ite.printStackTrace();
 155                         } catch (IllegalAccessException iae) {
 156                             iae.printStackTrace();
 157                         }
 158                         return;
 159                     }
 160                 }
 161             }, 0xffffffffffffffffL);
 162 
 163         Method[] allMethods;
 164 
 165         try {
 166             allMethods = AutoTestOnTop.class.getDeclaredMethods();
 167         } catch (SecurityException se) {
 168             throw new RuntimeException(se);
 169         }
 170 
 171         for (int i = 0; i < allMethods.length; i++) {
 172             String name = allMethods[i].getName();
 173             if (name.startsWith("preAction")) {
 174                 preActions[name.charAt(name.length() - 1) - '0'] = allMethods[i];
 175             } else if (name.startsWith("postAction")) {
 176                 postActions[name.charAt(name.length() - 1) - '0'] = allMethods[i];
 177             } else if (name.startsWith("isActionAllowed")) {
 178                 isActionsAllowed[name.charAt(name.length() - 1) - '0'] = allMethods[i];
 179             } else if (name.startsWith("checkActionEvents")) {
 180                 checksActionEvents[name.charAt(name.length() - 1) - '0'] = allMethods[i];
 181             }
 182         }
 183 
 184         f = new Frame("Auxiliary Frame");
 185         f.setBounds(X, Y, 650, 100);
 186         f.setVisible(true);
 187         waitTillShown(f);
 188 
 189         try {
 190             robot = new Robot();
 191             robot.setAutoDelay(100);
 192         } catch (AWTException e) {
 193             throw new RuntimeException("Error: unable to create robot", e);
 194         }
 195 
 196         mainTest();
 197 
 198         if (testResult != 0) {
 199             System.err.println("The following errors were encountered: ");
 200             for (int i = 0; i < errors.size(); i++) {
 201                 System.err.println(errors.get(i).toString());
 202             }
 203             throw new RuntimeException("Test failed.");
 204         } else {
 205             System.err.println("Test PASSED.");
 206         }
 207     }
 208 
 209     public static void mainTest() {
 210 //         stageNum = 0;
 211 //         for (int i = 0; i < 5; i++) {
 212 //             actNum = 2;
 213 //             System.err.println("************************* A C T I O N " + actNum + " *************************");
 214 //             doStage(stageNum, actNum);
 215 // //             pause(500);
 216 //             actNum = 3;
 217 //             System.err.println("************************* A C T I O N " + actNum + " *************************");
 218 //             doStage(stageNum, actNum);
 219 // //             pause(500);
 220 //         }
 221         for (stageNum = 0; stageNum < stagesCount; stageNum++) {
 222             System.err.println("************************* S T A G E " + stageNum + " *************************");
 223             for (actNum = 0; actNum < actionsCount; actNum++) {
 224                 System.err.println("************************* A C T I O N " + actNum + " *************************");
 225                 doStage(stageNum, actNum);
 226             } // for thru actNum
 227         } // fow thru stageNum
 228 
 229         eventSrc = null;
 230     }
 231 
 232     private static void doStage(int stageNum, int actNum) {
 233         try {
 234 
 235             if (!((Boolean)isActionsAllowed[actNum].invoke(null, new Object[0])).booleanValue()) {
 236                 System.err.println("Action skipped due to a platform limitations");
 237                 return;
 238             }
 239 
 240             STATE_SEMA.reset();
 241             createWindow(stageNum);
 242 
 243             //*************************
 244             // Set window always-on-top
 245             //*************************
 246 
 247             preActions[actNum].invoke(null, new Object[0]);
 248             setAlwaysOnTop(topw, true);
 249             waitForIdle(true);
 250 
 251             if (!topw.isAlwaysOnTopSupported()) return;
 252 
 253             postActions[actNum].invoke(null, new Object[0]);
 254             waitForIdle(false);
 255 
 256             STATE_SEMA.reset();
 257 
 258             testForAlwaysOnTop();
 259 
 260             //*****************************
 261             // Set window not always-on-top
 262             //*****************************
 263 
 264             preActions[actNum].invoke(null, new Object[0]);
 265             setAlwaysOnTop(topw, false);
 266             waitForIdle(true);
 267             postActions[actNum].invoke(null, new Object[0]);
 268             waitForIdle(false);
 269             STATE_SEMA.reset();
 270 
 271             testForNotAlwaysOnTop();
 272 
 273         } catch (InvocationTargetException ite) {
 274             ite.printStackTrace();
 275         } catch (Exception ex) {
 276             throw new RuntimeException(ex);
 277         }
 278     }
 279 
 280     private static void checkTesting() {
 281         if (Toolkit.getDefaultToolkit().isAlwaysOnTopSupported()) {
 282             performTesting();
 283         }
 284     }
 285 
 286     public static void testForAlwaysOnTop() {
 287         System.err.println("Checking for always-on-top " + topw);
 288 
 289         ensureInitialWinPosition(topw);
 290 
 291         // Check that always-on-top window is topmost.
 292         // - Click on always-on-top window on the windows cross area.
 293         clickOn(topw, f, 10, 50, "setting " + msgVisibility +
 294                 " window (1) always-on-top didn't make it topmost");
 295 
 296         // Check that we can't change z-order of always-on-top window.
 297         // - a) Try to put the other window on the top.
 298         f.toFront();
 299         clickOn(uncheckedSrc, f, 450, 50, ""); // coz toFront() works not always
 300         pause(300);
 301 
 302         // - b) Click on always-on-top window on the windows cross area.
 303         clickOn(topw, f, 10, 50, "setting " + msgVisibility +
 304                 " window (1) always-on-top didn't make it such");
 305 
 306         // Ask for always-on-top property
 307         if (isAlwaysOnTop(topw) != true)
 308                 error("Test failed: stage #" + stageNum + ", action #" + actNum + ": " + msgCase + ": " + msgAction +
 309                                    ": isAlwaysOnTop() returned 'false' for window (1) set always-on-top at state "
 310                                    + msgVisibility);
 311     }
 312 
 313     public static void testForNotAlwaysOnTop() {
 314         System.err.println("Checking for non always-on-top of " + topw);
 315         ensureInitialWinPosition(topw);
 316 
 317         if (msgVisibility.equals("visible") && actNum != 2) {
 318             // Check that the window remains topmost.
 319             // - click on the window on the windows cross area.
 320             clickOn(topw, f, 10, 50, "setting " + msgVisibility +
 321                     " window (1) not always-on-top didn't keep it topmost");
 322         }
 323 
 324         // Check that we can change z-order of not always-on-top window.
 325         // - a) try to put the other window on the top.
 326         f.toFront();
 327         clickOn(uncheckedSrc, f, 450, 50, ""); // coz toFront() works not always
 328         pause(300);
 329 
 330         // - b) click on not always-on-top window on the windows cross area.
 331         clickOn(f, f, 10, 50, "setting " + msgVisibility +
 332                 " window (1) not always-on-top didn't make it such");
 333 
 334         // Ask for always-on-top property
 335         if (isAlwaysOnTop(topw) != false)
 336             error("Test failed: stage #" + stageNum + ", action #" + actNum + ": " + msgCase + ": " + msgAction +
 337                                ": isAlwaysOnTop() returned 'true' for window (1) set not always-on-top at state "
 338                                + msgVisibility);
 339     }
 340 
 341 
 342     private static void createWindow(int stageNum) {
 343         // Free native resourses
 344         if (topw != null) {
 345             topw.dispose();
 346         }
 347 
 348         switch (stageNum) {
 349         case 0:
 350             topw = new Frame("Top Frame");
 351             msgCase.replace(0, msgCase.length(), "Frame (1) over Frame (2)");
 352             break;
 353         case 1:
 354             topw = new JFrame("Top JFrame");
 355             msgCase.replace(0, msgCase.length(), "JFrame (1) over Frame (2)");
 356             break;
 357         case 2:
 358             topw = new Dialog(parentw, "Top Dialog");
 359             msgCase.replace(0, msgCase.length(), "Dialog (1) over Frame (2)");
 360             break;
 361         case 3:
 362             topw = new JDialog(parentw, "Top JDialog");
 363             msgCase.replace(0, msgCase.length(), "JDialog (1) over Frame (2)");
 364             break;
 365         case 4:
 366             topw = new Frame("Top Frame");
 367             f.dispose();
 368             f = new Dialog(parentf, "Auxiliary Dialog");
 369             f.setBounds(X, Y, 650, 100);
 370             f.setVisible(true);
 371             waitTillShown(f);
 372             msgCase.replace(0, msgCase.length(), "Frame (1) over Dialog (2)");
 373             break;
 374         case 5:
 375             topw = new Window(parentw);
 376             msgCase.replace(0, msgCase.length(), "Window (1) over Frame (2)");
 377             break;
 378         case 6:
 379             topw = new JWindow(parentw);
 380             msgCase.replace(0, msgCase.length(), "JWindow (1) over Frame (2)");
 381             break;
 382         }
 383         topw.addWindowStateListener(new WindowAdapter() {
 384                 public void windowStateChanged(WindowEvent e) {
 385                     System.err.println("* " + e);
 386                     STATE_SEMA.raise();
 387                 }
 388             });
 389         topw.setSize(300, 100);
 390     }
 391 
 392     /**
 393      * 0: setting always-on-top to invisible window
 394      * 1: setting always-on-top to visible window
 395      * 2: always-on-top on visible non-focusable window
 396      * 3: always-on-top on visible, dragging topw after that
 397      * 4: always-on-top on visible, dragging f after that
 398      * 5: always-on-top on (visible, maximized), make normal after that
 399      * 6: always-on-top on (visible, iconified), make normal after that
 400      * 7: always-on-top on visible, iconify/deiconify after that
 401      * 8: always-on-top on visible, maximize/restore after that
 402      */
 403     public static void preAction_0() {
 404         topw.setVisible(false);
 405     }
 406     public static void postAction_0() {
 407         if (topw.isShowing()) {
 408             error("Test failed: stage #" + stageNum + ", action #" + actNum + ": " + msgCase +
 409                                ": no actions with windows: changing always-on-top property at window (1) state 'invisible' makes window (1) visible");
 410         }
 411         setWindowVisible("no actions with windows", "invisible");
 412     }
 413     public static boolean isActionAllowed_0() {
 414         // Window on Linux is always always-on-top!
 415         return !((stageNum == 5 || stageNum == 6) && isUnix) && (stageNum < stagesCount);
 416     }
 417     public static void checkActionEvents_0(AWTEvent e) {
 418         System.err.println(e.toString());
 419    }
 420 
 421     public static void preAction_1() {
 422         setWindowVisible("no actions with windows", "visible");
 423     }
 424     public static void postAction_1() {}
 425     public static boolean isActionAllowed_1() {
 426         return !((stageNum == 5 || stageNum == 6) && isUnix) && (stageNum < stagesCount );
 427     }
 428     public static void checkActionEvents_1(AWTEvent e) {
 429         System.err.println(e.toString());
 430         if (e instanceof PaintEvent) {
 431             return;
 432         }
 433         eventsCheckPassed = false;
 434         error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 435                            ":  unexpected event " + e + " was generated");
 436     }
 437 
 438     public static void preAction_2() {
 439         setWindowVisible("when window (1) set not focusable", "visible");
 440         topw.setFocusableWindowState(false);
 441         f.toFront();
 442         pause(300);
 443     }
 444     public static void postAction_2() {}
 445     public static boolean isActionAllowed_2() {
 446         return !((stageNum == 5 || stageNum == 6) && isUnix) && (stageNum < stagesCount);
 447     }
 448     public static void checkActionEvents_2(AWTEvent e) {
 449         System.err.println(e.toString());
 450         if ( (e.getID() >= FocusEvent.FOCUS_FIRST && e.getID() <= FocusEvent.FOCUS_LAST) ||
 451              (e.getID() == WindowEvent.WINDOW_LOST_FOCUS && e.getID() == WindowEvent.WINDOW_GAINED_FOCUS)) {
 452             eventsCheckPassed = false;
 453             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " +
 454                                msgAction + ": after call " + msgFunc +
 455                                ": unexpected event " + e + " was generated");
 456         }
 457     }
 458 
 459     public static void preAction_3() {
 460         setWindowVisible("after dragging",  "visible");
 461     }
 462     public static void postAction_3() {
 463         Point p = topw.getLocationOnScreen();
 464         int x = p.x + 150, y = p.y + 5;
 465 
 466         try {                      // Take a pause to avoid double click
 467             Thread.sleep(500);     // when called one after another.
 468         } catch (InterruptedException ie) {
 469             ie.printStackTrace();
 470         } catch (IllegalComponentStateException e) {
 471             e.printStackTrace();
 472         }
 473 
 474         // Drag the window.
 475         robot.mouseMove(x, y);
 476         robot.mousePress(InputEvent.BUTTON1_MASK);
 477         robot.mouseMove(X + 150, Y + 100);
 478         robot.mouseMove(x, y);
 479         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 480     }
 481     public static boolean isActionAllowed_3() {
 482         return (stageNum < 5);
 483     }
 484     public static void checkActionEvents_3(AWTEvent e) {
 485         System.err.println(e.toString());
 486     }
 487 
 488     public static void preAction_4() {
 489         setWindowVisible("after dragging window (2)",  "visible");
 490     }
 491     public static void postAction_4() {
 492         Point p = f.getLocationOnScreen();
 493         int x = p.x + 400, y = p.y + 5;
 494 
 495         try {                      // Take a pause to avoid double click
 496             Thread.sleep(500);     // when called one after another.
 497         } catch (InterruptedException ie) {
 498             ie.printStackTrace();
 499         } catch (IllegalComponentStateException e) {
 500             e.printStackTrace();
 501         }
 502 
 503         // Drag the window.
 504         robot.mouseMove(x, y);
 505         robot.mousePress(InputEvent.BUTTON1_MASK);
 506         robot.mouseMove(X + 400, Y + 100);
 507         robot.mouseMove(x, y);
 508         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 509 
 510         ensureInitialWinPosition(f);
 511     }
 512     public static boolean isActionAllowed_4() {
 513         return !((stageNum == 5 || stageNum == 6) && isUnix);
 514     }
 515     public static void checkActionEvents_4(AWTEvent e) {
 516         System.err.println(e.toString());
 517     }
 518 
 519     // Metacity has a bug not allowing to set a window to NORMAL state!!!
 520 
 521     public static void preAction_5() {
 522         setWindowVisible("at state 'maximized'",  "visible");
 523         ((Frame)topw).setExtendedState(Frame.MAXIMIZED_BOTH);
 524         waitForStateChange();
 525     }
 526     public static void postAction_5() {
 527         ((Frame)topw).setExtendedState(Frame.NORMAL);
 528         waitForStateChange();
 529     }
 530     public static boolean isActionAllowed_5() {
 531         return (stageNum < 2);
 532     }
 533     public static void checkActionEvents_5(AWTEvent e) {
 534         System.err.println("=" + e.toString());
 535         if (e.getID() == WindowEvent.WINDOW_STATE_CHANGED) {
 536             eventsCheckPassed = true;
 537         }
 538     }
 539 
 540     public static void preAction_6() {
 541         setWindowVisible("at state 'iconified'",  "visible");
 542         System.err.println("Iconifying " + topw);
 543         ((Frame)topw).setExtendedState(Frame.ICONIFIED);
 544         if (!waitForStateChange()) {
 545             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 546                                ":  state change to ICONIFIED hasn't been generated");
 547         }
 548     }
 549     public static void postAction_6() {
 550         System.err.println("Restoring " + topw);
 551         ((Frame)topw).setExtendedState(Frame.NORMAL);
 552         if (!waitForStateChange()) {
 553             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 554                                ":  state change to NORMAL hasn't been generated");
 555         }
 556     }
 557     public static boolean isActionAllowed_6() {
 558         return (stageNum < 2 );
 559     }
 560     public static void checkActionEvents_6(AWTEvent e) {
 561         System.err.println("+" + e.toString());
 562         if (e.getID() == WindowEvent.WINDOW_STATE_CHANGED) {
 563             eventsCheckPassed = true;
 564         }
 565     }
 566 
 567     public static void preAction_7() {
 568         setWindowVisible("before state 'iconified'",  "visible");
 569     }
 570     public static void postAction_7() {
 571         System.err.println("Setting iconified");
 572         ((Frame)topw).setExtendedState(Frame.ICONIFIED);
 573         if (!waitForStateChange()) {
 574             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 575                                ":  state change to ICONIFIED hasn't been generated");
 576         }
 577         System.err.println("Setting normal");
 578         ((Frame)topw).setExtendedState(Frame.NORMAL);
 579         if (!waitForStateChange()) {
 580             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 581                                ":  state change to NORMAL hasn't been generated");
 582         }
 583     }
 584     public static boolean isActionAllowed_7() {
 585         return (stageNum < 2);
 586     }
 587     public static void checkActionEvents_7(AWTEvent e) {
 588         System.err.println(e.toString());
 589         if (e.getID() == WindowEvent.WINDOW_STATE_CHANGED) {
 590             eventsCheckPassed = true;
 591         }
 592     }
 593 
 594     public static void preAction_8() {
 595         setWindowVisible("before state 'maximized'",  "visible");
 596     }
 597     public static void postAction_8() {
 598         ((Frame)topw).setExtendedState(Frame.MAXIMIZED_BOTH);
 599         if (!waitForStateChange()) {
 600             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 601                                ":  state change to MAXIMIZED hasn't been generated");
 602         }
 603         ((Frame)topw).setExtendedState(Frame.NORMAL);
 604         if (!waitForStateChange()) {
 605             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call " + msgFunc +
 606                                ":  state change to NORMAL hasn't been generated");
 607         }
 608     }
 609     public static boolean isActionAllowed_8() {
 610         return (stageNum < 2);
 611     }
 612     public static void checkActionEvents_8(AWTEvent e) {
 613         System.err.println(e.toString());
 614         if (e.getID() == WindowEvent.WINDOW_STATE_CHANGED) {
 615            eventsCheckPassed = true;
 616         }
 617     }
 618 
 619     //***************************************************************************
 620 
 621     private static void setWindowVisible(String mAction, String mVisibility) {
 622         msgAction.replace(0, msgAction.length(), mAction);
 623         msgVisibility.replace(0, msgVisibility.length(), mVisibility);
 624 
 625         topw.setVisible(true);
 626         pause(100); // Needs for Sawfish
 627         topw.setLocation(X, Y);
 628         waitTillShown(topw);
 629         f.toFront();
 630         pause(300);
 631     }
 632 
 633     private static void clickOn(Object src, Window relwin, int x, int y, String errorStr) {
 634         Point p = relwin.getLocationOnScreen();
 635         int counter = 10;
 636         while (--counter > 0) {
 637             eventSrc = src;
 638             msgError.replace(0, msgError.length(), errorStr);
 639 
 640             robot.mouseMove(p.x + x, p.y + y);
 641             robot.mousePress(InputEvent.BUTTON1_MASK);
 642             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 643 
 644             synchronized (eventSrc) {
 645                 if (!dispatchedCond) {
 646                     try {
 647                         eventSrc.wait(1000);
 648                     } catch (InterruptedException e) {
 649                         e.printStackTrace();
 650                     }
 651                 }
 652                 if (!dispatchedCond) {
 653                     //System.err.println("clickOn: MOUSE_CLICKED event losed, trying to generate it again...");
 654                     continue;
 655                 }
 656                 dispatchedCond = false;
 657             }
 658             break;
 659         } // end while
 660         if (counter <= 0) {
 661             eventSrc = uncheckedSrc;
 662             error("Test: internal error: could't catch MOUSE_CLICKED event. Skip testing this stage");
 663         }
 664     }
 665 
 666     private static void setAlwaysOnTop(Window w, boolean value) {
 667         System.err.println("Setting always on top on " + w + " to " + value);
 668         robot.mouseMove(X - 50, Y - 50); // Move out of the window
 669         msgFunc.replace(0, msgCase.length(), "setAlwaysOnTop()");
 670         try {
 671             w.setAlwaysOnTop(value);
 672         } catch (Exception e) {
 673             error("Test failed: stage#" + stageNum + "action #" + actNum + ": " + msgCase + ": " + msgAction +
 674                                ": setAlwaysOnTop(" + value + ") called at state " + msgVisibility +
 675                                " threw exeption " + e);
 676         }
 677     }
 678 
 679     private static boolean isAlwaysOnTop(Window w) {
 680         robot.mouseMove(X - 50, Y - 50); // Move out of the window
 681         msgFunc.replace(0, msgCase.length(), "isAlwaysOnTop()");
 682         boolean result = false;
 683         try {
 684             result = w.isAlwaysOnTop();
 685         } catch (Exception e) {
 686             error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction +
 687                                ": isAlwaysOnTop() called at state " + msgVisibility +
 688                                " threw exeption " + e);
 689         }
 690         return result;
 691     }
 692 
 693     private static void waitTillShown(Component c) {
 694         while (true) {
 695             try {
 696                 Thread.sleep(100);
 697                 c.getLocationOnScreen();
 698                 break;
 699             } catch (InterruptedException e) {
 700                 e.printStackTrace();
 701                 break;
 702             }
 703         }
 704     }
 705 
 706     private static void waitForIdle(boolean doCheck) {
 707         try {
 708             robot.waitForIdle();
 709             EventQueue.invokeAndWait( new Runnable() {
 710                     public void run() {} // Dummy implementation
 711                 } );
 712         } catch(InterruptedException ite) {
 713             System.err.println("waitForIdle, non-fatal exception caught:");
 714             ite.printStackTrace();
 715         } catch(InvocationTargetException ine) {
 716             System.err.println("waitForIdle, non-fatal exception caught:");
 717             ine.printStackTrace();
 718         }
 719         doCheckEvents = doCheck;
 720 
 721         if (doCheck) {
 722             eventsCheckPassed = eventsCheckInitVals[actNum]; // Initialize
 723         } else if (!eventsCheckPassed &&
 724                  msgEventsChecks[actNum] != null) {
 725 
 726 
 727             // Some expected event hasn't been catched,
 728             // so give it one more chance...
 729             doCheckEvents = true;
 730             pause(500);
 731             doCheckEvents = false;
 732 
 733             if (!eventsCheckPassed) {
 734                 testResult = -1;
 735                 error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": after call "
 736                                    + msgFunc + ": " + msgEventsChecks[actNum]);
 737             }
 738         }
 739     }
 740 
 741     private static boolean waitForStateChange() {
 742         System.err.println("------- Waiting for state change");
 743         try {
 744             STATE_SEMA.doWait(3000);
 745         } catch (InterruptedException ie) {
 746             System.err.println("Wait interrupted: " + ie);
 747         }
 748         boolean state = STATE_SEMA.getState();
 749         STATE_SEMA.reset();
 750         robot.delay(1000); // animation normal <--> maximized states
 751         return state;
 752     }
 753 
 754     private static void ensureInitialWinPosition(Window w) {
 755         int counter = 30;
 756         while (w.getLocationOnScreen().y != Y && --counter > 0) {
 757             try {
 758                 Thread.sleep(100);
 759             } catch (InterruptedException e) {
 760                 e.printStackTrace();
 761                 break;
 762             }
 763         }
 764         if (counter <= 0) {
 765             w.setLocation(X, Y);
 766             pause(100);
 767             System.err.println("Test: window set to initial position forcedly");
 768         }
 769     }
 770 
 771     private static void pause(int mls) {
 772         try {
 773             Thread.sleep(mls);
 774         } catch (InterruptedException e) {
 775             e.printStackTrace();
 776         }
 777     }
 778 
 779     private static void error(String msg) {
 780         errors.add(msg);
 781         System.err.println(msg);
 782     }
 783 }
 784 
 785 class Semaphore {
 786     boolean state = false;
 787     int waiting = 0;
 788     public Semaphore() {
 789     }
 790     public synchronized void doWait() throws InterruptedException {
 791         if (state) {
 792             return;
 793         }
 794         waiting++;
 795         wait();
 796         waiting--;
 797     }
 798     public synchronized void doWait(int timeout) throws InterruptedException {
 799         if (state) {
 800             return;
 801         }
 802         waiting++;
 803         wait(timeout);
 804         waiting--;
 805     }
 806     public synchronized void raise() {
 807         state = true;
 808         if (waiting > 0) {
 809             notifyAll();
 810         }
 811     }
 812 
 813     public synchronized void doNotify() {
 814         notifyAll();
 815     }
 816     public synchronized boolean getState() {
 817         return state;
 818     }
 819 
 820     public synchronized void reset() {
 821         state = false;
 822     }
 823 }