diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java index 75101e16228..9f207ee7a8b 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java @@ -14,6 +14,7 @@ package org.eclipse.swt.widgets; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.function.*; import java.util.stream.*; @@ -39,62 +40,104 @@ private Monitor createMonitor(CoordinateSystemMapper mapper, Rectangle boundsInP return monitor; } - void setupMonitors(CoordinateSystemMapper mapper) { + private void setupMonitors(CoordinateSystemMapper mapper) { Rectangle boundsInPixelsForLeftMonitor = new Rectangle(0, 0, 2000, 2000); Rectangle boundsInPixelsForRightMonitor = new Rectangle(2000, 0, 2000, 2000); monitors = new Monitor[] { createMonitor(mapper, boundsInPixelsForLeftMonitor, 200), createMonitor(mapper, boundsInPixelsForRightMonitor, 100) }; } - Stream provideCoordinateSystemMappers() { - return Stream.of(new MultiZoomCoordinateSystemMapper(null, () -> monitors), - new SingleZoomCoordinateSystemMapper(null)); + private Stream provideCoordinateSystemMappers() { + return Stream.of(getMultiZoomCoordinateSystemMapper(), getSingleZoomCoordinateSystemMapper()); + } + + private MultiZoomCoordinateSystemMapper getMultiZoomCoordinateSystemMapper() { + return new MultiZoomCoordinateSystemMapper(null, () -> monitors); + } + + private SingleZoomCoordinateSystemMapper getSingleZoomCoordinateSystemMapper() { + return new SingleZoomCoordinateSystemMapper(null); } @ParameterizedTest @MethodSource("provideCoordinateSystemMappers") void translatePointInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { setupMonitors(mapper); - Point pt = new Point(5000, -400); + Point pt = createExpectedPoint(mapper, 5000, -400, monitors[0]); Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom()); assertEquals(pt, mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom())); } - @ParameterizedTest - @MethodSource("provideCoordinateSystemMappers") - @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") - void translatePointInGapBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + @Test + void translatePointInGapBackAndForthInSingleZoomShouldBeTheSame() { + SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper(); setupMonitors(mapper); Point pt = new Point(1900, 400); Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom()); assertEquals(pt, mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom())); } + @Test + void translatePointInGapBackAndForthInMultiZoomShouldEndInsideTheSameMonitor() { + MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper(); + setupMonitors(mapper); + Point pt = new Point(1900, 400); + Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom()); + Point translatedPt = mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom()); + Point translatedPx = mapper.translateToDisplayCoordinates(translatedPt, monitors[0].getZoom()); + assertEquals(new Point(translatedPt.x, translatedPt.y), translatedPx); + assertEquals(translatedPx, px); + } + @ParameterizedTest @MethodSource("provideCoordinateSystemMappers") void translateRectangleInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { setupMonitors(mapper); - Rectangle rectInPts = new Rectangle(5000, -400, 200, 200); + Rectangle rectInPts = createExpectedRectangle(mapper, 5000, -400, 200, 200, monitors[0]); Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); } - @ParameterizedTest - @MethodSource("provideCoordinateSystemMappers") - @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") - void translateRectangleInGapBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + @Test + void translateRectangleInGapBackAndForthInSingleZoomShouldBeTheSame() { + SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper(); setupMonitors(mapper); Rectangle rectInPts = new Rectangle(1800, 400, 100, 100); Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); } - @ParameterizedTest - @MethodSource("provideCoordinateSystemMappers") - @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") - void translateRectangleInGapPartiallyInRightBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + @Test + void translateRectangleInGapBackAndForthInMultiZoomShouldBeInMonitorBounds() { + MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper(); + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(1800, 400, 100, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + Rectangle rectInPtsTranslated = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()); + boolean isInsideMonitor = false; + for (Monitor monitor : monitors) { + if (monitor.getClientArea().intersects(rectInPtsTranslated)) { + isInsideMonitor = true; + break; + } + } + assertTrue(isInsideMonitor, "The translated rectangle in points is inside the monitor bounds in points"); + } + + @Test + void translateRectangleInGapPartiallyInRightBackAndForthInSingleZoomShouldBeTheSame() { + SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper(); setupMonitors(mapper); - Rectangle rectInPts = new Rectangle(1950, 400, 100, 100); + Rectangle rectInPts = new Rectangle(1950, 400, 150, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); + } + + @Test + void translateRectangleInGapPartiallyInRightBackAndForthInMultiZoomShouldBeInside() { + MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper(); + setupMonitors(mapper); + Rectangle rectInPts = new MonitorAwareRectangle(1950, 400, 150, 100, monitors[1]); Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); } @@ -103,14 +146,14 @@ void translateRectangleInGapPartiallyInRightBackAndForthShouldBeTheSame(Coordina @MethodSource("provideCoordinateSystemMappers") void translateRectangleInGapPartiallyInLeftBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { setupMonitors(mapper); - Rectangle rectInPts = new Rectangle(750, 400, 100, 100); + Rectangle rectInPts = createExpectedRectangle(mapper, 750, 400, 100, 100, monitors[0]); Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); } - @ParameterizedTest - @MethodSource("provideCoordinateSystemMappers") - void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + @Test + void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthInSingleZoomShouldBeTheSame() { + SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper(); setupMonitors(mapper); Rectangle rectInPts = new Rectangle(950, 400, 1500, 100); Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); @@ -118,9 +161,20 @@ void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthShouldBeTheSam } @Test - @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") + void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthInMultiZoomShouldNotEndUpInGap() { + MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper(); + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(950, 400, 1500, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + Rectangle rectInPtsTranslated = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()); + Rectangle rectInPxsTranslated = mapper.translateToDisplayCoordinates(rectInPtsTranslated, + monitors[0].getZoom()); + assertEquals(rectInPxs, rectInPxsTranslated); + } + + @Test void moveRectangleInPixelsInRightMonitorsPartiallyBackAndForthShouldBeTheSame() { - CoordinateSystemMapper mapper = provideCoordinateSystemMappers().findFirst().get(); + MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper(); setupMonitors(mapper); Rectangle rectInPxs = new Rectangle(1990, -10, 2000, 2000); Rectangle expectedSmallRectInPxs = new Rectangle(0, 0, 0, monitors[0].getZoom()); @@ -140,10 +194,9 @@ void moveRectangleInPixelsInRightMonitorsPartiallyBackAndForthShouldBeTheSame() @ParameterizedTest @MethodSource("provideCoordinateSystemMappers") - @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") void translateRectangleInPixelsOutisdeMonitorsBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { setupMonitors(mapper); - Rectangle rectInPxs = new Rectangle(4400, 400, 1000, 1000); + Rectangle rectInPxs = new Rectangle(400, 2400, 1000, 1000); Rectangle rectInPts = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()); assertEquals(rectInPxs, mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom())); } @@ -157,4 +210,20 @@ void translateRectangleInPixelsInBothMonitorsBackAndForthShouldBeTheSame(Coordin assertEquals(rectInPxs, mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom())); } + private Point createExpectedPoint(CoordinateSystemMapper mapper, int x, int y, Monitor monitor) { + if (mapper instanceof SingleZoomCoordinateSystemMapper) { + return new Point(x, y); + } else { + return new MonitorAwarePoint(x, y, monitor); + } + } + + private Rectangle createExpectedRectangle(CoordinateSystemMapper mapper, int x, int y, int width, int height, Monitor monitor) { + if (mapper instanceof SingleZoomCoordinateSystemMapper) { + return new Rectangle(x, y, width, height); + } else { + return new MonitorAwareRectangle(x, y, width, height, monitor); + } + } + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/MonitorAwarePoint.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/MonitorAwarePoint.java new file mode 100644 index 00000000000..282acdbe07b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/MonitorAwarePoint.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Yatta Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import java.util.*; + +import org.eclipse.swt.widgets.*; + +/** + * Instances of this class represent {@link org.eclipse.swt.graphics.Point} + * objects along with the context of the monitor in relation to which they are + * placed on the display. The monitor awareness makes it easy to scale and + * translate the points between pixels and points. + * + * @since 3.129 + * @noreference This class is not intended to be referenced by clients + */ +public final class MonitorAwarePoint extends Point { + + private static final long serialVersionUID = 6077427420686999194L; + + private final Monitor monitor; + + /** + * Constructs a new MonitorAwarePoint + * + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @param monitor the monitor with whose context the point is created + */ + public MonitorAwarePoint(int x, int y, Monitor monitor) { + super(x, y); + this.monitor = monitor; + } + + /** + * {@return the monitor with whose context the instance is created} + */ + public Monitor getMonitor() { + return monitor; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!super.equals(object)) { + return false; + } + MonitorAwarePoint other = (MonitorAwarePoint) object; + return Objects.equals(this.monitor, other.monitor); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), monitor); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/MonitorAwareRectangle.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/MonitorAwareRectangle.java new file mode 100644 index 00000000000..f20d620e356 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/MonitorAwareRectangle.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Yatta Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import java.util.*; + +import org.eclipse.swt.widgets.*; + +/** + * Instances of this class represent {@link org.eclipse.swt.graphics.Rectangle} + * objects along with the context of the monitor in relation to which they are + * placed on the display. The monitor awareness makes it easy to scale and + * translate the rectangles between pixels and points. + * + * @since 3.129 + * @noreference This class is not intended to be referenced by clients + */ +public final class MonitorAwareRectangle extends Rectangle { + + private static final long serialVersionUID = 5041911840525116925L; + + private final Monitor monitor; + + /** + * Constructs a new MonitorAwareRectangle + * + * @param x the x coordinate of the top left corner of the rectangle + * @param y the y coordinate of the top left corner of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @param monitor the monitor with whose context the rectangle is created + */ + public MonitorAwareRectangle(int x, int y, int width, int height, Monitor monitor) { + super(x, y, width, height); + this.monitor = monitor; + } + + /** + * {@return the monitor with whose context the instance is created} + */ + public Monitor getMonitor() { + return monitor; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!super.equals(object)) { + return false; + } + MonitorAwareRectangle other = (MonitorAwareRectangle) object; + return Objects.equals(this.monitor, other.monitor); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), monitor); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Point.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Point.java index 069fb4d81eb..6de7f344460 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Point.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Point.java @@ -41,7 +41,7 @@ * @see Sample code and further information */ -public final class Point implements Serializable { +public sealed class Point implements Serializable permits MonitorAwarePoint { /** * the x coordinate of the point @@ -78,9 +78,17 @@ public Point (int x, int y) { */ @Override public boolean equals (Object object) { - if (object == this) return true; - if (!(object instanceof Point p)) return false; - return (p.x == this.x) && (p.y == this.y); + if (object == null) { + return false; + } + if (object == this) { + return true; + } + if (object.getClass() != this.getClass()) { + return false; + } + Point other = (Point) object; + return (other.x == this.x) && (other.y == this.y); } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Rectangle.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Rectangle.java index f15babb2ba9..b8e78d3b8da 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Rectangle.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Rectangle.java @@ -45,7 +45,7 @@ * @see Sample code and further information */ -public final class Rectangle implements Serializable { +public sealed class Rectangle implements Serializable permits MonitorAwareRectangle { /** * the x coordinate of the rectangle @@ -155,10 +155,18 @@ public boolean contains (Point pt) { * @see #hashCode() */ @Override -public boolean equals (Object object) { - if (object == this) return true; - if (!(object instanceof Rectangle r)) return false; - return (r.x == this.x) && (r.y == this.y) && (r.width == this.width) && (r.height == this.height); +public boolean equals(Object object) { + if (object == null) { + return false; + } + if (object == this) { + return true; + } + if (object.getClass() != this.getClass()) { + return false; + } + Rectangle other = (Rectangle) object; + return (other.x == this.x) && (other.y == this.y) && (other.width == this.width) && (other.height == this.height); } /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java index 7c3d8760ceb..2057c9305ed 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java @@ -66,13 +66,13 @@ public Rectangle map(Control from, Control to, int x, int y, int width, int heig Rectangle mappedRectangleInPoints; if (from == null) { Rectangle mappedRectangleInPixels = display.mapInPixels(from, to, - translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, + translateRectangleInPointsToPixels(x, y, width, height, to.getShell().getMonitor())); mappedRectangleInPoints = DPIUtil.scaleDown(mappedRectangleInPixels, to.getZoom()); } else if (to == null) { Rectangle mappedRectangleInPixels = display.mapInPixels(from, to, DPIUtil.scaleUp(new Rectangle(x, y, width, height), from.getZoom())); - mappedRectangleInPoints = translateRectangleInPointsInDisplayCoordinateSystem(mappedRectangleInPixels.x, + mappedRectangleInPoints = translateRectangleInPixelsToPoints(mappedRectangleInPixels.x, mappedRectangleInPixels.y, mappedRectangleInPixels.width, mappedRectangleInPixels.height, from.getShell().getMonitor()); } else { @@ -93,94 +93,94 @@ public Rectangle mapMonitorBounds(Rectangle rect, int zoom) { @Override public Point translateFromDisplayCoordinates(Point point, int zoom) { - return translateLocationInPixelsFromDisplayCoordinateSystem(point.x, point.y); + return translateLocationInPixelsToPoints(point.x, point.y); } @Override public Point translateToDisplayCoordinates(Point point, int zoom) { - return translateLocationInPointsToDisplayCoordinateSystem(point.x, point.y); + Monitor monitor = point instanceof MonitorAwarePoint monitorAwarePoint ? monitorAwarePoint.getMonitor() : null; + return translateLocationInPointsToPixels(point.x, point.y, monitor); } @Override public Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom) { - return translateRectangleInPixelsFromDisplayCoordinateSystemByContainment(rect.x, rect.y, rect.width, - rect.height); + Monitor monitor = rect instanceof MonitorAwareRectangle monitorAwareRect ? monitorAwareRect.getMonitor() : null; + return translateRectangleInPixelsToPoints(rect.x, rect.y, rect.width, rect.height, monitor); } @Override public Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom) { - return translateRectangleInPointsToDisplayCoordinateSystemByContainment(rect.x, rect.y, rect.width, - rect.height); + Monitor monitor = rect instanceof MonitorAwareRectangle monitorAwareRect ? monitorAwareRect.getMonitor() : null; + return translateRectangleInPointsToPixels(rect.x, rect.y, rect.width, rect.height, monitor); } @Override public Point getCursorLocation() { Point cursorLocationInPixels = display.getCursorLocationInPixels(); - return translateLocationInPixelsFromDisplayCoordinateSystem(cursorLocationInPixels.x, cursorLocationInPixels.y); + return translateLocationInPixelsToPoints(cursorLocationInPixels.x, cursorLocationInPixels.y); } @Override - public void setCursorLocation(int x, int y) { - Point cursorLocationInPixels = translateLocationInPointsToDisplayCoordinateSystem(x, y); - display.setCursorLocationInPixels(cursorLocationInPixels.x, cursorLocationInPixels.y); + public void setCursorLocation (int x, int y) { + Point cursorLocationInPixels = translateLocationInPointsToPixels(x, y, null); + display.setCursorLocationInPixels (cursorLocationInPixels.x, cursorLocationInPixels.y); } - private Point translateLocationInPointsToDisplayCoordinateSystem(int x, int y) { - Monitor monitor = getContainingMonitor(x, y); + private Point translateLocationInPointsToPixels(int x, int y, Monitor monitor) { + monitor = getValidMonitorIfApplicable(x, y, monitor); return getPixelsFromPoint(monitor, x, y); } - private Point translateLocationInPixelsFromDisplayCoordinateSystem(int x, int y) { - Monitor monitor = getContainingMonitorInPixelsCoordinate(x, y); + private Point translateLocationInPixelsToPoints(int x, int y) { + Monitor monitor = getContainingMonitorForPixels(x, y); return getPointFromPixels(monitor, x, y); } - private Rectangle translateRectangleInPointsToDisplayCoordinateSystemByContainment(int x, int y, int width, - int height) { - Monitor monitorByLocation = getContainingMonitor(x, y); - Monitor monitorByContainment = getContainingMonitor(x, y, width, height); - return translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, monitorByLocation, - monitorByContainment); - } - - private Rectangle translateRectangleInPixelsInDisplayCoordinateSystem(int x, int y, int width, int height, - Monitor monitor) { - return translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, monitor, monitor); - } - - private Rectangle translateRectangleInPixelsInDisplayCoordinateSystem(int x, int y, int width, int height, - Monitor monitorOfLocation, Monitor monitorOfArea) { - Point topLeft = getPixelsFromPoint(monitorOfLocation, x, y); - int zoom = getApplicableMonitorZoom(monitorOfArea); + private Rectangle translateRectangleInPointsToPixels(int x, int y, int width, int height, Monitor monitor) { + monitor = getValidMonitorIfApplicable(x, y, width, height, monitor); + Point topLeft = getPixelsFromPoint(monitor, x, y); + int zoom = getApplicableMonitorZoom(monitor); int widthInPixels = DPIUtil.scaleUp(width, zoom); int heightInPixels = DPIUtil.scaleUp(height, zoom); return new Rectangle(topLeft.x, topLeft.y, widthInPixels, heightInPixels); } - private Rectangle translateRectangleInPixelsFromDisplayCoordinateSystemByContainment(int x, int y, - int widthInPixels, int heightInPixels) { - Monitor monitorByLocation = getContainingMonitor(x, y); - Monitor monitorByContainment = getContainingMonitorInPixelsCoordinate(x, y, widthInPixels, heightInPixels); - return translateRectangleInPointsInDisplayCoordinateSystem(x, y, widthInPixels, heightInPixels, - monitorByLocation, monitorByContainment); + private Rectangle translateRectangleInPixelsToPoints(int x, int y, int widthInPixels, int heightInPixels, Monitor monitor) { + if (monitor == null) + monitor = getContainingMonitorForPixels(x, y, widthInPixels, heightInPixels); + int zoom = getApplicableMonitorZoom(monitor); + Point topLeft = getPointFromPixels(monitor, x, y); + int width = DPIUtil.scaleDown(widthInPixels, zoom); + int height = DPIUtil.scaleDown(heightInPixels, zoom); + MonitorAwareRectangle rect = new MonitorAwareRectangle(topLeft.x, topLeft.y, width, height, monitor); + return rect; } - private Rectangle translateRectangleInPointsInDisplayCoordinateSystem(int x, int y, int widthInPixels, - int heightInPixels, Monitor monitor) { - return translateRectangleInPointsInDisplayCoordinateSystem(x, y, widthInPixels, heightInPixels, monitor, - monitor); + private Monitor getValidMonitorIfApplicable(int x, int y, int width, int height, Monitor monitor) { + if(monitor != null) { + if (monitor.getClientArea().intersects(x, y, width, height)) { + return monitor; + } + Monitor containingMonitor = getContainingMonitorForPoints(x, y, width, height); + return containingMonitor != null ? containingMonitor : monitor; + } + Monitor containingMonitor = getContainingMonitorForPoints(x, y, width, height); + return containingMonitor != null ? containingMonitor : monitorSupplier.get()[0]; } - private Rectangle translateRectangleInPointsInDisplayCoordinateSystem(int x, int y, int widthInPixels, - int heightInPixels, Monitor monitorOfLocation, Monitor monitorOfArea) { - Point topLeft = getPointFromPixels(monitorOfLocation, x, y); - int zoom = getApplicableMonitorZoom(monitorOfArea); - int width = DPIUtil.scaleDown(widthInPixels, zoom); - int height = DPIUtil.scaleDown(heightInPixels, zoom); - return new Rectangle(topLeft.x, topLeft.y, width, height); + private Monitor getValidMonitorIfApplicable(int x, int y, Monitor monitor) { + if (monitor != null) { + if (monitor.getClientArea().contains(x, y)) { + return monitor; + } + Monitor containingMonitor = getContainingMonitorForPoints(x, y); + return containingMonitor != null ? containingMonitor : monitor; + } + Monitor containingMonitor = getContainingMonitorForPoints(x, y); + return containingMonitor != null ? containingMonitor : monitorSupplier.get()[0]; } - private Monitor getContainingMonitor(int x, int y) { + private Monitor getContainingMonitorForPoints(int x, int y) { Monitor[] monitors = monitorSupplier.get(); for (Monitor currentMonitor : monitors) { Rectangle clientArea = currentMonitor.getClientArea(); @@ -188,27 +188,33 @@ private Monitor getContainingMonitor(int x, int y) { return currentMonitor; } } - return monitors[0]; + return null; } - private Monitor getContainingMonitor(int x, int y, int width, int height) { - Rectangle rectangle = new Rectangle(x, y, width, height); + private Monitor getContainingMonitorForPoints(int x, int y, int width, int height) { Monitor[] monitors = monitorSupplier.get(); - Monitor selectedMonitor = monitors[0]; - int highestArea = 0; + Monitor selectedMonitor = null; + int highestIntersectionRatio = 0; for (Monitor currentMonitor : monitors) { - Rectangle clientArea = currentMonitor.getClientArea(); - Rectangle intersection = clientArea.intersection(rectangle); - int area = intersection.width * intersection.height; - if (area > highestArea) { + // Obtain the rectangle in pixels per monitor for absolute comparison + Point topLeftOfRectangle = getPixelsFromPoint(currentMonitor, x, y); + int widthInPixels = DPIUtil.scaleUp(width, getApplicableMonitorZoom(currentMonitor)); + int heightInPixels = DPIUtil.scaleUp(height, getApplicableMonitorZoom(currentMonitor)); + Rectangle boundsInPixel = new Rectangle(topLeftOfRectangle.x, topLeftOfRectangle.y, widthInPixels, heightInPixels); + Rectangle clientArea = getMonitorClientAreaInPixels(currentMonitor); + Rectangle intersection = clientArea.intersection(boundsInPixel); + int intersectionArea = intersection.width * intersection.height; + int boundsArea = boundsInPixel.width * boundsInPixel.height; + int intersectionRatio = (intersectionArea * 100) / boundsArea; + if (intersectionRatio > highestIntersectionRatio) { selectedMonitor = currentMonitor; - highestArea = area; + highestIntersectionRatio = intersectionRatio; } } return selectedMonitor; } - private Monitor getContainingMonitorInPixelsCoordinate(int xInPixels, int yInPixels) { + private Monitor getContainingMonitorForPixels(int xInPixels, int yInPixels) { Monitor[] monitors = monitorSupplier.get(); for (Monitor current : monitors) { Rectangle clientArea = getMonitorClientAreaInPixels(current); @@ -219,7 +225,7 @@ private Monitor getContainingMonitorInPixelsCoordinate(int xInPixels, int yInPix return monitors[0]; } - private Monitor getContainingMonitorInPixelsCoordinate(int xInPixels, int yInPixels, int widthInPixels, + private Monitor getContainingMonitorForPixels(int xInPixels, int yInPixels, int widthInPixels, int heightInPixels) { Rectangle rectangle = new Rectangle(xInPixels, yInPixels, widthInPixels, heightInPixels); Monitor[] monitors = monitorSupplier.get(); @@ -255,7 +261,7 @@ private Point getPointFromPixels(Monitor monitor, int x, int y) { int zoom = getApplicableMonitorZoom(monitor); int mappedX = DPIUtil.scaleDown(x - monitor.clientX, zoom) + monitor.clientX; int mappedY = DPIUtil.scaleDown(y - monitor.clientY, zoom) + monitor.clientY; - return new Point(mappedX, mappedY); + return new MonitorAwarePoint(mappedX, mappedY, monitor); } private int getApplicableMonitorZoom(Monitor monitor) {