Compare commits

...

72 Commits

Author SHA1 Message Date
Felix Rieseberg
6b84c60051 Update links 2023-03-15 11:09:27 -07:00
Felix Rieseberg
5cdaad84cc Pin Ubunut version 2023-03-14 13:59:49 -07:00
Felix Rieseberg
fb930035c7 v1.2.0 2023-03-14 13:51:16 -07:00
Felix Rieseberg
b3991ef1d0 More build changes 2023-03-14 13:48:53 -07:00
Felix Rieseberg
7dda450bf6 v1.2.3 2023-03-13 17:20:24 -07:00
Felix Rieseberg
d68097b59b GitHub Actions: Limit arch 2023-03-13 17:20:19 -07:00
Felix Rieseberg
34eccc706c v1.2.2 2023-03-13 17:14:42 -07:00
Felix Rieseberg
cc94f198e2 No Linux ia32 2023-03-13 17:14:29 -07:00
Felix Rieseberg
f5ef5da750 v1.2.1 2023-03-13 17:01:45 -07:00
Felix Rieseberg
1482f6d443 Upgrade Node in GitHub Actions 2023-03-13 16:41:10 -07:00
Felix Rieseberg
1533ba7ec0 Upgrade Node in GitHub Actions 2023-03-13 16:33:43 -07:00
Felix Rieseberg
8a8aa0e7eb v1.2.0 2023-03-13 16:06:14 -07:00
Felix Rieseberg
05136c28c1 Update Electron 2023-03-13 16:06:00 -07:00
Felix Rieseberg
e5b24cc04a
Merge pull request #118 from kipdec/scaling
Added basic window resizing
2023-03-13 15:38:05 -07:00
Felix Rieseberg
d58444bc18
Merge pull request #121 from hmsjy2017/patch-1
Correct the wrong links
2022-09-05 12:34:13 -07:00
Felix Rieseberg
dc0b8fe19f
Merge pull request #92 from ghost/patch-1
fix: Update label for 64-bit Linux downloads
2022-09-05 12:33:45 -07:00
Felix Rieseberg
895ce4c743
Merge pull request #141 from Arecsu/patch-1
fixed windows links in readme
2022-09-05 12:32:53 -07:00
Alejandro Romano
35b769949c
fixed windows links in readme 2022-07-02 23:03:06 -03:00
Tony
4acf8bb312
Correct the wrong links
I found that several quoted links were wrong, which caused the downloaded files to not meet expectations.
2021-08-24 01:38:29 +08:00
Kip DeCastro
8821a4749f Cleaned up some unnecessary spaces 2021-07-27 23:34:52 -04:00
Kip DeCastro
4d57fc494c Added basic window resizing to the application 2021-07-27 23:32:18 -04:00
Felix Rieseberg
ede11165a9
Merge pull request #90 from ponyville/patch-1
Fix swapped links for x64 and M1 versions for macOS
2021-04-28 10:12:54 -07:00
Felix Rieseberg
bdb1033958
Merge pull request #104 from erichelgeson/master
Support .hda extension used with RaSCSI or BlueSCSI.
2021-04-28 10:12:44 -07:00
Felix Rieseberg
78411c9fa4
Merge pull request #109 from egasimus/patch-1
Fix x86_64 label; show how to get CPU type on Linux
2021-04-28 10:12:29 -07:00
Felix Rieseberg
47aba5bb36
Merge pull request #110 from staltz/patch-1
Fix 64-bit typo on the readme
2021-04-28 10:12:15 -07:00
André Staltz
da495a9b39
Fix 64-bit typo on the readme 2021-04-28 16:32:22 +03:00
Adam Avramov
c30866e58e
Fix x86_64 label; show how to get CPU type on Linux 2021-04-28 15:14:02 +03:00
Eric Helgeson
6c1ffff0e0 Support .hda extension used with RaSCSI or BlueSCSI. 2021-03-29 10:55:09 -05:00
Felix Rieseberg
e3c6d96785 chore: Update Readme 2021-01-31 09:24:14 -08:00
Paulo Ribeiro
60a3e787f5
fix: Update label for 64-bit Linux downloads 2021-01-08 12:58:39 +00:00
Michael Schwarz
57ad789c61
Fix swapped links for x64 and M1 versions for macOS 2021-01-04 23:37:57 +01:00
Felix Rieseberg
47863bb45e build: Update Node version 2021-01-04 10:31:12 -08:00
Felix Rieseberg
9c98bf1eb8 build: Check links, update REAADME 2021-01-04 09:52:49 -08:00
Felix Rieseberg
6df468db4d v1.1.0 2021-01-03 19:38:56 -08:00
Felix Rieseberg
5320b29eed build: Build for all archs, update dependencies 2021-01-03 19:38:45 -08:00
Felix Rieseberg
d5688df03f build: Build for all architectures 2021-01-03 19:32:12 -08:00
Felix Rieseberg
e121c457af v1.0.7 2020-10-23 14:52:26 -07:00
Felix Rieseberg
45d061f051 build: Update dependencies 2020-10-23 14:52:19 -07:00
Felix Rieseberg
d9a0353091
Merge pull request #74 from felixrieseberg/dependabot/npm_and_yarn/node-fetch-2.6.1
build(deps): Bump node-fetch from 2.6.0 to 2.6.1
2020-10-23 14:48:25 -07:00
Felix Rieseberg
9622100513
Merge pull request #81 from felixrieseberg/dependabot/npm_and_yarn/electron-10.1.2
build(deps-dev): Bump electron from 10.0.0-beta.12 to 10.1.2
2020-10-23 14:48:07 -07:00
dependabot[bot]
55b97251a0
build(deps-dev): Bump electron from 10.0.0-beta.12 to 10.1.2
Bumps [electron](https://github.com/electron/electron) from 10.0.0-beta.12 to 10.1.2.
- [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/v10.0.0-beta.12...v10.1.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-06 17:55:38 +00:00
dependabot[bot]
576200b489
build(deps): Bump node-fetch from 2.6.0 to 2.6.1
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-09-13 03:31:35 +00:00
Felix Rieseberg
da7c0b1513 docs: Update readme 2020-08-03 15:50:50 -07:00
Felix Rieseberg
f2d8191b0d chore: Remove unused master certs 2020-08-02 13:27:12 -07:00
Felix Rieseberg
3bd800d296 1.0.6 2020-08-02 13:13:29 -07:00
Felix Rieseberg
5e9570023b build: Allow Windows cert failure 2020-08-02 13:05:34 -07:00
Felix Rieseberg
64d8f4a382 build: Trying to fix GH actions 2020-08-02 12:58:02 -07:00
Felix Rieseberg
de601111f9 build: Run on push to master 2020-08-02 12:55:30 -07:00
Felix Rieseberg
5c83088633 build: Only attempt to create code signature if secrets are set 2020-08-02 12:54:47 -07:00
Felix Rieseberg
c73331bf6a feat: Handle toast and dsk images 2020-08-01 22:56:14 +00:00
Felix Rieseberg
9a1bbd40fb
Merge pull request #45 from meeh0w/patch-1
Update README.md
2020-08-01 15:40:08 -07:00
Michał Leszczyk
1861b3b818
Update README.md 2020-07-31 18:34:59 +02:00
Felix Rieseberg
99c4e2e31c
Merge pull request #43 from jonathanpotts/master
Update README with current download links
2020-07-31 09:16:45 -07:00
Jonathan Potts
ec32c63b29
Update README.md 2020-07-30 22:52:05 -07:00
Jonathan Potts
09f4a9a3ed
Update README.md 2020-07-30 22:51:35 -07:00
Felix Rieseberg
d86d40f90d build: Icon for debian 2020-07-30 11:58:54 -07:00
Felix Rieseberg
7e32d63415 1.0.5 2020-07-30 11:49:50 -07:00
Felix Rieseberg
13f8d8bd7b
Merge pull request #30 from jonathanpotts/master
Proposed fix for issue #6
2020-07-30 11:48:28 -07:00
Jonathan Potts
473033ba7b
Update input.js
Make change according to https://github.com/felixrieseberg/macintosh.js/issues/6#issuecomment-665981700
2020-07-29 19:20:03 -07:00
Felix Rieseberg
5a4e6e6b37 docs: Update links 2020-07-29 12:15:03 -07:00
Felix Rieseberg
3aae0c143c 1.0.4 2020-07-29 12:05:20 -07:00
Felix Rieseberg
e5c008887b fix: If you can't rename, copy 2020-07-29 12:05:14 -07:00
Felix Rieseberg
9cd62be64d chore: Update readme 2020-07-29 11:59:46 -07:00
Felix Rieseberg
c72e1294c6 fix: Don't delete original disk 2020-07-29 11:43:12 -07:00
Felix Rieseberg
f4c1e4dedb fix: Work out of user data dir, not app dir 2020-07-29 11:36:51 -07:00
Felix Rieseberg
e2206e2ade 1.0.3 2020-07-29 10:02:59 -07:00
Felix Rieseberg
7aa3b3612f fix: Protect against prefs write failure 2020-07-29 08:40:17 -07:00
Felix Rieseberg
5b6079eb85
Merge pull request #12 from albuvee/patch-1
Update README.md
2020-07-29 08:28:38 -07:00
Felix Rieseberg
15834f9059
docs: Update the readme a little more 2020-07-29 08:27:34 -07:00
Stefan Rechsteiner
26f44cecd6
Update README.md 2020-07-29 10:17:29 +02:00
Felix Rieseberg
5ccdddde63 fix: Point to credits from readme 2020-07-28 18:57:03 -07:00
Felix Rieseberg
a0aef16192 chore: Update readme links 2020-07-28 18:37:03 -07:00
18 changed files with 1840 additions and 1885 deletions

3
.gitattributes vendored
View File

@ -1 +1,2 @@
* text eol=lf
text eol=lf
rom -text

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

View File

@ -3,24 +3,24 @@ name: Build & Release
on:
push:
branches:
# - master
- master
tags:
- v*
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: 12.x
node-version: lts/*
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
- uses: actions/cache@v3
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 }}
@ -28,26 +28,42 @@ jobs:
restore-keys: |
${{ runner.os }}-yarn-
- name: Install
run: yarn
run: yarn --frozen-lockfile
- name: lint
run: yarn lint
build:
needs: lint
name: Build (${{ matrix.os }})
name: Build (${{ matrix.os }} - ${{ matrix.arch }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ macOS-latest, ubuntu-latest, windows-latest ]
# Build for supported platforms
# https://github.com/electron/electron-packager/blob/ebcbd439ff3e0f6f92fa880ff28a8670a9bcf2ab/src/targets.js#L9
# 32-bit Linux unsupported as of 2019: https://www.electronjs.org/blog/linux-32bit-support
os: [ macOS-latest, ubuntu-20.04, windows-latest ]
arch: [ x64, arm64 ]
include:
- os: windows-latest
arch: ia32
- os: ubuntu-20.04
arch: armv7l
# Publishing artifacts for multiple Windows architectures has
# a bug which can cause the wrong architecture to be downloaded
# for an update, so until that is fixed, only build Windows x64
exclude:
- os: windows-latest
arch: arm64
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: 12.x
node-version: lts/*
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
- uses: actions/cache@v3
if: matrix.os != 'macOS-latest'
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
@ -63,6 +79,7 @@ jobs:
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:
@ -82,18 +99,12 @@ jobs:
run: yarn
- name: Make
if: startsWith(github.ref, 'refs/tags/')
run: yarn make
run: yarn make --arch=${{ matrix.arch }}
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: Make (ia32)
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
run: yarn make -- --arch=ia32
env:
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:
@ -105,6 +116,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
draft: true
files: |
out/**/*.deb
out/**/*.dmg

View File

@ -4,6 +4,8 @@ This app by <a href="https://www.felixrieseberg.com">Felix Rieseberg</a>. The re
**Emulator**: Basilisk II, a 68k Macintosh emulator, by [Christian Bauer et al](http://basilisk.cebix.net), modified and compiled [with Emscripten](https://jamesfriend.com.au/basilisk-ii-classic-mac-emulator-in-the-browser) by [James Friend](https://jamesfriend.com.au).
**Runtime**: The developers behind Electron, electron-forge, Chromium, Node.js.
**Installed software** from vintage computing archives: [WinWorldPC](https://winworldpc.com), [Macintosh Garden](https://macintoshgarden.org), and [Macintosh Repository](https://www.macintoshrepository.org/).
This software is not affiliated with nor authorized by Apple. It is provided for educational purposes only. This is an unstable toy and should not be expected to work properly.

105
README.md
View File

@ -6,13 +6,100 @@ This is Mac OS 8, running in an [Electron](https://electronjs.org/) app pretendi
## Downloads
| | Windows | macOS | Linux |
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Standalone Download | 📦[Standalone, 32-bit](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintosh.js-win32-ia32-1.0.1.zip) <br /> 📦[Standalone, 64-bit](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintosh.js-win32-x64-1.0.1.zip) | 📦[Standalone](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintosh.js-darwin-x64-1.0.1.zip) | |
| Installer | 💽[Setup, 64-bit](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintoshjs-1.0.1-setup-x64.exe) <br /> 💽[Setup, 32-bit](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintoshjs-1.0.1-setup-ia32.exe) | | 💽[deb, 64-bit](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintosh.js_1.0.1_amd64.deb) <br /> 💽[rpm, 64-bit](https://github.com/felixrieseberg/macintosh.js/releases/download/v1.0.1/macintosh.js-1.0.1-1.x86_64.rpm) |
<table class="is-fullwidth">
</thead>
<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/macintosh.js/releases/download/v1.2.0/macintoshjs-1.2.0-setup-ia32.exe">
💿 Installer
</a> |
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.2.0/macintosh.js-win32-ia32-1.2.0.zip">
📦 Standalone Zip
</a>
<br />
<span>64-bit</span>
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.2.0/macintoshjs-1.2.0-setup-x64.exe">
💿 Installer
</a> |
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.2.0/macintosh.js-win32-x64-1.2.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/macintosh.js/releases/download/v1.1.0/macintosh.js-darwin-x64-1.1.0.zip">
📦 Standalone Zip
</a><br />
<span>Apple M1 Processor</span>
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js-darwin-arm64-1.1.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/macintosh.js/releases/download/v1.1.0/macintosh.js-1.1.0-1.i386.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js_1.1.0_i386.deb">
💿 deb
</a><br />
<span>64-bit</span>
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js-1.1.0-1.x86_64.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js_1.1.0_amd64.deb">
💿 deb
</a><br />
<span>ARM64</span>
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js-1.1.0-1.arm64.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js_1.1.0_arm64.deb">
💿 deb
</a><br />
<span>ARMv7 (armhf)</span>
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js-1.1.0-1.armv7hl.rpm">
💿 rpm
</a> |
<a href="https://github.com/felixrieseberg/macintosh.js/releases/download/v1.1.0/macintosh.js_1.1.0_armhf.deb">
💿 deb
</a><br />
<span>
❓ Don't know what kind of chip you have? Run `uname -m` in the console.
</span>
</td>
</tr>
</table>
<hr />
## Does it work?
Yes! Quite well, actually - on macOS, Windows, and Linux. Bear in mind that this is written entirely in JavaScript, so please adjust your expectations. The virtual machine is emulating a 1991 Macintosh Quadra 900 with a Motorola CPU, which Apple used before switching to IBM's PowerPC architecture in the late 1990s.
Yes! Quite well, actually - on macOS, Windows, and Linux. Bear in mind that this is written entirely in JavaScript, so please adjust your expectations. The virtual machine is emulating a 1991 Macintosh Quadra 900 with a Motorola CPU, which Apple used before switching to the PowerPC architecture (Apple/IBM/Motorola) in the mid 1990s.
## Should this have been a native app?
Absolutely.
@ -30,6 +117,14 @@ Yes, you can. Click on the "Help" button at the bottom of the running app to see
No. For what it's worth, the web was quite different 30 years ago - and you wouldn't be able to open even Google. However, Internet Explorer and Netscape are installed, as is the "Web Sharing Server", if you want to play around a bit.
## Should I use this for [serious application]?
Probably not. This is a toy - it's not the best nor the most performant way to emulate an old Macintosh. It is, however, a quick and easy way to experience a bit of nostalgia if you're _not_ trying to do anything serious with it.
## Credits
Please check out the [CREDITS](CREDITS.md)! This app wouldn't be possible without the hard work of [Christian Bauer](https://www.cebix.net/) and [James Friend](https://jamesfriend.com.au/), who did everything that seems like computing magic here.
## License
This project is provided for educational purposes only. It is not affiliated with and has

Binary file not shown.

Binary file not shown.

View File

@ -75,7 +75,15 @@ module.exports = {
},
{
name: '@electron-forge/maker-deb',
platforms: ['linux']
platforms: ['linux'],
options: {
maintainer: 'Felix Rieseberg',
homepage: 'https://github.com/felixrieseberg/macintosh.js',
categories: [
'Education',
],
icon: path.resolve(__dirname, 'assets', 'icon.png')
}
},
{
name: '@electron-forge/maker-rpm',

View File

@ -1,7 +1,7 @@
{
"name": "macintosh.js",
"productName": "macintosh.js",
"version": "1.0.2",
"version": "1.2.0",
"description": "Macintosh's System 8 in an Electron app. I'm sorry.",
"main": "src/main/index.js",
"scripts": {
@ -9,8 +9,9 @@
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "npx prettier --check src/{main,renderer}/*.{js,css}",
"fix": "npx prettier --write src/{main,renderer}/*.{js,css}"
"lint": "npx prettier --check src/{main,renderer}/*.{js,css} && npm run check-links",
"fix": "npx prettier --write \"src/{main,renderer}/**.{js,css}\"",
"check-links": "node tools/check-links.js"
},
"keywords": [],
"author": {
@ -23,14 +24,15 @@
},
"dependencies": {
"electron-squirrel-startup": "^1.0.0",
"update-electron-app": "^1.5.0"
"update-electron-app": "^2.0.1"
},
"devDependencies": {
"@electron-forge/cli": "6.0.0-beta.52",
"@electron-forge/maker-deb": "6.0.0-beta.52",
"@electron-forge/maker-rpm": "6.0.0-beta.52",
"@electron-forge/maker-squirrel": "6.0.0-beta.52",
"@electron-forge/maker-zip": "6.0.0-beta.52",
"electron": "10.0.0-beta.12"
"@electron-forge/cli": "6.0.5",
"@electron-forge/maker-deb": "6.0.5",
"@electron-forge/maker-rpm": "6.0.5",
"@electron-forge/maker-squirrel": "6.0.5",
"@electron-forge/maker-zip": "6.0.5",
"electron": "23.1.3",
"node-fetch": "^2.6.1"
}
}

View File

@ -1,6 +1,5 @@
const fs = require("fs");
const path = require("path");
const { error } = require("console");
const homeDir = require("os").homedir();
const macDir = path.join(homeDir, "macintosh.js");
@ -10,7 +9,25 @@ const macintoshCopyPath = path.join(__dirname, "user_files");
let userDataPath;
function getUserDataDiskPath() {
return path.join(userDataPath, 'disk');
return path.join(userDataPath, "disk");
}
// File type utilities
function isFile(v = "") {
return fs.statSync(path.join(macDir, v)).isFile();
}
function isHiddenFile(filename = '') {
return filename.startsWith('.');
}
function isCDImage(filename = '') {
return filename.endsWith('.iso') || filename.endsWith('.toast');
}
function isDiskImage(filename = '') {
return filename.endsWith('.img') || filename.endsWith('.dsk') || filename.endsWith('.hda');
}
function cleanupCopyPath() {
@ -32,51 +49,47 @@ function getUserDataDiskImage() {
}
const diskImageUserPath = getUserDataDiskPath();
const diskImagePath = path.join(__dirname, 'disk');
const diskImagePath = path.join(__dirname, "disk");
// If there's a disk image, move it over
if (fs.existsSync(diskImageUserPath)) {
// Delete a possible basilisk disk image
if (fs.existsSync(diskImagePath)) {
console.log(`Disk image ${diskImageUserPath} exists, deleting ${diskImagePath}`);
fs.unlinkSync(diskImagePath);
if (!fs.existsSync(diskImageUserPath)) {
try {
fs.renameSync(diskImagePath, diskImageUserPath);
} catch (error) {
// This is _probably_ a permissions thing, let's copy the file
fs.copyFileSync(diskImagePath, diskImageUserPath);
}
fs.renameSync(diskImageUserPath, diskImagePath);
} else {
console.log(`getUserDataDiskImage: No image in user data dir, not doing anything`);
console.log(
`getUserDataDiskImage: Image in user data dir, not doing anything`
);
}
}
// Taken a given path, it'll look at all the files in there,
// copy them over to the basilisk folder, and then add them
// to MEMFS
function copyFilesAtPath(module, sourcePath) {
function preloadFilesAtPath(module, initalSourcePath) {
try {
const absoluteSourcePath = path.join(macDir, sourcePath);
const absoluteTargetPath = path.join(macintoshCopyPath, sourcePath);
const targetPath = `/macintosh.js${sourcePath ? `/${sourcePath}` : ""}`;
const files = fs.readdirSync(absoluteSourcePath).filter((v) => {
const sourcePath = path.join(macDir, initalSourcePath);
const targetPath = `/macintosh.js${
initalSourcePath ? `/${initalSourcePath}` : ""
}`;
const files = fs.readdirSync(sourcePath).filter((v) => {
// Remove hidden, iso, and img files
return !v.startsWith('.') && !v.endsWith(".iso") && !v.endsWith(".img");
return !isHiddenFile(v) && !isDiskImage(v) && !isCDImage(v);
});
(files || []).forEach((fileName) => {
try {
// If not, let's move on
const fileSourcePath = path.join(absoluteSourcePath, fileName);
const copyPath = path.join(absoluteTargetPath, fileName);
const fileSourcePath = path.join(sourcePath, fileName);
const relativeSourcePath = `${
sourcePath ? `${sourcePath}/` : ""
initalSourcePath ? `${initalSourcePath}/` : ""
}${fileName}`;
const fileUrl = `user_files/${relativeSourcePath}`;
// Check if directory
if (fs.statSync(fileSourcePath).isDirectory()) {
if (!fs.existsSync(copyPath)) {
fs.mkdirSync(copyPath);
}
try {
const virtualDirPath = `${targetPath}/${fileName}`;
module.FS.mkdir(virtualDirPath);
@ -84,21 +97,15 @@ function copyFilesAtPath(module, sourcePath) {
console.log(error);
}
copyFilesAtPath(module, relativeSourcePath);
preloadFilesAtPath(module, relativeSourcePath);
return;
}
// We copy the files over and then add them as preload
console.log(`copyFilesAtPath: Adding ${fileName}`);
fs.copyFileSync(fileSourcePath, copyPath);
module.FS_createPreloadedFile(
targetPath,
fileName,
fileUrl,
true,
true
);
createPreloadedFile(module, {
parent: targetPath,
name: fileName,
url: fileSourcePath,
});
} catch (error) {
postMessage("showMessageBoxSync", {
type: "error",
@ -106,7 +113,10 @@ function copyFilesAtPath(module, sourcePath) {
message: `We tried to transfer ${fileName} to the virtual machine, but failed. The error was: ${error}`,
});
console.error(`copyFilesAtPath: Failed to preload ${fileName}`, error);
console.error(
`preloadFilesAtPath: Failed to preload ${fileName}`,
error
);
}
});
} catch (error) {
@ -116,20 +126,24 @@ function copyFilesAtPath(module, sourcePath) {
message: `We tried to transfer files to the virtual machine, but failed. The error was: ${error}`,
});
console.error(`copyFilesAtPath: Failed to copyFilesAtPath`, error);
console.error(`preloadFilesAtPath: Failed to preloadFilesAtPath`, error);
}
};
}
function createPreloadedFile(module, options) {
const parent = options.parent || `/`;
const name = options.name || path.basename(options.url);
const url = options.url;
console.log(`Adding preload file`, { parent, name, url });
module.FS_createPreloadedFile(parent, name, url, true, true);
}
function addAutoloader(module) {
const loadDatafiles = function () {
module.autoloadFiles.forEach((filepath) => {
const parent = `/`;
const name = path.basename(filepath);
console.log(`Adding preload file`, { parent, name, url: filepath });
module.FS_createPreloadedFile(parent, name, filepath, true, true);
});
module.autoloadFiles.forEach(({ url, name }) =>
createPreloadedFile(module, { url, name })
);
// If the user has a macintosh.js dir, we'll copy over user
// data
@ -138,7 +152,7 @@ function addAutoloader(module) {
}
// Load user files
copyFilesAtPath(module, "");
preloadFilesAtPath(module, "");
};
if (module.autoloadFiles) {
@ -182,22 +196,23 @@ function writeSafely(filePath, fileData) {
});
}
function getPrefs(userImages = []) {
function writePrefs(userImages = []) {
try {
const prefsTemplatePath = path.join(__dirname, "prefs_template");
const prefsPath = path.join(__dirname, "prefs");
const prefsPath = path.join(userDataPath, "prefs");
let prefs = fs.readFileSync(prefsTemplatePath, { encoding: "utf-8" });
// Replace line endings, just in case
prefs = prefs.replaceAll('\r\n', '\n');
prefs = prefs.replaceAll("\r\n", "\n");
if (userImages && userImages.length > 0) {
console.log(`getPrefs: Found ${userImages.length} user images`);
userImages.forEach((file) => {
if (file.endsWith(".iso")) {
prefs += `\ncdrom ${file}`;
} else if (file.endsWith(".img")) {
prefs += `\ndisk ${file}`;
console.log(`writePrefs: Found ${userImages.length} user images`);
userImages.forEach(({ name }) => {
if (isCDImage(name)) {
prefs += `\ncdrom ${name}`;
} else if (isDiskImage(name)) {
prefs += `\ndisk ${name}`;
}
});
}
@ -206,81 +221,60 @@ function getPrefs(userImages = []) {
fs.writeFileSync(prefsPath, prefs);
} catch (error) {
console.error(`getPrefs: Failed to set prefs`, error);
console.error(`writePrefs: Failed to set prefs`, error);
}
return "prefs";
}
function isMacDirFileOfType(extension = "", v = "") {
const isType = v.endsWith(`.${extension}`);
const isMatch = isType && fs.statSync(path.join(macDir, v)).isFile();
console.log(`isMacDirFileOfType: ${v} is file and ${extension}: ${isMatch}`);
return isMatch;
}
function copyUserImages() {
function getUserImages() {
const result = [];
try {
// No need if the macDir doesn't exist
if (!fs.existsSync(macDir)) {
console.log(`autoMountImageFiles: ${macDir} does not exist, exit`);
console.log(`getUserImages: ${macDir} does not exist, exit`);
return result;
}
const macDirFiles = fs.readdirSync(macDir);
const imgFiles = macDirFiles.filter((v) => isMacDirFileOfType("img", v));
const isoFiles = macDirFiles.filter((v) => isMacDirFileOfType("iso", v));
const imgFiles = macDirFiles.filter((v) => isFile(v) && isDiskImage(v));
const isoFiles = macDirFiles.filter((v) => isFile(v) && isCDImage(v));
const isoImgFiles = [...isoFiles, ...imgFiles];
console.log(`copyUserImages: iso and img files`, isoImgFiles);
console.log(`getUserImages: iso and img files`, isoImgFiles);
isoImgFiles.forEach((fileName, i) => {
const sourcePath = path.join(macDir, fileName);
const url = path.join(macDir, fileName);
const sanitizedFileName = `user_image_${i}_${fileName.replace(
/[^\w\s\.]/gi,
""
)}`;
const targetPath = path.join(__dirname, sanitizedFileName);
if (fs.existsSync(targetPath)) {
const sourceStat = fs.statSync(sourcePath);
const targetStat = fs.statSync(targetPath);
// Copy if the length is different
if (sourceStat.size !== targetStat.size) {
fs.copyFileSync(sourcePath, targetPath);
} else {
console.log(
`autoMountImageFiles: ${sourcePath} already exists in ${targetPath}, not copying`
);
}
} else {
fs.copyFileSync(sourcePath, targetPath);
}
console.log(`Copied over ${targetPath}`);
result.push(sanitizedFileName);
});
// Delete all old files
const imagesCopyFiles = fs.readdirSync(__dirname);
imagesCopyFiles.forEach((v) => {
if (v.startsWith("user_image_") && !result.includes(v)) {
fs.unlinkSync(path.join(__dirname, v));
}
result.push({ url, name: sanitizedFileName });
});
} catch (error) {
console.error(`copyUserImages: Encountered error`, error);
console.error(`getUserImages: Encountered error`, error);
}
return result;
}
function getAutoLoadFiles(userImages = []) {
const autoLoadFiles = ["disk", "rom", "prefs", ...userImages];
const autoLoadFiles = [
{
name: "disk",
url: path.join(userDataPath, "disk"),
},
{
name: "rom",
url: path.join(__dirname, "rom"),
},
{
name: "prefs",
url: path.join(userDataPath, "prefs"),
},
...userImages,
];
return autoLoadFiles;
}
@ -362,7 +356,6 @@ self.onmessage = async function (msg) {
if (msg && msg.data === "disk_save") {
const diskData = Module.FS.readFile("/disk");
const diskPath = getUserDataDiskPath();
const basiliskDiskPath = path.join(__dirname, 'disk');
// I wish we could do this with promises, but OOM crashes kill that idea
try {
@ -373,14 +366,6 @@ self.onmessage = async function (msg) {
console.error(`Failed to write disk`, error);
}
try {
if (fs.existsSync(basiliskDiskPath) && !(Module && Module.isDevMode)) {
fs.unlinkSync(basiliskDiskPath);
}
} catch (error) {
console.error(`Failed to delete ${basiliskDiskPath}`);
}
// Now, user files
console.log(`Saving user files`);
await saveFilesInPath("/macintosh.js");
@ -483,14 +468,23 @@ function startEmulator(parentConfig) {
let AudioConfig = null;
let AudioBufferQueue = [];
const userImages = copyUserImages();
// Check for user images
const userImages = getUserImages();
// Write prefs to user data dir
writePrefs(userImages);
// Assemble preload files
const autoloadFiles = getAutoLoadFiles(userImages);
// Set arguments
const arguments = ["--config", "prefs"];
Module = {
autoloadFiles: getAutoLoadFiles(userImages),
userImages: userImages,
arguments: ["--config", getPrefs(userImages)],
autoloadFiles,
userImages,
arguments,
canvas: null,
blit: function blit(bufPtr, width, height, depth, usingPalette) {

View File

@ -1,4 +1,5 @@
const { app, dialog } = require("electron");
const { getIsDevMode } = require("./devmode");
// If the app doesn't run from the /Applications folder,
// we don't get to create files, which keeps the emulator from
@ -8,6 +9,10 @@ function moveToAppFolderMaybe() {
return;
}
if (getIsDevMode()) {
return;
}
if (app.isInApplicationsFolder()) {
return;
}

View File

@ -1,4 +1,4 @@
const { app, BrowserWindow, shell } = require("electron");
const { BrowserWindow, shell } = require("electron");
const path = require("path");
const { getIsDevMode } = require("./devmode");
@ -61,18 +61,31 @@ function createWindow() {
width: 900,
height: 730,
useContentSize: true,
frame: false,
frame: true,
transparent: true,
resizable: false,
resizable: true,
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true,
nativeWindowOpen: true,
contextIsolation: false,
navigateOnDragDrop: false,
nodeIntegrationInWorker: true,
sandbox: false,
},
});
// Ensure that we have access to SharedArrayBuffer
mainWindow.webContents.session.webRequest.onHeadersReceived(
(details, callback) => {
details.responseHeaders["Cross-Origin-Opener-Policy"] = ["same-origin"];
details.responseHeaders["Cross-Origin-Embedder-Policy"] = [
"require-corp",
];
callback({ responseHeaders: details.responseHeaders });
}
);
// and load the index.html of the app.
mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"));

View File

@ -43,8 +43,9 @@ function tryToSendInput() {
switch (inputEvent.type) {
case "mousemove":
hasMouseMove = true;
mouseMoveX += inputEvent.dx;
mouseMoveY += inputEvent.dy;
// Make change according to https://github.com/felixrieseberg/macintosh.js/issues/6#issuecomment-665981700
mouseMoveX = inputEvent.dx;
mouseMoveY = inputEvent.dy;
break;
case "mousedown":
case "mouseup":

View File

@ -1,43 +1,63 @@
const { videoModeBufferView } = require("./video");
const { audioContext } = require("./audio");
const SCREEN_WIDTH = 800;
const SCREEN_HEIGHT = 600;
const SCREEN_BUFFER_SIZE = SCREEN_WIDTH * SCREEN_HEIGHT * 4; // 32bpp;
const BITS = 4;
const SCREEN_BUFFER_SIZE = 800 * 600 * BITS; // 32bpp;
const screenBuffer = new SharedArrayBuffer(SCREEN_BUFFER_SIZE);
const screenBufferView = new Uint8Array(screenBuffer);
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
let screenWidth = 800;
let screenHeight = 600;
canvas.width = screenWidth;
canvas.height = screenHeight;
const canvasCtx = canvas.getContext("2d");
const imageData = canvasCtx.createImageData(SCREEN_WIDTH, SCREEN_HEIGHT);
let imageData = canvasCtx.createImageData(screenWidth, screenHeight);
window.addEventListener("resize", () => {
screenHeight = window.innerHeight - 35;
screenWidth = Math.floor(screenHeight * (4 / 3));
if (window.innerWidth < screenWidth) {
screenWidth = window.innerWidth;
screenHeight = Math.floor(screenWidth * 0.75);
}
canvas.width = screenWidth;
canvas.height = screenHeight;
imageData = canvasCtx.createImageData(screenWidth, screenHeight);
});
let stopDrawing = false;
function drawScreen() {
if (stopDrawing) return;
const pixelsRGBA = imageData.data;
const numPixels = SCREEN_WIDTH * SCREEN_HEIGHT;
const numPixels = screenWidth * screenHeight;
const expandedFromPalettedMode = videoModeBufferView[3];
const start = audioContext.currentTime;
if (expandedFromPalettedMode) {
for (var i = 0; i < numPixels; i++) {
for (let i = 0; i < numPixels; i++) {
// palette
pixelsRGBA[i * 4 + 0] = screenBufferView[i * 4 + 0];
pixelsRGBA[i * 4 + 1] = screenBufferView[i * 4 + 1];
pixelsRGBA[i * 4 + 2] = screenBufferView[i * 4 + 2];
pixelsRGBA[i * 4 + 3] = 255; // full opacity
pixelsRGBA[i * BITS + 0] = screenBufferView[i * BITS + 0];
pixelsRGBA[i * BITS + 1] = screenBufferView[i * BITS + 1];
pixelsRGBA[i * BITS + 2] = screenBufferView[i * BITS + 2];
pixelsRGBA[i * BITS + 3] = 255; // full opacity
}
} else {
for (var i = 0; i < numPixels; i++) {
// ARGB
pixelsRGBA[i * 4 + 0] = screenBufferView[i * 4 + 1];
pixelsRGBA[i * 4 + 1] = screenBufferView[i * 4 + 2];
pixelsRGBA[i * 4 + 2] = screenBufferView[i * 4 + 3];
pixelsRGBA[i * 4 + 3] = 255; // full opacity
for (let i = 0; i < screenHeight; i++) {
for (let j = 0; j < screenWidth; j++) {
// ARGB
const xRatio = 800 / screenWidth;
const yRatio = 600 / screenHeight;
const px = Math.floor(j * xRatio);
const py = Math.floor(i * yRatio);
pixelsRGBA[(i * screenWidth + j) * 4 + 0] =
screenBufferView[(py * 800 + px) * 4 + 1]; //- lineMult];
pixelsRGBA[(i * screenWidth + j) * 4 + 1] =
screenBufferView[(py * 800 + px) * 4 + 2]; //- lineMult];
pixelsRGBA[(i * screenWidth + j) * 4 + 2] =
screenBufferView[(py * 800 + px) * 4 + 3]; //- lineMult];
pixelsRGBA[(i * screenWidth + j) * 4 + 3] = 255; // full opacity
}
}
}
@ -69,7 +89,7 @@ module.exports = {
screenBufferView,
SCREEN_BUFFER_SIZE,
drawScreen,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SCREEN_WIDTH: screenWidth,
SCREEN_HEIGHT: screenHeight,
setCanvasBlank,
};

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()

3166
yarn.lock

File diff suppressed because it is too large Load Diff