From 2adb3b409e8cc87685a4379be3f7beeb53706e2e Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 4 May 2023 15:39:08 +0000 Subject: [PATCH] 8306943: Open source several dnd AWT tests Reviewed-by: prr, serb --- test/jdk/java/awt/dnd/DnDAWTLockTest.java | 408 ++++++++++++++++++ .../awt/dnd/DragGestureInvokeLaterTest.java | 142 ++++++ .../DragOverDropTargetPerformanceTest.java | 233 ++++++++++ .../dnd/DragSourceDragEventModifiersTest.java | 273 ++++++++++++ .../java/awt/dnd/DragSourceGCrashTest.java | 293 +++++++++++++ 5 files changed, 1349 insertions(+) create mode 100644 test/jdk/java/awt/dnd/DnDAWTLockTest.java create mode 100644 test/jdk/java/awt/dnd/DragGestureInvokeLaterTest.java create mode 100644 test/jdk/java/awt/dnd/DragOverDropTargetPerformanceTest.java create mode 100644 test/jdk/java/awt/dnd/DragSourceDragEventModifiersTest.java create mode 100644 test/jdk/java/awt/dnd/DragSourceGCrashTest.java diff --git a/test/jdk/java/awt/dnd/DnDAWTLockTest.java b/test/jdk/java/awt/dnd/DnDAWTLockTest.java new file mode 100644 index 00000000000..1db4be45ccc --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDAWTLockTest.java @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4913349 + @summary verifies that AWT_LOCK is properly taken during DnD + @key headful + @run main DnDAWTLockTest +*/ + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.InputStream; +import java.util.StringTokenizer; + + +public class DnDAWTLockTest implements ClipboardOwner { + public static final int STARTUP_TIMEOUT = 2000; + volatile Frame frame; + + static final Clipboard clipboard = + Toolkit.getDefaultToolkit().getSystemClipboard(); + + volatile Process process = null; + volatile Point sourcePoint = null; + + public static void main(String[] args) throws Exception { + DnDAWTLockTest test = new DnDAWTLockTest(); + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> test.frame.dispose()); + } + } + + public void init() { + frame = new Frame("Drop target frame"); + frame.setLocation(200, 200); + Panel panel = new DragSourcePanel(); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + } + + public void start() throws Exception { + String stderr = null; + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + + Point p = frame.getLocationOnScreen(); + Dimension d = frame.getSize(); + + Point pp = new Point(p); + pp.translate(d.width / 2, d.height / 2); + + if (!Util.pointInComponent(robot, pp, frame)) { + System.err.println("WARNING: Couldn't locate " + frame + + " at point " + pp); + return; + } + + sourcePoint = pp; + clipboard.setContents(new StringSelection(Util.TRANSFER_DATA), + this); + + String javaPath = System.getProperty("java.home", ""); + String[] command = { + javaPath + File.separator + "bin" + File.separator + "java", + "-cp", System.getProperty("test.classes", "."), + "Child" + }; + + process = Runtime.getRuntime().exec(command); + ProcessResults pres = ProcessResults.doWaitFor(process); + + stderr = pres.stderr; + + if (pres.stderr != null && pres.stderr.length() > 0) { + System.err.println("========= Child VM System.err ========"); + System.err.print(pres.stderr); + System.err.println("======================================"); + } + + if (pres.stdout != null && pres.stdout.length() > 0) { + System.err.println("========= Child VM System.out ========"); + System.err.print(pres.stdout); + System.err.println("======================================"); + } + + System.err.println("Child VM return code: " + pres.exitValue); + + if (stderr != null && stderr.contains("InternalError")) { + throw new RuntimeException("Test failed"); + } + } + + public void lostOwnership(Clipboard c, Transferable trans) { + Runnable r = new Runnable() { + public void run() { + try { + if (process == null) { + throw new RuntimeException("Null process"); + } + + if (sourcePoint == null) { + throw new RuntimeException("Null point"); + } + + Thread.sleep(STARTUP_TIMEOUT); + Transferable t = clipboard.getContents(null); + + String s = + (String) t.getTransferData(DataFlavor.stringFlavor); + StringTokenizer st = new StringTokenizer(s); + + int x = Integer.parseInt(st.nextToken()); + int y = Integer.parseInt(st.nextToken()); + + Point targetPoint = new Point(x, y); + + Robot robot = new Robot(); + + robot.mouseMove(sourcePoint.x, sourcePoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !sourcePoint.equals(targetPoint); + sourcePoint.translate( + sign(targetPoint.x - sourcePoint.x), + sign(targetPoint.y - sourcePoint.y) + )) { + robot.mouseMove(sourcePoint.x, sourcePoint.y); + robot.delay(25); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } catch (Exception e) { + e.printStackTrace(); + process.destroy(); + } + } + }; + new Thread(r).start(); + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } +} + +class Child { + public static final int ACTION_TIMEOUT = 30000; + + volatile Frame frame; + volatile Panel panel; + + + public void init() { + panel = new DropTargetPanel(); + + frame = new Frame("Drag source frame"); + frame.setLocation(500, 200); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + } + + public void run() { + try { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + + Point targetPoint = panel.getLocationOnScreen(); + Dimension d = panel.getSize(); + targetPoint.translate(d.width / 2, d.height / 2); + + if (!Util.pointInComponent(robot, targetPoint, panel)) { + System.err.println("WARNING: Couldn't locate " + panel + + " at point " + targetPoint); + System.exit(0); + } + + String positionData = "" + targetPoint.x + " " + targetPoint.y; + DnDAWTLockTest.clipboard.setContents( + new StringSelection(positionData), null); + + Thread.sleep(ACTION_TIMEOUT); + } catch (Throwable e) { + e.printStackTrace(); + } + System.exit(0); + } + + public static void main(String[] args) throws Exception { + Child child = new Child(); + EventQueue.invokeAndWait(child::init); + try { + child.run(); + } finally { + EventQueue.invokeAndWait(() -> child.frame.dispose()); + } + } +} + +class Util implements AWTEventListener { + private static final Toolkit tk = Toolkit.getDefaultToolkit(); + public static final Object SYNC_LOCK = new Object(); + private Component clickedComponent = null; + private static final int PAINT_TIMEOUT = 10000; + private static final int MOUSE_RELEASE_TIMEOUT = 10000; + private static final Util util = new Util(); + public static final String TRANSFER_DATA = "TRANSFER_DATA"; + + static { + tk.addAWTEventListener(util, 0xFFFFFFFF); + } + + private void reset() { + clickedComponent = null; + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component)e.getSource(); + synchronized (SYNC_LOCK) { + SYNC_LOCK.notifyAll(); + } + } + } + + public static boolean pointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + return util.isPointInComponent(robot, p, comp); + } + + private boolean isPointInComponent(Robot robot, Point p, Component comp) + throws InterruptedException { + tk.sync(); + robot.waitForIdle(); + reset(); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + synchronized (SYNC_LOCK) { + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SYNC_LOCK.wait(MOUSE_RELEASE_TIMEOUT); + } + + Component c = clickedComponent; + + while (c != null && c != comp) { + c = c.getParent(); + } + + return c == comp; + } +} + +class DragSourcePanel extends Panel { + public DragSourcePanel() { + final Transferable t = new StringSelection(Util.TRANSFER_DATA); + final DragGestureListener dgl = new DragGestureListener() { + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, t); + } + }; + final DragSource ds = DragSource.getDefaultDragSource(); + final DragGestureRecognizer dgr = + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + dgl); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } +} + +class DropTargetPanel extends Panel { + public DropTargetPanel() { + final DropTargetListener dtl = new DropTargetAdapter() { + public void drop(DropTargetDropEvent dtde) { + Transferable t = dtde.getTransferable(); + dtde.acceptDrop(dtde.getDropAction()); + try { + t.getTransferData(DataFlavor.stringFlavor); + } catch (Exception e) { + e.printStackTrace(); + } + dtde.dropComplete(true); + EventQueue.invokeLater(new Runnable() { + public void run() { + System.exit(0); + } + }); + } + }; + final DropTarget dt = new DropTarget(this, dtl); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } +} + +class ProcessResults { + public int exitValue; + public String stdout; + public String stderr; + + public ProcessResults() { + exitValue = -1; + stdout = ""; + stderr = ""; + } + + /** + * Method to perform a "wait" for a process and return its exit value. + * This is a workaround for Process.waitFor() never returning. + */ + public static ProcessResults doWaitFor(Process p) { + ProcessResults pres = new ProcessResults(); + + InputStream in = null; + InputStream err = null; + + try { + in = p.getInputStream(); + err = p.getErrorStream(); + + boolean finished = false; + + while (!finished) { + try { + while (in.available() > 0) { + pres.stdout += (char)in.read(); + } + while (err.available() > 0) { + pres.stderr += (char)err.read(); + } + // Ask the process for its exitValue. If the process + // is not finished, an IllegalThreadStateException + // is thrown. If it is finished, we fall through and + // the variable finished is set to true. + pres.exitValue = p.exitValue(); + finished = true; + } + catch (IllegalThreadStateException e) { + // Process is not finished yet; + // Sleep a little to save on CPU cycles + Thread.sleep(500); + } + } + if (in != null) in.close(); + if (err != null) err.close(); + } + catch (Throwable e) { + System.err.println("doWaitFor(): unexpected exception"); + e.printStackTrace(); + } + return pres; + } +} diff --git a/test/jdk/java/awt/dnd/DragGestureInvokeLaterTest.java b/test/jdk/java/awt/dnd/DragGestureInvokeLaterTest.java new file mode 100644 index 00000000000..aba465a5693 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragGestureInvokeLaterTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4354044 + @summary tests that a drag can be initiated with MOUSE_MOVED event + @key headful +*/ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.event.InputEvent; + +public class DragGestureInvokeLaterTest { + + volatile Frame frame; + volatile DragSourcePanel panel; + + public static void main(String[] args) throws Exception { + DragGestureInvokeLaterTest test = + new DragGestureInvokeLaterTest(); + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(() -> test.frame.dispose()); + } + } + + public void init() { + panel = new DragSourcePanel(); + frame = new Frame("DragGestureInvokeLaterTest frame"); + frame.setSize(200, 200); + frame.setLocation(200, 200); + frame.add(panel); + frame.setVisible(true); + } + + public void start() throws Exception { + Robot robot = new Robot(); + + robot.waitForIdle(); + robot.delay(1000); + + Point loc = panel.getLocationOnScreen(); + + robot.mouseMove(loc.x + 2, loc.y + 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + + for (int i = 0; i < 10; i++) { + robot.delay(100); + robot.mouseMove(loc.x + 2 + i, loc.y + 2 + i); + } + + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + } +} + +class DragSourcePanel extends Panel + implements DragSourceListener, DragGestureListener { + + DragSource ds; + DragGestureRecognizer dgr; + + public DragSourcePanel() { + ds = new DragSource(); + dgr = ds.createDefaultDragGestureRecognizer(this, + DnDConstants.ACTION_COPY_OR_MOVE, this); + } + + public void dragGestureRecognized(DragGestureEvent e) { + Runnable dragThread = new DragThread(e); + EventQueue.invokeLater(dragThread); + } + + class DragThread implements Runnable { + + DragGestureEvent event; + + public DragThread(DragGestureEvent e) { + event = e; + } + + public void run() { + try { + event.startDrag(DragSource.DefaultCopyNoDrop, + new StringSelection("Test"), DragSourcePanel.this); + } catch (InvalidDnDOperationException e) { + System.out.println("The test PASSED"); + return; + } + throw new RuntimeException( + "Test failed, InvalidDnDOperationException is not thrown"); + } + } + + public void dragEnter(DragSourceDragEvent e) {} + + public void dragOver(DragSourceDragEvent e) {} + + public void dropActionChanged(DragSourceDragEvent e) {} + + public void dragExit(DragSourceEvent e) {} + + public void dragDropEnd(DragSourceDropEvent e) {} +} diff --git a/test/jdk/java/awt/dnd/DragOverDropTargetPerformanceTest.java b/test/jdk/java/awt/dnd/DragOverDropTargetPerformanceTest.java new file mode 100644 index 00000000000..886165637b0 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragOverDropTargetPerformanceTest.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4445747 + @summary tests that drag over drop target is not very slow on Win9X/WinME + @key headful +*/ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.io.Serializable; + +public class DragOverDropTargetPerformanceTest { + + Frame frame; + volatile DragSourceButton dragSourceButton; + volatile DropTargetPanel dropTargetPanel; + + static final int FRAME_ACTIVATION_TIMEOUT = 1000; + static final int DROP_COMPLETION_TIMEOUT = 1000; + + public static void main(String[] args) throws Exception { + DragOverDropTargetPerformanceTest test = + new DragOverDropTargetPerformanceTest(); + + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(()-> test.frame.dispose()); + } + } + + public void init() { + dragSourceButton = new DragSourceButton(); + dropTargetPanel = new DropTargetPanel(); + + frame = new Frame(); + frame.setTitle("DragOverDropTargetPerformanceTest frame"); + frame.setLocation(200, 200); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourceButton); + frame.add(dropTargetPanel); + + frame.pack(); + frame.setVisible(true); + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } + + public void start() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(10); + robot.waitForIdle(); + robot.delay(FRAME_ACTIVATION_TIMEOUT); + + Point srcPoint = dragSourceButton.getLocationOnScreen(); + Dimension d = dragSourceButton.getSize(); + srcPoint.translate(d.width / 2, d.height / 2); + + Point dstPoint = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + dstPoint.translate(d.width / 2, d.height / 2); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + + for (;!srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + + robot.delay(DROP_COMPLETION_TIMEOUT); + + long dstime = dragSourceButton.getDragSourceTime(); + long dttime = dragSourceButton.getDropTargetTime(); + if (dstime == 0 || dttime == 0) { + System.err.println( + "WARNING: couldn't emulate DnD to measure performance."); + } else if (dttime > dstime * 4) { + throw new RuntimeException("The test failed." + + "Over drag source: " + dstime + "." + + "Over drop target: " + dttime); + } + } +} + +class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + private volatile long dsTime = 0; + private volatile long dtTime = 0; + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + try { + dge.startDrag(null, this, this); + dsTime = System.currentTimeMillis(); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + public void dragEnter(DragSourceDragEvent dsde) { + long currentTime = System.currentTimeMillis(); + dsTime = currentTime - dsTime; + dtTime = currentTime; + } + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) { + long currentTime = System.currentTimeMillis(); + dtTime = currentTime - dtTime; + } + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + return this; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + + public long getDragSourceTime() { + return dsTime; + } + + public long getDropTargetTime() { + return dtTime; + } +} + +class DropTargetPanel extends Panel { + + final Dimension preferredDimension = new Dimension(200, 200); + final DropTargetListener dtl = new DropTargetAdapter() { + public void drop(DropTargetDropEvent dtde) { + dtde.rejectDrop(); + } + }; + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, dtl)); + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + +} diff --git a/test/jdk/java/awt/dnd/DragSourceDragEventModifiersTest.java b/test/jdk/java/awt/dnd/DragSourceDragEventModifiersTest.java new file mode 100644 index 00000000000..ac7d31b6b94 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragSourceDragEventModifiersTest.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4924527 + @summary tests DragSourceDragEvent.getGestureModifiers[Ex]() \ + for valid and invalid modifiers + @key headful +*/ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceContext; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.event.InputEvent; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; + +public class DragSourceDragEventModifiersTest { + boolean failed; + + static class DummyImage extends Image { + public DummyImage() {} + public int getWidth(ImageObserver observer) {return 0;} + public int getHeight(ImageObserver observer){return 0;} + public ImageProducer getSource() {return null;} + public Graphics getGraphics() {return null;} + public void flush() {} + + public Object getProperty(String name, ImageObserver observer) { + return null; + } + } + + static class DummyDGRecognizer extends DragGestureRecognizer { + private final DragSource dragSource; + private final Component component; + + public DummyDGRecognizer(DragSource ds,Component c) { + super(ds,c); + component = c; + dragSource = ds; + } + + public void addDragGestureListener(DragGestureListener dgl) {} + public void appendEvent(InputEvent awtie) {} + public void fireDragGestureRecognized(int dragAction, Point p) {} + public Component getComponent() {return component;} + public DragSource getDragSource() {return dragSource;} + public int getSourceActions() {return DnDConstants.ACTION_COPY_OR_MOVE;} + public InputEvent getTriggerEvent() {return null;} + public void registerListeners() {} + public void removeDragGestureListener(DragGestureListener dgl) {} + public void resetRecognizer() {} + public void setComponent(Component c) {} + public void setSourceActions(int actions) {} + public void unregisterListeners() {} + } + + + DragSource ds = new DragSource(); + + int[] actions = { + DnDConstants.ACTION_NONE, + DnDConstants.ACTION_COPY, + DnDConstants.ACTION_MOVE, + DnDConstants.ACTION_COPY_OR_MOVE, + DnDConstants.ACTION_LINK, + DnDConstants.ACTION_REFERENCE + }; + + Cursor[] cursors = { + DragSource.DefaultCopyDrop, + DragSource.DefaultMoveDrop, + DragSource.DefaultLinkDrop, + DragSource.DefaultCopyNoDrop, + DragSource.DefaultMoveNoDrop, + DragSource.DefaultLinkNoDrop + }; + + DummyImage image = new DummyImage(); + + Point point = new Point(0,0); + + Transferable transferable = new Transferable() { + public DataFlavor[] getTransferDataFlavors() {return null;} + public boolean isDataFlavorSupported(DataFlavor flavor) {return false;} + public Object getTransferData(DataFlavor flavor) {return null;} + }; + + DragSourceListener dsl = new DragSourceListener() { + public void dragEnter(DragSourceDragEvent dsde) {} + public void dragOver(DragSourceDragEvent dsde) {} + public void dropActionChanged(DragSourceDragEvent dsde) {} + public void dragExit(DragSourceEvent dsde) {} + public void dragDropEnd(DragSourceDropEvent dsde) {} + }; + /* + int modifiers[] = { + InputEvent.ALT_GRAPH_MASK, + InputEvent.ALT_MASK, + InputEvent.BUTTON1_MASK, + InputEvent.BUTTON2_MASK, + InputEvent.BUTTON3_MASK, + InputEvent.CTRL_MASK, + InputEvent.META_MASK, + InputEvent.SHIFT_MASK + }; + + int exModifiers[] = { + InputEvent.SHIFT_DOWN_MASK, + InputEvent.ALT_DOWN_MASK, + InputEvent.BUTTON1_DOWN_MASK, + InputEvent.BUTTON2_DOWN_MASK, + InputEvent.BUTTON3_DOWN_MASK, + InputEvent.CTRL_DOWN_MASK, + InputEvent.META_DOWN_MASK, + InputEvent.ALT_GRAPH_DOWN_MASK, + }; + */ + DragGestureEvent getDragGestureEvent() { + java.util.Vector vector = new java.util.Vector(); + vector.add(new java.lang.Integer(0)); + return new DragGestureEvent(new DummyDGRecognizer(ds, new Button()), + actions[1], + new java.awt.Point(0,0), + vector); + } + DragGestureEvent dge = getDragGestureEvent(); + + DragSourceContext dsc = new DragSourceContext(dge, + cursors[0], + image, + point, + transferable, + dsl); + + public static void main(String[] args) { + new DragSourceDragEventModifiersTest().start(); + } + + public void start() { + try { + // valid modifiers: + + check(InputEvent.BUTTON1_MASK, InputEvent.BUTTON1_MASK, + InputEvent.BUTTON1_DOWN_MASK); + + check(InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK, + InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK, + InputEvent.BUTTON1_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + + check(InputEvent.BUTTON1_DOWN_MASK, InputEvent.BUTTON1_MASK, + InputEvent.BUTTON1_DOWN_MASK); + + check(InputEvent.BUTTON1_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK, + InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK, + InputEvent.BUTTON1_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + + // invalid modifiers: + + int invalidMods = 0; + check(invalidMods, invalidMods, invalidMods); + + invalidMods = InputEvent.BUTTON1_DOWN_MASK | InputEvent.SHIFT_MASK; + check(invalidMods, invalidMods, invalidMods); + + invalidMods = (InputEvent.ALT_GRAPH_DOWN_MASK << 1); + check(invalidMods, invalidMods, invalidMods); + + invalidMods = InputEvent.BUTTON1_DOWN_MASK + | (InputEvent.ALT_GRAPH_DOWN_MASK << 1); + check(invalidMods, invalidMods, invalidMods); + + invalidMods = InputEvent.BUTTON1_MASK + | (InputEvent.ALT_GRAPH_DOWN_MASK << 1); + check(invalidMods, invalidMods, invalidMods); + + invalidMods = InputEvent.BUTTON1_DOWN_MASK + | InputEvent.SHIFT_MASK + | (InputEvent.ALT_GRAPH_DOWN_MASK << 1); + check(invalidMods, invalidMods, invalidMods); + + } catch (Throwable e) { + e.printStackTrace(); + } + + if (failed) { + throw new RuntimeException("wrong behavior of " + + "DragSourceDragEvent.getModifiers[Ex]()," + + " see error messages above"); + } + + System.err.println("test passed!"); + } + + void check(int mods, int expectedMods, int expectedExMods) { + System.err.println("testing DragSourceDragEvent " + + "created with 1st constructor"); + System.err.println("modifiers passed to the constructor: " + + Integer.toBinaryString(mods)); + verify(create1(mods), expectedMods, expectedExMods); + + System.err.println("testing DragSourceDragEvent " + + "created with 2nd constructor"); + System.err.println("modifiers passed to the constructor: " + + Integer.toBinaryString(mods)); + verify(create2(mods), expectedMods, expectedExMods); + } + + void verify(DragSourceDragEvent dsde, int expectedMods, int expectedExMods) { + if (dsde.getGestureModifiers() != expectedMods) { + failed = true; + System.err.print("ERROR: "); + } + System.err.println("getGestureModifiers() returned: " + + Integer.toBinaryString(dsde.getGestureModifiers()) + + " ; expected: " + Integer.toBinaryString(expectedMods)); + + if (dsde.getGestureModifiersEx() != expectedExMods) { + failed = true; + System.err.print("ERROR: "); + } + System.err.println("getGestureModifiersEx() returned: " + + Integer.toBinaryString(dsde.getGestureModifiersEx()) + + " ; expected: " + Integer.toBinaryString(expectedExMods)); + + System.err.println(); + } + + DragSourceDragEvent create1(int mods) { + return new DragSourceDragEvent(dsc, actions[0], actions[0], mods); + } + + DragSourceDragEvent create2(int mods) { + return new DragSourceDragEvent(dsc, actions[0], actions[0], mods, 0, 0); + } +} diff --git a/test/jdk/java/awt/dnd/DragSourceGCrashTest.java b/test/jdk/java/awt/dnd/DragSourceGCrashTest.java new file mode 100644 index 00000000000..ddfbf40c4c0 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragSourceGCrashTest.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4888520 + @summary tests that drag source application invoked via debug java does not + crash on exit after drop on other Java drop target application + @key headful +*/ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.io.File; +import java.io.InputStream; +import java.io.Reader; + + +public class DragSourceGCrashTest { + + volatile Frame frame; + volatile Panel panel; + + public static void main(String[] args) throws Exception { + DragSourceGCrashTest test = new DragSourceGCrashTest(); + EventQueue.invokeAndWait(test::init); + try { + test.start(); + } finally { + EventQueue.invokeAndWait(()-> test.frame.dispose()); + } + } + + public void init() { + frame = new Frame("target - DragSourceGCrashTest"); + panel = new Panel(); + frame.add(panel); + frame.setBounds(100, 100, 100, 100); + + DropTargetListener dtl = new DropTargetAdapter() { + public void drop(DropTargetDropEvent dtde) { + dtde.acceptDrop(DnDConstants.ACTION_MOVE); + Transferable t = dtde.getTransferable(); + try { + DataFlavor df = new DataFlavor( + "text/plain;class=java.io.Reader"); + Reader r = df.getReaderForText(t); + // To verify the bug do not close the reader! + dtde.dropComplete(true); + } catch (Exception e) { + e.printStackTrace(); + dtde.dropComplete(false); + } + } + }; + + new DropTarget(frame, dtl); + + frame.setVisible(true); + } + + public void start() throws Exception { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + + ProcessResults pres = null; + + Point endPoint = panel.getLocationOnScreen(); + + endPoint.translate(panel.getWidth() / 2, panel.getHeight() / 2); + + String jdkPath = System.getProperty("java.home"); + String javaPath = jdkPath + File.separator + "bin" + + File.separator + "java"; + + String[] cmd = { + javaPath, "-cp", + System.getProperty("test.classes", "."), + "Child", + String.valueOf(endPoint.x), + String.valueOf(endPoint.y) + }; + Process process = Runtime.getRuntime().exec(cmd); + pres = ProcessResults.doWaitFor(process); + + if (pres.stderr != null && pres.stderr.length() > 0) { + System.err.println("========= Child VM System.err ========"); + System.err.print(pres.stderr); + System.err.println("======================================"); + } + + if (pres.stdout != null && pres.stdout.length() > 0) { + System.err.println("========= Child VM System.out ========"); + System.err.print(pres.stdout); + System.err.println("======================================"); + } + + if (pres.exitValue != 0) { + throw new RuntimeException("FAILURE: child java exited " + + "with code " + pres.exitValue); + } + } +} + +class Child { + volatile Frame frame; + volatile Panel panel; + + public static void main(String[] args) throws Exception { + int endX = Integer.parseInt(args[0]); + int endY = Integer.parseInt(args[1]); + Point endPoint = new Point(endX, endY); + + Child child = new Child(); + EventQueue.invokeAndWait(child::init); + try { + child.start(endPoint); + } finally { + EventQueue.invokeAndWait(() -> child.frame.dispose()); + } + } + + public void init() { + frame = new Frame("source - DragSourceGCrashTest"); + panel = new Panel(); + frame.add(panel); + frame.setBounds(200, 100, 100, 100); + + final DragSourceListener dsl = new DragSourceAdapter() { + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("DragSourceListener.dragDropEnd(): " + + "exiting application"); + System.exit(0); + } + }; + DragGestureListener dgl = new DragGestureListener() { + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, + new StringSelection("test"), dsl); + } + }; + + new DragSource().createDefaultDragGestureRecognizer(panel, + DnDConstants.ACTION_MOVE, dgl); + + frame.setVisible(true); + } + + public void start(Point endPoint) throws Exception { + Robot robot = new Robot(); + + robot.waitForIdle(); + robot.delay(1000); + + Point startPoint = panel.getLocationOnScreen(); + + startPoint.translate( + panel.getWidth() / 2, + panel.getHeight() / 2 + ); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate( + Integer.compare(endPoint.x - p.x, 0), + Integer.compare(endPoint.y - p.y, 0) + )) { + robot.mouseMove(p.x, p.y); + robot.delay(50); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + long timeout = 30000; + Object LOCK = new Object(); + synchronized (LOCK) { + LOCK.wait(timeout); + System.err.println(System.currentTimeMillis() + " end"); + } + System.err.println("WARNING: drop has not ended within " + timeout + + " ms, exiting application!"); + System.exit(0); + } +} + +class ProcessResults { + final static long TIMEOUT = 60000; + + public int exitValue; + public String stdout; + public String stderr; + + public ProcessResults() { + exitValue = -1; + stdout = ""; + stderr = ""; + } + + /** + * Method to perform a "wait" for a process and return its exit value. + * This is a workaround for Process.waitFor() never returning. + */ + public static ProcessResults doWaitFor(Process p) { + ProcessResults pres = new ProcessResults(); + + InputStream in = null; + InputStream err = null; + + long startTime = System.currentTimeMillis(); + + try { + in = p.getInputStream(); + err = p.getErrorStream(); + + boolean finished = false; + + while (!finished) { + try { + while (in.available() > 0) { + pres.stdout += (char)in.read(); + } + while (err.available() > 0) { + pres.stderr += (char)err.read(); + } + // Ask the process for its exitValue. If the process + // is not finished, an IllegalThreadStateException + // is thrown. If it is finished, we fall through and + // the variable finished is set to true. + pres.exitValue = p.exitValue(); + finished = true; + } + catch (IllegalThreadStateException e) { + if (System.currentTimeMillis() > startTime + TIMEOUT) { + System.err.println("WARNING: child process has not " + + "exited within " + TIMEOUT + " ms, returning" + + " from ProcessResults.doWaitFor()"); + pres.exitValue = 0; + return pres; + } + // Process is not finished yet; + // Sleep a little to save on CPU cycles + Thread.currentThread().sleep(500); + } + } + if (in != null) in.close(); + if (err != null) err.close(); + } + catch (Throwable e) { + System.err.println("doWaitFor(): unexpected exception"); + e.printStackTrace(); + } + return pres; + } +}