8027628: JWindow jumps to (0, 0) after mouse clicked
authorbagiras
Mon, 18 Nov 2013 23:24:27 +0400
changeset 21786 2f3ad6aa2ac5
parent 21785 fc0bfa7d9d95
child 21787 11c9c9dfa450
8027628: JWindow jumps to (0, 0) after mouse clicked Reviewed-by: anthony, serb
jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java
jdk/test/java/awt/Window/TopLevelLocation/TopLevelLocation.java
--- a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java	Mon Nov 18 19:22:29 2013 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java	Mon Nov 18 23:24:27 2013 +0400
@@ -740,37 +740,7 @@
         // Bounds of the window
         Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds((Component)target);
 
-        Point newLocation = targetBounds.getLocation();
-        if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) {
-            // Location, Client size + insets
-            newLocation = new Point(xe.get_x() - currentInsets.left, xe.get_y() - currentInsets.top);
-        } else {
-            // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when
-            // a window is resized but the client can not tell if the window was
-            // moved or not. The client should consider the position as unkown
-            // and use TranslateCoordinates to find the actual position.
-            //
-            // TODO this should be the default for every case.
-            switch (XWM.getWMID()) {
-                case XWM.CDE_WM:
-                case XWM.MOTIF_WM:
-                case XWM.METACITY_WM:
-                case XWM.MUTTER_WM:
-                case XWM.SAWFISH_WM:
-                {
-                    Point xlocation = queryXLocation();
-                    if (log.isLoggable(PlatformLogger.Level.FINE)) {
-                        log.fine("New X location: {0}", xlocation);
-                    }
-                    if (xlocation != null) {
-                        newLocation = xlocation;
-                    }
-                    break;
-                }
-                default:
-                    break;
-            }
-        }
+        Point newLocation = getNewLocation(xe, currentInsets.left, currentInsets.top);
 
         WindowDimensions newDimensions =
                 new WindowDimensions(newLocation,
@@ -1261,12 +1231,4 @@
         }
         super.handleWindowFocusOut(oppositeWindow, serial);
     }
-
-    private Point queryXLocation()
-    {
-        return XlibUtil.translateCoordinates(
-            getContentWindow(),
-            XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()),
-            new Point(0, 0));
-    }
 }
--- a/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Mon Nov 18 19:22:29 2013 +0400
+++ b/jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java	Mon Nov 18 23:24:27 2013 +0400
@@ -740,15 +740,67 @@
     public void paletteChanged() {
     }
 
