Compare commits

...

30 commits

Author SHA1 Message Date
Felix Rieseberg d8b4a139ac
Merge pull request #203 from maacarbo/patch-1
macOS download links inverted for Intel/M1
2021-02-07 12:52:49 -08:00
Felix Rieseberg 9f4771bf26 chore: Update Readme 2021-01-31 09:24:51 -08:00
Maarten 552b97eec5
macOS download links inverted for Intel/M1 2021-01-07 10:31:39 +01:00
Felix Rieseberg 6c0f00170c
Update README.md 2021-01-05 10:53:35 -08:00
Felix Rieseberg e3b9a839f5 build: Update Node version 2021-01-04 10:31:33 -08:00
Felix Rieseberg 238b07b7dd build: Add a check-links tool 2021-01-04 09:54:20 -08:00
Felix Rieseberg 9dc1e422ff
chore: One more readme update 2021-01-03 19:30:55 -08:00
Felix Rieseberg ebe7427385 chore: Include images 2021-01-03 19:27:11 -08:00
Felix Rieseberg 3e3bee2062 chore: Pretty readme 2021-01-03 19:26:06 -08:00
Felix Rieseberg c93b6878a9 chore: Update the readme again 2021-01-03 19:18:38 -08:00
Felix Rieseberg d2e26ef5d1
chore: Update readme 2021-01-03 18:52:39 -08:00
Felix Rieseberg c41befae64 build: Update dependencies 2021-01-03 12:58:37 -08:00
Felix Rieseberg 8b720750db build: Try to build for all archs 2021-01-02 15:38:15 -08:00
Felix Rieseberg ee317ec5aa v2.3.0 2020-12-13 16:37:37 -08:00
Felix Rieseberg d7c657e671 build: Build on ARM 2020-12-13 16:32:44 -08:00
Felix Rieseberg 7a8a54c76b build: Update Electron & React 2020-12-13 16:14:18 -08:00
Felix Rieseberg c29f98b6bc
Merge pull request #183 from felixrieseberg/dependabot/npm_and_yarn/electron-9.3.1
build(deps-dev): bump electron from 9.1.2 to 9.3.1
2020-11-08 09:48:10 -08:00
dependabot[bot] 8d1847a8d1
build(deps-dev): bump electron from 9.1.2 to 9.3.1
Bumps [electron](https://github.com/electron/electron) from 9.1.2 to 9.3.1.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/master/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v9.1.2...v9.3.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-06 19:02:36 +00:00
Felix Rieseberg 194f4fabaf
Merge pull request #169 from PeterVatistas/patch-1
Fix amd64.deb download link
2020-08-04 16:00:56 -07:00
Peter Vatistas 3f4a5e97fa
Revised all download links
All 7 download links were fixed using the latest release.
2020-08-04 10:01:46 -07:00
Peter Vatistas 3eb789d055
Fix amd64.deb download link 2020-08-03 19:33:08 -07:00
Felix Rieseberg 8a8f064864 docs Update readme 2020-08-03 15:50:13 -07:00
Felix Rieseberg 58add05655 build: Build on push 2020-08-02 13:33:54 -07:00
Felix Rieseberg 0a400d915f build: Fix macOS cert 2020-08-02 13:27:05 -07:00
Felix Rieseberg f615e7754c 2.2.2 2020-08-02 13:13:52 -07:00
Felix Rieseberg 92717c8047 chore: Updated prettier run 2020-08-02 13:11:20 -07:00
Felix Rieseberg 045b83f843 build: Move to GitHub Actions, upgrade dependencies 2020-08-02 13:09:13 -07:00
Felix Rieseberg 1dd3b76187
Merge pull request #153 from PF94/patch-1
Improve HELP.MD a little bit.
2020-01-15 15:38:04 -08:00
PF94 4b1dd6146c
Improve HELP.MD a little bit.
* Add some caplization to "Command Prompt", "Window Mode" and "Full Screen" mode
* Changed "brick" to "mess up" as "bricked" means that the operating system is permanently damaged.
* Add another "enter" for the "What's the FrontPage Username and Password?" section, now people won't accidently connect as "windows95Password".
* Fix DisplacedGamers missing "s" in the end.
2020-01-11 22:18:39 -05:00
Felix Rieseberg 3601599ff1
docs: Update readme 2019-12-04 10:17:07 -08:00
36 changed files with 9443 additions and 12304 deletions

View file

@ -1,49 +0,0 @@
environment:
matrix:
- nodejs_version: "10"
init:
- git config --global core.symlinks true
install:
# Setup the code signing certificate
- ps: >-
if (Test-Path Env:\WINDOWS_CERTIFICATE_P12) {
$workingDirectory = Convert-Path (Resolve-Path -path ".")
$filename = "$workingDirectory\cert.p12"
$bytes = [Convert]::FromBase64String($env:WINDOWS_CERTIFICATE_P12)
[IO.File]::WriteAllBytes($filename, $bytes)
$env:WINDOWS_CERTIFICATE_FILE = $filename
$sec = ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText
$cert = Get-PfxData -Password $sec $filename
Write-Host $cert.EndEntityCertificates
}
- ps: Install-Product node $env:nodejs_version x64
- node --version
- npm ci
- ps: mkdir images
- ps: cd images
- ps: Start-FileDownload 'https://1drv.ws/u/s!AkfaAw_EaahOkulh8rA41x2phgfYXQ' -FileName images.zip -Timeout 600000
- ps: 7z x images.zip -y -aoa
- ps: Remove-Item images.zip
- ps: Remove-Item __MACOSX -Recurse -ErrorAction Ignore
- ps: cd ..
- ps: Tree ./src /F
- ps: Tree ./images /F
cache:
- '%APPDATA%\npm-cache -> appveyor.yml'
test_script:
- node --version
- npm --version
- npm run lint
artifacts:
- path: 'out\make\squirrel.windows\**\*.exe'
build_script:
- if %APPVEYOR_REPO_TAG% EQU false npm run make
- if %APPVEYOR_REPO_TAG% EQU true npm run publish
- if %APPVEYOR_REPO_TAG% EQU true npm run publish -- --arch=ia32
- ps: Tree ./out/make /F

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
text eol=lf

BIN
.github/images/linux.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
.github/images/macos.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
.github/images/windows.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

109
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,109 @@
name: Build & Release
on:
push:
branches:
- master
tags:
- v*
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 15.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install
run: yarn
- name: lint
run: yarn lint
build:
needs: lint
name: Build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ macOS-latest, ubuntu-latest, windows-latest ]
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
if: matrix.os != 'macOS-latest'
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Set MacOS signing certs
if: matrix.os == 'macOS-latest'
run: chmod +x tools/add-macos-cert.sh && ./tools/add-macos-cert.sh
env:
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
- name: Set Windows signing certificate
if: matrix.os == 'windows-latest'
continue-on-error: true
id: write_file
uses: timheuer/base64-to-file@v1
with:
fileName: 'win-certificate.pfx'
encodedString: ${{ secrets.WINDOWS_CODESIGN_P12 }}
- name: Download disk image (ps1)
run: tools/download-disk.ps1
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
env:
DISK_URL: ${{ secrets.DISK_URL }}
- name: Download disk image (sh)
run: chmod +x tools/download-disk.sh && ./tools/download-disk.sh
if: matrix.os != 'windows-latest' && startsWith(github.ref, 'refs/tags/')
env:
DISK_URL: ${{ secrets.DISK_URL }}
- name: Install
run: yarn
- name: Make
if: startsWith(github.ref, 'refs/tags/')
run: yarn make --arch=all
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
WINDOWS_CODESIGN_FILE: ${{ steps.write_file.outputs.filePath }}
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
# - name: Archive production artifacts
# uses: actions/upload-artifact@v2
# with:
# name: ${{ matrix.os }}
# path: out/make/**/*
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
draft: true
files: |
out/**/*.deb
out/**/*.dmg
out/**/*setup*.exe
out/**/*.rpm
out/**/*.zip

