refactor(core): normalize core service naming

Standardize core service module and export names to reduce naming ambiguity and make imports predictable across runtime, tests, scripts, and docs.
This commit is contained in:
2026-02-17 01:18:10 -08:00
parent 02034e6dc7
commit a359e91b14
80 changed files with 793 additions and 771 deletions

View File

@@ -0,0 +1,147 @@
import { BrowserWindow } from "electron";
import * as path from "path";
import { WindowGeometry } from "../../types";
import { createLogger } from "../../logger";
const logger = createLogger("main:overlay-window");
export type OverlayWindowKind = "visible" | "invisible";
export function updateOverlayWindowBounds(
geometry: WindowGeometry,
window: BrowserWindow | null,
): void {
if (!geometry || !window || window.isDestroyed()) return;
window.setBounds({
x: geometry.x,
y: geometry.y,
width: geometry.width,
height: geometry.height,
});
}
export function ensureOverlayWindowLevel(window: BrowserWindow): void {
if (process.platform === "darwin") {
window.setAlwaysOnTop(true, "screen-saver", 1);
window.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
window.setFullScreenable(false);
return;
}
window.setAlwaysOnTop(true);
}
export function enforceOverlayLayerOrder(options: {
visibleOverlayVisible: boolean;
invisibleOverlayVisible: boolean;
mainWindow: BrowserWindow | null;
invisibleWindow: BrowserWindow | null;
ensureOverlayWindowLevel: (window: BrowserWindow) => void;
}): void {
if (!options.visibleOverlayVisible || !options.invisibleOverlayVisible) return;
if (!options.mainWindow || options.mainWindow.isDestroyed()) return;
if (!options.invisibleWindow || options.invisibleWindow.isDestroyed()) return;
options.ensureOverlayWindowLevel(options.mainWindow);
options.mainWindow.moveTop();
}
export function createOverlayWindow(
kind: OverlayWindowKind,
options: {
isDev: boolean;
overlayDebugVisualizationEnabled: boolean;
ensureOverlayWindowLevel: (window: BrowserWindow) => void;
onRuntimeOptionsChanged: () => void;
setOverlayDebugVisualizationEnabled: (enabled: boolean) => void;
isOverlayVisible: (kind: OverlayWindowKind) => boolean;
tryHandleOverlayShortcutLocalFallback: (input: Electron.Input) => boolean;
onWindowClosed: (kind: OverlayWindowKind) => void;
},
): BrowserWindow {
const window = new BrowserWindow({
show: false,
width: 800,
height: 600,
x: 0,
y: 0,
transparent: true,
frame: false,
alwaysOnTop: true,
skipTaskbar: true,
resizable: false,
hasShadow: false,
focusable: true,
webPreferences: {
preload: path.join(__dirname, "..", "..", "preload.js"),
contextIsolation: true,
nodeIntegration: false,
webSecurity: true,
additionalArguments: [`--overlay-layer=${kind}`],
},
});
options.ensureOverlayWindowLevel(window);
const htmlPath = path.join(__dirname, "..", "..", "renderer", "index.html");
window
.loadFile(htmlPath, {
query: { layer: kind === "visible" ? "visible" : "invisible" },
})
.catch((err) => {
logger.error("Failed to load HTML file:", err);
});
window.webContents.on(
"did-fail-load",
(_event, errorCode, errorDescription, validatedURL) => {
logger.error(
"Page failed to load:",
errorCode,
errorDescription,
validatedURL,
);
},
);
window.webContents.on("did-finish-load", () => {
options.onRuntimeOptionsChanged();
window.webContents.send(
"overlay-debug-visualization:set",
options.overlayDebugVisualizationEnabled,
);
});
if (kind === "visible") {
window.webContents.on("devtools-opened", () => {
options.setOverlayDebugVisualizationEnabled(true);
});
window.webContents.on("devtools-closed", () => {
options.setOverlayDebugVisualizationEnabled(false);
});
}
window.webContents.on("before-input-event", (event, input) => {
if (!options.isOverlayVisible(kind)) return;
if (!options.tryHandleOverlayShortcutLocalFallback(input)) return;
event.preventDefault();
});
window.hide();
window.on("closed", () => {
options.onWindowClosed(kind);
});
window.on("blur", () => {
if (!window.isDestroyed()) {
options.ensureOverlayWindowLevel(window);
}
});
if (options.isDev && kind === "visible") {
window.webContents.openDevTools({ mode: "detach" });
}
return window;
}