From 79946fddc0faec9d686609deaf5c959e28702912 Mon Sep 17 00:00:00 2001 From: Ajinkya Vidwans Date: Mon, 30 Mar 2026 01:33:23 +0530 Subject: [PATCH] fix: Add fix to resolve editors freezing on windows (Discard Changes dialog) --- src/main/main.ts | 43 +++++++++++++++++++++++++++++++++++++++---- src/main/preload.js | 22 +++++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/main/main.ts b/src/main/main.ts index 2a0b9bb4..20612921 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -254,6 +254,41 @@ const createWindow = async () => { new AutoUpdate(webAppWindow); remote.enable(webAppWindow.webContents); + // -- Fix: Electron Windows bug #20400 -- + // Built-in window.confirm on Windows causes input fields to lose their + // caret / freeze. We replace it with dialog.showMessageBoxSync via IPC. + // The preload exposes __rqConfirmSync (ipcRenderer.sendSync wrapper) into + // the renderer world. Here we: + // a) Handle the synchronous IPC call with the native dialog. + // b) Inject JS after dom-ready that wires window.confirm → __rqConfirmSync. + if (process.platform === "win32") { + ipcMain.on("rq:show-confirm-dialog", (event, message) => { + const buttonIdx = dialog.showMessageBoxSync( + webAppWindow as BrowserWindow, + { + type: "question", + buttons: ["OK", "Cancel"], + defaultId: 0, + cancelId: 1, + detail: String(message ?? ""), + message: "", + } + ); + // sendSync expects event.returnValue to be set + event.returnValue = buttonIdx === 0; + }); + + webAppWindow.webContents.on("dom-ready", () => { + webAppWindow?.webContents.executeJavaScript(` + if (typeof window.__rqConfirmSync === 'function') { + window.confirm = function(message) { + return window.__rqConfirmSync(message); + }; + } + `); + }); + } + // TODO @sahil: Prod and Local Urls should be supplied by @requestly/requestly-core-npm package. const DESKTOP_APP_URL = getWebAppURL(); webAppWindow.loadURL(DESKTOP_APP_URL, { @@ -504,17 +539,17 @@ export const loadWebAppUrl = async (newURL: string) => { if (!webAppWindow || webAppWindow.isDestroyed()) { throw new Error("Web app window is not available"); } - + await webAppWindow.loadURL(newURL, { extraHeaders: "pragma: no-cache\n", }); - + customWebAppURL = newURL; - + if (!webAppWindow.isVisible()) { webAppWindow.show(); } - + webAppWindow.focus(); }; diff --git a/src/main/preload.js b/src/main/preload.js index 6b4069c0..0db3594c 100644 --- a/src/main/preload.js +++ b/src/main/preload.js @@ -3,7 +3,7 @@ require("core-js/stable"); require("regenerator-runtime/runtime"); // Core -const { contextBridge } = require("electron"); +const { contextBridge, ipcRenderer } = require("electron"); const { app } = require("@electron/remote"); const DesktopStorageService = require("./preload-apis/DesktopStorageService"); @@ -20,6 +20,26 @@ if (process.env.NODE_ENV === "development") { appVersion = app.getVersion(); } +// Work around Electron Windows bug where built-in confirm/alert cause input +// fields (including CodeMirror editors) to lose the visible caret and stop +// accepting text until the window is re-focused. +// See: https://github.com/electron/electron/issues/20400 +// +// contextIsolation is enabled (default since Electron 12), so the preload's +// window is isolated from the renderer's window. Assigning +// window.confirm = ... here only affects the preload world, NOT the web +// page. To override the renderer's window.confirm we: +// 1. Expose a synchronous helper (__rqConfirmSync) via contextBridge that +// uses ipcRenderer.sendSync to call the main process. +// 2. In main.ts, after dom-ready, inject JS that replaces window.confirm +// with a call to window.__rqConfirmSync. +if (process.platform === "win32") { + contextBridge.exposeInMainWorld("__rqConfirmSync", (message) => { + // sendSync blocks the renderer until the main process replies. + return ipcRenderer.sendSync("rq:show-confirm-dialog", String(message ?? "")); + }); +} + (function (window) { // Build the RQ object const RQ = window.RQ || {};