3
.gitignore vendored
View file

@ -3,4 +3,5 @@ out
src/images src/images
.DS_Store .DS_Store
images images
dist dist
!.github/images

View file

@ -1,64 +0,0 @@
language: node_js
node_js: "12"
os:
- linux
- osx
dist: trusty
osx_image: xcode10
sudo: false
cache:
directories:
- node_modules
- $HOME/.cache/electron
addons:
apt:
packages:
- fakeroot
- rpm
branches:
only:
- master
- /^v\d+\.\d+\.\d+/
install:
- npm install
- mkdir -p ./images
- cd ./images
- wget -O images.zip https://1drv.ws/u/s!AkfaAw_EaahOkulh8rA41x2phgfYXQ
- unzip -o images.zip
- rm images.zip
- rm -r __MACOSX
- cd ..
- ls src
- ls images
- |
if [[ "$TRAVIS_OS_NAME" == "osx" && "$TRAVIS_SECURE_ENV_VARS" == "true" ]]; then
export CERTIFICATE_P12=cert.p12;
echo $MACOS_CERT_P12 | base64 --decode > $CERTIFICATE_P12;
export KEYCHAIN=build.keychain;
# Create the keychain with a password
security create-keychain -p travis $KEYCHAIN;
# Make the custom keychain default, so xcodebuild will use it for signing
security default-keychain -s $KEYCHAIN;
# Unlock the keychain
security unlock-keychain -p travis $KEYCHAIN;
# Add certificates to keychain and allow codesign to access them
# Apple Worldwide Developer Relations Certification Authority
security import ./assets/certs/apple.cer -k ~/Library/Keychains/$KEYCHAIN -T /usr/bin/codesign
# Developer Authentication Certification Authority
security import ./assets/certs/dac.cer -k ~/Library/Keychains/$KEYCHAIN -T /usr/bin/codesign
# Developer ID Felix
security import $CERTIFICATE_P12 -k $KEYCHAIN -P $MACOS_CERT_PASSWORD -T /usr/bin/codesign 2>&1 >/dev/null;
rm $CERTIFICATE_P12;
security set-key-partition-list -S apple-tool:,apple: -s -k travis $KEYCHAIN
# Echo the identity
security find-identity -v -p codesigning
fi
script:
- npm run lint
- if test -z "$TRAVIS_TAG"; then npm run make; fi
after_success: if test -n "$TRAVIS_TAG"; then npm run publish; fi

View file

@ -1,10 +1,10 @@
# Help & Commonly Asked Questions # Help & Commonly Asked Questions
## MS-DOS seems to brick the screen ## MS-DOS seems to mess up the screen
Hit `Alt + Enter` to make the command screen "full screen" (as far as Windows 95 is Hit `Alt + Enter` to make the command screen "Full Screen" (as far as Windows 95 is
concerned). This should restore the display from the garbled mess you see and allow concerned). This should restore the display from the garbled mess you see and allow
you to access the command prompt. Press Alt-Enter again to leave full screen and go you to access the Command Prompt. Press Alt-Enter again to leave Full Screen and go
back to a window mode. (Thanks to @DisplacedGamer for that wisdom) back to Window Mode. (Thanks to @DisplacedGamers for that wisdom)
## Windows 95 is stuck in a bad state ## Windows 95 is stuck in a bad state
@ -31,4 +31,5 @@ with the image as input.
## What's the FrontPage Username and Password? ## What's the FrontPage Username and Password?
Username: windows95 Username: windows95
Password: password Password: password

100
README.md
View file

