Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,21 @@ describe("MainDesktopAutotypeMvpService", () => {
{ windowTitle: "Notepad" },
);
});

it("should not throw on shortcut activation if the window does not exist", () => {
const toggleHandler = ipcHandlers.get(AUTOTYPE_MVP_IPC_CHANNELS.TOGGLE);
toggleHandler({}, true);

mockWindowMain.win = null;

// Get the registered callback
const registeredCallback = (globalShortcut.register as jest.Mock).mock.calls[0][1];

expect(() => registeredCallback()).not.toThrow();
expect(autotype_mvp.getForegroundWindowTitle).not.toHaveBeenCalled();
expect(mockLogService.debug).toHaveBeenCalledWith(
"Autotype keyboard shortcut activated, but the main window does not exist.",
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@ export class MainDesktopAutotypeMvpService {
const result = globalShortcut.register(
this.autotypeKeyboardShortcut.getElectronFormat(),
() => {
const windowTitle = autotype_mvp.getForegroundWindowTitle();

this.windowMain.win.webContents.send(AUTOTYPE_MVP_IPC_CHANNELS.LISTEN, {
windowTitle,
});
if (this.windowMain.win != null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 SUGGESTED: Also guard on isDestroyed() to close the remaining shutdown race.

Details and fix

WindowMain only clears this.win inside the closed handler after an await:

// window.main.ts:474
this.win.on("closed", async () => {
  this.isClosing = false;
  await this.updateWindowState(mainWindowSizeKey, this.win); // <- yields
  this.win = null;
});

During that await the window is destroyed but win is still non-null, so a shortcut press in that gap reaches this.windowMain.win.webContents.send(...) and throws Object has been destroyed β€” the exact crash this PR is closing.

Suggested change
if (this.windowMain.win != null) {
if (this.windowMain.win != null && !this.windowMain.win.isDestroyed()) {

This matches the existing pattern used elsewhere in the desktop main process (window.main.ts:335 and window.main.ts:592).

const windowTitle = autotype_mvp.getForegroundWindowTitle();

this.windowMain.win.webContents.send(AUTOTYPE_MVP_IPC_CHANNELS.LISTEN, {
windowTitle,
});
} else {
this.logService.debug(
"Autotype keyboard shortcut activated, but the main window does not exist.",
);
}
},
);

Expand Down
Loading