1 /*
   2  * Copyright (c) 2014, 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 4658741
  27   @summary verifies that getDropSuccess() returns correct value for inter-JVM DnD
  28   @author das@sparc.spb.su area=dnd
  29   @run applet InterJVMGetDropSuccessTest.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 'InterJVMGetDropSuccessTest.html' in the run tag.  This should
  42 //  be changed to the name of the test.
  43 
  44 
  45 /**
  46  * InterJVMGetDropSuccessTest.java
  47  *
  48  * summary: verifies that getDropSuccess() returns correct value for inter-JVM DnD
  49  */
  50 
  51 import java.applet.Applet;
  52 import java.awt.*;
  53 import java.awt.datatransfer.*;
  54 import java.awt.dnd.*;
  55 import java.awt.event.*;
  56 import java.io.*;
  57 import javax.swing.*;
  58 
  59 
  60 //Automated tests should run as applet tests if possible because they
  61 // get their environments cleaned up, including AWT threads, any
  62 // test created threads, and any system resources used by the test
  63 // such as file descriptors.  (This is normally not a problem as
  64 // main tests usually run in a separate VM, however on some platforms
  65 // such as the Mac, separate VMs are not possible and non-applet
  66 // tests will cause problems).  Also, you don't have to worry about
  67 // synchronisation stuff in Applet tests they way you do in main
  68 // tests...
  69 
  70 
  71 public class InterJVMGetDropSuccessTest extends Applet {
  72 
  73     private int returnCode = Util.CODE_NOT_RETURNED;
  74     private boolean successCodes[] = { true, false };
  75     private int dropCount = 0;
  76 
  77     final Frame frame = new Frame("Target Frame");
  78 
  79     final DropTargetListener dropTargetListener = new DropTargetAdapter() {
  80             public void drop(DropTargetDropEvent dtde) {
  81                 dtde.acceptDrop(DnDConstants.ACTION_COPY);
  82                 dtde.dropComplete(successCodes[dropCount]);
  83                 dropCount++;
  84             }
  85         };
  86     final DropTarget dropTarget = new DropTarget(frame, dropTargetListener);
  87 
  88     public void init() {
  89         frame.setTitle("Test frame");
  90         frame.setBounds(100, 100, 150, 150);
  91     } // init()
  92 
  93     public void start() {
  94 
  95         frame.setVisible(true);
  96 
  97         try {
  98             Thread.sleep(Util.FRAME_ACTIVATION_TIMEOUT);
  99 
 100             Point p = frame.getLocationOnScreen();
 101             Dimension d = frame.getSize();
 102 
 103             String javaPath = System.getProperty("java.home", "");
 104             String command = javaPath + File.separator + "bin" +
 105                 File.separator + "java -cp " + System.getProperty("test.classes", ".") +
 106                 " Child " +
 107                 p.x + " " + p.y + " " + d.width + " " + d.height;
 108 
 109             Process process = Runtime.getRuntime().exec(command);
 110             returnCode = process.waitFor();
 111 
 112             InputStream errorStream = process.getErrorStream();
 113             int count = errorStream.available();
 114             if (count > 0) {
 115                 byte[] b = new byte[count];
 116                 errorStream.read(b);
 117                 System.err.println("========= Child VM System.err ========");
 118                 System.err.print(new String(b));
 119                 System.err.println("======================================");
 120             }
 121 
 122             InputStream outputStream = process.getInputStream();
 123             count = outputStream.available();
 124             if (count > 0) {
 125                 byte[] b = new byte[count];
 126                 outputStream.read(b);
 127                 System.err.println("========= Child VM System.out ========");
 128                 System.err.print(new String(b));
 129                 System.err.println("======================================");
 130             }
 131         } catch (Throwable e) {
 132             e.printStackTrace();
 133             throw new RuntimeException(e);
 134         }
 135         switch (returnCode) {
 136         case Util.CODE_NOT_RETURNED:
 137             throw new RuntimeException("Child VM: failed to start");
 138         case Util.CODE_FAILURE:
 139             throw new RuntimeException("Child VM: abnormal termination");
 140         default:
 141             if (dropCount == 2) {
 142                 int expectedRetCode = 0;
 143                 if (successCodes[0]) {
 144                     expectedRetCode |= Util.CODE_FIRST_SUCCESS;
 145                 }
 146                 if (successCodes[1]) {
 147                     expectedRetCode |= Util.CODE_SECOND_SUCCESS;
 148                 }
 149                 if (expectedRetCode != returnCode) {
 150                     throw new RuntimeException("The test failed. Expected:" +
 151                                                expectedRetCode + ". Returned:" +
 152                                                returnCode);
 153                 }
 154             }
 155             break;
 156         }
 157     } // start()
 158 } // class InterJVMGetDropSuccessTest
 159 
 160 final class Util implements AWTEventListener {
 161     public static final int CODE_NOT_RETURNED = -1;
 162     public static final int CODE_FIRST_SUCCESS = 0x2;
 163     public static final int CODE_SECOND_SUCCESS = 0x2;
 164     public static final int CODE_FAILURE = 0x1;
 165 
 166     public static final int FRAME_ACTIVATION_TIMEOUT = 3000;
 167 
 168     static final Object SYNC_LOCK = new Object();
 169     static final int MOUSE_RELEASE_TIMEOUT = 1000;
 170 
 171     static final Util theInstance = new Util();
 172 
 173     static {
 174         Toolkit.getDefaultToolkit().addAWTEventListener(theInstance, AWTEvent.MOUSE_EVENT_MASK);
 175     }
 176 
 177     public static Point getCenterLocationOnScreen(Component c) {
 178         Point p = c.getLocationOnScreen();
 179         Dimension d = c.getSize();
 180         p.translate(d.width / 2, d.height / 2);
 181         return p;
 182     }
 183 
 184     public static int sign(int n) {
 185         return n < 0 ? -1 : n == 0 ? 0 : 1;
 186     }
 187 
 188     private Component clickedComponent = null;
 189 
 190     private void reset() {
 191         clickedComponent = null;
 192     }
 193 
 194     public void eventDispatched(AWTEvent e) {
 195         if (e.getID() == MouseEvent.MOUSE_RELEASED) {
 196             clickedComponent = (Component)e.getSource();
 197             synchronized (SYNC_LOCK) {
 198                 SYNC_LOCK.notifyAll();
 199             }
 200         }
 201     }
 202 
 203     public static boolean pointInComponent(Robot robot, Point p, Component comp)
 204       throws InterruptedException {
 205         return theInstance.pointInComponentImpl(robot, p, comp);
 206     }
 207 
 208     private boolean pointInComponentImpl(Robot robot, Point p, Component comp)
 209       throws InterruptedException {
 210         robot.waitForIdle();
 211         reset();
 212         robot.mouseMove(p.x, p.y);
 213         robot.mousePress(InputEvent.BUTTON1_MASK);
 214         synchronized (SYNC_LOCK) {
 215             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 216             SYNC_LOCK.wait(MOUSE_RELEASE_TIMEOUT);
 217         }
 218 
 219         Component c = clickedComponent;
 220 
 221         while (c != null && c != comp) {
 222             c = c.getParent();
 223         }
 224 
 225         return c == comp;
 226     }
 227 }
 228 
 229 class Child {
 230     static class DragSourceDropListener extends DragSourceAdapter {
 231         private boolean finished = false;
 232         private boolean dropSuccess = false;
 233 
 234         public void reset() {
 235             finished = false;
 236             dropSuccess = false;
 237         }
 238 
 239         public boolean isDropFinished() {
 240             return finished;
 241         }
 242 
 243         public boolean getDropSuccess() {
 244             return dropSuccess;
 245         }
 246 
 247         public void dragDropEnd(DragSourceDropEvent dsde) {
 248             finished = true;
 249             dropSuccess = dsde.getDropSuccess();
 250             synchronized (Util.SYNC_LOCK) {
 251                 Util.SYNC_LOCK.notifyAll();
 252             }
 253         }
 254     }
 255 
 256     final Frame frame = new Frame("Source Frame");
 257     final DragSource dragSource = DragSource.getDefaultDragSource();
 258     final DragSourceDropListener dragSourceListener = new DragSourceDropListener();
 259     final Transferable transferable = new StringSelection("TEXT");
 260     final DragGestureListener dragGestureListener = new DragGestureListener() {
 261             public void dragGestureRecognized(DragGestureEvent dge) {
 262                 dge.startDrag(null, transferable, dragSourceListener);
 263             }
 264         };
 265     final DragGestureRecognizer dragGestureRecognizer =
 266         dragSource.createDefaultDragGestureRecognizer(frame, DnDConstants.ACTION_COPY,
 267                                                       dragGestureListener);
 268 
 269     public static void main(String[] args) {
 270         Child child = new Child();
 271         child.run(args);
 272     }
 273 
 274     public void run(String[] args) {
 275         try {
 276             if (args.length != 4) {
 277                 throw new RuntimeException("Incorrect command line arguments.");
 278             }
 279 
 280             int x = Integer.parseInt(args[0]);
 281             int y = Integer.parseInt(args[1]);
 282             int w = Integer.parseInt(args[2]);
 283             int h = Integer.parseInt(args[3]);
 284 
 285             frame.setBounds(300, 200, 150, 150);
 286             frame.setVisible(true);
 287 
 288             Thread.sleep(Util.FRAME_ACTIVATION_TIMEOUT);
 289 
 290             Point sourcePoint = Util.getCenterLocationOnScreen(frame);
 291 
 292             Point targetPoint = new Point(x + w / 2, y + h / 2);
 293 
 294             Robot robot = new Robot();
 295             robot.mouseMove(sourcePoint.x, sourcePoint.y);
 296             robot.mousePress(InputEvent.BUTTON1_MASK);
 297             for (Point p = new Point(sourcePoint); !p.equals(targetPoint);
 298                  p.translate(Util.sign(targetPoint.x - p.x),
 299                              Util.sign(targetPoint.y - p.y))) {
 300                 robot.mouseMove(p.x, p.y);
 301                 Thread.sleep(50);
 302             }
 303 
 304             synchronized (Util.SYNC_LOCK) {
 305                 robot.mouseRelease(InputEvent.BUTTON1_MASK);
 306                 Util.SYNC_LOCK.wait(Util.FRAME_ACTIVATION_TIMEOUT);
 307             }
 308 
 309             if (!dragSourceListener.isDropFinished()) {
 310                 throw new RuntimeException("Drop not finished");
 311             }
 312 
 313             boolean success1 = dragSourceListener.getDropSuccess();
 314 
 315             dragSourceListener.reset();
 316             robot.mouseMove(sourcePoint.x, sourcePoint.y);
 317             robot.mousePress(InputEvent.BUTTON1_MASK);
 318             for (Point p = new Point(sourcePoint); !p.equals(targetPoint);
 319                  p.translate(Util.sign(targetPoint.x - p.x),
 320                              Util.sign(targetPoint.y - p.y))) {
 321                 robot.mouseMove(p.x, p.y);
 322                 Thread.sleep(50);
 323             }
 324 
 325             synchronized (Util.SYNC_LOCK) {
 326                 robot.mouseRelease(InputEvent.BUTTON1_MASK);
 327                 Util.SYNC_LOCK.wait(Util.FRAME_ACTIVATION_TIMEOUT);
 328             }
 329 
 330             if (!dragSourceListener.isDropFinished()) {
 331                 throw new RuntimeException("Drop not finished");
 332             }
 333 
 334             boolean success2 = dragSourceListener.getDropSuccess();
 335             int retCode = 0;
 336 
 337             if (success1) {
 338                 retCode |= Util.CODE_FIRST_SUCCESS;
 339             }
 340             if (success2) {
 341                 retCode |= Util.CODE_SECOND_SUCCESS;
 342             }
 343             // This returns the diagnostic code from the child VM
 344             System.exit(retCode);
 345         } catch (Throwable e) {
 346             e.printStackTrace();
 347             // This returns the diagnostic code from the child VM
 348             System.exit(Util.CODE_FAILURE);
 349         }
 350     } // run()
 351 } // class child