Ensure window stays on screen after external monitor removed.
This commit is contained in:
109
src/main/util/ensureWindowOnScreen.ts
Normal file
109
src/main/util/ensureWindowOnScreen.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { screen } from "electron";
|
||||
|
||||
function ensureWindowOnScreen(
|
||||
x: number | undefined,
|
||||
y: number | undefined,
|
||||
windowWidth: number,
|
||||
windowHeight: number,
|
||||
): { validX: number | undefined; validY: number | undefined } {
|
||||
// If no coordinates stored, let Electron position window automatically
|
||||
if (x === undefined || y === undefined) {
|
||||
return { validX: undefined, validY: undefined };
|
||||
}
|
||||
|
||||
const displays = screen.getAllDisplays();
|
||||
|
||||
// Minimum visible pixels required on each edge to be considered "visible enough"
|
||||
const MIN_VISIBLE = 50; // Ensure at least 50px from each edge is visible
|
||||
|
||||
// Try to find a display where the window would be almost fully visible
|
||||
for (const display of displays) {
|
||||
const { bounds } = display;
|
||||
|
||||
// Check if window is mostly within this display
|
||||
if (
|
||||
x + MIN_VISIBLE >= bounds.x &&
|
||||
x + windowWidth - MIN_VISIBLE <= bounds.x + bounds.width &&
|
||||
y + MIN_VISIBLE >= bounds.y &&
|
||||
y + windowHeight - MIN_VISIBLE <= bounds.y + bounds.height
|
||||
) {
|
||||
// Window is adequately visible on this display
|
||||
return { validX: x, validY: y };
|
||||
}
|
||||
}
|
||||
|
||||
// If window isn't adequately visible on any display, try to adjust it to fit the closest display
|
||||
const closestDisplay = findClosestDisplay(displays, x, y);
|
||||
const { bounds } = closestDisplay;
|
||||
|
||||
// Adjust position to ensure window is fully on screen
|
||||
let adjustedX = x;
|
||||
let adjustedY = y;
|
||||
|
||||
// Adjust horizontal position if needed
|
||||
if (x < bounds.x) {
|
||||
adjustedX = bounds.x;
|
||||
} else if (x + windowWidth > bounds.x + bounds.width) {
|
||||
adjustedX = bounds.x + bounds.width - windowWidth;
|
||||
}
|
||||
|
||||
// Adjust vertical position if needed
|
||||
if (y < bounds.y) {
|
||||
adjustedY = bounds.y;
|
||||
} else if (y + windowHeight > bounds.y + bounds.height) {
|
||||
adjustedY = bounds.y + bounds.height - windowHeight;
|
||||
}
|
||||
|
||||
// If adjustments keep window on screen, use adjusted position
|
||||
if (
|
||||
adjustedX >= bounds.x &&
|
||||
adjustedX + windowWidth <= bounds.x + bounds.width &&
|
||||
adjustedY >= bounds.y &&
|
||||
adjustedY + windowHeight <= bounds.y + bounds.height
|
||||
) {
|
||||
return { validX: adjustedX, validY: adjustedY };
|
||||
}
|
||||
|
||||
// If all else fails, center on primary display
|
||||
const primaryDisplay = screen.getPrimaryDisplay();
|
||||
const primaryBounds = primaryDisplay.bounds;
|
||||
|
||||
return {
|
||||
validX: Math.floor(
|
||||
primaryBounds.x + (primaryBounds.width - windowWidth) / 2,
|
||||
),
|
||||
validY: Math.floor(
|
||||
primaryBounds.y + (primaryBounds.height - windowHeight) / 2,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// Helper function to find the closest display to a point
|
||||
function findClosestDisplay(
|
||||
displays: Electron.Display[],
|
||||
x: number,
|
||||
y: number,
|
||||
): Electron.Display {
|
||||
let closestDisplay = displays[0];
|
||||
let shortestDistance = Number.MAX_VALUE;
|
||||
|
||||
for (const display of displays) {
|
||||
const { bounds } = display;
|
||||
// Calculate distance to center of display
|
||||
const displayCenterX = bounds.x + bounds.width / 2;
|
||||
const displayCenterY = bounds.y + bounds.height / 2;
|
||||
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(x - displayCenterX, 2) + Math.pow(y - displayCenterY, 2),
|
||||
);
|
||||
|
||||
if (distance < shortestDistance) {
|
||||
shortestDistance = distance;
|
||||
closestDisplay = display;
|
||||
}
|
||||
}
|
||||
|
||||
return closestDisplay;
|
||||
}
|
||||
|
||||
export default ensureWindowOnScreen;
|
||||
Reference in New Issue
Block a user