@ -3,10 +3,102 @@
This is Windows 95, running in an [Electron](https://electronjs.org/) app. Yes, it's the full thing. I'm sorry. This is Windows 95, running in an [Electron](https://electronjs.org/) app. Yes, it's the full thing. I'm sorry.
## Downloads ## Downloads
| | Windows | macOS | Linux |
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| <table class="is-fullwidth">
| Standalone Download | 📦[Standalone, 32-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-win32-standalone-ia32.zip) <br /> 📦[Standalone, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-win32-standalone-x64.zip) | 📦[Standalone](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-macos-2.2.0.zip) | | </thead>
| Installer | 💽[Setup, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-setup-win32-x64.exe) <br /> 💽[Setup, 32-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-setup-win32-ia32.exe) | | 💽[deb, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-linux-2.2.0_amd64.deb) <br /> 💽[rpm, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-linux-2.2.0.x86_64.rpm) | <tbody>
</tbody>
<tr>
<td>
<img src="./.github/images/windows.png" width="24"><br />
Windows
</td>
<td>
<span>32-bit</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-setup-ia32.exe">
💿 Installer
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-win32-ia32-2.3.0.zip">
📦 Standalone Zip
</a>
<br />
<span>64-bit</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-setup-x64.exe">
💿 Installer
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-win32-ia32-2.3.0.zip">
📦 Standalone Zip
</a><br />
<span>ARM64</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-setup-arm64.exe">
💿 Installer
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-win32-ia32-2.3.0.zip">
📦 Standalone Zip
</a><br />
<span>
❓ Don't know what kind of chip you have? Hit start, enter "processor" for info.
</span>
</td>
</tr>
<tr>
<td>
<img src="./.github/images/macos.png" width="24"><br />
macOS
</td>
<td>
<span>Intel Processor</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-darwin-x64-2.3.0.zip">
📦 Standalone Zip
</a><br />
<span>Apple M1 Processor</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-darwin-arm64-2.3.0.zip">
📦 Standalone Zip
</a><br />
<span>
❓ Don't know what kind of chip you have? Learn more at <a href="https://support.apple.com/en-us/HT211814">apple.com</a>.
</span>
</td>
</tr>
<tr>
<td>
<img src="./.github/images/linux.png" width="24"><br />
Linux
</td>
<td>
<span>32-bit</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.i386.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_i386.deb">
💿 deb
</a><br />
<span>64-bit</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.x86_64.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_amd64.deb">
💿 deb
</a><br />
<span>ARM64</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.arm64.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_arm64.deb">
💿 deb
</a><br />
<span>ARMv7 (armhf)</span>
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.arm64.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_armhf.deb">
💿 deb
</a>
</td>
</tr>
</table>
<hr />
![Screenshot](https://user-images.githubusercontent.com/1426799/44532591-4ceb3680-a6a8-11e8-8c2c-bc29f3bfdef7.png) ![Screenshot](https://user-images.githubusercontent.com/1426799/44532591-4ceb3680-a6a8-11e8-8c2c-bc29f3bfdef7.png)

Binary file not shown.

Binary file not shown.

16
assets/entitlements.plist Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.automation.apple-events</key>
<true/>
</dict>
</plist>

View file

@ -1,10 +1,19 @@
const path = require('path'); const path = require('path');
const fs = require('fs');
const package = require('./package.json'); const package = require('./package.json');
if (process.env['WINDOWS_CODESIGN_FILE']) {
const certPath = path.join(__dirname, 'win-certificate.pfx');
const certExists = fs.existsSync(certPath);
if (certExists) {
process.env['WINDOWS_CODESIGN_FILE'] = certPath;
}
}
module.exports = { module.exports = {
hooks: { hooks: {
generateAssets: require('./tools/generateAssets'), generateAssets: require('./tools/generateAssets'),
postPackage: require('./tools/notarize')
}, },
packagerConfig: { packagerConfig: {
asar: false, asar: false,
@ -19,10 +28,16 @@ module.exports = {
identity: 'Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)', identity: 'Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)',
'hardened-runtime': true, 'hardened-runtime': true,
'gatekeeper-assess': false, 'gatekeeper-assess': false,
'entitlements': 'static/entitlements.plist', 'entitlements': 'assets/entitlements.plist',
'entitlements-inherit': 'static/entitlements.plist', 'entitlements-inherit': 'assets/entitlements.plist',
'signature-flags': 'library' 'signature-flags': 'library'
}, },
osxNotarize: {
appBundleId: 'com.felixrieseberg.macintoshjs',
appleId: process.env['APPLE_ID'],
appleIdPassword: process.env['APPLE_ID_PASSWORD'],
ascProvider: 'LT94ZKYDCJ'
},
ignore: [ ignore: [
/\/assets(\/?)/, /\/assets(\/?)/,
/\/docs(\/?)/, /\/docs(\/?)/,
@ -49,8 +64,8 @@ module.exports = {
remoteReleases: '', remoteReleases: '',
setupExe: `windows95-${package.version}-setup-${arch}.exe`, setupExe: `windows95-${package.version}-setup-${arch}.exe`,
setupIcon: path.resolve(__dirname, 'assets', 'icon.ico'), setupIcon: path.resolve(__dirname, 'assets', 'icon.ico'),
certificateFile: process.env.WINDOWS_CERTIFICATE_FILE, certificateFile: process.env['WINDOWS_CODESIGN_FILE'],
certificatePassword: process.env.WINDOWS_CERTIFICATE_PASSWORD certificatePassword: process.env['WINDOWS_CODESIGN_PASSWORD'],
} }
} }
}, },
@ -66,18 +81,5 @@ module.exports = {
name: '@electron-forge/maker-rpm', name: '@electron-forge/maker-rpm',
platforms: ['linux'] platforms: ['linux']
} }
],
publishers: [
{
name: '@electron-forge/publisher-github',
config: {
repository: {
owner: 'felixrieseberg',
name: 'windows95'
},
draft: true,
prerelease: true
}
}
] ]
}; };

