rev 58018 : 8238575: DragSourceEvent.getLocation() returns wrong value on HiDPI screens (Windows) Reviewed-by: XXX
1 /* 2 * Copyright (c) 2014, 2020, 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 8024061 28 * @summary Checks that no exception is thrown if dragGestureRecognized 29 * takes a while to complete. 30 */ 31 32 import java.awt.AWTException; 33 import java.awt.Color; 34 import java.awt.Container; 35 import java.awt.Dimension; 36 import java.awt.Graphics; 37 import java.awt.Graphics2D; 38 import java.awt.GridLayout; 39 import java.awt.Point; 40 import java.awt.Robot; 41 import java.awt.datatransfer.DataFlavor; 42 import java.awt.datatransfer.Transferable; 43 import java.awt.datatransfer.UnsupportedFlavorException; 44 import java.awt.dnd.DnDConstants; 45 import java.awt.dnd.DragGestureEvent; 46 import java.awt.dnd.DragGestureListener; 47 import java.awt.dnd.DragSource; 48 import java.awt.dnd.DragSourceDragEvent; 49 import java.awt.dnd.DragSourceDropEvent; 50 import java.awt.dnd.DragSourceEvent; 51 import java.awt.dnd.DragSourceListener; 52 import java.awt.dnd.DropTarget; 53 import java.awt.dnd.DropTargetDragEvent; 54 import java.awt.dnd.DropTargetDropEvent; 55 import java.awt.dnd.DropTargetEvent; 56 import java.awt.dnd.DropTargetListener; 57 import java.awt.event.InputEvent; 58 import java.io.IOException; 59 import java.lang.reflect.InvocationTargetException; 60 import java.util.concurrent.CountDownLatch; 61 import java.util.concurrent.TimeUnit; 62 63 import javax.swing.JFrame; 64 import javax.swing.JPanel; 65 import javax.swing.SwingUtilities; 66 import javax.swing.WindowConstants; 67 68 /** 69 * If dragGestureRecognized() takes a while to complete and if user performs a drag quickly, 70 * an exception is thrown from DropTargetListener.dragEnter when it calls 71 * DropTargetDragEvent.getTransferable(). 72 * <p> 73 * This class introduces a delay in dragGestureRecognized() to cause the exception. 74 */ 75 public class bug8024061 { 76 private static final DataFlavor DropObjectFlavor; 77 private static final int DELAY = 1000; 78 79 static final DnDPanel panel1 = new DnDPanel(Color.yellow); 80 static final DnDPanel panel2 = new DnDPanel(Color.pink); 81 private final JFrame frame; 82 static Point here; 83 static Point there; 84 static Dimension d; 85 86 87 88 private static final CountDownLatch lock = new CountDownLatch(1); 89 private static volatile Exception dragEnterException = null; 90 91 static { 92 DataFlavor flavor = null; 93 try { 94 flavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType); 95 } catch (ClassNotFoundException e) { 96 e.printStackTrace(); 97 } 98 DropObjectFlavor = flavor; 99 } 100 101 bug8024061() { 102 frame = new JFrame("DnDWithRobot"); 103 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 104 105 d = new Dimension(100, 100); 106 107 panel1.setPreferredSize(d); 108 panel2.setPreferredSize(d); 109 110 Container content = frame.getContentPane(); 111 content.setLayout(new GridLayout(1, 2, 5, 5)); 112 content.add(panel1); 113 content.add(panel2); 114 115 frame.pack(); 116 frame.setLocationRelativeTo(null); 117 DropObject drop = new DropObject(); 118 drop.place(panel1, new Point(10, 10)); 119 frame.setVisible(true); 120 } 121 122 public static void main(String[] args) throws AWTException, InvocationTargetException, InterruptedException { 123 final bug8024061[] dnd = {null}; 124 SwingUtilities.invokeAndWait(new Runnable() { 125 @Override 126 public void run() { 127 dnd[0] = new bug8024061(); 128 } 129 }); 130 final Robot robot = new Robot(); 131 robot.setAutoDelay(10); 132 robot.waitForIdle(); 133 robot.delay(200); 134 135 JFrame frame = dnd[0].frame; 136 SwingUtilities.invokeAndWait(() -> { 137 here = panel1.getLocationOnScreen(); 138 there = panel2.getLocationOnScreen(); 139 }); 140 here.translate(d.width / 2, d.height / 2); 141 there.translate(d.width / 2, d.height / 2); 142 robot.mouseMove(here.x, here.y); 143 robot.mousePress(InputEvent.BUTTON1_MASK); 144 while (here.x < there.x) { 145 here.x += 20; 146 robot.mouseMove(here.x, here.y); 147 System.out.println("x = " + here.x); 148 } 149 robot.mouseRelease(InputEvent.BUTTON1_MASK); 150 robot.waitForIdle(); 151 robot.mousePress(InputEvent.BUTTON1_MASK); 152 robot.mouseRelease(InputEvent.BUTTON1_MASK); 153 System.out.println("finished"); 154 155 try { 156 if (lock.await(5, TimeUnit.SECONDS)) { 157 if (dragEnterException == null) { 158 System.out.println("Test passed."); 159 } else { 160 System.out.println("Test failed."); 161 dragEnterException.printStackTrace(); 162 throw new RuntimeException(dragEnterException); 163 } 164 } else { 165 System.out.println("Test failed. Timeout reached"); 166 throw new RuntimeException("Timed out waiting for dragEnter()"); 167 } 168 } finally { 169 SwingUtilities.invokeAndWait(frame::dispose); 170 } 171 } 172 173 class DropObject implements Transferable { 174 DnDPanel panel; 175 Color color = Color.CYAN; 176 int width = 50; 177 int height = 50; 178 int x; 179 int y; 180 181 void draw(Graphics2D g) { 182 Color savedColor = g.getColor(); 183 g.setColor(color); 184 g.fillRect(x, y, width, height); 185 g.setColor(Color.lightGray); 186 g.drawRect(x, y, width, height); 187 g.setColor(savedColor); 188 } 189 190 boolean contains(int x, int y) { 191 return (x > this.x && x < this.x + width) 192 && (y > this.y && y < this.y + height); 193 } 194 195 @Override 196 public DataFlavor[] getTransferDataFlavors() { 197 return new DataFlavor[]{DropObjectFlavor}; 198 } 199 200 void place(DnDPanel panel, Point location) { 201 if (panel != this.panel) { 202 x = location.x; 203 y = location.y; 204 if (this.panel != null) { 205 this.panel.setDropObject(null); 206 this.panel.repaint(); 207 } 208 this.panel = panel; 209 this.panel.setDropObject(this); 210 this.panel.repaint(); 211 } 212 } 213 214 @Override 215 public boolean isDataFlavorSupported(DataFlavor flavor) { 216 return DropObjectFlavor.equals(flavor); 217 } 218 219 @Override 220 public Object getTransferData(DataFlavor flavor) 221 throws UnsupportedFlavorException, IOException { 222 if (isDataFlavorSupported(flavor)) { 223 return this; 224 } else { 225 throw new UnsupportedFlavorException(flavor); 226 } 227 } 228 } 229 230 static class DnDPanel extends JPanel { 231 DropObject dropObject; 232 final DragSource dragSource; 233 final DropTarget dropTarget; 234 final Color color; 235 final DragGestureListener dgListener; 236 final DragSourceListener dsListener; 237 final DropTargetListener dtListener; 238 239 DnDPanel(Color color) { 240 this.color = color; 241 this.dragSource = DragSource.getDefaultDragSource(); 242 dgListener = new DragGestureListener() { 243 @Override 244 public void dragGestureRecognized(DragGestureEvent dge) { 245 Point location = dge.getDragOrigin(); 246 if (dropObject != null && dropObject.contains(location.x, location.y)) { 247 dragSource.startDrag(dge, DragSource.DefaultCopyNoDrop, dropObject, dsListener); 248 try { 249 Thread.sleep(DELAY); 250 } catch (InterruptedException e) { 251 } 252 } 253 } 254 }; 255 256 dsListener = new DragSourceListener() { 257 @Override 258 public void dragEnter(DragSourceDragEvent dsde) { 259 } 260 261 @Override 262 public void dragOver(DragSourceDragEvent dsde) { 263 } 264 265 @Override 266 public void dropActionChanged(DragSourceDragEvent dsde) { 267 } 268 269 @Override 270 public void dragExit(DragSourceEvent dse) { 271 } 272 273 @Override 274 public void dragDropEnd(DragSourceDropEvent dsde) { 275 } 276 }; 277 278 dtListener = new DropTargetListener() { 279 @Override 280 public void dragEnter(DropTargetDragEvent dtde) { 281 if (dropObject != null) { 282 dtde.rejectDrag(); 283 return; 284 } 285 dtde.acceptDrag(DnDConstants.ACTION_MOVE); 286 try { 287 Transferable t = dtde.getTransferable(); 288 Object data = t.getTransferData(DropObjectFlavor); 289 } catch (Exception e) { 290 dragEnterException = e; 291 e.printStackTrace(); 292 } finally { 293 lock.countDown(); 294 } 295 } 296 297 @Override 298 public void dragOver(DropTargetDragEvent dtde) { 299 if (dropObject != null) { 300 dtde.rejectDrag(); 301 return; 302 } 303 dtde.acceptDrag(DnDConstants.ACTION_MOVE); 304 } 305 306 @Override 307 public void dropActionChanged(DropTargetDragEvent dtde) { 308 } 309 310 @Override 311 public void dragExit(DropTargetEvent dte) { 312 } 313 314 @Override 315 public void drop(DropTargetDropEvent dtde) { 316 if (dropObject != null) { 317 dtde.rejectDrop(); 318 return; 319 } 320 try { 321 dtde.acceptDrop(DnDConstants.ACTION_MOVE); 322 Transferable t = dtde.getTransferable(); 323 DropObject dropObject = (DropObject) t.getTransferData(DropObjectFlavor); 324 Point location = dtde.getLocation(); 325 dropObject.place(DnDPanel.this, location); 326 dtde.dropComplete(true); 327 } catch (Exception e) { 328 e.printStackTrace(); 329 } 330 331 } 332 }; 333 334 dragSource.createDefaultDragGestureRecognizer(this, 335 DnDConstants.ACTION_MOVE, dgListener); 336 337 dropTarget = new DropTarget(this, DnDConstants.ACTION_MOVE, dtListener, true); 338 339 } 340 341 public void paintComponent(Graphics g) { 342 super.paintComponent(g); 343 Color savedColor = g.getColor(); 344 g.setColor(color); 345 g.fillRect(0, 0, getWidth(), getHeight()); 346 g.setColor(savedColor); 347 if (dropObject != null) { 348 dropObject.draw((Graphics2D) g); 349 } 350 } 351 352 void setDropObject(DropObject dropObject) { 353 this.dropObject = dropObject; 354 } 355 356 DropObject findDropObject(int x, int y) { 357 if (dropObject != null && dropObject.contains(x, y)) { 358 return dropObject; 359 } 360 return null; 361 } 362 } 363 } --- EOF ---