From c70fad3998e18b72a3f35cd934fcd2e3b4186646 Mon Sep 17 00:00:00 2001 From: Ekaterina Berezhko Date: Wed, 12 Nov 2025 15:03:50 +0200 Subject: [PATCH] [UI][IJPL-61730] Normalize window state to fit screen bounds Normalize window position and size when restoring the state to ensure it fits within screen bounds. Adjust location to center if out of bounds. GitOrigin-RevId: 4daf53c5f4b3995a3a51cea2e9a31fd30014288a --- .../openapi/util/WindowStateServiceImpl.java | 51 +++++++++++++++++-- .../ui/src/com/intellij/ui/ScreenUtil.java | 31 +++-------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/util/WindowStateServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/util/WindowStateServiceImpl.java index 86c412c19124..bfa2095d40e5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/util/WindowStateServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/util/WindowStateServiceImpl.java @@ -348,12 +348,53 @@ abstract class WindowStateServiceImpl extends WindowStateService implements Modi T get(@NotNull Class type, @Nullable Rectangle screen) { Point location = apply(Point::new, myLocation); Dimension size = apply(Dimension::new, mySize); - // convert location and size according to the given screen - if (myScreen != null && !myScreen.isEmpty() && screen != null && !screen.isEmpty()) { - if (location != null) ScreenUtil.moveAndScale(location, myScreen, screen); - if (size != null) ScreenUtil.moveAndScale(size, myScreen, screen); - if (!isVisible(location, size)) return null; // adjusted state is not visible + // convert location and size according to the given screen and normalize to fit + if (location != null || size != null) { + if (myScreen != null && !myScreen.isEmpty() && screen != null && !screen.isEmpty()) { + if (location != null) ScreenUtil.moveAndScale(location, myScreen, screen); + if (size != null) ScreenUtil.moveAndScale(size, myScreen, screen); + + if (location != null && size != null) { + Rectangle r = new Rectangle(location, size); + Rectangle original = new Rectangle(r); + ScreenUtil.moveToFit(r, screen.getBounds(), null, true); + if (!r.equals(original)) { + LOG.warn("Window state forced to fit screen: " + original + " -> " + r + " (screen: " + screen + ")"); + } + location = r.getLocation(); + size = r.getSize(); + } + else if (location != null) { + Point original = new Point(location); + if (location.x < screen.x || location.x >= screen.x + screen.width) { + location.x = screen.x + screen.width / 2; + } + if (location.y < screen.y || location.y >= screen.y + screen.height) { + location.y = screen.y + screen.height / 2; + } + if (!location.equals(original)) { + LOG.warn("Window location forced to fit screen: " + original + " -> " + location + " (screen: " + screen + ")"); + } + } + else { + location = new Point(screen.x + screen.width / 2, screen.y + screen.height / 2); + Rectangle r = new Rectangle(location, size); + Dimension original = new Dimension(size); + ScreenUtil.moveToFit(r, screen.getBounds(), null, true); + if (!size.equals(original)) { + LOG.warn("Window size forced to fit screen: " + original + " -> " + size + " (screen: " + screen + ")"); + } + location = r.getLocation(); + size = r.getSize(); + } + + if (!isVisible(location, size)) { + LOG.warn("Adjusted window state is not visible: location=" + location + ", size=" + size + " (screen: " + screen + ")"); + return null; // adjusted state is not visible + } + } } + if (type == Point.class) return (T)location; if (type == Dimension.class) return (T)size; if (type == Rectangle.class) return location == null || size == null ? null : (T)new Rectangle(location, size); diff --git a/platform/util/ui/src/com/intellij/ui/ScreenUtil.java b/platform/util/ui/src/com/intellij/ui/ScreenUtil.java index bbc0fe983830..c5c08aadec5d 100644 --- a/platform/util/ui/src/com/intellij/ui/ScreenUtil.java +++ b/platform/util/ui/src/com/intellij/ui/ScreenUtil.java @@ -1,7 +1,6 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ui; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.ui.scale.JBUIScale; import com.intellij.util.SystemProperties; @@ -334,13 +333,17 @@ public final class ScreenUtil { } public static void moveRectangleToFitTheScreen(@NotNull Rectangle aRectangle) { + moveRectangleToFitTheScreen(aRectangle, false); + } + + private static void moveRectangleToFitTheScreen(@NotNull Rectangle aRectangle, boolean crop) { if (StartupUiUtil.isWaylandToolkit()) return; // No abs coordinates in Wayland int screenX = aRectangle.x + aRectangle.width / 2; int screenY = aRectangle.y + aRectangle.height / 2; Rectangle screen = getScreenRectangle(screenX, screenY); - moveToFit(aRectangle, screen, null); + moveToFit(aRectangle, screen, null, crop); } public static void moveToFit(final @NotNull Rectangle rectangle, final @NotNull Rectangle container, @Nullable Insets padding) { @@ -421,29 +424,7 @@ public final class ScreenUtil { } public static void fitToScreen(@NotNull Rectangle r) { - if (StartupUiUtil.isWaylandToolkit()) return; // No abs coordinates in Wayland - - Rectangle screen = getScreenRectangle(r.x, r.y); - - int xOverdraft = r.x + r.width - screen.x - screen.width; - if (xOverdraft > 0) { - int shift = Math.min(xOverdraft, r.x - screen.x); - xOverdraft -= shift; - r.x -= shift; - if (xOverdraft > 0) { - r.width -= xOverdraft; - } - } - - int yOverdraft = r.y + r.height - screen.y - screen.height; - if (yOverdraft > 0) { - int shift = Math.min(yOverdraft, r.y - screen.y); - yOverdraft -= shift; - r.y -= shift; - if (yOverdraft > 0) { - r.height -= yOverdraft; - } - } + moveRectangleToFitTheScreen(r, true); } public static @NotNull Point findNearestPointOnBorder(@NotNull Rectangle rect, @NotNull Point p) {