11965
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{ {
"name": "windows95", "name": "windows95",
"productName": "windows95", "productName": "windows95",
"version": "2.2.1", "version": "2.3.0",
"description": "Windows 95, in an app. I'm sorry.", "description": "Windows 95, in an app. I'm sorry.",
"main": "./dist/src/main/main", "main": "./dist/src/main/main",
"scripts": { "scripts": {
@ -9,8 +9,10 @@
"package": "electron-forge package", "package": "electron-forge package",
"make": "electron-forge make", "make": "electron-forge make",
"publish": "electron-forge publish", "publish": "electron-forge publish",
"lint": "prettier --write src/**/*.{ts,tsx}", "lint": "prettier --write src/**/*.{ts,tsx} && npm run check-links",
"less": "node ./tools/lessc.js" "less": "node ./tools/lessc.js",
"tsc": "tsc -p tsconfig.json --noEmit",
"check-links": "node tools/check-links.js"
}, },
"keywords": [], "keywords": [],
"author": "Felix Rieseberg, felix@felixrieseberg.com", "author": "Felix Rieseberg, felix@felixrieseberg.com",
@ -20,32 +22,31 @@
}, },
"dependencies": { "dependencies": {
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"fs-extra": "^8.1.0", "fs-extra": "^9.0.1",
"react": "^16.12.0", "react": "^17.0.1",
"react-dom": "^16.12.0", "react-dom": "^17.0.1",
"tslib": "^1.10.0", "tslib": "^2.0.3",
"update-electron-app": "^1.5.0" "update-electron-app": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@electron-forge/cli": "^6.0.0-beta.45", "@electron-forge/cli": "^6.0.0-beta.54",
"@electron-forge/maker-deb": "^6.0.0-beta.45", "@electron-forge/maker-deb": "^6.0.0-beta.54",
"@electron-forge/maker-flatpak": "^6.0.0-beta.45", "@electron-forge/maker-flatpak": "^6.0.0-beta.54",
"@electron-forge/maker-rpm": "^6.0.0-beta.45", "@electron-forge/maker-rpm": "^6.0.0-beta.54",
"@electron-forge/maker-squirrel": "^6.0.0-beta.45", "@electron-forge/maker-squirrel": "^6.0.0-beta.54",
"@electron-forge/maker-zip": "^6.0.0-beta.45", "@electron-forge/maker-zip": "^6.0.0-beta.54",
"@electron-forge/publisher-github": "^6.0.0-beta.45", "@electron-forge/publisher-github": "^6.0.0-beta.54",
"@types/fs-extra": "^8.0.1", "@types/fs-extra": "^9.0.5",
"@types/node": "^12.12.14", "@types/node": "^12.19.9",
"@types/react": "^16.9.13", "@types/react": "^17.0.0",
"@types/react-dom": "^16.9.4", "@types/react-dom": "^17.0.0",
"electron": "7.1.2", "electron": "11.1.1",
"electron-notarize": "^0.2.1", "less": "^3.13.0",
"less": "^3.10.3", "node-abi": "^2.19.3",
"node-abi": "^2.13.0",
"parcel-bundler": "^1.12.4", "parcel-bundler": "^1.12.4",
"prettier": "^1.19.1", "prettier": "^2.2.1",
"rimraf": "^3.0.0", "rimraf": "^3.0.2",
"standard": "^14.3.1", "standard": "^16.0.3",
"typescript": "^3.7.2" "typescript": "^4.1.3"
} }
} }

View file

@ -1,8 +1,8 @@
import { session } from 'electron'; import { session } from "electron";
export async function clearCaches() { export async function clearCaches() {
await clearCache() await clearCache();
await clearStorageData() await clearStorageData();
} }
export async function clearCache() { export async function clearCache() {
@ -11,15 +11,22 @@ export async function clearCache() {
} }
} }
export function clearStorageData() { export async function clearStorageData() {
return new Promise((resolve) => { if (!session.defaultSession) {
if (!session.defaultSession) { return;
return resolve(); }
}
session.defaultSession.clearStorageData({ await session.defaultSession.clearStorageData({
storages: [ 'appcache', 'cookies', 'filesystem', 'indexdb', 'localstorage', 'shadercache', 'websql', 'serviceworkers' ], storages: [
quotas: [ 'temporary', 'persistent', 'syncable' ] "appcache",
}, resolve) "cookies",
}) "filesystem",
"indexdb",
"localstorage",
"shadercache",
"websql",
"serviceworkers",
],
quotas: ["temporary", "persistent", "syncable"],
});
} }

View file

@ -1,31 +1,30 @@
import { remote, app } from 'electron'; import * as path from "path";
import * as path from 'path';
const _app = app || remote.app
export const CONSTANTS = { export const CONSTANTS = {
IMAGE_PATH: path.join(__dirname, '../../images/windows95.img'), IMAGE_PATH: path.join(__dirname, "../../images/windows95.img"),
IMAGE_DEFAULT_SIZE: 1073741824, // 1GB IMAGE_DEFAULT_SIZE: 1073741824, // 1GB
DEFAULT_STATE_PATH: path.join(__dirname, '../../images/default-state.bin'), DEFAULT_STATE_PATH: path.join(__dirname, "../../images/default-state.bin"),
STATE_PATH: path.join(_app.getPath('userData'), 'state-v2.bin') };
}
export const IPC_COMMANDS = { export const IPC_COMMANDS = {
TOGGLE_INFO: 'TOGGLE_INFO', TOGGLE_INFO: "TOGGLE_INFO",
SHOW_DISK_IMAGE: 'SHOW_DISK_IMAGE', SHOW_DISK_IMAGE: "SHOW_DISK_IMAGE",
ZOOM_IN: 'ZOOM_IN', ZOOM_IN: "ZOOM_IN",
ZOOM_OUT: 'ZOOM_OUT', ZOOM_OUT: "ZOOM_OUT",
ZOOM_RESET: 'ZOOM_RESET', ZOOM_RESET: "ZOOM_RESET",
// Machine instructions // Machine instructions
MACHINE_START: 'MACHINE_START', MACHINE_START: "MACHINE_START",
MACHINE_RESTART: 'MACHINE_RESTART', MACHINE_RESTART: "MACHINE_RESTART",
MACHINE_STOP: 'MACHINE_STOP', MACHINE_STOP: "MACHINE_STOP",
MACHINE_RESET: 'MACHINE_RESET', MACHINE_RESET: "MACHINE_RESET",
MACHINE_ALT_F4: 'MACHINE_ALT_F4', MACHINE_ALT_F4: "MACHINE_ALT_F4",
MACHINE_ESC: 'MACHINE_ESC', MACHINE_ESC: "MACHINE_ESC",
MACHINE_ALT_ENTER: 'MACHINE_ALT_ENTER', MACHINE_ALT_ENTER: "MACHINE_ALT_ENTER",
MACHINE_CTRL_ALT_DEL: 'MACHINE_CTRL_ALT_DEL', MACHINE_CTRL_ALT_DEL: "MACHINE_CTRL_ALT_DEL",
// Machine events // Machine events
MACHINE_STARTED: 'MACHINE_STARTED', MACHINE_STARTED: "MACHINE_STARTED",
MACHINE_STOPPED: 'MACHINE_STOPPED' MACHINE_STOPPED: "MACHINE_STOPPED",
} // Else
APP_QUIT: "APP_QUIT",
GET_STATE_PATH: "GET_STATE_PATH",
};

View file

