mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
fix(main): restore modal pointer events after fallback reveal when open confirmed
This commit is contained in:
@@ -2,11 +2,9 @@ import type { BrowserWindow } from 'electron';
|
|||||||
import type { WindowGeometry } from '../types';
|
import type { WindowGeometry } from '../types';
|
||||||
|
|
||||||
type OverlayHostedModal = 'runtime-options' | 'subsync' | 'jimaku' | 'kiku';
|
type OverlayHostedModal = 'runtime-options' | 'subsync' | 'jimaku' | 'kiku';
|
||||||
type OverlayHostLayer = 'visible' | 'invisible';
|
|
||||||
|
|
||||||
export interface OverlayWindowResolver {
|
export interface OverlayWindowResolver {
|
||||||
getMainWindow: () => BrowserWindow | null;
|
getMainWindow: () => BrowserWindow | null;
|
||||||
getInvisibleWindow: () => BrowserWindow | null;
|
|
||||||
getModalWindow: () => BrowserWindow | null;
|
getModalWindow: () => BrowserWindow | null;
|
||||||
createModalWindow: () => BrowserWindow | null;
|
createModalWindow: () => BrowserWindow | null;
|
||||||
getModalGeometry: () => WindowGeometry;
|
getModalGeometry: () => WindowGeometry;
|
||||||
@@ -21,6 +19,7 @@ export interface OverlayModalRuntime {
|
|||||||
) => boolean;
|
) => boolean;
|
||||||
openRuntimeOptionsPalette: () => void;
|
openRuntimeOptionsPalette: () => void;
|
||||||
handleOverlayModalClosed: (modal: OverlayHostedModal) => void;
|
handleOverlayModalClosed: (modal: OverlayHostedModal) => void;
|
||||||
|
notifyOverlayModalOpened: (modal: OverlayHostedModal) => void;
|
||||||
getRestoreVisibleOverlayOnModalClose: () => Set<OverlayHostedModal>;
|
getRestoreVisibleOverlayOnModalClose: () => Set<OverlayHostedModal>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +33,8 @@ export function createOverlayModalRuntimeService(
|
|||||||
): OverlayModalRuntime {
|
): OverlayModalRuntime {
|
||||||
const restoreVisibleOverlayOnModalClose = new Set<OverlayHostedModal>();
|
const restoreVisibleOverlayOnModalClose = new Set<OverlayHostedModal>();
|
||||||
let modalActive = false;
|
let modalActive = false;
|
||||||
|
let pendingModalWindowReveal: BrowserWindow | null = null;
|
||||||
|
let pendingModalWindowRevealTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
const notifyModalStateChange = (nextState: boolean): void => {
|
const notifyModalStateChange = (nextState: boolean): void => {
|
||||||
if (modalActive === nextState) return;
|
if (modalActive === nextState) return;
|
||||||
@@ -53,44 +54,97 @@ export function createOverlayModalRuntimeService(
|
|||||||
return createdWindow;
|
return createdWindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTargetOverlayWindow = (): {
|
const getTargetOverlayWindow = (): BrowserWindow | null => {
|
||||||
window: BrowserWindow;
|
|
||||||
layer: OverlayHostLayer;
|
|
||||||
} | null => {
|
|
||||||
const visibleMainWindow = deps.getMainWindow();
|
const visibleMainWindow = deps.getMainWindow();
|
||||||
const invisibleWindow = deps.getInvisibleWindow();
|
|
||||||
|
|
||||||
if (visibleMainWindow && !visibleMainWindow.isDestroyed()) {
|
if (visibleMainWindow && !visibleMainWindow.isDestroyed()) {
|
||||||
return { window: visibleMainWindow, layer: 'visible' };
|
return visibleMainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invisibleWindow && !invisibleWindow.isDestroyed()) {
|
|
||||||
return { window: invisibleWindow, layer: 'invisible' };
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const showModalWindow = (window: BrowserWindow): void => {
|
const isWindowReadyForIpc = (window: BrowserWindow): boolean => {
|
||||||
|
if (window.webContents.isLoading()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getURL = window.webContents.getURL;
|
||||||
|
if (typeof getURL !== 'function') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentURL = getURL.call(window.webContents);
|
||||||
|
return currentURL !== '' && currentURL !== 'about:blank';
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendOrQueueForWindow = (
|
||||||
|
window: BrowserWindow,
|
||||||
|
sendNow: (window: BrowserWindow) => void,
|
||||||
|
): void => {
|
||||||
|
if (isWindowReadyForIpc(window)) {
|
||||||
|
sendNow(window);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.webContents.once('did-finish-load', () => {
|
||||||
|
if (!window.isDestroyed() && !window.webContents.isLoading()) {
|
||||||
|
sendNow(window);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showModalWindow = (
|
||||||
|
window: BrowserWindow,
|
||||||
|
options: {
|
||||||
|
passThroughMouseEvents: boolean;
|
||||||
|
} = { passThroughMouseEvents: false },
|
||||||
|
): void => {
|
||||||
window.show();
|
window.show();
|
||||||
|
if (options.passThroughMouseEvents) {
|
||||||
|
window.setIgnoreMouseEvents(true, { forward: true });
|
||||||
|
} else {
|
||||||
window.setIgnoreMouseEvents(false);
|
window.setIgnoreMouseEvents(false);
|
||||||
|
}
|
||||||
window.focus();
|
window.focus();
|
||||||
if (!window.webContents.isFocused()) {
|
if (!window.webContents.isFocused()) {
|
||||||
window.webContents.focus();
|
window.webContents.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showOverlayWindowForModal = (window: BrowserWindow, layer: OverlayHostLayer): void => {
|
const showOverlayWindowForModal = (window: BrowserWindow): void => {
|
||||||
if (layer === 'invisible' && typeof window.showInactive === 'function') {
|
|
||||||
window.showInactive();
|
|
||||||
} else {
|
|
||||||
window.show();
|
window.show();
|
||||||
}
|
|
||||||
if (!window.isFocused()) {
|
if (!window.isFocused()) {
|
||||||
window.focus();
|
window.focus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clearPendingModalWindowReveal = (): void => {
|
||||||
|
if (pendingModalWindowRevealTimeout === null) {
|
||||||
|
pendingModalWindowReveal = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(pendingModalWindowRevealTimeout);
|
||||||
|
pendingModalWindowRevealTimeout = null;
|
||||||
|
pendingModalWindowReveal = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const scheduleModalWindowReveal = (window: BrowserWindow): void => {
|
||||||
|
pendingModalWindowReveal = window;
|
||||||
|
if (pendingModalWindowRevealTimeout !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingModalWindowRevealTimeout = setTimeout(() => {
|
||||||
|
const targetWindow = pendingModalWindowReveal;
|
||||||
|
clearPendingModalWindowReveal();
|
||||||
|
if (!targetWindow || targetWindow.isDestroyed() || targetWindow.isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showModalWindow(targetWindow, { passThroughMouseEvents: true });
|
||||||
|
}, 250);
|
||||||
|
};
|
||||||
|
|
||||||
const sendToActiveOverlayWindow = (
|
const sendToActiveOverlayWindow = (
|
||||||
channel: string,
|
channel: string,
|
||||||
payload?: unknown,
|
payload?: unknown,
|
||||||
@@ -119,43 +173,24 @@ export function createOverlayModalRuntimeService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!wasVisible) {
|
if (!wasVisible) {
|
||||||
showModalWindow(modalWindow);
|
scheduleModalWindowReveal(modalWindow);
|
||||||
} else if (!modalWindow.isFocused()) {
|
} else if (!modalWindow.isFocused()) {
|
||||||
showModalWindow(modalWindow);
|
showModalWindow(modalWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modalWindow.webContents.isLoading()) {
|
sendOrQueueForWindow(modalWindow, sendNow);
|
||||||
modalWindow.webContents.once('did-finish-load', () => {
|
|
||||||
if (modalWindow && !modalWindow.isDestroyed() && !modalWindow.webContents.isLoading()) {
|
|
||||||
sendNow(modalWindow);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendNow(modalWindow);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = getTargetOverlayWindow();
|
const target = getTargetOverlayWindow();
|
||||||
if (!target) return false;
|
if (!target) return false;
|
||||||
|
|
||||||
const { window: targetWindow, layer } = target;
|
const wasVisible = target.isVisible();
|
||||||
const wasVisible = targetWindow.isVisible();
|
|
||||||
if (!wasVisible) {
|
if (!wasVisible) {
|
||||||
showOverlayWindowForModal(targetWindow, layer);
|
showOverlayWindowForModal(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetWindow.webContents.isLoading()) {
|
sendOrQueueForWindow(target, sendNow);
|
||||||
targetWindow.webContents.once('did-finish-load', () => {
|
|
||||||
if (targetWindow && !targetWindow.isDestroyed() && !targetWindow.webContents.isLoading()) {
|
|
||||||
sendNow(targetWindow);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendNow(targetWindow);
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -171,6 +206,7 @@ export function createOverlayModalRuntimeService(
|
|||||||
const modalWindow = deps.getModalWindow();
|
const modalWindow = deps.getModalWindow();
|
||||||
if (!modalWindow || modalWindow.isDestroyed()) return;
|
if (!modalWindow || modalWindow.isDestroyed()) return;
|
||||||
if (restoreVisibleOverlayOnModalClose.size === 0) {
|
if (restoreVisibleOverlayOnModalClose.size === 0) {
|
||||||
|
clearPendingModalWindowReveal();
|
||||||
notifyModalStateChange(false);
|
notifyModalStateChange(false);
|
||||||
}
|
}
|
||||||
if (restoreVisibleOverlayOnModalClose.size === 0) {
|
if (restoreVisibleOverlayOnModalClose.size === 0) {
|
||||||
@@ -178,10 +214,33 @@ export function createOverlayModalRuntimeService(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const notifyOverlayModalOpened = (modal: OverlayHostedModal): void => {
|
||||||
|
if (!restoreVisibleOverlayOnModalClose.has(modal)) return;
|
||||||
|
const targetWindow = deps.getModalWindow();
|
||||||
|
clearPendingModalWindowReveal();
|
||||||
|
if (!targetWindow || targetWindow.isDestroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetWindow.isVisible()) {
|
||||||
|
targetWindow.setIgnoreMouseEvents(false);
|
||||||
|
if (!targetWindow.isFocused()) {
|
||||||
|
targetWindow.focus();
|
||||||
|
}
|
||||||
|
if (!targetWindow.webContents.isFocused()) {
|
||||||
|
targetWindow.webContents.focus();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showModalWindow(targetWindow);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sendToActiveOverlayWindow,
|
sendToActiveOverlayWindow,
|
||||||
openRuntimeOptionsPalette,
|
openRuntimeOptionsPalette,
|
||||||
handleOverlayModalClosed,
|
handleOverlayModalClosed,
|
||||||
|
notifyOverlayModalOpened,
|
||||||
getRestoreVisibleOverlayOnModalClose: () => restoreVisibleOverlayOnModalClose,
|
getRestoreVisibleOverlayOnModalClose: () => restoreVisibleOverlayOnModalClose,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user