1 /* 2 * Copyright (c) 2015, 2017, 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 import java.awt.Dialog; 25 import java.awt.Frame; 26 import java.awt.Point; 27 import java.awt.Robot; 28 import java.awt.Window; 29 import java.awt.datatransfer.DataFlavor; 30 import java.awt.datatransfer.Transferable; 31 import java.awt.dnd.DnDConstants; 32 import java.awt.dnd.DragGestureEvent; 33 import java.awt.dnd.DragGestureListener; 34 import java.awt.dnd.DragSource; 35 import java.awt.dnd.DropTarget; 36 import java.awt.dnd.DropTargetDragEvent; 37 import java.awt.dnd.DropTargetDropEvent; 38 import java.awt.dnd.DropTargetEvent; 39 import java.awt.dnd.DropTargetListener; 40 import java.awt.event.InputEvent; 41 import java.awt.event.MouseAdapter; 42 import java.awt.event.MouseEvent; 43 44 import java.io.BufferedReader; 45 import java.io.File; 46 import java.io.IOException; 47 import java.io.InputStream; 48 import java.io.InputStreamReader; 49 import java.util.concurrent.TimeUnit; 50 51 /* 52 * @test 53 * @key headful 54 * @bug 8134917 8139050 55 * @summary [macosx] JOptionPane doesn't receive mouse events when opened from a drop event 56 * @run main MissingEventsOnModalDialogTest RUN_PROCESS 57 */ 58 public class MissingEventsOnModalDialogTest { 59 60 private static final String RUN_PROCESS = "RUN_PROCESS"; 61 private static final String RUN_TEST = "RUN_TEST"; 62 private static boolean exception = false; 63 private static volatile boolean passed = false; 64 65 public static void main(String[] args) throws Exception { 66 String command = args.length < 1 ? RUN_TEST : args[0]; 67 switch (command) { 68 case RUN_PROCESS: 69 runProcess(); 70 break; 71 case RUN_TEST: 72 runTest(); 73 break; 74 default: 75 throw new RuntimeException("Unknown command: " + command); 76 } 77 } 78 79 private static void runTest() throws Exception { 80 Frame sourceFrame = createFrame("Source Frame", 100, 100); 81 Frame targetFrame = createFrame("Target Frame", 350, 350); 82 83 DragSource defaultDragSource 84 = DragSource.getDefaultDragSource(); 85 defaultDragSource.createDefaultDragGestureRecognizer(sourceFrame, 86 DnDConstants.ACTION_COPY_OR_MOVE, 87 new TestDragGestureListener()); 88 new DropTarget(targetFrame, DnDConstants.ACTION_COPY_OR_MOVE, 89 new TestDropTargetListener(targetFrame)); 90 91 Robot robot = new Robot(); 92 robot.setAutoDelay(50); 93 94 sourceFrame.toFront(); 95 robot.waitForIdle(); 96 97 Point point = getCenterPoint(sourceFrame); 98 robot.mouseMove(point.x, point.y); 99 robot.waitForIdle(); 100 101 mouseDragAndDrop(robot, point, getCenterPoint(targetFrame)); 102 103 long time = System.currentTimeMillis() + 1000; 104 105 while (!passed) { 106 if (time < System.currentTimeMillis()) { 107 sourceFrame.dispose(); 108 targetFrame.dispose(); 109 throw new RuntimeException("Mouse clicked event is lost!"); 110 } 111 Thread.sleep(10); 112 } 113 sourceFrame.dispose(); 114 targetFrame.dispose(); 115 } 116 117 private static Frame createFrame(String title, int x, int y) { 118 Frame frame = new Frame(); 119 frame.setSize(200, 200); 120 frame.setLocation(x, y); 121 frame.setTitle(title); 122 frame.setVisible(true); 123 return frame; 124 } 125 126 private static Point getCenterPoint(Window window) { 127 Point centerPoint = window.getLocationOnScreen(); 128 centerPoint.translate(window.getWidth() / 2, window.getHeight() / 2); 129 return centerPoint; 130 } 131 132 public static void mouseDragAndDrop(Robot robot, Point from, Point to) { 133 mouseDND(robot, from.x, from.y, to.x, to.y); 134 } 135 136 public static void mouseDND(Robot robot, int x1, int y1, int x2, int y2) { 137 138 int N = 20; 139 int x = x1; 140 int y = y1; 141 int dx = (x2 - x1) / N; 142 int dy = (y2 - y1) / N; 143 144 robot.mousePress(InputEvent.BUTTON1_MASK); 145 146 for (int i = 0; i < N; i++) { 147 robot.mouseMove(x += dx, y += dy); 148 } 149 150 robot.mouseRelease(InputEvent.BUTTON1_MASK); 151 } 152 153 private static class TestDragGestureListener implements DragGestureListener { 154 155 public void dragGestureRecognized(DragGestureEvent dge) { 156 dge.startDrag(null, new StringTransferable()); 157 } 158 } 159 160 static class StringTransferable implements Transferable { 161 162 @Override 163 public DataFlavor[] getTransferDataFlavors() { 164 return new DataFlavor[]{DataFlavor.stringFlavor}; 165 } 166 167 @Override 168 public boolean isDataFlavorSupported(DataFlavor flavor) { 169 return flavor.equals(DataFlavor.stringFlavor); 170 } 171 172 @Override 173 public Object getTransferData(DataFlavor flavor) { 174 return "Hello World!"; 175 } 176 } 177 178 private static class TestDropTargetListener implements DropTargetListener { 179 180 private final Frame targetFrame; 181 182 public TestDropTargetListener(Frame targetFrame) { 183 this.targetFrame = targetFrame; 184 } 185 186 @Override 187 public void dragEnter(DropTargetDragEvent dtde) { 188 dtde.acceptDrag(dtde.getDropAction()); 189 } 190 191 @Override 192 public void dragOver(DropTargetDragEvent dtde) { 193 dtde.acceptDrag(dtde.getDropAction()); 194 } 195 196 @Override 197 public void dropActionChanged(DropTargetDragEvent dtde) { 198 dtde.acceptDrag(dtde.getDropAction()); 199 } 200 201 @Override 202 public void dragExit(DropTargetEvent dte) { 203 } 204 205 @Override 206 public void drop(DropTargetDropEvent dtde) { 207 dtde.acceptDrop(dtde.getDropAction()); 208 showModalDialog(targetFrame); 209 dtde.dropComplete(true); 210 } 211 } 212 213 private static void showModalDialog(Frame targetFrame) { 214 215 Dialog dialog = new Dialog(targetFrame, true); 216 217 dialog.addMouseListener(new MouseAdapter() { 218 219 @Override 220 public void mouseClicked(MouseEvent e) { 221 passed = true; 222 dialog.dispose(); 223 } 224 }); 225 226 dialog.setSize(400, 300); 227 dialog.setTitle("Modal Dialog!"); 228 229 clickOnModalDialog(dialog); 230 dialog.setVisible(true); 231 } 232 233 private static void clickOnModalDialog(Dialog dialog) { 234 new Thread(() -> { 235 clickOnDialog(dialog); 236 }).start(); 237 } 238 239 private static void clickOnDialog(Dialog dialog) { 240 try { 241 long time = System.currentTimeMillis() + 200; 242 243 while (!dialog.isVisible()) { 244 if (time < System.currentTimeMillis()) { 245 throw new RuntimeException("Dialog is not visible!"); 246 } 247 Thread.sleep(10); 248 } 249 Robot robot = new Robot(); 250 robot.setAutoDelay(50); 251 robot.waitForIdle(); 252 robot.delay(200); 253 254 Point point = getCenterPoint(dialog); 255 256 robot.mouseMove(point.x, point.y); 257 robot.mousePress(InputEvent.BUTTON1_MASK); 258 robot.mouseRelease(InputEvent.BUTTON1_MASK); 259 260 } catch (Exception e) { 261 throw new RuntimeException(e); 262 } 263 } 264 265 private static void runProcess() throws Exception { 266 String javaPath = System.getProperty("java.home", ""); 267 String command = javaPath + File.separator + "bin" + File.separator + "java" 268 + " " + MissingEventsOnModalDialogTest.class.getName() + " " + RUN_TEST; 269 270 Process process = Runtime.getRuntime().exec(command); 271 boolean processExit = process.waitFor(20, TimeUnit.SECONDS); 272 273 StringBuilder inStream = new StringBuilder(); 274 StringBuilder errStream = new StringBuilder(); 275 checkErrors(process.getErrorStream(), errStream); 276 checkErrors(process.getInputStream(), inStream); 277 278 if (exception) { 279 System.out.println(inStream); 280 System.err.println(errStream); 281 throw new RuntimeException("Exception in the output!"); 282 } 283 284 if (!processExit) { 285 process.destroy(); 286 throw new RuntimeException("" 287 + "The sub process has not exited!"); 288 } 289 } 290 291 private static boolean containsError(String line) { 292 line = line.toLowerCase(); 293 return line.contains("exception") || line.contains("error") 294 || line.contains("selector"); 295 } 296 297 private static void checkErrors(InputStream in, StringBuilder stream) throws IOException { 298 try (BufferedReader bufferedReader 299 = new BufferedReader(new InputStreamReader(in))) { 300 301 String line = null; 302 while ((line = bufferedReader.readLine()) != null) { 303 if (!exception) { 304 exception = containsError(line); 305 } 306 stream.append(line).append("\n"); 307 } 308 } 309 } 310 }