diff --git a/.gitignore b/.gitignore index 1d792df..63bb3b0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ out .DS_Store /images*/ +/helper-images/ dist !.github/images diff --git a/docs/qemu.md b/docs/qemu.md index dab35b5..92f405e 100644 --- a/docs/qemu.md +++ b/docs/qemu.md @@ -20,7 +20,7 @@ Installation qemu-system-i386 \ -cdrom Win95_OSR25.iso \ -m 128 \ - -hda images/windows95_v4.raw \ + -hda windows95.img \ -device sb16 \ -nic user,model=ne2k_pci \ -fda Win95_boot.img \ @@ -39,10 +39,10 @@ qemu-system-i386 \ ```sh qemu-system-i386 \ -m 128 \ - -hda images/windows95_v4.raw \ + -hda images/windows95.img \ -device sb16 \ -M pc,acpi=off \ -cpu pentium \ - -netdev user,id=mynet0,net=192.168.76.0/24,dhcpstart=192.168.76.9 \ + -netdev user,id=mynet0 \ -device ne2k_isa,netdev=mynet0,irq=10 ``` diff --git a/src/main/menu.ts b/src/main/menu.ts index d5d026a..0e94071 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -1,4 +1,4 @@ -import { app, shell, Menu, BrowserWindow, ipcMain } from "electron"; +import { app, shell, Menu, BrowserWindow, ipcMain, dialog } from "electron"; import { clearCaches } from "../cache"; import { IPC_COMMANDS } from "../constants"; @@ -164,7 +164,20 @@ async function createMenu({ isRunning } = { isRunning: false }) { }, { label: "Reset", - click: () => send(IPC_COMMANDS.MACHINE_RESET), + click: async () => { + const result = await dialog.showMessageBox({ + type: 'warning', + buttons: ['Reset', 'Cancel'], + defaultId: 1, + title: 'Reset Machine', + message: 'Are you sure you want to reset the machine?', + detail: 'This will delete the machine state, including all changes you have made.', + }); + + if (result.response === 0) { + send(IPC_COMMANDS.MACHINE_RESET); + } + }, enabled: isRunning, }, { diff --git a/src/renderer/card-settings.tsx b/src/renderer/card-settings.tsx index 361d120..d74733d 100644 --- a/src/renderer/card-settings.tsx +++ b/src/renderer/card-settings.tsx @@ -1,7 +1,6 @@ import * as React from "react"; -import * as fs from "fs"; -import { getStatePath } from "./utils/get-state-path"; +import { resetState } from "./utils/reset-state"; interface CardSettingsProps { bootFromScratch: () => void; @@ -213,16 +212,7 @@ export class CardSettings extends React.Component< * Handle the state reset */ private async onResetState() { - const statePath = await getStatePath(); - - if (fs.existsSync(statePath)) { - try { - await fs.promises.unlink(statePath); - } catch (error) { - console.error(`Failed to delete state file: ${error}`); - } - } - + await resetState(); this.setState({ isStateReset: true }); } } diff --git a/src/renderer/emulator.tsx b/src/renderer/emulator.tsx index e410442..d618071 100644 --- a/src/renderer/emulator.tsx +++ b/src/renderer/emulator.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import * as fs from "fs"; import * as path from "path"; -import { ipcRenderer, shell } from "electron"; +import { ipcRenderer, shell, webUtils } from "electron"; import { CONSTANTS, IPC_COMMANDS } from "../constants"; import { getDiskImageSize } from "../utils/disk-image-size"; @@ -11,6 +11,7 @@ import { CardSettings } from "./card-settings"; import { EmulatorInfo } from "./emulator-info"; import { getStatePath } from "./utils/get-state-path"; import { Win95Window } from "./app"; +import { resetState } from "./utils/reset-state"; declare let window: Win95Window; @@ -53,10 +54,6 @@ export class Emulator extends React.Component<{}, EmulatorState> { this.setupInputListeners(); this.setupIpcListeners(); this.setupUnloadListeners(); - - if (document.location.hash.includes("AUTO_START")) { - this.startEmulator(); - } } /** @@ -274,6 +271,10 @@ export class Emulator extends React.Component<{}, EmulatorState> { private async startEmulator() { document.body.classList.remove("paused"); + const cdromPath = this.state.cdromFile + ? webUtils.getPathForFile(this.state.cdromFile) + : null; + const options = { wasm_path: path.join(__dirname, "build/v86.wasm"), memory_size: 128 * 1024 * 1024, @@ -303,11 +304,11 @@ export class Emulator extends React.Component<{}, EmulatorState> { buffer: this.state.floppyFile, } : undefined, - cdrom: this.state.cdromFile?.path + cdrom: cdromPath ? { - url: this.state.cdromFile.path, + url: cdromPath, async: true, - size: await getDiskImageSize(this.state.cdromFile.path), + size: await getDiskImageSize(cdromPath), } : undefined, boot_order: 0x132, @@ -378,7 +379,10 @@ export class Emulator extends React.Component<{}, EmulatorState> { */ private async resetEmulator() { this.isResetting = true; - document.location.hash = `#AUTO_START`; + + await this.stopEmulator(); + await resetState(); + document.location.reload(); } @@ -518,7 +522,7 @@ export class Emulator extends React.Component<{}, EmulatorState> { */ private resetCanvas() { const canvas = document.getElementById("emulator-canvas"); - + if (canvas instanceof HTMLCanvasElement) { const ctx = canvas.getContext('2d'); ctx?.clearRect(0, 0, canvas.width, canvas.height); diff --git a/src/renderer/utils/reset-state.ts b/src/renderer/utils/reset-state.ts new file mode 100644 index 0000000..4f7c175 --- /dev/null +++ b/src/renderer/utils/reset-state.ts @@ -0,0 +1,14 @@ +import fs from "fs"; +import { getStatePath } from "./get-state-path"; + +export async function resetState() { + const statePath = await getStatePath(); + + if (fs.existsSync(statePath)) { + try { + await fs.promises.unlink(statePath); + } catch (error) { + console.error(`Failed to delete state file: ${error}`); + } + } +}