@ -12,7 +12,7 @@ export function setupAboutPanel(): void {
applicationName: "windows95", applicationName: "windows95",
applicationVersion: app.getVersion(), applicationVersion: app.getVersion(),
version: process.versions.electron, version: process.versions.electron,
copyright: "Felix Rieseberg" copyright: "Felix Rieseberg",
}; };
switch (process.platform) { switch (process.platform) {

14
src/main/ipc.ts Normal file
View file

@ -0,0 +1,14 @@
import { ipcMain, app } from "electron";
import * as path from "path";
import { IPC_COMMANDS } from "../constants";
export function setupIpcListeners() {
ipcMain.handle(IPC_COMMANDS.GET_STATE_PATH, () => {
return path.join(app.getPath("userData"), "state-v2.bin");
});
ipcMain.handle(IPC_COMMANDS.APP_QUIT, () => {
app.quit();
});
}

View file

@ -6,6 +6,7 @@ import { shouldQuit } from "./squirrel";
import { setupUpdates } from "./update"; import { setupUpdates } from "./update";
import { getOrCreateWindow } from "./windows"; import { getOrCreateWindow } from "./windows";
import { setupMenu } from "./menu"; import { setupMenu } from "./menu";
import { setupIpcListeners } from "./ipc";
/** /**
* Handle the app's "ready" event. This is essentially * Handle the app's "ready" event. This is essentially
@ -14,6 +15,7 @@ import { setupMenu } from "./menu";
export async function onReady() { export async function onReady() {
if (!isDevMode()) process.env.NODE_ENV = "production"; if (!isDevMode()) process.env.NODE_ENV = "production";
setupIpcListeners();
getOrCreateWindow(); getOrCreateWindow();
setupAboutPanel(); setupAboutPanel();
setupMenu(); setupMenu();

View file

@ -1,15 +1,14 @@
import { app, shell, Menu, BrowserWindow, ipcMain, webFrame } from "electron"; import { app, shell, Menu, BrowserWindow, ipcMain } from "electron";
import { clearCaches } from "../cache"; import { clearCaches } from "../cache";
import { IPC_COMMANDS } from "../constants"; import { IPC_COMMANDS } from "../constants";
import { isDevMode } from "../utils/devmode"; import { isDevMode } from "../utils/devmode";
import { getOrCreateWindow } from "./windows";
const LINKS = { const LINKS = {
homepage: "https://www.twitter.com/felixrieseberg", homepage: "https://www.twitter.com/felixrieseberg",
repo: "https://github.com/felixrieseberg/windows95", repo: "https://github.com/felixrieseberg/windows95",
credits: "https://github.com/felixrieseberg/windows95/blob/master/CREDITS.md", credits: "https://github.com/felixrieseberg/windows95/blob/master/CREDITS.md",
help: "https://github.com/felixrieseberg/windows95/blob/master/HELP.md" help: "https://github.com/felixrieseberg/windows95/blob/master/HELP.md",
}; };
export async function setupMenu() { export async function setupMenu() {
@ -41,52 +40,52 @@ async function createMenu({ isRunning } = { isRunning: false }) {
submenu: [ submenu: [
{ {
label: "Toggle Full Screen", label: "Toggle Full Screen",
accelerator: (function() { accelerator: (function () {
if (process.platform === "darwin") { if (process.platform === "darwin") {
return "Ctrl+Command+F"; return "Ctrl+Command+F";
} else { } else {
return "F11"; return "F11";
} }
})(), })(),
click: function(_item, focusedWindow) { click: function (_item, focusedWindow) {
if (focusedWindow) { if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
} }
} },
}, },
{ {
label: "Toggle Developer Tools", label: "Toggle Developer Tools",
accelerator: (function() { accelerator: (function () {
if (process.platform === "darwin") { if (process.platform === "darwin") {
return "Alt+Command+I"; return "Alt+Command+I";
} else { } else {
return "Ctrl+Shift+I"; return "Ctrl+Shift+I";
} }
})(), })(),
click: function(_item, focusedWindow) { click: function (_item, focusedWindow) {
if (focusedWindow) { if (focusedWindow) {
focusedWindow.webContents.toggleDevTools(); focusedWindow.webContents.toggleDevTools();
} }
} },
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
label: "Toggle Emulator Info", label: "Toggle Emulator Info",
click: () => send(IPC_COMMANDS.TOGGLE_INFO) click: () => send(IPC_COMMANDS.TOGGLE_INFO),
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
role: "reload" role: "reload",
} },
] ],
}, },
{ {
role: "editMenu", role: "editMenu",
visible: isDevMode() visible: isDevMode(),
}, },
{ {
label: "Window", label: "Window",
@ -95,32 +94,32 @@ async function createMenu({ isRunning } = { isRunning: false }) {
{ {
label: "Minimize", label: "Minimize",
accelerator: "CmdOrCtrl+M", accelerator: "CmdOrCtrl+M",
role: "minimize" role: "minimize",
}, },
{ {
label: "Close", label: "Close",
accelerator: "CmdOrCtrl+W", accelerator: "CmdOrCtrl+W",
role: "close" role: "close",
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
label: "Zoom in", label: "Zoom in",
click: () => send(IPC_COMMANDS.ZOOM_IN), click: () => send(IPC_COMMANDS.ZOOM_IN),
enabled: isRunning enabled: isRunning,
}, },
{ {
label: "Zoom out", label: "Zoom out",
click: () => send(IPC_COMMANDS.ZOOM_OUT), click: () => send(IPC_COMMANDS.ZOOM_OUT),
enabled: isRunning enabled: isRunning,
}, },
{ {
label: "Reset zoom", label: "Reset zoom",
click: () => send(IPC_COMMANDS.ZOOM_RESET), click: () => send(IPC_COMMANDS.ZOOM_RESET),
enabled: isRunning enabled: isRunning,
} },
] ],
}, },
{ {
label: "Machine", label: "Machine",
@ -128,53 +127,53 @@ async function createMenu({ isRunning } = { isRunning: false }) {
{ {
label: "Send Ctrl+Alt+Del", label: "Send Ctrl+Alt+Del",
click: () => send(IPC_COMMANDS.MACHINE_CTRL_ALT_DEL), click: () => send(IPC_COMMANDS.MACHINE_CTRL_ALT_DEL),
enabled: isRunning enabled: isRunning,
}, },
{ {
label: "Send Alt+F4", label: "Send Alt+F4",
click: () => send(IPC_COMMANDS.MACHINE_ALT_F4), click: () => send(IPC_COMMANDS.MACHINE_ALT_F4),
enabled: isRunning enabled: isRunning,
}, },
{ {
label: "Send Alt+Enter", label: "Send Alt+Enter",
click: () => send(IPC_COMMANDS.MACHINE_ALT_ENTER), click: () => send(IPC_COMMANDS.MACHINE_ALT_ENTER),
enabled: isRunning enabled: isRunning,
}, },
{ {
label: "Send Esc", label: "Send Esc",
click: () => send(IPC_COMMANDS.MACHINE_ESC), click: () => send(IPC_COMMANDS.MACHINE_ESC),
enabled: isRunning enabled: isRunning,
}, },
{ {
type: "separator" type: "separator",
}, },
isRunning isRunning
? { ? {
label: "Stop", label: "Stop",
click: () => send(IPC_COMMANDS.MACHINE_STOP) click: () => send(IPC_COMMANDS.MACHINE_STOP),
} }
: { : {
label: "Start", label: "Start",
click: () => send(IPC_COMMANDS.MACHINE_START) click: () => send(IPC_COMMANDS.MACHINE_START),
}, },
{ {
label: "Restart", label: "Restart",
click: () => send(IPC_COMMANDS.MACHINE_RESTART), click: () => send(IPC_COMMANDS.MACHINE_RESTART),
enabled: isRunning enabled: isRunning,
}, },
{ {
label: "Reset", label: "Reset",
click: () => send(IPC_COMMANDS.MACHINE_RESET), click: () => send(IPC_COMMANDS.MACHINE_RESET),
enabled: isRunning enabled: isRunning,
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
label: "Go to Disk Image", label: "Go to Disk Image",
click: () => send(IPC_COMMANDS.SHOW_DISK_IMAGE) click: () => send(IPC_COMMANDS.SHOW_DISK_IMAGE),
} },
] ],
}, },
{ {
label: "Help", label: "Help",
@ -182,18 +181,18 @@ async function createMenu({ isRunning } = { isRunning: false }) {
submenu: [ submenu: [
{ {
label: "Author", label: "Author",
click: () => shell.openExternal(LINKS.homepage) click: () => shell.openExternal(LINKS.homepage),
}, },
{ {
label: "windows95 on GitHub", label: "windows95 on GitHub",
click: () => shell.openExternal(LINKS.repo) click: () => shell.openExternal(LINKS.repo),
}, },
{ {
label: "Help", label: "Help",
click: () => shell.openExternal(LINKS.help) click: () => shell.openExternal(LINKS.help),
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
label: "Troubleshooting", label: "Troubleshooting",
@ -205,12 +204,12 @@ async function createMenu({ isRunning } = { isRunning: false }) {
app.relaunch(); app.relaunch();
app.quit(); app.quit();
} },
} },
] ],
} },
] ],
} },
]; ];
if (process.platform === "darwin") { if (process.platform === "darwin") {
@ -218,41 +217,41 @@ async function createMenu({ isRunning } = { isRunning: false }) {
label: "windows95", label: "windows95",
submenu: [ submenu: [
{ {
role: "about" role: "about",
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
role: "services" role: "services",
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
label: "Hide windows95", label: "Hide windows95",
accelerator: "Command+H", accelerator: "Command+H",
role: "hide" role: "hide",
}, },
{ {
label: "Hide Others", label: "Hide Others",
accelerator: "Command+Shift+H", accelerator: "Command+Shift+H",
role: "hideothers" role: "hideothers",
}, },
{ {
role: "unhide" role: "unhide",
}, },
{ {
type: "separator" type: "separator",
}, },
{ {
label: "Quit", label: "Quit",
accelerator: "Command+Q", accelerator: "Command+Q",
click() { click() {
app.quit(); app.quit();
} },
} },
] ],
} as any); } as any);
} }

View file

@ -4,7 +4,7 @@ export function setupUpdates() {
if (app.isPackaged) { if (app.isPackaged) {
require("update-electron-app")({ require("update-electron-app")({
repo: "felixrieseberg/windows95", repo: "felixrieseberg/windows95",
updateInterval: "1 hour" updateInterval: "1 hour",
}); });
} }
} }

View file

@ -13,8 +13,8 @@ export function getOrCreateWindow(): BrowserWindow {
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
sandbox: false, sandbox: false,
webviewTag: false webviewTag: false,
} },
}); });
mainWindow.loadFile("./dist/static/index.html"); mainWindow.loadFile("./dist/static/index.html");

View file

@ -28,7 +28,7 @@ export class App {
} }
window["win95"] = window["win95"] || { window["win95"] = window["win95"] || {
app: new App() app: new App(),
}; };
window["win95"].app.setup(); window["win95"].app.setup();

View file

@ -1,5 +1,4 @@
import * as React from "react"; import * as React from "react";
import { shell } from "electron";
interface CardDriveProps { interface CardDriveProps {
showDiskImage: () => void; showDiskImage: () => void;
@ -54,13 +53,8 @@ export class CardDrive extends React.Component<CardDriveProps, CardDriveState> {
<p> <p>
Windows 10 cannot mount raw disk images (ironically, macOS and Linux Windows 10 cannot mount raw disk images (ironically, macOS and Linux
can). However, tools exist that let you mount this drive, like the can). However, tools exist that let you mount this drive, like the
freeware tool{" "} freeware tool <a href="https://google.com">OSFMount</a>. I am not
<a affiliated with it, so please use it at your own risk.
href="https://google.com"
>
OSFMount
</a>
. I am not affiliated with it, so please use it at your own risk.
</p> </p>
{this.renderMountButton("Windows Explorer")} {this.renderMountButton("Windows Explorer")}
</fieldset> </fieldset>

View file

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import * as fs from "fs-extra"; import * as fs from "fs-extra";
import { CONSTANTS } from "../constants"; import { getStatePath } from "./utils/get-state-path";
interface CardSettingsProps { interface CardSettingsProps {
bootFromScratch: () => void; bootFromScratch: () => void;
@ -24,7 +24,7 @@ export class CardSettings extends React.Component<
this.onResetState = this.onResetState.bind(this); this.onResetState = this.onResetState.bind(this);
this.state = { this.state = {
isStateReset: false isStateReset: false,
}; };
} }
@ -152,8 +152,10 @@ export class CardSettings extends React.Component<
* Handle the state reset * Handle the state reset
*/ */
private async onResetState() { private async onResetState() {
if (fs.existsSync(CONSTANTS.STATE_PATH)) { const statePath = await getStatePath();
await fs.remove(CONSTANTS.STATE_PATH);
if (fs.existsSync(statePath)) {
await fs.remove(statePath);
} }
this.setState({ isStateReset: true }); this.setState({ isStateReset: true });

View file

@ -29,7 +29,7 @@ export class EmulatorInfo extends React.Component<
cpu: 0, cpu: 0,
disk: "Idle", disk: "Idle",
lastCounter: 0, lastCounter: 0,
lastTick: 0 lastTick: 0,
}; };
} }
@ -160,7 +160,7 @@ export class EmulatorInfo extends React.Component<
this.setState({ this.setState({
lastTick: now, lastTick: now,
lastCounter: instructionCounter, lastCounter: instructionCounter,
cpu: Math.round(ips / deltaTime) cpu: Math.round(ips / deltaTime),
}); });
} }
} }