+    private Point queryXLocation()
+    {
+        return XlibUtil.translateCoordinates(
+            getContentWindow(),
+            XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()),
+            new Point(0, 0));
+    }
+
+    protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset) {
+        // Bounds of the window
+        Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds((Component)target);
+
+        int runningWM = XWM.getWMID();
+        Point newLocation = targetBounds.getLocation();
+        if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) {
+            // Location, Client size + insets
+            newLocation = new Point(xe.get_x() - leftInset, xe.get_y() - topInset);
+        } else {
+            // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when
+            // a window is resized but the client can not tell if the window was
+            // moved or not. The client should consider the position as unkown
+            // and use TranslateCoordinates to find the actual position.
+            //
+            // TODO this should be the default for every case.
+            switch (runningWM) {
+                case XWM.CDE_WM:
+                case XWM.MOTIF_WM:
+                case XWM.METACITY_WM:
+                case XWM.MUTTER_WM:
+                case XWM.SAWFISH_WM:
+                {
+                    Point xlocation = queryXLocation();
+                    if (log.isLoggable(PlatformLogger.Level.FINE)) {
+                        log.fine("New X location: {0}", xlocation);
+                    }
+                    if (xlocation != null) {
+                        newLocation = xlocation;
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+        return newLocation;
+    }
+
     /*
      * Overridden to check if we need to update our GraphicsDevice/Config
      * Added for 4934052.
      */
     @Override
     public void handleConfigureNotifyEvent(XEvent xev) {
-        // TODO: We create an XConfigureEvent every time we override
-        // handleConfigureNotify() - too many!
         XConfigureEvent xe = xev.get_xconfigure();
+        /*
+         * Correct window location which could be wrong in some cases.
+         * See getNewLocation() for the details.
+         */
+        Point newLocation = getNewLocation(xe, 0, 0);
+        xe.set_x(newLocation.x);
+        xe.set_y(newLocation.y);
         checkIfOnNewScreen(new Rectangle(xe.get_x(),
                                          xe.get_y(),
                                          xe.get_width(),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Window/TopLevelLocation/TopLevelLocation.java	Mon Nov 18 23:24:27 2013 +0400
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013, 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 8027628
+ * @author Oleg Pekhovskiy
+ * @summary JWindow jumps to (0, 0) after mouse clicked
+ * @run main TopLevelLocation
+ */
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.JFrame;
+import javax.swing.JWindow;
+
+public class TopLevelLocation {
+
+    private static JFrame frame;
+    private static JWindow window;
+    private static boolean passed = true;
+
+    public static void main(String[] args) throws Exception {
+        EventQueue.invokeAndWait(() -> {
+            frame = new JFrame();
+            frame.getContentPane().setBackground(Color.PINK);
+            frame.setBounds(100, 100, 500, 400);
+            frame.setUndecorated(true);
+            frame.setVisible(true);
+            window = new JWindow(frame);
+            window.setBackground(Color.BLUE);
+            window.setAlwaysOnTop(true);
+            window.setBounds(200, 200, 200, 200);
+            window.addMouseListener(new MouseAdapter() {
+                private Point dragOrigin = null;
+                private Dimension origSize = null;
+                private Point origLoc = null;
+                private Point lastLoc = null;
+                private boolean left = false;
+                private boolean top = false;
+                private boolean bottom = false;
+                private boolean right = false;
+
+                @Override
+                public void mousePressed(MouseEvent e) {
+                    System.out.println("mousePressed");
+                    dragOrigin = e.getLocationOnScreen();
+                    origSize = window.getSize();
+                    origLoc = window.getLocationOnScreen();
+                    if (lastLoc != null) {
+                        System.out.println("SET LOCATION: " + lastLoc);
+                        System.out.println("CURRENT LOCATION: " + origLoc);
+                        if (lastLoc.x != origLoc.x || lastLoc.y != origLoc.y) {
+                            passed = false;
+                        }
+                    }
+                    right = (origLoc.x + window.getWidth() - dragOrigin.x) < 5;
+                    left = !right && dragOrigin.x - origLoc.x < 5;
+                    bottom = (origLoc.y + window.getHeight() - dragOrigin.y) < 5;
+                    top = !bottom && dragOrigin.y - origLoc.y < 5;
+                }
+
+                @Override
+                public void mouseDragged(MouseEvent e) {
+                    System.out.println("mouseDragged");
+                    resize(e);
+                }
+
+                @Override
+                public void mouseReleased(MouseEvent e) {
+                    System.out.println("mouseReleased");
+                    resize(e);
+                }
+
+                void resize(MouseEvent e) {
+                    Point dragDelta = e.getLocationOnScreen();
+                    dragDelta.translate(-dragOrigin.x, -dragOrigin.y);
+                    Point newLoc = new Point(origLoc);
+                    newLoc.translate(dragDelta.x, dragDelta.y);
+                    Dimension newSize = new Dimension(origSize);
+                    if (left || right) {
+                        newSize.width += right ? dragDelta.x : -dragDelta.x;
+                    }
+                    if (top || bottom) {
+                        newSize.height += bottom ? dragDelta.y : -dragDelta.y;
+                    }
+                    if (right || (top || bottom) && !left) {
+                        newLoc.x = origLoc.x;
+                    }
+                    if (bottom || (left || right) && !top) {
+                        newLoc.y = origLoc.y;
+                    }
+                    window.setBounds(newLoc.x, newLoc.y, newSize.width, newSize.height);
+                    lastLoc = newLoc;
+                }
+            });
+            window.setVisible(true);
+        });
+        Thread.sleep(500);
+        Dimension size = window.getSize();
+        Point location = window.getLocation();
+        Robot robot = new Robot();
+        robot.setAutoDelay(200);
+        robot.setAutoWaitForIdle(true);
+        robot.waitForIdle();
+        robot.mouseMove(location.x + size.height - 2, location.y + size.width - 2);
+        robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK);
+        robot.mouseMove(location.x + size.height, location.y + size.width);
+        robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK);
+        robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK);
+        robot.mouseMove(location.x + size.height + 2, location.y + size.width + 2);
+        robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK);
+        Thread.sleep(500);
+        frame.dispose();
+        if (!passed) {
+            throw new RuntimeException("TEST FAILED: Location doesn't match!");
+        }
+        System.out.println("TEST PASSED!");
+    }
+}
+