${getParentFolderLinkHtml(parentPath)} | ${getDesktopLinkHtml()} | ${getDownloadsLinkHtml()}
++
windows95 failed to find the file or directory on your host computer: ${requestedPath}
Options:
+ + + + `; +} diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 84d3501..6c6fc58 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -5,7 +5,7 @@ import { IPC_COMMANDS } from "../constants"; export function setupIpcListeners() { ipcMain.handle(IPC_COMMANDS.GET_STATE_PATH, () => { - return path.join(app.getPath("userData"), "state-v3.bin"); + return path.join(app.getPath("userData"), "state-v4.bin"); }); ipcMain.handle(IPC_COMMANDS.APP_QUIT, () => { diff --git a/src/main/logging.ts b/src/main/logging.ts new file mode 100644 index 0000000..0a71210 --- /dev/null +++ b/src/main/logging.ts @@ -0,0 +1,3 @@ +export function log(message: string, ...args: unknown[]) { + console.log(`[${new Date().toLocaleString()}] ${message}`, ...args); +} diff --git a/src/main/main.ts b/src/main/main.ts index 7960590..8d5d609 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -7,6 +7,8 @@ import { setupUpdates } from "./update"; import { getOrCreateWindow } from "./windows"; import { setupMenu } from "./menu"; import { setupIpcListeners } from "./ipc"; +import { setupSession } from "./session"; +import { setupFileServer } from './fileserver/fileserver'; /** * Handle the app's "ready" event. This is essentially @@ -15,11 +17,13 @@ import { setupIpcListeners } from "./ipc"; export async function onReady() { if (!isDevMode()) process.env.NODE_ENV = "production"; + setupSession(); setupIpcListeners(); getOrCreateWindow(); setupAboutPanel(); setupMenu(); setupUpdates(); + setupFileServer(); } /** diff --git a/src/main/menu.ts b/src/main/menu.ts index f990f54..09136aa 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -3,6 +3,7 @@ import { app, shell, Menu, BrowserWindow, ipcMain } from "electron"; import { clearCaches } from "../cache"; import { IPC_COMMANDS } from "../constants"; import { isDevMode } from "../utils/devmode"; +import { log } from "./logging"; const LINKS = { homepage: "https://www.twitter.com/felixrieseberg", @@ -26,10 +27,10 @@ function send(cmd: string) { const windows = BrowserWindow.getAllWindows(); if (windows[0]) { - console.log(`Sending "${cmd}"`); + log(`Sending "${cmd}"`); windows[0].webContents.send(cmd); } else { - console.log(`Tried to send "${cmd}", but could not find window`); + log(`Tried to send "${cmd}", but could not find window`); } } diff --git a/src/main/session.ts b/src/main/session.ts new file mode 100644 index 0000000..f91bb7a --- /dev/null +++ b/src/main/session.ts @@ -0,0 +1,20 @@ +import { session } from "electron"; + +export function setupSession() { + const s = session.defaultSession; + + s.webRequest.onBeforeSendHeaders( + (details, callback) => { + callback({ requestHeaders: { Origin: '*', ...details.requestHeaders } }); + }, + ); + + s.webRequest.onHeadersReceived((details, callback) => { + callback({ + responseHeaders: { + 'Access-Control-Allow-Origin': ['*'], + ...details.responseHeaders, + }, + }); + }); +} diff --git a/src/main/settings.ts b/src/main/settings.ts new file mode 100644 index 0000000..7be8f49 --- /dev/null +++ b/src/main/settings.ts @@ -0,0 +1,72 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { app } from 'electron'; + +export interface Settings { + isFileServerEnabled: boolean; + isFileServerShowingHiddenFiles: boolean; + isFileServerShowingSystemHiddenFiles: boolean; +} + +const DEFAULT_SETTINGS: Settings = { + isFileServerEnabled: true, + isFileServerShowingHiddenFiles: false, + isFileServerShowingSystemHiddenFiles: false, +}; + +class SettingsManager { + private filePath: string; + private data: Settings; + + constructor() { + this.filePath = path.join(app.getPath('userData'), 'settings.json'); + this.data = this.load(); + } + + private load(): Settings { + try { + if (fs.existsSync(this.filePath)) { + const fileContent = fs.readFileSync(this.filePath, 'utf8'); + const parsed = JSON.parse(fileContent); + + return { + ...DEFAULT_SETTINGS, + ...parsed, + }; + } + } catch (error) { + console.error('Error loading settings:', error); + } + + return DEFAULT_SETTINGS; + } + + private save(): void { + try { + fs.writeFileSync(this.filePath, JSON.stringify(this.data, null, 2)); + } catch (error) { + console.error('Error saving settings:', error); + } + } + + get(key: keyof Settings): any { + return this.data[key]; + } + + set(key: keyof Settings, value: any): void { + this.data[key] = value; + this.save(); + } + + delete(key: keyof Settings): void { + delete this.data[key]; + this.save(); + } + + clear(): void { + this.data = DEFAULT_SETTINGS; + this.save(); + } +} + +export const settings = new SettingsManager(); diff --git a/src/main/windows.ts b/src/main/windows.ts index 53b52e9..d850056 100644 --- a/src/main/windows.ts +++ b/src/main/windows.ts @@ -24,9 +24,6 @@ export function getOrCreateWindow(): BrowserWindow { mainWindow.webContents.on("will-navigate", (event, url) => handleNavigation(event, url), ); - mainWindow.webContents.on("new-window", (event, url) => - handleNavigation(event, url), - ); mainWindow.on("closed", () => { mainWindow = null; diff --git a/src/renderer/emulator.tsx b/src/renderer/emulator.tsx index 7bcdff6..4102618 100644 --- a/src/renderer/emulator.tsx +++ b/src/renderer/emulator.tsx @@ -279,8 +279,13 @@ export class Emulator extends React.Component<{}, EmulatorState> { const options = { wasm_path: path.join(__dirname, "build/v86.wasm"), memory_size: 128 * 1024 * 1024, - vga_memory_size: 32 * 1024 * 1024, + vga_memory_size: 64 * 1024 * 1024, screen_container: document.getElementById("emulator"), + preserve_mac_from_state_image: true, + net_device: { + relay_url: "fetch", + type: "ne2k", + }, bios: { url: path.join(__dirname, "../../bios/seabios.bin"), }, @@ -367,7 +372,7 @@ export class Emulator extends React.Component<{}, EmulatorState> { } /** - * Reset the emulator by reloading the whole page (lol) + * Reset the emulator by reloading the whole page */ private async resetEmulator() { this.isResetting = true; diff --git a/static/www/apps.htm b/static/www/apps.htm new file mode 100644 index 0000000..e18d852 --- /dev/null +++ b/static/www/apps.htm @@ -0,0 +1,20 @@ + + +|
+
+ windows95 Apps & Games
+ + + I've installed a few apps and games for you to try out. Check out the Games folder on the desktop! +If you want to try other games, I recommend trying to find them on the Internet Archive. On your host computer, visit https://archive.org, then find the "Classic PC Games" category. Once downloaded, you can import them into windows95 from your host's Download folder. + + |
+
|
+
+ windows95 Credits
+ + + Emulation Engine++ None of this would be possible without the people working on v86, in particular Fabian Hemmer aka copy. + You can visit his website at copy.sh. It also wouldn't be + possible without the QEMU project. If you enjoy running old systems, you probably want QEMU - windows95 + is merely a toy, QEMU lets you actually run old systems in a stable manner. + + +Electron++ Electron is a framework for building desktop applications using web technologies. It's what powers windows95. + You can visit the project's website at electronjs.org (in a modern browser, not in windows95). + + + |
+
|
+
+ windows95 Help
+ + + MS-DOS Display Issues+If MS-DOS seems to mess up the screen: +
(Thanks to @DisplacedGamers for that wisdom) + +windows95 Stuck in Bad State+If windows95 becomes unresponsive or stuck: +
|
+
|
+ Hi, I'm Felix, the maker behind windows95. I hope you're having fun! + +Reach out to me in a modern browser (as in: not in windows95) on felixrieseberg.com or find me on Bluesky at @felixrieseberg. + ++ + + + In a major update since the last version, windows95 now has working Internet! That said, most modern websites will not work, so brace yourself. I recommend using The Old Net to travel back in time. + + + |
+
|
+
+ |
|
+
+ |
|
+
+ |
|
+
+ |
|
+
+ |
+
+ Best viewed with
+ Internet Explorer 5.5 and windows95
+
+