@@ -345,18 +345,19 @@ static void moveToOverlap(Rectangle what, Rectangle where) {
345345 assert what .intersects (where ) : String .format ("Failed to move %s to overlap %s" , what , where );
346346 }
347347
348- Point nativeLocationForPopup (Window popup , Component popupParent , Window toplevel ) {
348+ Point nativeLocationForPopup (Window popup , Window toplevel ) {
349+ Objects .requireNonNull (popup );
350+ Objects .requireNonNull (toplevel );
349351 // NB: all the coordinates are in the "surface" space as consumed by Wayland,
350352 // not in pixels and not in the Java units.
351353
352- // We need to provide popup's "parent" location relative to the surface this parent is painted upon:
353- Point parentLocation = javaUnitsToSurfaceUnits (getRelativeLocation (popupParent , toplevel ));
354-
355- // Offset is relative to the top-left corner of the "parent".
356- Point offsetFromParent = javaUnitsToSurfaceUnits (popup .getLocation ());
354+ Point popupOnScreen = popup .getLocation ();
355+ Point toplevelOnScreen = toplevel .getLocationOnScreen ();
356+ Point popupOnToplevel = new Point (popupOnScreen .x - toplevelOnScreen .x , popupOnScreen .y - toplevelOnScreen .y );
357+ Point offsetFromToplevel = javaUnitsToSurfaceUnits (popupOnToplevel );
357358 var popupBounds = new Rectangle (
358- parentLocation . x + offsetFromParent .x ,
359- parentLocation . y + offsetFromParent .y ,
359+ offsetFromToplevel .x ,
360+ offsetFromToplevel .y ,
360361 wlSize .getSurfaceWidth (),
361362 wlSize .getSurfaceHeight ());
362363 var safeToplevelBounds = toplevel .getSize ();
@@ -372,7 +373,7 @@ Point nativeLocationForPopup(Window popup, Component popupParent, Window topleve
372373 // go outside the parent surface's bounds.
373374 moveToOverlap (popupBounds , safePopupBounds );
374375 }
375- return popupBounds .getLocation ();
376+ return popupBounds .getLocation (); // This is offset relative to the top-left corner of the toplevel
376377 }
377378
378379 private boolean isPopupPositionUnconstrained () {
@@ -454,7 +455,7 @@ private void show() {
454455 Window popup = (Window ) target ;
455456 Component popupParent = AWTAccessor .getWindowAccessor ().getPopupParent (popup );
456457 Window toplevel = getToplevelFor (popupParent );
457- Point nativeLocation = nativeLocationForPopup (popup , popupParent , toplevel );
458+ Point nativeLocation = nativeLocationForPopup (popup , toplevel );
458459 nativeCreatePopup (nativePtr , getNativePtrFor (toplevel ), wlSurfacePtr ,
459460 thisWidth , thisHeight , nativeLocation .x , nativeLocation .y , isUnconstrained );
460461 stage = 1 ;
@@ -518,7 +519,7 @@ protected void notifyNativeWindowToBeHidden(long nativePtr) {
518519 * Returns true if our target should be treated as a popup in Wayland's sense,
519520 * i.e. it has to have a parent to position relative to.
520521 */
521- protected boolean targetIsWlPopup () {
522+ protected final boolean targetIsWlPopup () {
522523 return target instanceof Window window && isWlPopup (window );
523524 }
524525
@@ -588,7 +589,7 @@ public void updateSurfaceSize() {
588589 Window popup = (Window ) target ;
589590 final Component popupParent = AWTAccessor .getWindowAccessor ().getPopupParent (popup );
590591 final Window toplevel = getToplevelFor (popupParent );
591- Point nativeLocation = nativeLocationForPopup (popup , popupParent , toplevel );
592+ Point nativeLocation = nativeLocationForPopup (popup , toplevel );
592593 boolean isUnconstrained = isPopupPositionUnconstrained ();
593594 nativeRepositionWLPopup (nativePtr , surfaceWidth , surfaceHeight , nativeLocation .x , nativeLocation .y , isUnconstrained );
594595 }
@@ -830,18 +831,8 @@ private Point getFakeLocationOnScreen() {
830831 // their parents' fake screen location.
831832 if (targetIsWlPopup ()) {
832833 Window popup = (Window ) target ;
833- Component popupParent = AWTAccessor .getWindowAccessor ().getPopupParent (popup );
834- Window toplevel = getToplevelFor (popupParent );
835- Point popupOffset = popup .getLocation (); // popup's offset from its parent
836- if (toplevel != null ) {
837- Point parentOffset = getRelativeLocation (popupParent , toplevel );
838- Point thisLocation = toplevel .getLocationOnScreen ();
839- thisLocation .translate (parentOffset .x , parentOffset .y );
840- thisLocation .translate (popupOffset .x , popupOffset .y );
841- return thisLocation ;
842- } else {
843- return popupOffset ;
844- }
834+ // Popup's Window location is the "location on screen"
835+ return popup .getLocation ();
845836 } else {
846837 GraphicsConfiguration graphicsConfig = target .getGraphicsConfiguration ();
847838 if (graphicsConfig != null ) {
@@ -1784,14 +1775,15 @@ void notifyConfigured(int newSurfaceX, int newSurfaceY, int newSurfaceWidth, int
17841775 int newX = surfaceUnitsToJavaUnits (newSurfaceX );
17851776 int newY = surfaceUnitsToJavaUnits (newSurfaceY );
17861777
1787- // The popup itself stores its location relative to its parent , but what we've got is
1778+ // The popup location is in it toplevel's screen coordinate system , but what we've got is
17881779 // the location relative to the toplevel. Let's convert:
17891780 Window popup = (Window ) target ;
17901781 Component popupParent = AWTAccessor .getWindowAccessor ().getPopupParent (popup );
17911782 Window toplevel = getToplevelFor (popupParent );
1792- Point parentLocation = getRelativeLocation (popupParent , toplevel );
1793- Point locationRelativeToParent = new Point (newX - parentLocation .x , newY - parentLocation .y );
1794- resetTargetLocationTo (locationRelativeToParent .x , locationRelativeToParent .y );
1783+ Point toplevelOnScreen = toplevel == null // highly unlikely, if at all possible
1784+ ? target .getGraphicsConfiguration ().getBounds ().getLocation ()
1785+ : toplevel .getLocationOnScreen ();
1786+ resetTargetLocationTo (newX + toplevelOnScreen .x , newY + toplevelOnScreen .y );
17951787 }
17961788
17971789 // From xdg-shell.xml: "If the width or height arguments are zero,
@@ -1869,7 +1861,22 @@ void checkIfOnNewScreen() {
18691861 if (oldDevice != newDevice ) {
18701862 oldDevice .removeWindow (this );
18711863 newDevice .addWindow (this );
1864+
1865+ if (targetIsWlPopup ()) {
1866+ Point loc = target .getLocation ();
1867+ Point oldScreenLocation = oldDevice .getBounds ().getLocation ();
1868+ loc .translate (-oldScreenLocation .x , -oldScreenLocation .y );
1869+ Point newScreenLocation = newDevice .getBounds ().getLocation ();
1870+ loc .translate (newScreenLocation .x , newScreenLocation .y );
1871+ resetTargetLocationTo (loc .x , loc .y );
1872+ } else {
1873+ // A window has been moved to another screen. Since windows are assumed to be located at (0, 0)
1874+ // on their respective screens, update the location to reflect that.
1875+ Point newLocation = newDevice .getBounds ().getLocation ();
1876+ resetTargetLocationTo (newLocation .x , newLocation .y );
1877+ }
18721878 }
1879+
18731880 performUnlocked (() -> {
18741881 var acc = AWTAccessor .getComponentAccessor ();
18751882 acc .setGraphicsConfiguration (target , gc );
0 commit comments