View file

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import * as fs from "fs-extra"; import * as fs from "fs-extra";
import * as path from "path"; import * as path from "path";
import { ipcRenderer, remote, shell } from "electron"; import { ipcRenderer, shell } from "electron";
import { CONSTANTS, IPC_COMMANDS } from "../constants"; import { CONSTANTS, IPC_COMMANDS } from "../constants";
import { getDiskImageSize } from "../utils/disk-image-size"; import { getDiskImageSize } from "../utils/disk-image-size";
@ -10,6 +10,7 @@ import { StartMenu } from "./start-menu";
import { CardSettings } from "./card-settings"; import { CardSettings } from "./card-settings";
import { EmulatorInfo } from "./emulator-info"; import { EmulatorInfo } from "./emulator-info";
import { CardDrive } from "./card-drive"; import { CardDrive } from "./card-drive";
import { getStatePath } from "./utils/get-state-path";
export interface EmulatorState { export interface EmulatorState {
currentUiCard: string; currentUiCard: string;
@ -41,7 +42,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
isRunning: false, isRunning: false,
currentUiCard: "start", currentUiCard: "start",
isInfoDisplayed: true, isInfoDisplayed: true,
scale: 1 scale: 1,
}; };
this.setupInputListeners(); this.setupInputListeners();
@ -58,7 +59,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
*/ */
public setupInputListeners() { public setupInputListeners() {
// ESC // ESC
document.onkeydown = evt => { document.onkeydown = (evt) => {
const { isCursorCaptured } = this.state; const { isCursorCaptured } = this.state;
evt = evt || window.event; evt = evt || window.event;
@ -95,11 +96,11 @@ export class Emulator extends React.Component<{}, EmulatorState> {
this.isQuitting = true; this.isQuitting = true;
setImmediate(() => { setImmediate(() => {
remote.app.quit(); ipcRenderer.invoke(IPC_COMMANDS.APP_QUIT);
}); });
}; };
window.onbeforeunload = event => { window.onbeforeunload = (event: Event) => {
if (this.isQuitting || this.isResetting) { if (this.isQuitting || this.isResetting) {
console.log(`Unload: Not preventing`); console.log(`Unload: Not preventing`);
return; return;
@ -122,27 +123,27 @@ export class Emulator extends React.Component<{}, EmulatorState> {
this.sendKeys([ this.sendKeys([
0x1d, // ctrl 0x1d, // ctrl
0x38, // alt 0x38, // alt
0x53 // delete 0x53, // delete
]); ]);
}); });
ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_F4, () => { ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_F4, () => {
this.sendKeys([ this.sendKeys([
0x38, // alt 0x38, // alt
0x3e // f4 0x3e, // f4
]); ]);
}); });
ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_ENTER, () => { ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_ENTER, () => {
this.sendKeys([ this.sendKeys([
0x38, // alt 0x38, // alt
0 // enter 0, // enter
]); ]);
}); });
ipcRenderer.on(IPC_COMMANDS.MACHINE_ESC, () => { ipcRenderer.on(IPC_COMMANDS.MACHINE_ESC, () => {
this.sendKeys([ this.sendKeys([
0x18 // alt 0x18, // alt
]); ]);
}); });
@ -189,7 +190,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
if (currentUiCard === "settings") { if (currentUiCard === "settings") {
card = ( card = (
<CardSettings <CardSettings
setFloppy={floppyFile => this.setState({ floppyFile })} setFloppy={(floppyFile) => this.setState({ floppyFile })}
bootFromScratch={this.bootFromScratch} bootFromScratch={this.bootFromScratch}
floppy={floppyFile} floppy={floppyFile}
/> />
@ -204,7 +205,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
<> <>
{card} {card}
<StartMenu <StartMenu
navigate={target => this.setState({ currentUiCard: target })} navigate={(target) => this.setState({ currentUiCard: target })}
/> />
</> </>
); );
@ -257,10 +258,10 @@ export class Emulator extends React.Component<{}, EmulatorState> {
*/ */
public showDiskImage() { public showDiskImage() {
// Contents/Resources/app/dist/static // Contents/Resources/app/dist/static
const imagePath = path const imagePath = path.join(__dirname, "../../images/windows95.img");
.join(__dirname, "../../images/windows95.img");
console.log(`Showing disk image in ${imagePath}`);`` console.log(`Showing disk image in ${imagePath}`);
``;
shell.showItemInFolder(imagePath); shell.showItemInFolder(imagePath);
} }
@ -277,20 +278,20 @@ export class Emulator extends React.Component<{}, EmulatorState> {
video_memory_size: 32 * 1024 * 1024, video_memory_size: 32 * 1024 * 1024,
screen_container: document.getElementById("emulator"), screen_container: document.getElementById("emulator"),
bios: { bios: {
url: "../../bios/seabios.bin" url: "../../bios/seabios.bin",
}, },
vga_bios: { vga_bios: {
url: "../../bios/vgabios.bin" url: "../../bios/vgabios.bin",
}, },
hda: { hda: {
url: "../../images/windows95.img", url: "../../images/windows95.img",
async: true, async: true,
size: imageSize size: imageSize,
}, },
fda: { fda: {
buffer: this.state.floppyFile buffer: this.state.floppyFile,
}, },
boot_order: 0x132 boot_order: 0x132,
}; };
console.log(`🚜 Starting emulator with options`, options); console.log(`🚜 Starting emulator with options`, options);
@ -300,7 +301,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
// New v86 instance // New v86 instance
this.setState({ this.setState({
emulator: window["emulator"], emulator: window["emulator"],
isRunning: true isRunning: true,
}); });
ipcRenderer.send(IPC_COMMANDS.MACHINE_STARTED); ipcRenderer.send(IPC_COMMANDS.MACHINE_STARTED);
@ -366,8 +367,9 @@ export class Emulator extends React.Component<{}, EmulatorState> {
*/ */
private async saveState(): Promise<void> { private async saveState(): Promise<void> {
const { emulator } = this.state; const { emulator } = this.state;
const statePath = await getStatePath();
return new Promise(resolve => { return new Promise((resolve) => {
if (!emulator || !emulator.save_state) { if (!emulator || !emulator.save_state) {
console.log(`restoreState: No emulator present`); console.log(`restoreState: No emulator present`);
return resolve(); return resolve();
@ -379,9 +381,9 @@ export class Emulator extends React.Component<{}, EmulatorState> {
return resolve(); return resolve();
} }
await fs.outputFile(CONSTANTS.STATE_PATH, Buffer.from(newState)); await fs.outputFile(statePath, Buffer.from(newState));
console.log(`saveState: Saved state to ${CONSTANTS.STATE_PATH}`); console.log(`saveState: Saved state to ${statePath}`);
resolve(); resolve();
}); });
@ -391,9 +393,9 @@ export class Emulator extends React.Component<{}, EmulatorState> {
/** /**
* Restores state to the emulator. * Restores state to the emulator.
*/ */
private restoreState() { private async restoreState() {
const { emulator } = this.state; const { emulator } = this.state;
const state = this.getState(); const state = await this.getState();
// Nothing to do with if we don't have a state // Nothing to do with if we don't have a state
if (!state) { if (!state) {
@ -420,9 +422,10 @@ export class Emulator extends React.Component<{}, EmulatorState> {
* *
* @returns {ArrayBuffer} * @returns {ArrayBuffer}
*/ */
private getState(): ArrayBuffer | null { private async getState(): Promise<ArrayBuffer | null> {
const statePath = fs.existsSync(CONSTANTS.STATE_PATH) const expectedStatePath = await getStatePath();
? CONSTANTS.STATE_PATH const statePath = fs.existsSync(expectedStatePath)
? expectedStatePath
: CONSTANTS.DEFAULT_STATE_PATH; : CONSTANTS.DEFAULT_STATE_PATH;
if (fs.existsSync(statePath)) { if (fs.existsSync(statePath)) {

View file

@ -0,0 +1,13 @@
import { ipcRenderer } from "electron";
import { IPC_COMMANDS } from "../../constants";
let _statePath = "";
export async function getStatePath(): Promise<string> {
if (_statePath) {
return _statePath;
}
const statePath = await ipcRenderer.invoke(IPC_COMMANDS.GET_STATE_PATH);
return (_statePath = statePath);
}

23
tools/add-macos-cert.sh Normal file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env sh
KEY_CHAIN=build.keychain
MACOS_CERT_P12_FILE=certificate.p12
# Recreate the certificate from the secure environment variable
echo $MACOS_CERT_P12 | base64 --decode > $MACOS_CERT_P12_FILE
#create a keychain
security create-keychain -p actions $KEY_CHAIN
# Make the keychain the default so identities are found
security default-keychain -s $KEY_CHAIN
# Unlock the keychain
security unlock-keychain -p actions $KEY_CHAIN
security import $MACOS_CERT_P12_FILE -k $KEY_CHAIN -P $MACOS_CERT_PASSWORD -T /usr/bin/codesign;
security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN
# remove certs
rm -fr *.p12

38
tools/check-links.js Normal file
View file

@ -0,0 +1,38 @@
const fs = require('fs/promises')
const path = require('path')
const fetch = require('node-fetch')
const LINK_RGX = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?/g;
async function main() {
const readmePath = path.join(__dirname, '../README.md')
const readme = await fs.readFile(readmePath, 'utf-8')
const links = readme.match(LINK_RGX)
let failed = false
for (const link of links) {
try {
const response = await fetch(link, { method: 'HEAD' })
if (!response.ok) {
// If we're inside GitHub's release asset server, we just ran into AWS not allowing
// HEAD requests, which is different from a 404.
if (!response.url.startsWith('https://github-production-release-asset')) {
throw new Error (`HTTP Error Response: ${response.status} ${response.statusText}`)
}
}
console.log(`${link}`);
} catch (error) {
failed = true
console.log(`${link}\n${error}`)
}
}
if (failed) {
process.exit(-1);
}
}
main()

11
tools/download-disk.ps1 Normal file
View file

@ -0,0 +1,11 @@
mkdir images
cd images
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($env:DISK_URL, "$(Resolve-Path .)\images.zip")
7z x images.zip -y -aoa
Remove-Item images.zip
Remove-Item __MACOSX -Recurse -ErrorAction Ignore
cd ..
Tree ./ /F

10
tools/download-disk.sh Normal file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env sh
mkdir -p ./images
cd ./images
wget -O images.zip $DISK_URL
unzip -o images.zip
rm images.zip
rm -r __MACOSX
cd -
ls images

View file

@ -1,30 +0,0 @@
const { notarize } = require('electron-notarize');
const path = require('path');
const buildOutput = path.resolve(
__dirname,
'..',
'out',
'windows95-darwin-x64',
'windows95.app'
);
module.exports = function () {
if (process.platform !== 'darwin') {
console.log('Not a Mac; skipping notarization');
return;
}
console.log('Notarizing...');
return notarize({
appBundleId: 'com.felixrieseberg.windows95',
appPath: buildOutput,
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_ID_PASSWORD,
ascProvider: 'LT94ZKYDCJ'
}).catch((e) => {
console.error(e);
throw e;
});
}

8909
yarn.lock Normal file

File diff suppressed because it is too large Load diff