├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── swift.yml
├── .gitattributes
├── Screenshots
├── MacBox.png
├── Screenshot.png
├── MacBox_Templates.png
├── MacBox_Amstrad_PC1512.png
├── MacBox_CompaqPortable.png
├── MacBox_Presario4532.png
└── MacBox_Commodore_PC_30_III.png
├── MacBox
├── Assets.xcassets
│ ├── Contents.json
│ ├── Icons
│ │ ├── Contents.json
│ │ ├── pc.imageset
│ │ │ ├── pc.png
│ │ │ └── Contents.json
│ │ ├── add.imageset
│ │ │ ├── add.png
│ │ │ └── Contents.json
│ │ ├── hdd.imageset
│ │ │ ├── hdd.png
│ │ │ └── Contents.json
│ │ ├── ram.imageset
│ │ │ ├── ram.png
│ │ │ └── Contents.json
│ │ ├── run.imageset
│ │ │ ├── run.png
│ │ │ └── Contents.json
│ │ ├── gear.imageset
│ │ │ ├── gear.png
│ │ │ └── Contents.json
│ │ ├── pcon.imageset
│ │ │ ├── pcon.png
│ │ │ └── Contents.json
│ │ ├── 86Box.imageset
│ │ │ ├── 86Box.png
│ │ │ └── Contents.json
│ │ ├── clean.imageset
│ │ │ ├── clean.png
│ │ │ └── Contents.json
│ │ ├── print.imageset
│ │ │ ├── print.png
│ │ │ └── Contents.json
│ │ ├── trash.imageset
│ │ │ ├── trash.png
│ │ │ └── Contents.json
│ │ ├── MacBox.imageset
│ │ │ ├── MacBox.png
│ │ │ └── Contents.json
│ │ ├── camera.imageset
│ │ │ ├── camera.png
│ │ │ └── Contents.json
│ │ ├── options.imageset
│ │ │ ├── options.png
│ │ │ └── Contents.json
│ │ ├── x_mark.imageset
│ │ │ ├── x_mark.png
│ │ │ └── Contents.json
│ │ ├── 86BoxROMs.imageset
│ │ │ ├── 86BoxROMs.png
│ │ │ └── Contents.json
│ │ ├── check_mark.imageset
│ │ │ ├── check_mark.png
│ │ │ └── Contents.json
│ │ ├── emulator_tray.imageset
│ │ │ ├── emulator_tray.png
│ │ │ └── Contents.json
│ │ └── exclamation_mark.imageset
│ │ │ ├── exclamation_mark.png
│ │ │ └── Contents.json
│ ├── logos
│ │ ├── Contents.json
│ │ ├── Pb_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Pb_logo.svg
│ │ ├── Dell_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Dell_logo.svg
│ │ ├── Epson_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Epson_logo.svg
│ │ ├── IBM_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── IBM_logo.svg
│ │ ├── NEC_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── NEC_logo.svg
│ │ ├── Amstrad_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Amstrad_logo.svg
│ │ ├── Compaq_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Compaq_logo.svg
│ │ ├── Commodore_logo.imageset
│ │ │ ├── Contents.json
│ │ │ └── Commodore_logo.svg
│ │ ├── Tandy_logo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Tandy_logo.svg
│ │ │ └── Tandy_logo 1.svg
│ │ ├── Pb_logo_old.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Pb_logo_old.svg
│ │ │ └── Pb_logo_old 1.svg
│ │ └── Compaq_logo_old.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Compaq_logo_old.svg
│ │ │ └── Compaq_logo_old 1.svg
│ ├── AppIcon.appiconset
│ │ ├── Icon-MacOS-512x512.png
│ │ ├── Icon-MacOS-512x512@2x.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── Templates
│ ├── epson_apc_2600
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cpq_presario_4532
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── dell_dim_xps_p60
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── pb_platinum_55
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── ibm_ps1es
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── amstrd_pc1512
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── ibm_ps1_2121
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── ibm_vp_433
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cmdr_pc_30_iii
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── tndy_1000
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cpq_deskpro
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cpq_portable
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cpq_portable_386
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cpq_portable_ii
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ ├── cpq_portable_iii
│ │ ├── macbox.inf
│ │ └── 86box.cfg
│ └── cpq_portable_plus
│ │ ├── macbox.inf
│ │ └── 86box.cfg
├── MacBox.entitlements
├── Classes
│ ├── RunningVMProcess.swift
│ ├── VM.swift
│ ├── VMTemplate.swift
│ ├── ScreensaverManager.swift
│ └── SpecsParser.swift
├── README.md
├── Extensions
│ ├── Date.swift
│ ├── URL.swift
│ └── FileManager.swift
├── Structs
│ ├── VersionInfoObject.swift
│ ├── GithubResponseObject.swift
│ └── JenkinsResponseObject.swift
├── AppDelegate.swift
├── Utils
│ └── IniParser.swift
├── ViewControllers
│ ├── AddVMViewController.swift
│ ├── ImportVMViewController.swift
│ └── SettingsViewController.swift
├── Shaders
│ └── crt-guest-cgwg-curvature.glsl
└── Strings Localization
│ └── Localizable.xcstrings
├── .gitignore
├── MacBox.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ ├── moonif.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ │ └── filipmotyczka.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
├── xcuserdata
│ └── moonif.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── xcshareddata
│ └── xcschemes
│ └── MacBox.xcscheme
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ['https://paypal.me/pastelpix']
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/Screenshots/MacBox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/MacBox.png
--------------------------------------------------------------------------------
/Screenshots/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/Screenshot.png
--------------------------------------------------------------------------------
/Screenshots/MacBox_Templates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/MacBox_Templates.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Screenshots/MacBox_Amstrad_PC1512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/MacBox_Amstrad_PC1512.png
--------------------------------------------------------------------------------
/Screenshots/MacBox_CompaqPortable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/MacBox_CompaqPortable.png
--------------------------------------------------------------------------------
/Screenshots/MacBox_Presario4532.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/MacBox_Presario4532.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .DS_Store?
3 | **/.DS_Store
4 | ._*
5 | .Spotlight-V100
6 | .Trashes
7 | ehthumbs.db
8 | Thumbs.db
9 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Screenshots/MacBox_Commodore_PC_30_III.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/Screenshots/MacBox_Commodore_PC_30_III.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/pc.imageset/pc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/pc.imageset/pc.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/add.imageset/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/add.imageset/add.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/hdd.imageset/hdd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/hdd.imageset/hdd.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/ram.imageset/ram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/ram.imageset/ram.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/run.imageset/run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/run.imageset/run.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/gear.imageset/gear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/gear.imageset/gear.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/pcon.imageset/pcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/pcon.imageset/pcon.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/86Box.imageset/86Box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/86Box.imageset/86Box.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/clean.imageset/clean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/clean.imageset/clean.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/print.imageset/print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/print.imageset/print.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/trash.imageset/trash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/trash.imageset/trash.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/MacBox.imageset/MacBox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/MacBox.imageset/MacBox.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/camera.imageset/camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/camera.imageset/camera.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/options.imageset/options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/options.imageset/options.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/x_mark.imageset/x_mark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/x_mark.imageset/x_mark.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/86BoxROMs.imageset/86BoxROMs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/86BoxROMs.imageset/86BoxROMs.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-512x512.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/check_mark.imageset/check_mark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/check_mark.imageset/check_mark.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-512x512@2x.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/emulator_tray.imageset/emulator_tray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/emulator_tray.imageset/emulator_tray.png
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/exclamation_mark.imageset/exclamation_mark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox/Assets.xcassets/Icons/exclamation_mark.imageset/exclamation_mark.png
--------------------------------------------------------------------------------
/MacBox/Templates/epson_apc_2600/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Epson
3 | Description=Epson Action PC 2600
4 | Logo=Epson_logo
5 | Year=1995
6 | Author=Moonif
7 |
8 | [Shader]
9 | enable_overscan = 1
10 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MacBox/MacBox.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_presario_4532/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Presario 4532
4 | Logo=Compaq_logo
5 | Year=1997
6 | Author=Moonif
7 |
8 | [Shader]
9 | enable_overscan = 1
10 |
--------------------------------------------------------------------------------
/MacBox/Templates/dell_dim_xps_p60/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Dell
3 | Description=Dell Dimension XPS P60
4 | Logo=Dell_logo
5 | Year=1994
6 | Author=npjg
7 |
8 | [Shader]
9 | enable_overscan = 1
10 |
11 |
--------------------------------------------------------------------------------
/MacBox/Templates/pb_platinum_55/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Packard Bell
3 | Description=Packard Bell Platinum 55
4 | Logo=Pb_logo
5 | Year=1996
6 | Author=Moonif
7 |
8 | [Shader]
9 | enable_overscan = 1
10 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/project.xcworkspace/xcuserdata/moonif.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox.xcodeproj/project.xcworkspace/xcuserdata/moonif.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/MacBox.xcodeproj/xcuserdata/moonif.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/project.xcworkspace/xcuserdata/filipmotyczka.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moonif/MacBox/HEAD/MacBox.xcodeproj/project.xcworkspace/xcuserdata/filipmotyczka.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/MacBox/Classes/RunningVMProcess.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RunningVMProcess.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 5/1/23.
6 | //
7 |
8 | struct RunningVMProcess {
9 | var vmProcessID: Int32?
10 | var vmRowNumber: Int?
11 | }
12 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/pc.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "pc.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/86Box.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "86Box.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/add.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "add.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/clean.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "clean.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/gear.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "gear.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/hdd.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "hdd.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/pcon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "pcon.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/print.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "print.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/ram.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ram.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/run.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "run.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/trash.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "trash.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/MacBox.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "MacBox.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/camera.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "camera.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/options.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "options.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/x_mark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "x_mark.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Pb_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Pb_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/86BoxROMs.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "86BoxROMs.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/check_mark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "check_mark.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Dell_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Dell_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Epson_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Epson_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/IBM_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "IBM_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/NEC_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "NEC_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Amstrad_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Amstrad_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Compaq_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Compaq_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/emulator_tray.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "emulator_tray.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Commodore_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Commodore_logo.svg",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/Icons/exclamation_mark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "exclamation_mark.png",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MacBox/Templates/ibm_ps1es/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=IBM
3 | Description=IBM PS/1 (Model 2011)
4 | Logo=IBM_logo
5 | Year=1990
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 |
--------------------------------------------------------------------------------
/MacBox/Templates/amstrd_pc1512/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Amstrad
3 | Description=Amstrad PC 1512
4 | Logo=Amstrad_logo
5 | Year=1986
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 |
--------------------------------------------------------------------------------
/MacBox/Templates/ibm_ps1_2121/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=IBM
3 | Description=IBM PS/1 (Model 2121)
4 | Logo=IBM_logo
5 | Year=1991
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 |
--------------------------------------------------------------------------------
/MacBox/Templates/ibm_vp_433/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=IBM
3 | Description=IBM PS/ValuePoint 433DX/Si
4 | Logo=IBM_logo
5 | Year=1994
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 |
--------------------------------------------------------------------------------
/MacBox/Templates/cmdr_pc_30_iii /macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Commodore
3 | Description=Commodore PC 30-III
4 | Logo=Commodore_logo
5 | Year=1989
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 |
--------------------------------------------------------------------------------
/MacBox/Templates/tndy_1000/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Tandy
3 | Description=Tandy 1000 SX
4 | Logo=Tandy_logo
5 | Year=1987
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_deskpro/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Deskpro
4 | Logo=Compaq_logo_old
5 | Year=1984
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Portable
4 | Logo=Compaq_logo_old
5 | Year=1983
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox/Classes/VM.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VM.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/10/23.
6 | //
7 |
8 | struct VM: Codable {
9 | var name: String?
10 | var description: String?
11 | var path: String?
12 | var logo: String?
13 | var appPath: String?
14 | var fullScreen: Bool?
15 | }
16 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_386/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Portable 386
4 | Logo=Compaq_logo_old
5 | Year=1987
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_ii/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Portable II
4 | Logo=Compaq_logo_old
5 | Year=1986
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_iii/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Portable III
4 | Logo=Compaq_logo_old
5 | Year=1987
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_plus/macbox.inf:
--------------------------------------------------------------------------------
1 | [General]
2 | Manufacturer=Compaq
3 | Description=Compaq Portable Plus
4 | Logo=Compaq_logo_old
5 | Year=1983
6 | Author=Moonif
7 |
8 | [Shader]
9 | vid_renderer = qt_opengl3
10 | video_gl_shader = crt-guest-cgwg-curvature.glsl
11 | enable_overscan = 1
12 | vid_cga_contrast = 1
13 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MacBox/README.md:
--------------------------------------------------------------------------------
1 | # MacBox
2 | MacBox for 86Box
3 |
4 | #
5 | MacBox is an optional manager app for the [86Box emulator](https://github.com/86Box/86Box) to make it easier to handle multiple virtual machines.
6 |
It's written in Swift and supports both Apple Silicon and Intel based machines.
7 |
8 | # System requirements
9 | * MacOS 10.14
10 |
--------------------------------------------------------------------------------
/MacBox/Classes/VMTemplate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VMTemplate.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/20/23.
6 | //
7 |
8 | struct VMTemplate {
9 | var name: String?
10 | var year: String?
11 | var infoPath: String?
12 | var configPath: String?
13 | var machineLogo: String?
14 | var useShader: Bool = false
15 | }
16 |
--------------------------------------------------------------------------------
/MacBox/Extensions/Date.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Date.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 1/17/24.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Date {
11 | func getFormattedDate(format: String) -> String {
12 | let dateformat = DateFormatter()
13 | dateformat.dateFormat = format
14 | return dateformat.string(from: self)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MacBox/Templates/tndy_1000/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = tandy1000sx
3 | cpu_family = 8088
4 | cpu_speed = 7159092
5 | cpu_multi = 1
6 | cpu_use_dynarec = 0
7 | time_sync = disabled
8 | mem_size = 640
9 |
10 | [Video]
11 | gfxcard = internal
12 |
13 | [Input devices]
14 | mouse_type = none
15 |
16 | [Sound]
17 | fm_driver = nuked
18 |
19 | [Storage controllers]
20 | hdc = none
21 | cassette_mode = load
22 |
23 | [Ports (COM & LPT)]
24 | serial2_enabled = 0
25 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = portable
3 | cpu_family = 8088
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 4772728
8 | mem_size = 128
9 |
10 | [Input devices]
11 | mouse_type = none
12 |
13 | [Ports (COM & LPT)]
14 | serial2_enabled = 0
15 |
16 | [Video]
17 | gfxcard = compaq_cga
18 |
19 | [Sound]
20 | fm_driver = nuked
21 |
22 | [Compaq CGA]
23 | display_type = 0
24 | composite_type = 0
25 | rgb_type = 1
26 | snow_enabled = 1
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Tandy_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Tandy_logo.svg",
5 | "idiom" : "universal"
6 | },
7 | {
8 | "appearances" : [
9 | {
10 | "appearance" : "luminosity",
11 | "value" : "dark"
12 | }
13 | ],
14 | "filename" : "Tandy_logo 1.svg",
15 | "idiom" : "universal"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Pb_logo_old.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Pb_logo_old.svg",
5 | "idiom" : "universal"
6 | },
7 | {
8 | "appearances" : [
9 | {
10 | "appearance" : "luminosity",
11 | "value" : "dark"
12 | }
13 | ],
14 | "filename" : "Pb_logo_old 1.svg",
15 | "idiom" : "universal"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "b26c070fd1f0b029780331f3cefa3909a6d58ea6b3ae242bffe49d6011fe06fe",
3 | "pins" : [
4 | {
5 | "identity" : "zipfoundation",
6 | "kind" : "remoteSourceControl",
7 | "location" : "https://github.com/weichsel/ZIPFoundation.git",
8 | "state" : {
9 | "revision" : "02b6abe5f6eef7e3cbd5f247c5cc24e246efcfe0",
10 | "version" : "0.9.19"
11 | }
12 | }
13 | ],
14 | "version" : 3
15 | }
16 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Compaq_logo_old.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Compaq_logo_old.svg",
5 | "idiom" : "universal"
6 | },
7 | {
8 | "appearances" : [
9 | {
10 | "appearance" : "luminosity",
11 | "value" : "dark"
12 | }
13 | ],
14 | "filename" : "Compaq_logo_old 1.svg",
15 | "idiom" : "universal"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/MacBox/Extensions/URL.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 1/31/24.
6 | //
7 |
8 | import Foundation
9 |
10 | extension URL {
11 | var fileSize: Int? {
12 | do {
13 | let val = try self.resourceValues(forKeys: [.totalFileAllocatedSizeKey, .fileAllocatedSizeKey])
14 | return val.totalFileAllocatedSize ?? val.fileAllocatedSize
15 | } catch {
16 | print("Error: \(error.localizedDescription)")
17 | return nil
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.github/workflows/swift.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Swift project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift
3 |
4 | name: Swift
5 |
6 | on:
7 | push:
8 | branches: [ "main" ]
9 | pull_request:
10 | branches: [ "main" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: macos-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | - name: Build
20 | run: swift build -v
21 | - name: Run tests
22 | run: swift test -v
23 |
--------------------------------------------------------------------------------
/MacBox/Structs/VersionInfoObject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VersionInfoObject.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 1/22/24.
6 | //
7 |
8 | import Cocoa
9 |
10 | struct VersionInfoObject {
11 | // 86Box emulator info
12 | var emulatorUpdateChannel: String?
13 | var emulatorAutoUrl: URL?
14 | var emulatorCustomUrl: URL?
15 | // 86Box ROMs info
16 | var romsUrls: [URL] = []
17 | // Update objects
18 | var emulatorUpdateObject: GithubResponseObject?
19 | var romsUpdateObject: GithubResponseObject?
20 | var macboxUpdateObject: GithubResponseObject?
21 | }
22 |
--------------------------------------------------------------------------------
/MacBox/Templates/ibm_ps1es/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = ibmps1es
3 | cpu_family = 286
4 | cpu_speed = 10000000
5 | cpu_multi = 1
6 | mem_size = 512
7 | cpu_use_dynarec = 0
8 | time_sync = disabled
9 |
10 | [Input devices]
11 | mouse_type = ps2
12 |
13 | [Standard PS/2 Mouse]
14 | buttons = 2
15 |
16 | [Ports (COM & LPT)]
17 | serial2_enabled = 0
18 |
19 | [Video]
20 | gfxcard = internal
21 |
22 | [Sound]
23 | fm_driver = nuked
24 |
25 | [Hard disks]
26 | hdd_01_parameters = 33, 2, 921, 0, xta
27 | hdd_01_xta_channel = 0
28 | hdd_01_fn = disks/hdd.IMG
29 |
30 | [Floppy and CD-ROM drives]
31 | fdd_01_type = 35_2hd
32 | fdd_02_type = none
33 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/xcuserdata/moonif.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MacBox.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | F9D6077E29E2BABE002541BF
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/MacBox/Templates/epson_apc_2600/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = actionpc2600
3 | cpu_family = i486dx
4 | cpu_speed = 25000000
5 | cpu_multi = 1
6 | cpu_use_dynarec = 0
7 | time_sync = disabled
8 | fpu_type = internal
9 | mem_size = 4096
10 |
11 | [Storage controllers]
12 | hdc = internal
13 |
14 | [Input devices]
15 | mouse_type = ps2
16 |
17 | [Video]
18 | gfxcard = tvga8900d
19 |
20 | [Sound]
21 | fm_driver = nuked
22 |
23 | [Hard disks]
24 | hdd_01_parameters = 63, 16, 856, 0, ide
25 | hdd_01_fn = disks/hdd.IMG
26 | hdd_01_speed = 1994_4500rpm
27 | hdd_01_ide_channel = 0:0
28 |
29 | [Floppy and CD-ROM drives]
30 | fdd_01_type = 35_2hd
31 | fdd_02_type = none
32 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_deskpro/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = deskpro
3 | cpu_family = 8086
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 7159092
8 | mem_size = 256
9 |
10 | [Storage controllers]
11 | hdc = st506_xt_dtc5150x
12 |
13 | [Input devices]
14 | mouse_type = msserial
15 |
16 | [Ports (COM & LPT)]
17 | serial2_enabled = 0
18 |
19 | [Video]
20 | gfxcard = compaq_cga
21 |
22 | [Sound]
23 | fm_driver = nuked
24 |
25 | [Compaq CGA]
26 | display_type = 0
27 | composite_type = 0
28 | rgb_type = 2
29 | snow_enabled = 1
30 |
31 | [Hard disks]
32 | hdd_01_parameters = 17, 4, 306, 0, mfm
33 | hdd_01_fn = disks/hdd.IMG
34 | hdd_01_mfm_channel = 0
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for MacBox
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/MacBox/Templates/ibm_vp_433/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = valuepoint433
3 | cpu_family = i486dx
4 | cpu_speed = 33333333
5 | cpu_multi = 1
6 | cpu_use_dynarec = 1
7 | time_sync = disabled
8 | fpu_type = internal
9 | cpu = 7
10 | mem_size = 16384
11 |
12 | [Storage controllers]
13 | hdc = internal
14 |
15 | [Input devices]
16 | mouse_type = ps2
17 |
18 | [Standard PS/2 Mouse]
19 | buttons = 2
20 |
21 | [Video]
22 | gfxcard = internal
23 |
24 | [Sound]
25 | fm_driver = nuked
26 |
27 | [Hard disks]
28 | hdd_01_parameters = 17, 14, 1024, 0, ide
29 | hdd_01_fn = disks/hdd.IMG
30 | hdd_01_speed = 1992_3600rpm
31 | hdd_01_ide_channel = 0:0
32 |
33 | [Floppy and CD-ROM drives]
34 | fdd_01_type = 35_2hd
35 | fdd_02_type = none
36 |
--------------------------------------------------------------------------------
/MacBox/Templates/amstrd_pc1512/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = pc1512
3 | cpu_family = 8086
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 8000000
8 | mem_size = 512
9 |
10 | [Storage controllers]
11 | hdc = st506_xt_dtc5150x
12 |
13 | [Input devices]
14 | mouse_type = internal
15 |
16 | [Ports (COM & LPT)]
17 | serial2_enabled = 0
18 |
19 | [Video]
20 | gfxcard = internal
21 |
22 | [Sound]
23 | fm_driver = nuked
24 |
25 | [Amstrad PC1512 (video)]
26 | display_type = 0
27 | codepage = 3
28 | language = 7
29 |
30 | [Hard disks]
31 | hdd_01_parameters = 17, 4, 306, 0, mfm
32 | hdd_01_mfm_channel = 0
33 | hdd_01_fn = disks/hdd.IMG
34 |
35 | [Floppy and CD-ROM drives]
36 | fdd_02_type = none
37 |
--------------------------------------------------------------------------------
/MacBox/Templates/ibm_ps1_2121/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = ibmps1_2121
3 | cpu_family = i386sx
4 | cpu_speed = 20000000
5 | cpu_multi = 1
6 | cpu_use_dynarec = 0
7 | time_sync = disabled
8 | mem_size = 2048
9 |
10 | [Storage controllers]
11 | hdc = internal
12 |
13 | [Input devices]
14 | mouse_type = ps2
15 |
16 | [Standard PS/2 Mouse]
17 | buttons = 2
18 |
19 | [Ports (COM & LPT)]
20 | serial2_enabled = 0
21 |
22 | [Video]
23 | gfxcard = internal
24 |
25 | [Sound]
26 | fm_driver = nuked
27 |
28 | [Hard disks]
29 | hdd_01_parameters = 17, 8, 615, 0, ide
30 | hdd_01_fn = disks/hdd.IMG
31 | hdd_01_speed = 1989_3500rpm
32 | hdd_01_ide_channel = 0:0
33 |
34 | [Floppy and CD-ROM drives]
35 | fdd_01_type = 35_2hd
36 | fdd_02_type = none
37 |
--------------------------------------------------------------------------------
/MacBox/Templates/cmdr_pc_30_iii /86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = cmdpc30
3 | cpu_family = 286
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 12500000
8 | cpu = 3
9 | mem_size = 640
10 |
11 | [Storage controllers]
12 | hdc = st506_at
13 |
14 | [Input devices]
15 | mouse_type = mssystems
16 |
17 | [Ports (COM & LPT)]
18 | serial2_enabled = 0
19 |
20 | [Video]
21 | gfxcard = egawonder800p
22 |
23 | [Sound]
24 | fm_driver = nuked
25 |
26 | [ATI EGA Wonder 800+]
27 | memory = 256
28 | monitor_type = 9
29 |
30 | [Hard disks]
31 | hdd_01_parameters = 17, 4, 615, 0, mfm
32 | hdd_01_mfm_channel = 0
33 | hdd_01_fn = disks/hdd.IMG
34 |
35 | [Floppy and CD-ROM drives]
36 | fdd_02_type = none
37 | fdd_01_type = 35_2hd
38 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_plus/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = portable
3 | cpu_family = 8088
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 4772728
8 | mem_size = 128
9 |
10 | [Storage controllers]
11 | hdc = st506_xt_dtc5150x
12 |
13 | [Input devices]
14 | mouse_type = none
15 |
16 | [Ports (COM & LPT)]
17 | serial2_enabled = 0
18 |
19 | [Video]
20 | gfxcard = compaq_cga
21 |
22 | [Sound]
23 | fm_driver = nuked
24 |
25 | [Compaq CGA]
26 | display_type = 0
27 | composite_type = 0
28 | rgb_type = 1
29 | snow_enabled = 1
30 |
31 | [Hard disks]
32 | hdd_01_parameters = 17, 4, 306, 0, mfm
33 | hdd_01_mfm_channel = 0
34 | hdd_01_fn = disks/hdd.IMG
35 |
36 | [Floppy and CD-ROM drives]
37 | fdd_02_type = none
38 |
--------------------------------------------------------------------------------
/MacBox/Structs/GithubResponseObject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GithubResponseObject.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 1/8/24.
6 | //
7 |
8 | struct GithubResponseObject: Decodable {
9 | let url: String?
10 | let html_url: String?
11 | let tag_name: String?
12 | let body: String?
13 | let published_at: String?
14 | let sha: String?
15 | let assets: [GithubAsset]?
16 | let commit: GithubCommit?
17 | }
18 |
19 | struct GithubAsset: Decodable {
20 | let url: String?
21 | let browser_download_url: String?
22 | }
23 |
24 | struct GithubCommit: Decodable {
25 | let author: GithubCommitAuthor?
26 | }
27 |
28 | struct GithubCommitAuthor: Decodable {
29 | let name: String?
30 | let date: String?
31 | }
32 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_ii/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = portableii
3 | cpu_family = 286
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 8000000
8 | cpu = 1
9 | mem_size = 640
10 |
11 | [Storage controllers]
12 | hdc = st506_at
13 |
14 | [Input devices]
15 | mouse_type = mssystems
16 |
17 | [Ports (COM & LPT)]
18 | serial2_enabled = 0
19 |
20 | [Video]
21 | gfxcard = compaq_cga_2
22 |
23 | [Sound]
24 | fm_driver = nuked
25 |
26 | [Compaq CGA 2]
27 | display_type = 0
28 | composite_type = 0
29 | rgb_type = 1
30 | double_type = 1
31 | snow_enabled = 1
32 |
33 | [Hard disks]
34 | hdd_01_parameters = 17, 4, 306, 0, mfm
35 | hdd_01_mfm_channel = 0
36 | hdd_01_fn = disks/hdd.IMG
37 |
38 | [Floppy and CD-ROM drives]
39 | fdd_02_type = none
40 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_386/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = portableiii386
3 | cpu_family = i386dx
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 20000000
8 | cpu = 1
9 | fpu_type = 387
10 | mem_size = 1024
11 |
12 | [Storage controllers]
13 | hdc = st506_at
14 |
15 | [Input devices]
16 | mouse_type = mssystems
17 |
18 | [Ports (COM & LPT)]
19 | serial2_enabled = 0
20 |
21 | [Video]
22 | gfxcard = internal
23 |
24 | [Sound]
25 | fm_driver = nuked
26 |
27 | [Compaq Plasma]
28 | display_type = 0
29 | composite_type = 0
30 | rgb_type = 2
31 |
32 | [Hard disks]
33 | hdd_01_parameters = 17, 6, 805, 0, mfm
34 | hdd_01_mfm_channel = 0
35 | hdd_01_fn = disks/hdd.IMG
36 |
37 | [Floppy and CD-ROM drives]
38 | fdd_02_type = none
39 | fdd_01_type = 525_2hd
40 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_portable_iii/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = portableiii
3 | cpu_family = 286
4 | cpu_multi = 1
5 | cpu_use_dynarec = 0
6 | time_sync = disabled
7 | cpu_speed = 12500000
8 | cpu = 3
9 | mem_size = 640
10 |
11 | [Storage controllers]
12 | hdc = st506_xt_wd1004a_wx1
13 |
14 | [Input devices]
15 | mouse_type = mssystems
16 |
17 | [Ports (COM & LPT)]
18 | serial2_enabled = 0
19 |
20 | [Video]
21 | gfxcard = internal
22 |
23 | [Sound]
24 | fm_driver = nuked
25 |
26 | [Compaq Plasma]
27 | display_type = 0
28 | composite_type = 0
29 | rgb_type = 2
30 |
31 | [Hard disks]
32 | hdd_01_parameters = 17, 4, 615, 0, ide
33 | hdd_01_fn = disks/hdd.IMG
34 | hdd_01_speed = 1989_3500rpm
35 | hdd_01_ide_channel = 0:0
36 |
37 | [Floppy and CD-ROM drives]
38 | fdd_02_type = none
39 | fdd_01_type = 525_2hd
40 |
--------------------------------------------------------------------------------
/MacBox/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/9/23.
6 | //
7 |
8 | import Cocoa
9 |
10 | @main
11 | class AppDelegate: NSObject, NSApplicationDelegate {
12 |
13 | func applicationDidFinishLaunching(_ aNotification: Notification) {
14 | // Insert code here to initialize your application
15 | }
16 |
17 | func applicationWillTerminate(_ aNotification: Notification) {
18 | // Insert code here to tear down your application
19 | if let mainVC = MainViewController.instance {
20 | mainVC.screensaverManager.enableScreensaver()
21 | }
22 | }
23 |
24 | func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
25 | return true
26 | }
27 |
28 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
29 | return true
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/NEC_logo.imageset/NEC_logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MacBox/Extensions/FileManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FileManager.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/18/23.
6 | //
7 |
8 | import Foundation
9 |
10 | extension FileManager {
11 | func sizeOfFile(atPath path: String) -> Int64? {
12 | guard let attrs = try? attributesOfItem(atPath: path) else {
13 | return nil
14 | }
15 |
16 | return attrs[.size] as? Int64
17 | }
18 |
19 | func sizeOfDirectory(atPath path: String) -> Int? {
20 | let url = URL(fileURLWithPath: path)
21 | if let enumerator = self.enumerator(at: url, includingPropertiesForKeys: [.totalFileAllocatedSizeKey, .fileAllocatedSizeKey], options: [], errorHandler: { (_, error) -> Bool in
22 | print("Error: \(error.localizedDescription)")
23 | return false
24 | }) {
25 | var bytes = 0
26 | for case let url as URL in enumerator {
27 | bytes += url.fileSize ?? 0
28 | }
29 | return bytes
30 | } else {
31 | return nil
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/MacBox/Classes/ScreensaverManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScreensaverManager.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 5/18/24.
6 | //
7 |
8 | import IOKit.pwr_mgt
9 |
10 | class ScreensaverManager {
11 | private var assertionID: IOPMAssertionID = 0
12 | private let assertionName = "Moonif.MacBox.preventsleep" as CFString
13 | var sleepDisabled = false
14 |
15 | // Disable screensaver & screen sleep
16 | func disableScreensaver() {
17 | if !sleepDisabled {
18 | sleepDisabled = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep as CFString,
19 | IOPMAssertionLevel(kIOPMAssertionLevelOn),
20 | assertionName,
21 | &assertionID) == kIOReturnSuccess
22 | }
23 | }
24 |
25 | // Enable screensaver & screen sleep (release the assertion)
26 | func enableScreensaver() {
27 | if sleepDisabled {
28 | IOPMAssertionRelease(assertionID)
29 | sleepDisabled = false
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "filename" : "Icon-MacOS-512x512.png",
45 | "idiom" : "mac",
46 | "scale" : "1x",
47 | "size" : "512x512"
48 | },
49 | {
50 | "filename" : "Icon-MacOS-512x512@2x.png",
51 | "idiom" : "mac",
52 | "scale" : "2x",
53 | "size" : "512x512"
54 | }
55 | ],
56 | "info" : {
57 | "author" : "xcode",
58 | "version" : 1
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/MacBox/Templates/cpq_presario_4532/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = presario4500
3 | cpu_family = pentium_p55c
4 | cpu_speed = 200000000
5 | cpu_multi = 3
6 | fpu_type = internal
7 | cpu_use_dynarec = 1
8 | time_sync = disabled
9 | cpu = 11
10 | mem_size = 32768
11 |
12 | [Storage controllers]
13 | hdc = internal
14 |
15 | [Input devices]
16 | mouse_type = ps2
17 |
18 | [Standard PS/2 Mouse]
19 | buttons = 2
20 |
21 | [Video]
22 | gfxcard = internal
23 |
24 | [S3 Trio64V2/DX On-Board PCI]
25 | memory = 2
26 |
27 | [Sound]
28 | sndcard = sbawe32
29 | midi_device = mt32
30 | fm_driver = nuked
31 |
32 | [Sound Blaster AWE32]
33 | base = 0220
34 | emu_base = 0620
35 | base401 = 0330
36 | irq = 5
37 | dma = 1
38 | dma16 = 5
39 | onboard_ram = 512
40 | opl = 1
41 | receive_input = 1
42 | receive_input401 = 1
43 |
44 | [Roland MT-32 Emulation]
45 | output_gain = 100
46 | reverb = 1
47 | reverb_output_gain = 100
48 | reversed_stereo = 0
49 | nice_ramp = 1
50 |
51 | [Hard disks]
52 | hdd_01_parameters = 63, 16, 6501, 0, ide
53 | hdd_01_ide_channel = 0:0
54 | hdd_01_speed = 1997_5400rpm
55 | hdd_01_fn = disks/hdd.IMG
56 |
57 | [Floppy and CD-ROM drives]
58 | fdd_01_type = 35_2hd
59 | fdd_02_type = none
60 | cdrom_01_speed = 16
61 | cdrom_01_parameters = 1, atapi
62 | cdrom_01_ide_channel = 0:1
63 | cdrom_01_type = 86BOX_CD-ROM_1.00
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MacBox for 86Box
2 |
3 | [](LICENSE) [](https://github.com/Moonif/MacBox/releases) [](https://github.com/Moonif/MacBox/releases) [](https://sonarcloud.io/summary/new_code?id=Moonif_MacBox)
4 |
5 | MacBox is an optional manager app for the [86Box emulator](https://github.com/86Box/86Box) to make it easier to handle multiple virtual machines.
6 |
It's written in Swift and supports both Apple Silicon and Intel based machines.
7 |
8 | 
9 |
10 | # Features
11 | * Create and manage multiple virtual machines.
12 | * You can create virtual machines from templates based on real hardware settings.
13 | * Easily import previously created 86Box virtual machines into MacBox.
14 | * Keep your 86Box, ROMs and MacBox up-to-date with the built-in version manager.
15 | * Set a custom 86Box version for each virtual machine.
16 |
17 | # Screenshot
18 | 
19 |
20 | # System requirements
21 | * macOS Mojave 10.14 or higher.
22 |
--------------------------------------------------------------------------------
/MacBox/Templates/pb_platinum_55/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = pb680
3 | cpu_family = pentium_p54c
4 | cpu_speed = 133333333
5 | cpu_multi = 2
6 | fpu_type = internal
7 | cpu_use_dynarec = 1
8 | time_sync = disabled
9 | cpu = 6
10 | mem_size = 16384
11 |
12 | [Storage controllers]
13 | hdc = internal
14 |
15 | [Input devices]
16 | mouse_type = logibus
17 |
18 | [Logitech/Microsoft Bus Mouse]
19 | base = 023C
20 | irq = 5
21 | hz = 45
22 | buttons = 2
23 |
24 | [Video]
25 | gfxcard = virge325_pci
26 |
27 | [S3 ViRGE (325) PCI]
28 | memory = 2
29 | bilinear = 1
30 | dithering = 1
31 |
32 | [Sound]
33 | sndcard = azt2316a
34 | midi_device = cm32l
35 | fm_driver = nuked
36 |
37 | [Aztech Sound Galaxy Pro 16 AB (Washington)]
38 | codec = 1
39 | wss_interrupt_after_config = 0
40 | addr = 0000
41 | wss_irq = 10
42 | wss_dma = 0
43 | opl = 1
44 | receive_input = 1
45 | receive_input401 = 1
46 |
47 | [Roland CM-32L Emulation]
48 | output_gain = 100
49 | reverb = 1
50 | reverb_output_gain = 100
51 | reversed_stereo = 0
52 | nice_ramp = 1
53 |
54 | [Hard disks]
55 | hdd_01_parameters = 63, 16, 3250, 0, ide
56 | hdd_01_fn = disks/hdd.IMG
57 | hdd_01_speed = 1996_5400rpm
58 | hdd_01_ide_channel = 0:0
59 |
60 | [Floppy and CD-ROM drives]
61 | fdd_01_type = 35_2hd
62 | fdd_02_type = none
63 | cdrom_01_parameters = 1, atapi
64 | cdrom_01_ide_channel = 0:1
65 | cdrom_01_type = NEC_CD-ROM_DRIVE280_1.05
66 |
67 | [Other removable devices]
68 | zip_01_parameters = 0, atapi
69 | zip_01_ide_channel = 1:0
70 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Tandy_logo.imageset/Tandy_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
22 |
--------------------------------------------------------------------------------
/MacBox/Templates/dell_dim_xps_p60/86box.cfg:
--------------------------------------------------------------------------------
1 | [Machine]
2 | machine = dellxp60
3 | cpu_family = pentium_p5
4 | cpu_speed = 60000000
5 | cpu_multi = 1
6 | fpu_type = internal
7 | cpu_use_dynarec = 1
8 | time_sync = disabled
9 | mem_size = 16384
10 | fpu_softfloat = 0
11 |
12 | [Storage controllers]
13 | hdc = internal
14 |
15 | [Input devices]
16 | mouse_type = logibus
17 |
18 | [Logitech/Microsoft Bus Mouse]
19 | base = 023C
20 | irq = 5
21 | hz = 45
22 | buttons = 2
23 |
24 | [Video]
25 | gfxcard = virge325_pci
26 |
27 | [S3 ViRGE (325) PCI]
28 | memory = 2
29 | bilinear = 1
30 | dithering = 1
31 |
32 | [Sound]
33 | sndcard = azt2316a
34 | midi_device = cm32l
35 | fm_driver = nuked
36 |
37 | [Aztech Sound Galaxy Pro 16 AB (Washington)]
38 | codec = 1
39 | wss_interrupt_after_config = 0
40 | addr = 0000
41 | wss_irq = 10
42 | wss_dma = 0
43 | opl = 1
44 | receive_input = 1
45 | receive_input401 = 1
46 |
47 | [Roland CM-32L Emulation]
48 | output_gain = 100
49 | reverb = 1
50 | reverb_output_gain = 100
51 | reversed_stereo = 0
52 | nice_ramp = 1
53 |
54 | [Hard disks]
55 | hdd_01_parameters = 63, 16, 3250, 0, ide
56 | hdd_01_fn = disks/hdd.IMG
57 | hdd_01_speed = 1996_5400rpm
58 | hdd_01_ide_channel = 0:0
59 |
60 | [Floppy and CD-ROM drives]
61 | fdd_01_type = 35_2hd
62 | fdd_02_type = none
63 | cdrom_01_parameters = 1, atapi
64 | cdrom_01_ide_channel = 0:1
65 | cdrom_01_type = NEC_CD-ROM_DRIVE280_1.05
66 |
67 | [Other removable devices]
68 | zip_01_parameters = 0, atapi
69 | zip_01_ide_channel = 1:0
70 |
71 | [General]
72 | vid_renderer = qt_software
73 |
74 |
--------------------------------------------------------------------------------
/MacBox/Structs/JenkinsResponseObject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JenkinsResponseObject.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 1/17/24.
6 | //
7 |
8 | import Cocoa
9 |
10 | struct JenkinsResponseObject: Decodable {
11 | let id: String?
12 | let number: Int?
13 | let timestamp: Double?
14 | let url: String?
15 | let artifacts: [JenkinsArtifact]?
16 | let changeSets: [JenkinsChangeSets]?
17 | }
18 |
19 | struct JenkinsArtifact: Decodable {
20 | let fileName: String?
21 | let relativePath: String?
22 | }
23 |
24 | struct JenkinsChangeSets: Decodable {
25 | let items: [JenkinsChangeSetItem]?
26 | }
27 |
28 | struct JenkinsChangeSetItem: Decodable {
29 | let msg: String?
30 | let comment: String?
31 | }
32 |
33 | extension JenkinsResponseObject {
34 | func toGithubResponseObject() -> GithubResponseObject {
35 | // Convert timestamp to date
36 | let dateVal = TimeInterval(timestamp ?? 0) / 1000.0
37 | let date = Date(timeIntervalSince1970: dateVal)
38 | let formattedDate = date.getFormattedDate(format: "yyyy-MM-dd'T'HH:mm:ssZ")
39 |
40 | // Convert artifacts to assets
41 | var assets = [GithubAsset]()
42 | for artifact in artifacts ?? [] {
43 | let asset = GithubAsset(url: artifact.fileName, browser_download_url: artifact.relativePath)
44 | assets.append(asset)
45 | }
46 |
47 | let githubObject = GithubResponseObject(
48 | url: url,
49 | html_url: nil,
50 | tag_name: id,
51 | body: changeSets?.first?.items?.first?.comment,
52 | published_at: formattedDate,
53 | sha: nil,
54 | assets: assets,
55 | commit: nil
56 | )
57 |
58 | return githubObject
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/MacBox/Utils/IniParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IniParser.swift
3 | // MacBox
4 | //
5 |
6 | import Foundation
7 |
8 | class IniParser {
9 | typealias SectionConfig = [String: String]
10 | typealias Config = [String: SectionConfig]
11 |
12 | private func trim(_ s: String) -> String {
13 | let whitespaces = CharacterSet(charactersIn: " \n\r\t")
14 | return s.trimmingCharacters(in: whitespaces)
15 | }
16 |
17 | private func stripComment(_ line: String) -> String {
18 | let parts = line.split(
19 | separator: "#",
20 | maxSplits: 1,
21 | omittingEmptySubsequences: false)
22 | if parts.count > 0 {
23 | return String(parts[0])
24 | }
25 | return ""
26 | }
27 |
28 | private func parseSectionHeader(_ line: String) -> String {
29 | let from = line.index(after: line.startIndex)
30 | let to = line.index(before: line.endIndex)
31 | return String(line[from.. (String, String)? {
35 | let parts = stripComment(line).split(separator: "=", maxSplits: 1)
36 | if parts.count == 2 {
37 | let k = trim(String(parts[0]))
38 | let v = trim(String(parts[1]))
39 | return (k, v)
40 | }
41 | return nil
42 | }
43 |
44 | func parseConfig(_ filename : String) -> Config {
45 | var config = Config()
46 |
47 | if let f = try? String(contentsOfFile: filename) {
48 | var currentSectionName = "main"
49 | for l in f.components(separatedBy: "\n") {
50 | let line = trim(l)
51 | if line.hasPrefix("[") && line.hasSuffix("]") {
52 | currentSectionName = parseSectionHeader(line)
53 | } else if let (k, v) = parseLine(line) {
54 | var section = config[currentSectionName] ?? [:]
55 | section[k] = v
56 | config[currentSectionName] = section
57 | }
58 | }
59 | }
60 |
61 | return config
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Compaq_logo_old.imageset/Compaq_logo_old.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Dell_logo.imageset/Dell_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
54 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Tandy_logo.imageset/Tandy_logo 1.svg:
--------------------------------------------------------------------------------
1 |
2 |
81 |
--------------------------------------------------------------------------------
/MacBox.xcodeproj/xcshareddata/xcschemes/MacBox.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
42 |
44 |
50 |
51 |
52 |
53 |
59 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Epson_logo.imageset/Epson_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
72 |
--------------------------------------------------------------------------------
/MacBox/Classes/SpecsParser.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpecsParser.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/26/23.
6 | //
7 |
8 | import Foundation
9 |
10 | class SpecsParser {
11 |
12 | // Parse config file and return machine specs in a string format
13 | public func parseVMConfigFile(vmConfigPath: String) -> (machine: String, cpu: String, ram: String, hdd: String) {
14 | var machineString = ""
15 | var cpuString = ""
16 | var ramString = ""
17 | var hddString = ""
18 |
19 | let ini = IniParser()
20 | // Parse machine type
21 | let machineType = ini.parseConfig(vmConfigPath)["Machine"]?["machine"]
22 | // Parse cpu family
23 | let cpuFamily = ini.parseConfig(vmConfigPath)["Machine"]?["cpu_family"]
24 | // Parse cpu speed
25 | let cpuSpeed = ini.parseConfig(vmConfigPath)["Machine"]?["cpu_speed"] ?? "0"
26 | // Parse ram size
27 | let ramSize = ini.parseConfig(vmConfigPath)["Machine"]?["mem_size"] ?? "0"
28 | // Parse ram expansion size
29 | let ramExpansionSize = ini.parseConfig(vmConfigPath)["IBM PC/XT Memory Expansion #1"]?["size"] ?? "0"
30 | // Parse hdd size
31 | let hddPath = ini.parseConfig(vmConfigPath)["Hard disks"]?["hdd_01_fn"] ?? nil
32 | // Parse hdd parameters
33 | let hddParams = ini.parseConfig(vmConfigPath)["Hard disks"]?["hdd_01_parameters"] ?? ""
34 | let hddParamsSplit = hddParams.split(separator: ",")
35 | var hddS: Int64 = 0
36 | var hddH: Int64 = 0
37 | var hddC: Int64 = 0
38 | if hddParamsSplit.count > 0 {
39 | hddS = Int64(hddParamsSplit[0].trimmingCharacters(in: .whitespaces)) ?? 0
40 | hddH = Int64(hddParamsSplit[1].trimmingCharacters(in: .whitespaces)) ?? 0
41 | hddC = Int64(hddParamsSplit[2].trimmingCharacters(in: .whitespaces)) ?? 0
42 | }
43 |
44 | // Parse and define devices name
45 | let nameDefs = Bundle.main.path(forResource: "namedefs.inf", ofType: nil)
46 |
47 | // Define machine type name
48 | if let machinesDef = (ini.parseConfig(nameDefs ?? "")["machine"]) {
49 | if machinesDef[machineType ?? ""] != nil {
50 | machineString = machinesDef[machineType ?? ""] ?? "-"
51 | }
52 | else {
53 | machineString = machineType ?? "-"
54 | }
55 | }
56 |
57 | // Define cpu family name
58 | var cpuFamilyName = ""
59 | if let cpuDef = (ini.parseConfig(nameDefs ?? "")["cpu_family"]) {
60 | if cpuDef[cpuFamily ?? ""] != nil {
61 | cpuFamilyName = cpuDef[cpuFamily ?? ""] ?? "-"
62 | }
63 | else {
64 | cpuFamilyName = cpuFamily ?? "-"
65 | }
66 | }
67 |
68 | // Define cpu speed
69 | let cpuSpeedConverted = (Float(cpuSpeed) ?? 0.0) / 1000000
70 | let cpuSpeedRounded = String(format: "%.2f", cpuSpeedConverted)
71 | cpuString = "\(cpuFamilyName) \(cpuSpeedRounded) MHz"
72 |
73 | // Define and format ram size
74 | let ramBCF = ByteCountFormatter()
75 | ramBCF.allowedUnits = [.useAll]
76 | ramBCF.countStyle = .memory
77 | let ramSizeConverted = ramBCF.string(fromByteCount: (Int64(ramSize) ?? 0) * 1024)
78 | ramString = "RAM \(ramSizeConverted)"
79 |
80 | // Define ram expansion
81 | if Int64(ramExpansionSize) ?? 0 > 0 {
82 | let ramExpansionSizeConverted = ramBCF.string(fromByteCount: (Int64(ramExpansionSize) ?? 0) * 1024)
83 | ramString = "RAM \(ramSizeConverted) + \(ramExpansionSizeConverted) Expansion"
84 | }
85 |
86 | // Define hdd size
87 | if hddPath != nil {
88 | // Calculate hdd size
89 | let hddSize = hddS * hddH * hddC * 512
90 | // Format hdd size
91 | let hddBCF = ByteCountFormatter()
92 | hddBCF.allowedUnits = [.useAll]
93 | hddBCF.countStyle = .binary
94 | let hddSizeConverted = hddBCF.string(fromByteCount: hddSize)
95 | hddString = "HDD \(hddSizeConverted)"
96 | }
97 | else {
98 | hddString = "No HDD"
99 | }
100 | // Return strings
101 | return (machineString, cpuString, ramString, hddString)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Pb_logo.imageset/Pb_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/IBM_logo.imageset/IBM_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
55 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Pb_logo_old.imageset/Pb_logo_old.svg:
--------------------------------------------------------------------------------
1 |
2 |
28 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Compaq_logo_old.imageset/Compaq_logo_old 1.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
130 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Compaq_logo.imageset/Compaq_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Pb_logo_old.imageset/Pb_logo_old 1.svg:
--------------------------------------------------------------------------------
1 |
2 |
108 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Commodore_logo.imageset/Commodore_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
29 |
--------------------------------------------------------------------------------
/MacBox/Assets.xcassets/logos/Amstrad_logo.imageset/Amstrad_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
47 |
48 |
--------------------------------------------------------------------------------
/MacBox/ViewControllers/AddVMViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddVMViewController.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/10/23.
6 | //
7 |
8 | import Cocoa
9 |
10 | class AddVMViewController: NSViewController {
11 |
12 | // IBOutlets
13 | @IBOutlet weak var vmNameTextField: NSTextField!
14 | @IBOutlet var vmDescriptionTextView: NSTextView!
15 | @IBOutlet weak var vmPathStatusTextField: NSTextField!
16 | @IBOutlet weak var vmTemplateComboBox: NSComboBox!
17 | @IBOutlet weak var vmSpecMachine: NSTextField!
18 | @IBOutlet weak var vmSpecCPU: NSTextField!
19 | @IBOutlet weak var vmSpecRAM: NSTextField!
20 | @IBOutlet weak var vmSpecHDD: NSTextField!
21 | @IBOutlet weak var vmSpecMachineLogo: NSImageView!
22 | @IBOutlet weak var vmTemplateShaderOption: NSButton!
23 |
24 | // Variables
25 | private let fileManager = FileManager.default
26 | var vmTemplateList: [VMTemplate] = []
27 | var currentVMTemplate: VMTemplate?
28 |
29 | let nameTextFieldMaxLimit: Int = 32
30 |
31 | // View did load
32 | override func viewDidLoad() {
33 | super.viewDidLoad()
34 |
35 | // Set delegates
36 | vmNameTextField.delegate = self
37 | vmTemplateComboBox.delegate = self
38 | vmTemplateComboBox.dataSource = self
39 |
40 | // Config views
41 | configView()
42 |
43 | // Populate VM templates
44 | populateVMTemplates()
45 | }
46 |
47 | // View will appear
48 | override func viewWillAppear() {
49 | // Remove fullscreen window button
50 | self.view.window?.styleMask.remove(.fullScreen)
51 | self.view.window?.styleMask.remove(.resizable)
52 | }
53 |
54 | // Config views initial properties
55 | private func configView() {
56 | // Specs text
57 | vmSpecMachine.stringValue = "-"
58 | vmSpecCPU.stringValue = "-"
59 | vmSpecRAM.stringValue = "-"
60 | vmSpecHDD.stringValue = "-"
61 | vmSpecMachineLogo.image = nil
62 | // Patch status text
63 | let homeDirPath = MainViewController.instance.homeDirURL.path
64 | vmPathStatusTextField.stringValue = String(format: NSLocalizedString("VM will be created at: \"%@\".", comment: ""), homeDirPath)
65 | // Shader option
66 | vmTemplateShaderOption.isTransparent = true
67 | }
68 |
69 | // Populate VM templates
70 | private func populateVMTemplates() {
71 | // Clear list
72 | vmTemplateList.removeAll()
73 | // Add default item
74 | vmTemplateList.append(VMTemplate())
75 |
76 | // Add VM templates paths
77 | var vmTemplateListSort: [VMTemplate] = []
78 | let vmTemplatesPaths = Bundle.main.paths(forResourcesOfType: nil, inDirectory: "Templates")
79 | for path in vmTemplatesPaths {
80 | // Create and add VM template
81 | var vmTemplate = VMTemplate()
82 |
83 | // Set template data paths
84 | vmTemplate.infoPath = path.appending("/macbox.inf")
85 | vmTemplate.configPath = path.appending("/86box.cfg")
86 |
87 | if fileManager.fileExists(atPath: vmTemplate.infoPath ?? "") {
88 | let ini = IniParser()
89 |
90 | let vmTemplateDescription = ini.parseConfig(vmTemplate.infoPath ?? "")["General"]?["Description"] ?? ""
91 | let vmTemplateYear = ini.parseConfig(vmTemplate.infoPath ?? "")["General"]?["Year"] ?? ""
92 |
93 | // VM template name
94 | vmTemplate.name = vmTemplateDescription
95 | // VM template year
96 | vmTemplate.year = vmTemplateYear
97 | // VM template logo
98 | if let machineLogo = ini.parseConfig(vmTemplate.infoPath ?? "")["General"]?["Logo"] {
99 | vmTemplate.machineLogo = machineLogo
100 | }
101 | }
102 |
103 | vmTemplateListSort.append(vmTemplate)
104 | }
105 | // Add and sort VM templates list
106 | vmTemplateList.append(contentsOf: vmTemplateListSort.sorted(by: { $0.year ?? "" < $1.year ?? "" }))
107 |
108 | // Reload combo box data
109 | vmTemplateComboBox.reloadData()
110 | }
111 |
112 | // Create VM
113 | private func createVM(name: String, description: String?, path: String?, logo: String?) -> VM {
114 | var vm = VM()
115 |
116 | // Set VM properties
117 | vm.name = name
118 | vm.description = description
119 | vm.path = path
120 | vm.logo = logo
121 |
122 | return vm
123 | }
124 |
125 | // Set current VM specs
126 | private func setVMSpecs(vmConfigPath: String) {
127 | if vmConfigPath != "" {
128 | // Parse config file and return string values
129 | let specsParser = SpecsParser()
130 | let parsedSpecs = specsParser.parseVMConfigFile(vmConfigPath: vmConfigPath)
131 | // Set specs strings
132 | vmSpecMachine.stringValue = parsedSpecs.machine
133 | vmSpecCPU.stringValue = parsedSpecs.cpu
134 | vmSpecRAM.stringValue = parsedSpecs.ram
135 | vmSpecHDD.stringValue = parsedSpecs.hdd
136 |
137 | // Define machine logo
138 | if let machineLogo = currentVMTemplate?.machineLogo {
139 | vmSpecMachineLogo.image = NSImage(named: machineLogo)
140 | }
141 | else {
142 | vmSpecMachineLogo.image = nil
143 | }
144 | }
145 | else {
146 | // Empty template selected
147 | vmSpecMachine.stringValue = "-"
148 | vmSpecCPU.stringValue = "-"
149 | vmSpecRAM.stringValue = "-"
150 | vmSpecHDD.stringValue = "-"
151 | vmSpecMachineLogo.image = nil
152 | }
153 | }
154 |
155 | // ------------------------------------
156 | // IBActions
157 | // ------------------------------------
158 |
159 | // Add VM button action
160 | @IBAction func addVMButtonAction(_ sender: NSButton) {
161 | // Check if VM name was provided
162 | if vmNameTextField.stringValue.isEmpty {
163 | vmNameTextField.backgroundColor = .systemRed
164 | vmNameTextField.becomeFirstResponder()
165 | return
166 | }
167 |
168 | // Check if VM name was already taken
169 | for vmListEntry in MainViewController.instance.vmList {
170 | if vmNameTextField.stringValue == vmListEntry.name {
171 | // Show name taken alert
172 | let alert = NSAlert()
173 |
174 | alert.messageText = NSLocalizedString("VM name is already taken!", comment: "")
175 | alert.alertStyle = .critical
176 | alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
177 |
178 | let _ = alert.runModal()
179 |
180 | return
181 | }
182 | }
183 |
184 | // Create a VM and add it to the table view
185 | var logo: String?
186 | if vmTemplateComboBox.indexOfSelectedItem > 0 {
187 | // Logo
188 | if let machineLogo = currentVMTemplate?.machineLogo {
189 | logo = machineLogo
190 | }
191 | // Shader
192 | if vmTemplateShaderOption.state == .on {
193 | currentVMTemplate?.useShader = true
194 | }
195 | }
196 |
197 | let vm = createVM(name: vmNameTextField.stringValue, description: vmDescriptionTextView.string, path: nil, logo: logo)
198 | MainViewController.instance.addVM(vm: vm, vmTemplate: currentVMTemplate)
199 |
200 | // Dismiss the add VM tabVC modal view
201 | if let tabVC = self.parent as? NSTabViewController {
202 | dismiss(tabVC)
203 | }
204 | }
205 | }
206 |
207 | // ------------------------------------
208 | // TextField Delegate
209 | // ------------------------------------
210 | extension AddVMViewController: NSTextFieldDelegate {
211 | func controlTextDidChange(_ obj: Notification) {
212 | if let textField = obj.object as? NSTextField {
213 | textField.backgroundColor = NSColor.textBackgroundColor
214 | if textField.stringValue.count > nameTextFieldMaxLimit {
215 | textField.stringValue = String(textField.stringValue.dropLast())
216 | }
217 | }
218 | }
219 | }
220 |
221 | // ------------------------------------
222 | // VMTemplate ComboBox Delegate
223 | // ------------------------------------
224 | extension AddVMViewController: NSComboBoxDelegate, NSComboBoxDataSource {
225 | func numberOfItems(in comboBox: NSComboBox) -> Int {
226 | return vmTemplateList.count
227 | }
228 |
229 | func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
230 | var vmDescription = ""
231 | if let vmYear = vmTemplateList[index].year {
232 | vmDescription.append("[\(vmYear)]")
233 | }
234 | if let vmName = vmTemplateList[index].name {
235 | vmDescription.append(" \(vmName)")
236 | }
237 | return vmDescription
238 | }
239 |
240 | func comboBoxSelectionDidChange(_ notification: Notification) {
241 | if vmTemplateComboBox.indexOfSelectedItem >= 0 {
242 | // Set shader option
243 | if vmTemplateComboBox.indexOfSelectedItem > 0 {
244 | vmTemplateShaderOption.isTransparent = false
245 | vmTemplateShaderOption.state = .on
246 | }
247 | else {
248 | vmTemplateShaderOption.isTransparent = true
249 | }
250 | // Set current vm template
251 | let vmTemplate = vmTemplateList[vmTemplateComboBox.indexOfSelectedItem]
252 | currentVMTemplate = vmTemplateComboBox.indexOfSelectedItem == 0 ? nil : vmTemplate
253 | // Set current vm template specs
254 | setVMSpecs(vmConfigPath: vmTemplate.configPath ?? "")
255 | }
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/MacBox/ViewControllers/ImportVMViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImportVMViewController.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 4/13/23.
6 | //
7 |
8 | import Cocoa
9 |
10 | class ImportVMViewController: NSViewController {
11 |
12 | // IBOutlets
13 | @IBOutlet weak var configFilesTableView: NSTableView!
14 | @IBOutlet weak var spinningProgressIndicator: NSProgressIndicator!
15 | @IBOutlet weak var searchText: NSTextField!
16 | @IBOutlet weak var foundText: NSTextField!
17 | @IBOutlet weak var addButton: NSButton!
18 |
19 | // Variables
20 | private let fileManager = FileManager.default
21 | private var searchURL: URL?
22 | private var cancelSearch: Bool = false
23 | private var configFilesList: [String] = []
24 | private var importedVMPath : String?
25 |
26 | // View did load
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 |
30 | // Set delegates
31 | configFilesTableView.delegate = self
32 | configFilesTableView.dataSource = self
33 |
34 | // Set defaults
35 | searchURL = fileManager.homeDirectoryForCurrentUser
36 | }
37 |
38 | // Start the search when the view appear
39 | override func viewWillAppear() {
40 | // Config views
41 | configView()
42 |
43 | cancelSearch = false
44 | findConfigFiles()
45 | }
46 |
47 | // Cancel the search when the view disappear
48 | override func viewDidDisappear() {
49 | cancelSearch = true
50 | }
51 |
52 | // Config views initial properties
53 | private func configView() {
54 | spinningProgressIndicator.startAnimation(self)
55 | searchText.isHidden = false
56 | foundText.isHidden = true
57 | addButton.isEnabled = false
58 | }
59 |
60 | // Find 86Box config files
61 | private func findConfigFiles() {
62 | // Clear the config files list
63 | configFilesList.removeAll()
64 | configFilesTableView.reloadData()
65 |
66 | // Set the search path at the user's home directory
67 | let url = searchURL
68 | let localFileManager = FileManager()
69 |
70 | if let enumerator: FileManager.DirectoryEnumerator = localFileManager.enumerator(atPath: url?.path ?? "") {
71 | // Conduct the search as a background process as not to block the user interaction
72 | DispatchQueue.global(qos: .background).async {
73 | while let element = enumerator.nextObject() as? String {
74 | if self.cancelSearch {
75 | // Break the loop when cancel search is true
76 | break
77 | }
78 | let configFileSuffix = "/86box.cfg"
79 | guard element.hasSuffix(configFileSuffix) else { continue }
80 |
81 | let vmPath = "\(url?.path ?? "")/\(element)".dropLast(configFileSuffix.count)
82 |
83 | // Check if path already present in the VMs list
84 | let match = MainViewController.instance.vmList.contains(where: { vm in
85 | if let path = vm.path, path == vmPath {
86 | return true
87 | }
88 | return false
89 | })
90 |
91 | // If path is not present, add it for import
92 | if !match {
93 | self.configFilesList.append(String(vmPath))
94 | }
95 |
96 | DispatchQueue.main.async {
97 | self.configFilesTableView.reloadData()
98 | }
99 | }
100 | // Done
101 | DispatchQueue.main.async {
102 | self.spinningProgressIndicator.stopAnimation(self)
103 | self.searchText.isHidden = true
104 | self.foundText.isHidden = false
105 | if self.configFilesList.count > 0 {
106 | self.foundText.stringValue = String(format: NSLocalizedString("MacBox found %d VMs on your Mac, press the \"Add\" button to import them.", comment: ""), self.configFilesList.count)
107 | self.addButton.isEnabled = true
108 | }
109 | else {
110 | self.foundText.stringValue = NSLocalizedString("MacBox could not find any VM on your Mac.", comment: "")
111 | }
112 | }
113 | }
114 | }
115 | }
116 |
117 | // Create VM
118 | private func createVM(name: String, description: String?, path: String?) -> VM {
119 | var vm = VM()
120 |
121 | // Set name and description
122 | vm.name = name
123 | vm.description = description
124 |
125 | // Set path
126 | var defaultPath = MainViewController.instance.homeDirURL
127 | if #available(macOS 13.0, *) {
128 | defaultPath = defaultPath.appending(component: "\(vm.name ?? "")")
129 | } else {
130 | // Fallback on earlier versions
131 | defaultPath = defaultPath.appendingPathComponent("\(vm.name ?? "")")
132 | }
133 | vm.path = path != nil ? path : defaultPath.path
134 |
135 | return vm
136 | }
137 |
138 | // Dismiss the add VM tabVC modal view
139 | private func dismissView() {
140 | if let tabVC = self.parent as? NSTabViewController {
141 | dismiss(tabVC)
142 | }
143 | }
144 |
145 | // ------------------------------------
146 | // IBActions
147 | // ------------------------------------
148 |
149 | // Add button action
150 | @IBAction func addButtonAction(_ sender: NSButton) {
151 | for vmConfigPath in configFilesList {
152 | // Create a VM and add it to the table view
153 | let vmPathURL = URL(fileURLWithPath: vmConfigPath)
154 | let vm = createVM(name: vmPathURL.lastPathComponent, description: nil, path: vmConfigPath)
155 | MainViewController.instance.addVM(vm: vm)
156 | }
157 |
158 | // Dismiss the add VM tabVC modal view
159 | dismissView()
160 | }
161 |
162 | // Add manually button action
163 | @IBAction func addManuallyButtonAction(_ sender: NSButton) {
164 | // Cancel search
165 | cancelSearch = true
166 |
167 | // Open the file picker
168 | let filePickerPanel = NSOpenPanel()
169 |
170 | filePickerPanel.allowsMultipleSelection = false
171 | filePickerPanel.canChooseDirectories = true
172 | filePickerPanel.canChooseFiles = false
173 |
174 | if filePickerPanel.runModal() == .OK {
175 | if let vmDirectoryURL = filePickerPanel.url?.path {
176 | let vmConfigFileURL = vmDirectoryURL.appending("/86box.cfg")
177 | if fileManager.fileExists(atPath: vmConfigFileURL) {
178 | // 86Box config file was found
179 | importedVMPath = vmDirectoryURL
180 |
181 | // Check if path already present in the VMs list
182 | let match = MainViewController.instance.vmList.contains(where: { vm in
183 | if let path = vm.path, path == importedVMPath {
184 | return true
185 | }
186 | return false
187 | })
188 |
189 | if !match {
190 | // Create a VM and add it to the table view
191 | let vm = createVM(name: filePickerPanel.url?.lastPathComponent ?? "Imported VM", description: nil, path: importedVMPath)
192 | MainViewController.instance.addVM(vm: vm)
193 |
194 | // Dismiss the add VM tabVC modal view
195 | dismissView()
196 | }
197 | else {
198 | // Dismiss the add VM tabVC modal view
199 | dismissView()
200 |
201 | // Show error: Selected VM is already added
202 | let alert = NSAlert()
203 |
204 | alert.messageText = NSLocalizedString("Selected VM is already added!", comment: "")
205 | alert.alertStyle = .critical
206 | alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
207 |
208 | alert.runModal()
209 | }
210 | }
211 | else {
212 | // No 86Box was found at path
213 | importedVMPath = nil
214 |
215 | // Show error: No 86Box was found
216 | let alert = NSAlert()
217 |
218 | alert.messageText = NSLocalizedString("No 86Box config files was found!", comment: "")
219 | alert.alertStyle = .critical
220 | alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
221 |
222 | let alertResult = alert.runModal()
223 | if alertResult == .alertFirstButtonReturn {
224 | // Config views
225 | configView()
226 |
227 | cancelSearch = false
228 | findConfigFiles()
229 | }
230 | }
231 | }
232 | }
233 | else {
234 | // Config views
235 | configView()
236 |
237 | cancelSearch = false
238 | findConfigFiles()
239 | }
240 | }
241 |
242 | // Search popup button action
243 | @IBAction func searchPopUpButtonAction(_ sender: NSPopUpButton) {
244 | // Cancel current search
245 | cancelSearch = true
246 |
247 | // Set selected search directory
248 | switch sender.selectedItem?.identifier {
249 | case NSUserInterfaceItemIdentifier(rawValue: "searchItemHome") :
250 | searchURL = fileManager.homeDirectoryForCurrentUser
251 | case NSUserInterfaceItemIdentifier(rawValue: "searchItemDocuments") :
252 | searchURL = URL(fileURLWithPath: "Documents", isDirectory: true, relativeTo: fileManager.homeDirectoryForCurrentUser)
253 | case NSUserInterfaceItemIdentifier(rawValue: "searchItemCustom") :
254 | // Open the file picker
255 | let filePickerPanel = NSOpenPanel()
256 |
257 | filePickerPanel.allowsMultipleSelection = false
258 | filePickerPanel.canChooseDirectories = true
259 | filePickerPanel.canChooseFiles = false
260 |
261 | if filePickerPanel.runModal() == .OK, let customDirectoryURL = filePickerPanel.url {
262 | searchURL = customDirectoryURL
263 | }
264 | default:
265 | break
266 | }
267 |
268 | // Config views
269 | configView()
270 |
271 | cancelSearch = false
272 | findConfigFiles()
273 | }
274 | }
275 |
276 | // ------------------------------------
277 | // Config files TableView Delegate and Datasource
278 | // ------------------------------------
279 | extension ImportVMViewController: NSTableViewDelegate, NSTableViewDataSource {
280 | // Return number of cells for config files table view
281 | func numberOfRows(in tableView: NSTableView) -> Int {
282 | return configFilesList.count
283 | }
284 |
285 | // Populate cells based on configFilesList data
286 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
287 | let vmObject = configFilesList[row]
288 | let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "textCellID"), owner: self) as? NSTableCellView
289 | cell?.textField?.stringValue = vmObject
290 | return cell
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/MacBox/Shaders/crt-guest-cgwg-curvature.glsl:
--------------------------------------------------------------------------------
1 | /*
2 | CRT - Guest
3 | edited by metallic77
4 |
5 | Copyright (C) 2017-2018 guest(r) - guest.r@gmail.com
6 |
7 | This program is free software; you can redistribute it and/or
8 | modify it under the terms of the GNU General Public License
9 | as published by the Free Software Foundation; either version 2
10 | of the License, or (at your option) any later version.
11 |
12 | This program is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program; if not, write to the Free Software
19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 |
21 | */
22 |
23 | // Parameter lines go here:
24 | #pragma parameter brightboost "Bright boost" 1.0 0.5 2.0 0.05
25 | #pragma parameter sat "Saturation adjustment" 1.0 0.0 2.0 0.05
26 | #pragma parameter scanline "Scanline adjust" 8.0 1.0 12.0 1.0
27 | #pragma parameter beam_min "Scanline dark" 1.35 0.5 3.0 0.05
28 | #pragma parameter beam_max "Scanline bright" 1.05 0.5 3.0 0.05
29 | #pragma parameter h_sharp "Horizontal sharpness" 2.00 1.0 5.0 0.05
30 | #pragma parameter gamma_out "Gamma out" 0.5 0.2 0.6 0.01
31 | #pragma parameter shadowMask "CRT Mask: 0:CGWG, 1-4:Lottes, 5-6:'Trinitron'" 0.0 -1.0 10.0 1.0
32 | #pragma parameter masksize "CRT Mask Size (2.0 is nice in 4k)" 1.0 1.0 2.0 1.0
33 | #pragma parameter mcut "Mask 5-7-10 cutoff" 0.2 0.0 0.5 0.05
34 | #pragma parameter maskDark "Lottes maskDark" 0.5 0.0 2.0 0.1
35 | #pragma parameter maskLight "Lottes maskLight" 1.5 0.0 2.0 0.1
36 | #pragma parameter CGWG "CGWG Mask Str." 0.4 0.0 1.0 0.1
37 | #pragma parameter warpX "warpX" 0.0 0.0 0.125 0.01
38 | #pragma parameter warpY "warpY" 0.0 0.0 0.125 0.01
39 | #pragma parameter vignette "Vignette On/Off" 0.0 0.0 1.0 1.0
40 | #pragma parameter vpower "Vignette Power" 0.2 0.0 1.0 0.01
41 | #pragma parameter vstr "Vignette strength" 40.0 0.0 50.0 1.0
42 |
43 | #if defined(VERTEX)
44 |
45 | #if __VERSION__ >= 130
46 | #define COMPAT_VARYING out
47 | #define COMPAT_ATTRIBUTE in
48 | #define COMPAT_TEXTURE texture
49 | #else
50 | #define COMPAT_VARYING varying
51 | #define COMPAT_ATTRIBUTE attribute
52 | #define COMPAT_TEXTURE texture2D
53 | #endif
54 |
55 | #ifdef GL_ES
56 | #define COMPAT_PRECISION mediump
57 | #else
58 | #define COMPAT_PRECISION
59 | #endif
60 |
61 | COMPAT_ATTRIBUTE vec4 VertexCoord;
62 | COMPAT_ATTRIBUTE vec4 COLOR;
63 | COMPAT_ATTRIBUTE vec4 TexCoord;
64 | COMPAT_VARYING vec4 COL0;
65 | COMPAT_VARYING vec4 TEX0;
66 |
67 | vec4 _oPosition1;
68 | uniform mat4 MVPMatrix;
69 | uniform COMPAT_PRECISION int FrameDirection;
70 | uniform COMPAT_PRECISION int FrameCount;
71 | uniform COMPAT_PRECISION vec2 OutputSize;
72 | uniform COMPAT_PRECISION vec2 TextureSize;
73 | uniform COMPAT_PRECISION vec2 InputSize;
74 |
75 | void main()
76 | {
77 | gl_Position = MVPMatrix * VertexCoord;
78 | COL0 = COLOR;
79 | TEX0.xy = TexCoord.xy * 1.00001;
80 | }
81 |
82 | #elif defined(FRAGMENT)
83 |
84 | #if __VERSION__ >= 130
85 | #define COMPAT_VARYING in
86 | #define COMPAT_TEXTURE texture
87 | out vec4 FragColor;
88 | #else
89 | #define COMPAT_VARYING varying
90 | #define FragColor gl_FragColor
91 | #define COMPAT_TEXTURE texture2D
92 | #endif
93 |
94 | #ifdef GL_ES
95 | #ifdef GL_FRAGMENT_PRECISION_HIGH
96 | precision highp float;
97 | #else
98 | precision mediump float;
99 | #endif
100 | #define COMPAT_PRECISION mediump
101 | #else
102 | #define COMPAT_PRECISION
103 | #endif
104 |
105 | uniform COMPAT_PRECISION int FrameDirection;
106 | uniform COMPAT_PRECISION int FrameCount;
107 | uniform COMPAT_PRECISION vec2 OutputSize;
108 | uniform COMPAT_PRECISION vec2 TextureSize;
109 | uniform COMPAT_PRECISION vec2 InputSize;
110 | uniform sampler2D Texture;
111 | COMPAT_VARYING vec4 TEX0;
112 |
113 | // compatibility #defines
114 | #define Source Texture
115 | #define vTexCoord TEX0.xy
116 |
117 | #define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
118 | #define OutputSize vec4(OutputSize, 1.0 / OutputSize)
119 |
120 | #ifdef PARAMETER_UNIFORM
121 | // All parameter floats need to have COMPAT_PRECISION in front of them
122 | uniform COMPAT_PRECISION float brightboost;
123 | uniform COMPAT_PRECISION float scanline;
124 | uniform COMPAT_PRECISION float beam_min;
125 | uniform COMPAT_PRECISION float beam_max;
126 | uniform COMPAT_PRECISION float h_sharp;
127 | uniform COMPAT_PRECISION float gamma_out;
128 | uniform COMPAT_PRECISION float sat;
129 | uniform COMPAT_PRECISION float shadowMask;
130 | uniform COMPAT_PRECISION float masksize;
131 | uniform COMPAT_PRECISION float mcut;
132 | uniform COMPAT_PRECISION float maskDark;
133 | uniform COMPAT_PRECISION float maskLight;
134 | uniform COMPAT_PRECISION float CGWG;
135 | uniform COMPAT_PRECISION float warpX;
136 | uniform COMPAT_PRECISION float warpY;
137 | uniform COMPAT_PRECISION float vignette;
138 | uniform COMPAT_PRECISION float vpower;
139 | uniform COMPAT_PRECISION float vstr;
140 | #else
141 | #define brightboost 1.20 // adjust brightness
142 | #define scanline 8.0 // scanline param, vertical sharpness
143 | #define beam_min 1.35 // dark area beam min - wide
144 | #define beam_max 1.05 // bright area beam max - narrow
145 | #define h_sharp 1.25 // pixel sharpness
146 | #define gamma_out 0.50 // output gamma
147 | #define sat 1.0 // saturation
148 | #define shadowMask 0.0 // Shadow mask type
149 | #define masksize 1.0 // Shadow mask size
150 | #define mcut 0.20 // Mask 5&6 cutoff
151 | #define maskDark 0.50 // Dark "Phosphor"
152 | #define maskLight 1.50 // Light "Phosphor"
153 | #define CGWG 0.40 // CGWG Mask Strength
154 | #define warpX 0.0 // Curvature X
155 | #define warpY 0.0 // Curvature Y
156 | #define vignette 1.0
157 | #define vpower 0.2
158 | #define vstr 40.0
159 | #endif
160 |
161 | float sw (vec3 x,vec3 color)
162 | {
163 | float scan = mix(scanline-2.0,scanline,x.y);
164 | vec3 tmp = mix(vec3(beam_min),vec3(beam_max), color);
165 | vec3 ex = x*tmp;
166 | return exp2(-scan*ex.y*ex.y);
167 | }
168 |
169 | // Shadow mask (1-4 from PD CRT Lottes shader).
170 | vec3 Mask(vec2 pos, vec3 c)
171 | {
172 | pos = floor(pos/masksize);
173 | vec3 mask = vec3(maskDark, maskDark, maskDark);
174 |
175 | // No mask
176 | if (shadowMask == -1.0)
177 | {
178 | mask = vec3(1.0);
179 | }
180 |
181 | // Phosphor.
182 | else if (shadowMask == 0.0)
183 | {
184 | pos.x = fract(pos.x*0.5);
185 | float mc = 1.0 - CGWG;
186 | if (pos.x < 0.5) { mask.r = 1.1; mask.g = mc; mask.b = 1.1; }
187 | else { mask.r = mc; mask.g = 1.1; mask.b = mc; }
188 | }
189 |
190 | // Very compressed TV style shadow mask.
191 | else if (shadowMask == 1.0)
192 | {
193 | float line = maskLight;
194 | float odd = 0.0;
195 |
196 | if (fract(pos.x/6.0) < 0.5)
197 | odd = 1.0;
198 | if (fract((pos.y + odd)/2.0) < 0.5)
199 | line = maskDark;
200 |
201 | pos.x = fract(pos.x/3.0);
202 |
203 | if (pos.x < 0.3333) mask.b = maskLight;
204 | else if (pos.x < 0.6666) mask.g = maskLight;
205 | else mask.r = maskLight;
206 |
207 | mask*=line;
208 | }
209 |
210 | // Aperture-grille.
211 | else if (shadowMask == 2.0)
212 | {
213 | pos.x = fract(pos.x/3.0);
214 |
215 | if (pos.x < 0.3333) mask.b = maskLight;
216 | else if (pos.x < 0.6666) mask.g = maskLight;
217 | else mask.r = maskLight;
218 | }
219 |
220 | // Stretched VGA style shadow mask (same as prior shaders).
221 | else if (shadowMask == 3.0)
222 | {
223 | pos.x += pos.y*3.0;
224 | pos.x = fract(pos.x/6.0);
225 |
226 | if (pos.x < 0.3333) mask.r = maskLight;
227 | else if (pos.x < 0.6666) mask.g = maskLight;
228 | else mask.b = maskLight;
229 | }
230 |
231 | // VGA style shadow mask.
232 | else if (shadowMask == 4.0)
233 | {
234 | pos.xy = floor(pos.xy*vec2(1.0, 0.5));
235 | pos.x += pos.y*3.0;
236 | pos.x = fract(pos.x/6.0);
237 |
238 | if (pos.x < 0.3333) mask.r = maskLight;
239 | else if (pos.x < 0.6666) mask.g = maskLight;
240 | else mask.b = maskLight;
241 | }
242 |
243 | // Alternate mask 5
244 | else if (shadowMask == 5.0)
245 | {
246 | float mx = max(max(c.r,c.g),c.b);
247 | vec3 maskTmp = vec3( min( 1.25*max(mx-mcut,0.0)/(1.0-mcut) ,maskDark + 0.2*(1.0-maskDark)*mx));
248 | float adj = 0.80*maskLight - 0.5*(0.80*maskLight - 1.0)*mx + 0.75*(1.0-mx);
249 | mask = maskTmp;
250 | pos.x = fract(pos.x/2.0);
251 | if (pos.x < 0.5)
252 | { mask.r = adj;
253 | mask.b = adj;
254 | }
255 | else mask.g = adj;
256 | }
257 |
258 | // Alternate mask 6
259 | else if (shadowMask == 6.0)
260 | {
261 | float mx = max(max(c.r,c.g),c.b);
262 | vec3 maskTmp = vec3( min( 1.33*max(mx-mcut,0.0)/(1.0-mcut) ,maskDark + 0.225*(1.0-maskDark)*mx));
263 | float adj = 0.80*maskLight - 0.5*(0.80*maskLight - 1.0)*mx + 0.75*(1.0-mx);
264 | mask = maskTmp;
265 | pos.x = fract(pos.x/3.0);
266 | if (pos.x < 0.3333) mask.r = adj;
267 | else if (pos.x < 0.6666) mask.g = adj;
268 | else mask.b = adj;
269 | }
270 |
271 | // Alternate mask 7
272 | else if (shadowMask == 7.0)
273 | {
274 | float mc = 1.0 - CGWG;
275 | float mx = max(max(c.r,c.g),c.b);
276 | float maskTmp = min(1.6*max(mx-mcut,0.0)/(1.0-mcut) , mc);
277 | mask = vec3(maskTmp);
278 | pos.x = fract(pos.x/2.0);
279 | if (pos.x < 0.5) mask = vec3(1.0 + 0.6*(1.0-mx));
280 | }
281 | else if (shadowMask == 8.0)
282 | {
283 | float line = maskLight;
284 | float odd = 0.0;
285 |
286 | if (fract(pos.x/4.0) < 0.5)
287 | odd = 1.0;
288 | if (fract((pos.y + odd)/2.0) < 0.5)
289 | line = maskDark;
290 |
291 | pos.x = fract(pos.x/2.0);
292 |
293 | if (pos.x < 0.5) {mask.r = maskLight; mask.b = maskLight;}
294 | else mask.g = maskLight;
295 | mask*=line;
296 | }
297 |
298 | else if (shadowMask == 9.0)
299 | {
300 | vec3 Mask = vec3(maskDark);
301 |
302 | float bright = maskLight;
303 | float left = 0.0;
304 |
305 |
306 | if (fract(pos.x/6.0) < 0.5)
307 | left = 1.0;
308 |
309 |
310 | float m = fract(pos.x/3.0);
311 |
312 | if (m < 0.3333) Mask.b = 0.9;
313 | else if (m < 0.6666) Mask.g = 0.9;
314 | else Mask.r = 0.9;
315 |
316 | if (mod(pos.y,2.0)==1.0 && left == 1.0 || mod(pos.y,2.0)==0.0 && left == 0.0 ) Mask*=bright;
317 |
318 | return Mask;
319 | }
320 |
321 | else if (shadowMask == 10.0)
322 | {
323 | vec3 Mask = vec3(maskDark);
324 | float line = maskLight;
325 | float odd = 0.0;
326 |
327 | if (fract(pos.x/6.0) < 0.5)
328 | odd = 1.0;
329 | if (fract((pos.y + odd)/2.0) < 0.5)
330 | line = 1.0;
331 |
332 | float m = fract(pos.x/3.0);
333 | float y = fract(pos.y/2.0);
334 |
335 | if (m > 0.3333) {Mask.r = 1.0; Mask.b = 1.0;}
336 | else if (m > 0.6666) Mask.g = 1.0;
337 | else Mask = vec3(mcut);
338 | if (m>0.333) Mask*=line;
339 | return Mask;
340 | }
341 |
342 | return mask;
343 | }
344 |
345 | mat3 vign( float l )
346 | {
347 | vec2 vpos = vTexCoord * (TextureSize.xy / InputSize.xy);
348 |
349 | vpos *= 1.0 - vpos.xy;
350 | float vig = vpos.x * vpos.y * vstr;
351 | vig = min(pow(vig, vpower), 1.0);
352 | if (vignette == 0.0) vig=1.0;
353 |
354 | return mat3(vig, 0, 0,
355 | 0, vig, 0,
356 | 0, 0, vig);
357 |
358 | }
359 |
360 | // Distortion of scanlines, and end of screen alpha.
361 | vec2 Warp(vec2 pos)
362 | {
363 | pos = pos*2.0-1.0;
364 | pos *= vec2(1.0 + (pos.y*pos.y)*warpX, 1.0 + (pos.x*pos.x)*warpY);
365 | return pos*0.5 + 0.5;
366 | }
367 |
368 | vec3 saturation (vec3 textureColor)
369 | {
370 | float lum=length(textureColor.rgb)*0.5775;
371 |
372 | vec3 luminanceWeighting = vec3(0.3,0.6,0.1);
373 | if (lum<0.5) luminanceWeighting.rgb=(luminanceWeighting.rgb*luminanceWeighting.rgb)+(luminanceWeighting.rgb*luminanceWeighting.rgb);
374 |
375 | float luminance = dot(textureColor.rgb, luminanceWeighting);
376 | vec3 greyScaleColor = vec3(luminance);
377 |
378 | vec3 res = vec3(mix(greyScaleColor, textureColor.rgb, sat));
379 | return res;
380 | }
381 |
382 | void main()
383 | {
384 | vec2 pos = Warp(TEX0.xy*(TextureSize.xy/InputSize.xy))*(InputSize.xy/TextureSize.xy);
385 |
386 | vec2 ps = SourceSize.zw;
387 | vec2 OGL2Pos = pos * SourceSize.xy;
388 | vec2 fp = fract(OGL2Pos);
389 | vec2 dx = vec2(ps.x,0.0);
390 | vec2 dy = vec2(0.0, ps.y);
391 |
392 | vec2 pC4 = floor(OGL2Pos) * ps + 0.5*ps;
393 | float f = fp.y; if (InputSize.y > 400.0) f=1.0;
394 | vec3 f1 = vec3(f);
395 | vec3 color = vec3 (0.0);
396 |
397 | // Reading the texels
398 | vec3 ul = COMPAT_TEXTURE(Texture, pC4 ).xyz; ul*=ul;
399 | vec3 ur = COMPAT_TEXTURE(Texture, pC4 + dx).xyz; ur*=ur;
400 | vec3 dl = COMPAT_TEXTURE(Texture, pC4 + dy).xyz; dl*=dl;
401 | vec3 dr = COMPAT_TEXTURE(Texture, pC4 + ps).xyz; dr*=dr;
402 |
403 | float lx = fp.x; lx = pow(lx, h_sharp);
404 | float rx = 1.0 - fp.x; rx = pow(rx, h_sharp);
405 |
406 | vec3 color1 = (ur*lx + ul*rx)/(lx+rx);
407 | vec3 color2 = (dr*lx + dl*rx)/(lx+rx);
408 |
409 | // calculating scanlines
410 |
411 | color = color1*sw(f1,color1) + color2*sw(1.0-f1,color2);
412 |
413 | color = color*Mask(gl_FragCoord.xy*1.0001, color);
414 | float lum = color.r*0.3+color.g*0.6+color.b*0.1;
415 | color = pow(color, vec3(gamma_out, gamma_out, gamma_out));
416 | color*= mix(1.0,brightboost,lum);
417 | color = saturation(color);
418 | color*= vign(lum);
419 |
420 | #if defined GL_ES
421 | // hacky clamp fix for GLES
422 | vec2 bordertest = (pos);
423 | if ( bordertest.x > 0.0001 && bordertest.x < 0.9999 && bordertest.y > 0.0001 && bordertest.y < 0.9999)
424 | color = color;
425 | else
426 | color = vec3(0.0);
427 | #endif
428 |
429 | FragColor = vec4(color, 1.0);
430 | }
431 | #endif
432 |
--------------------------------------------------------------------------------
/MacBox/ViewControllers/SettingsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsViewController.swift
3 | // MacBox
4 | //
5 | // Created by Moonif on 1/12/24.
6 | //
7 |
8 | import Cocoa
9 |
10 | class SettingsViewController: NSViewController {
11 |
12 | // IBOutlets
13 | @IBOutlet weak var appearancePicker: NSPopUpButton!
14 | @IBOutlet weak var macboxPathPicker: NSPopUpButton!
15 | @IBOutlet weak var defaultPathPicker: NSPopUpButton!
16 | @IBOutlet weak var updateChannelPicker: NSPopUpButton!
17 | @IBOutlet weak var macboxPathTextField: NSTextField!
18 | @IBOutlet weak var pathTextField: NSTextField!
19 | @IBOutlet weak var preventDisplaySleepCheckbox: NSButton!
20 |
21 | // Variables
22 | private let userDefaults = UserDefaults.standard
23 | private let fileManager = FileManager.default
24 | private var macboxCustomPathString: String?
25 | private var emulatorCustomPathString: String?
26 | private let defaultHomeDir = URL(fileURLWithPath: "MacBox", isDirectory: true, relativeTo: FileManager.default.homeDirectoryForCurrentUser)
27 |
28 | // View did load
29 | override func viewDidLoad() {
30 | super.viewDidLoad()
31 |
32 | // Config views
33 | configView()
34 | }
35 |
36 | // View will appear
37 | override func viewWillAppear() {
38 | // Remove fullscreen window button
39 | self.view.window?.styleMask.remove(.fullScreen)
40 | self.view.window?.styleMask.remove(.resizable)
41 | }
42 |
43 | // Config views initial properties
44 | private func configView() {
45 | // Set the appearance picker selected item
46 | if let appAppearance = userDefaults.string(forKey: "appAppearance") {
47 | switch appAppearance {
48 | case "aqua":
49 | appearancePicker.selectItem(at: 2)
50 | case "darkAqua":
51 | appearancePicker.selectItem(at: 3)
52 | default:
53 | break
54 | }
55 | }
56 |
57 | // Set the Prevent Display Sleep Checkbox state
58 | let disableScreensaver = userDefaults.bool(forKey: "disableScreensaver")
59 | if disableScreensaver == true {
60 | preventDisplaySleepCheckbox.state = .on
61 | }
62 |
63 | // Set the MacBox default path picker selected item
64 | setMacBoxPathTextField(text: MainViewController.instance.homeDirURL.path)
65 | if let _ = userDefaults.string(forKey: "homeDirPath") {
66 | macboxPathPicker.selectItem(at: 1)
67 | }
68 |
69 | // Set the 86Box default path picker selected item
70 | setEmulatorPathTextField(text: MainViewController.instance.versionInfoObject.emulatorAutoUrl?.relativePath ?? NSLocalizedString("86Box is not installed.", comment: ""))
71 | if let emulatorDefaultPath = userDefaults.string(forKey: "emulatorDefaultPath") {
72 | if emulatorDefaultPath != "auto" {
73 | defaultPathPicker.selectItem(at: 1)
74 | setEmulatorPathTextField(text: emulatorDefaultPath)
75 | emulatorCustomPathString = emulatorDefaultPath
76 | }
77 | }
78 |
79 | // Set the 86Box update channel picker selected item
80 | if let emulatorUpdateChannel = userDefaults.string(forKey: "emulatorUpdateChannel") {
81 | switch emulatorUpdateChannel {
82 | case "stable":
83 | updateChannelPicker.selectItem(at: 0)
84 | default:
85 | break
86 | }
87 | }
88 | }
89 |
90 | // Set MacBox path text
91 | private func setMacBoxPathTextField(text: String) {
92 | macboxPathTextField.stringValue = text
93 | }
94 |
95 | // Reset the MacBox path picker selection back to default
96 | private func resetMacBoxPathPickerSelection() {
97 | if macboxCustomPathString == nil {
98 | macboxPathPicker.selectItem(at: 0)
99 | }
100 | }
101 |
102 | // Set 86Box path text
103 | private func setEmulatorPathTextField(text: String) {
104 | pathTextField.stringValue = text
105 | }
106 |
107 | // Reset the path picker selection back to default
108 | private func resetPathPickerSelection() {
109 | if emulatorCustomPathString == nil {
110 | defaultPathPicker.selectItem(at: 0)
111 | }
112 | }
113 |
114 | // Move MacBox home directory to custom location
115 | private func relocateHomeDir(destination: URL?) {
116 | do {
117 | let currentHomeDir = MainViewController.instance.homeDirURL
118 | let homeDirFiles = try fileManager.contentsOfDirectory(at: currentHomeDir, includingPropertiesForKeys: nil)
119 |
120 | if let customLocation = destination {
121 | // Custom location
122 | for homeDirFileURL in homeDirFiles {
123 | var customLocationFileURL = customLocation
124 | if #available(macOS 13.0, *) {
125 | customLocationFileURL = customLocationFileURL.appending(component: homeDirFileURL.lastPathComponent)
126 | } else {
127 | // Fallback on earlier versions
128 | customLocationFileURL = customLocationFileURL.appendingPathComponent(homeDirFileURL.lastPathComponent)
129 | }
130 | // Move the files
131 | if !fileManager.fileExists(atPath: customLocationFileURL.path) {
132 | try fileManager.moveItem(at: homeDirFileURL, to: customLocationFileURL)
133 | }
134 | }
135 | MainViewController.instance.updateConfigFile(previousLocation: currentHomeDir, newLocation: customLocation)
136 | userDefaults.set(customLocation.path, forKey: "homeDirPath")
137 | }
138 | else {
139 | // Default location
140 | for homeDirFileURL in homeDirFiles {
141 | var defaultLocationFileURL = defaultHomeDir
142 | if #available(macOS 13.0, *) {
143 | defaultLocationFileURL = defaultLocationFileURL.appending(component: homeDirFileURL.lastPathComponent)
144 | } else {
145 | // Fallback on earlier versions
146 | defaultLocationFileURL = defaultLocationFileURL.appendingPathComponent(homeDirFileURL.lastPathComponent)
147 | }
148 |
149 | // Try recreating the default home directory in case it was deleted by user
150 | try fileManager.createDirectory(atPath: defaultHomeDir.path, withIntermediateDirectories: true)
151 | // Move the files
152 | if !fileManager.fileExists(atPath: defaultLocationFileURL.path) {
153 | try fileManager.moveItem(at: homeDirFileURL, to: defaultLocationFileURL)
154 | }
155 | }
156 | MainViewController.instance.updateConfigFile(previousLocation: currentHomeDir, newLocation: defaultHomeDir)
157 | userDefaults.removeObject(forKey: "homeDirPath")
158 | }
159 | }
160 | catch {
161 | // Show error alert
162 | let alert = NSAlert()
163 |
164 | alert.messageText = "Error: \(error.localizedDescription)"
165 | alert.alertStyle = .critical
166 | alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
167 |
168 | let _ = alert.runModal()
169 | }
170 | }
171 |
172 | // ------------------------------------
173 | // IBActions
174 | // ------------------------------------
175 |
176 | // Appearance Picker Action
177 | @IBAction func appearancePickerAction(_ sender: NSPopUpButton) {
178 | if let selectedItem = sender.selectedItem {
179 | switch selectedItem.identifier {
180 | case NSUserInterfaceItemIdentifier(rawValue: "appearanceLight"):
181 | NSApp.appearance = NSAppearance(named: .aqua)
182 | userDefaults.set("aqua", forKey: "appAppearance")
183 | case NSUserInterfaceItemIdentifier(rawValue: "appearanceDark"):
184 | NSApp.appearance = NSAppearance(named: .darkAqua)
185 | userDefaults.set("darkAqua", forKey: "appAppearance")
186 | default:
187 | NSApp.appearance = NSAppearance()
188 | userDefaults.set("system", forKey: "appAppearance")
189 | }
190 | }
191 | }
192 |
193 | // Enable/Disable Display Sleep
194 | @IBAction func preventDisplaySleepCheckboxAction(_ sender: NSButton) {
195 | switch sender.state {
196 | case .on:
197 | // Disable Display Sleep
198 | MainViewController.instance.screensaverManager.disableScreensaver()
199 | userDefaults.set(true, forKey: "disableScreensaver")
200 | default:
201 | // Enable Display Sleep
202 | MainViewController.instance.screensaverManager.enableScreensaver()
203 | userDefaults.set(false, forKey: "disableScreensaver")
204 | }
205 | }
206 |
207 | // MacBox Path Picker Action
208 | @IBAction func macboxPathPickerAction(_ sender: NSPopUpButton) {
209 | if let selectedItem = sender.selectedItem {
210 | switch selectedItem.identifier {
211 | case NSUserInterfaceItemIdentifier(rawValue: "macboxPathCustom"):
212 | // Open the file picker
213 | let filePickerPanel = NSOpenPanel()
214 |
215 | filePickerPanel.allowsMultipleSelection = false
216 | filePickerPanel.canChooseDirectories = true
217 | filePickerPanel.canChooseFiles = false
218 | filePickerPanel.canCreateDirectories = true
219 |
220 | if filePickerPanel.runModal() == .OK {
221 | if let newHomeDirURL = filePickerPanel.url {
222 | macboxCustomPathString = newHomeDirURL.relativePath
223 | // Set path text
224 | setMacBoxPathTextField(text: macboxCustomPathString ?? "-")
225 | // Move the Home directory to the selected URL
226 | relocateHomeDir(destination: newHomeDirURL)
227 | // Refresh 86Box auto path
228 | if emulatorCustomPathString == nil {
229 | setEmulatorPathTextField(text: MainViewController.instance.versionInfoObject.emulatorAutoUrl?.relativePath ?? NSLocalizedString("86Box is not installed.", comment: ""))
230 | }
231 | }
232 | }
233 | else {
234 | // Reset selection
235 | resetMacBoxPathPickerSelection()
236 | }
237 | default:
238 | macboxCustomPathString = nil
239 | // Set path text
240 | setMacBoxPathTextField(text: defaultHomeDir.path)
241 | // Reset MacBox HomeDirURL
242 | if let _ = userDefaults.string(forKey: "homeDirPath") {
243 | relocateHomeDir(destination: nil)
244 | }
245 | // Refresh 86Box auto path
246 | if emulatorCustomPathString == nil {
247 | setEmulatorPathTextField(text: MainViewController.instance.versionInfoObject.emulatorAutoUrl?.relativePath ?? NSLocalizedString("86Box is not installed.", comment: ""))
248 | }
249 | }
250 | }
251 | }
252 |
253 | // Default 86Box Path Picker Action
254 | @IBAction func defaultPathPickerAction(_ sender: NSPopUpButton) {
255 | if let selectedItem = sender.selectedItem {
256 | switch selectedItem.identifier {
257 | case NSUserInterfaceItemIdentifier(rawValue: "pathCustom"):
258 | // Open the file picker
259 | let filePickerPanel = NSOpenPanel()
260 |
261 | filePickerPanel.allowsMultipleSelection = false
262 | filePickerPanel.canChooseDirectories = false
263 | filePickerPanel.canChooseFiles = true
264 | filePickerPanel.allowedFileTypes = ["app"]
265 |
266 | if filePickerPanel.runModal() == .OK {
267 | if let appURL = filePickerPanel.url {
268 | if let bundle = Bundle(url: appURL) {
269 | // Check if selected app is 86Box
270 | if bundle.bundleIdentifier == "net.86Box.86Box" {
271 | emulatorCustomPathString = appURL.relativePath
272 | userDefaults.set(emulatorCustomPathString ?? "-", forKey: "emulatorDefaultPath")
273 | setEmulatorPathTextField(text: emulatorCustomPathString ?? "-")
274 | // Update version status in MainVC
275 | MainViewController.instance.versionInfoObject.emulatorCustomUrl = appURL
276 | MainViewController.instance.checkFor86Box()
277 | }
278 | else {
279 | // Not 86Box; Reset selection
280 | resetPathPickerSelection()
281 | }
282 | }
283 | else {
284 | // Reset selection
285 | resetPathPickerSelection()
286 | }
287 | }
288 | }
289 | else {
290 | // Reset selection
291 | resetPathPickerSelection()
292 | }
293 | default:
294 | userDefaults.set("auto", forKey: "emulatorDefaultPath")
295 | setEmulatorPathTextField(text: MainViewController.instance.versionInfoObject.emulatorAutoUrl?.relativePath ?? NSLocalizedString("86Box is not installed.", comment: ""))
296 | emulatorCustomPathString = nil
297 | // Update version status in MainVC
298 | MainViewController.instance.versionInfoObject.emulatorCustomUrl = nil
299 | MainViewController.instance.checkFor86Box()
300 | }
301 | }
302 | }
303 |
304 | // Update Channel Picker Action
305 | @IBAction func updateChannelPickerAction(_ sender: NSPopUpButton) {
306 | if let selectedItem = sender.selectedItem {
307 | var updateChannelStr = ""
308 |
309 | switch selectedItem.identifier {
310 | case NSUserInterfaceItemIdentifier(rawValue: "updateStable"):
311 | updateChannelStr = "stable"
312 | userDefaults.set(updateChannelStr, forKey: "emulatorUpdateChannel")
313 | default:
314 | updateChannelStr = "beta"
315 | userDefaults.set(updateChannelStr, forKey: "emulatorUpdateChannel")
316 | }
317 |
318 | // Update version status in MainVC
319 | MainViewController.instance.versionInfoObject.emulatorUpdateChannel = updateChannelStr
320 | MainViewController.instance.checkFor86Box(url: nil, appVer: nil, buildVer: nil, ignoreVersionCheck: true)
321 | }
322 | }
323 | }
324 |
--------------------------------------------------------------------------------
/MacBox/Strings Localization/Localizable.xcstrings:
--------------------------------------------------------------------------------
1 | {
2 | "sourceLanguage" : "en",
3 | "strings" : {
4 | "86Box is not installed." : {
5 | "localizations" : {
6 | "pl" : {
7 | "stringUnit" : {
8 | "state" : "translated",
9 | "value" : "86Box nie jest zainstalowany."
10 | }
11 | }
12 | }
13 | },
14 | "86Box v%@ (Build %@)." : {
15 | "localizations" : {
16 | "af" : {
17 | "stringUnit" : {
18 | "state" : "new",
19 | "value" : "86Box v%1$@ (Build %2$@)."
20 | }
21 | },
22 | "ar" : {
23 | "stringUnit" : {
24 | "state" : "translated",
25 | "value" : "86Box v%1$@ (إصدار %2$@)."
26 | }
27 | },
28 | "ca" : {
29 | "stringUnit" : {
30 | "state" : "new",
31 | "value" : "86Box v%1$@ (Build %2$@)."
32 | }
33 | },
34 | "cs" : {
35 | "stringUnit" : {
36 | "state" : "translated",
37 | "value" : "86Box v%1$@ (Postav %2$@)."
38 | }
39 | },
40 | "da" : {
41 | "stringUnit" : {
42 | "state" : "translated",
43 | "value" : "86Box v%1$@ (Byg %2$@)."
44 | }
45 | },
46 | "de" : {
47 | "stringUnit" : {
48 | "state" : "translated",
49 | "value" : "86Box gegen%1$@ (Build %2$@)."
50 | }
51 | },
52 | "el" : {
53 | "stringUnit" : {
54 | "state" : "translated",
55 | "value" : "86Box v%1$@ (Build %2$@)."
56 | }
57 | },
58 | "en" : {
59 | "stringUnit" : {
60 | "state" : "new",
61 | "value" : "86Box v%1$@ (Build %2$@)."
62 | }
63 | },
64 | "en-US" : {
65 | "stringUnit" : {
66 | "state" : "new",
67 | "value" : "86Box v%1$@ (Build %2$@)."
68 | }
69 | },
70 | "es" : {
71 | "stringUnit" : {
72 | "state" : "translated",
73 | "value" : "86Box v%1$@ (Construir %2$@)."
74 | }
75 | },
76 | "fi" : {
77 | "stringUnit" : {
78 | "state" : "new",
79 | "value" : "86Box v%1$@ (Build %2$@)."
80 | }
81 | },
82 | "fr" : {
83 | "stringUnit" : {
84 | "state" : "translated",
85 | "value" : "86Box v%1$@ (Build %2$@)."
86 | }
87 | },
88 | "he" : {
89 | "stringUnit" : {
90 | "state" : "new",
91 | "value" : "86Box v%1$@ (Build %2$@)."
92 | }
93 | },
94 | "hu" : {
95 | "stringUnit" : {
96 | "state" : "new",
97 | "value" : "86Box v%1$@ (Build %2$@)."
98 | }
99 | },
100 | "it" : {
101 | "stringUnit" : {
102 | "state" : "translated",
103 | "value" : "86Box v%1$@ (Build %2$@)."
104 | }
105 | },
106 | "ja" : {
107 | "stringUnit" : {
108 | "state" : "translated",
109 | "value" : "86Box v%1$@ ( %2$@ をビルド)"
110 | }
111 | },
112 | "ko" : {
113 | "stringUnit" : {
114 | "state" : "new",
115 | "value" : "86Box v%1$@ (Build %2$@)."
116 | }
117 | },
118 | "nb" : {
119 | "stringUnit" : {
120 | "state" : "translated",
121 | "value" : "86Box v%1$@ (Bygg %2$@)."
122 | }
123 | },
124 | "nl" : {
125 | "stringUnit" : {
126 | "state" : "translated",
127 | "value" : "86Box v%1$@ (Bouw %2$@)."
128 | }
129 | },
130 | "pl" : {
131 | "stringUnit" : {
132 | "state" : "translated",
133 | "value" : "86Box v%1$@ (Zbuduj %2$@)."
134 | }
135 | },
136 | "pt-BR" : {
137 | "stringUnit" : {
138 | "state" : "translated",
139 | "value" : "86Box v%1$@ (Construa %2$@)."
140 | }
141 | },
142 | "pt-PT" : {
143 | "stringUnit" : {
144 | "state" : "translated",
145 | "value" : "86Box v%1$@ (Construa %2$@)."
146 | }
147 | },
148 | "ro" : {
149 | "stringUnit" : {
150 | "state" : "translated",
151 | "value" : "86Box v%1$@ (Build %2$@)."
152 | }
153 | },
154 | "ru" : {
155 | "stringUnit" : {
156 | "state" : "translated",
157 | "value" : "86Box v%1$@ (Версия %2$@)."
158 | }
159 | },
160 | "sr" : {
161 | "stringUnit" : {
162 | "state" : "new",
163 | "value" : "86Box v%1$@ (Build %2$@)."
164 | }
165 | },
166 | "sv" : {
167 | "stringUnit" : {
168 | "state" : "translated",
169 | "value" : "86Box v%1$@ (Bygg %2$@)."
170 | }
171 | },
172 | "tr" : {
173 | "stringUnit" : {
174 | "state" : "new",
175 | "value" : "86Box v%1$@ (Build %2$@)."
176 | }
177 | },
178 | "uk" : {
179 | "stringUnit" : {
180 | "state" : "translated",
181 | "value" : "86Box v%1$@ (Побудувати %2$@)."
182 | }
183 | },
184 | "vi" : {
185 | "stringUnit" : {
186 | "state" : "new",
187 | "value" : "86Box v%1$@ (Build %2$@)."
188 | }
189 | },
190 | "zh-Hans" : {
191 | "stringUnit" : {
192 | "state" : "translated",
193 | "value" : "86Box v%1$@ (Building %2$@)。"
194 | }
195 | },
196 | "zh-Hant" : {
197 | "stringUnit" : {
198 | "state" : "new",
199 | "value" : "86Box v%1$@ (Build %2$@)."
200 | }
201 | }
202 | }
203 | },
204 | "86Box v%@ (Build %@). Version status: %d %@ available." : {
205 | "localizations" : {
206 | "af" : {
207 | "stringUnit" : {
208 | "state" : "new",
209 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
210 | }
211 | },
212 | "ar" : {
213 | "stringUnit" : {
214 | "state" : "translated",
215 | "value" : "86Box v%1$@ (إصدار %2$@). حالة الإصدار: %3$d %4$@ متوفرة."
216 | }
217 | },
218 | "ca" : {
219 | "stringUnit" : {
220 | "state" : "new",
221 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
222 | }
223 | },
224 | "cs" : {
225 | "stringUnit" : {
226 | "state" : "translated",
227 | "value" : "86Box v%1$@ (Build %2$@). Stav verze: %3$d %4$@ k dispozici."
228 | }
229 | },
230 | "da" : {
231 | "stringUnit" : {
232 | "state" : "translated",
233 | "value" : "86Box v%1$@ (Byg %2$@). Version status: %3$d %4$@ tilgængelig."
234 | }
235 | },
236 | "de" : {
237 | "stringUnit" : {
238 | "state" : "translated",
239 | "value" : "86Box gegen%1$@ (Build %2$@). Versionsstatus: %3$d %4$@ verfügbar."
240 | }
241 | },
242 | "el" : {
243 | "stringUnit" : {
244 | "state" : "translated",
245 | "value" : "86Box v%1$@ (Build %2$@). Έκδοση κατάσταση: %3$d %4$@ διαθέσιμη."
246 | }
247 | },
248 | "en" : {
249 | "stringUnit" : {
250 | "state" : "new",
251 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
252 | }
253 | },
254 | "en-US" : {
255 | "stringUnit" : {
256 | "state" : "new",
257 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
258 | }
259 | },
260 | "es" : {
261 | "stringUnit" : {
262 | "state" : "translated",
263 | "value" : "86Box v%1$@ (Build %2$@). Estado de la versión: %3$d %4$@ disponible."
264 | }
265 | },
266 | "fi" : {
267 | "stringUnit" : {
268 | "state" : "new",
269 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
270 | }
271 | },
272 | "fr" : {
273 | "stringUnit" : {
274 | "state" : "translated",
275 | "value" : "86Box v%1$@ (Build %2$@). État de la version : %3$d %4$@ disponible."
276 | }
277 | },
278 | "he" : {
279 | "stringUnit" : {
280 | "state" : "new",
281 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
282 | }
283 | },
284 | "hu" : {
285 | "stringUnit" : {
286 | "state" : "new",
287 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
288 | }
289 | },
290 | "it" : {
291 | "stringUnit" : {
292 | "state" : "translated",
293 | "value" : "86Box v%1$@ (Build %2$@). Stato versione: %3$d %4$@ disponibile."
294 | }
295 | },
296 | "ja" : {
297 | "stringUnit" : {
298 | "state" : "translated",
299 | "value" : "86Box v%1$@ ( %2$@をビルド) バージョンステータス: %3$d %4$@ が利用可能です。"
300 | }
301 | },
302 | "ko" : {
303 | "stringUnit" : {
304 | "state" : "new",
305 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
306 | }
307 | },
308 | "nb" : {
309 | "stringUnit" : {
310 | "state" : "translated",
311 | "value" : "86Box v%1$@ (Bygg %2$@). Versjon status: %3$d %4$@ tilgjengelig."
312 | }
313 | },
314 | "nl" : {
315 | "stringUnit" : {
316 | "state" : "translated",
317 | "value" : "86Box v%1$@ (Build %2$@). Versie status: %3$d %4$@ beschikbaar."
318 | }
319 | },
320 | "pl" : {
321 | "stringUnit" : {
322 | "state" : "translated",
323 | "value" : "86Box v%1$@ (Zbuduj %2$@). Stan wersji: %3$d %4$@ dostępny."
324 | }
325 | },
326 | "pt-BR" : {
327 | "stringUnit" : {
328 | "state" : "translated",
329 | "value" : "86Box v%1$@ (Build %2$@). Status da versão: %3$d %4$@ disponível."
330 | }
331 | },
332 | "pt-PT" : {
333 | "stringUnit" : {
334 | "state" : "translated",
335 | "value" : "86Box v%1$@ (Build %2$@). Status da versão: %3$d %4$@ disponível."
336 | }
337 | },
338 | "ro" : {
339 | "stringUnit" : {
340 | "state" : "translated",
341 | "value" : "86Box v%1$@ (Build %2$@). Starea versiunii: %3$d %4$@ disponibile."
342 | }
343 | },
344 | "ru" : {
345 | "stringUnit" : {
346 | "state" : "translated",
347 | "value" : "86Box v%1$@ (Версия %2$@). Статус версии: %3$d %4$@ доступен."
348 | }
349 | },
350 | "sr" : {
351 | "stringUnit" : {
352 | "state" : "new",
353 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
354 | }
355 | },
356 | "sv" : {
357 | "stringUnit" : {
358 | "state" : "translated",
359 | "value" : "86Box v%1$@ (Bygg %2$@). Versionsstatus: %3$d %4$@ tillgänglig."
360 | }
361 | },
362 | "tr" : {
363 | "stringUnit" : {
364 | "state" : "new",
365 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
366 | }
367 | },
368 | "uk" : {
369 | "stringUnit" : {
370 | "state" : "translated",
371 | "value" : "86Box v%1$@ (Побудувати %2$@). Стан версії: %3$d %4$@ доступний."
372 | }
373 | },
374 | "vi" : {
375 | "stringUnit" : {
376 | "state" : "new",
377 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
378 | }
379 | },
380 | "zh-Hans" : {
381 | "stringUnit" : {
382 | "state" : "translated",
383 | "value" : "86Box v%1$@ (building %2$@)。版本状态: %3$d %4$@ 可用"
384 | }
385 | },
386 | "zh-Hant" : {
387 | "stringUnit" : {
388 | "state" : "new",
389 | "value" : "86Box v%1$@ (Build %2$@). Version status: %3$d %4$@ available."
390 | }
391 | }
392 | }
393 | },
394 | "86Box v%@ (Build %@). Version status: up-to-date." : {
395 | "localizations" : {
396 | "af" : {
397 | "stringUnit" : {
398 | "state" : "new",
399 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
400 | }
401 | },
402 | "ar" : {
403 | "stringUnit" : {
404 | "state" : "translated",
405 | "value" : "86Box v%1$@ (إصدار %2$@). حالة الإصدار: محدثة."
406 | }
407 | },
408 | "ca" : {
409 | "stringUnit" : {
410 | "state" : "new",
411 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
412 | }
413 | },
414 | "cs" : {
415 | "stringUnit" : {
416 | "state" : "translated",
417 | "value" : "86Box v%1$@ (sestavení %2$@). Stav verze: aktuální."
418 | }
419 | },
420 | "da" : {
421 | "stringUnit" : {
422 | "state" : "translated",
423 | "value" : "86Box v%1$@ (Byg %2$@). Versionsstatus: up-to-date."
424 | }
425 | },
426 | "de" : {
427 | "stringUnit" : {
428 | "state" : "translated",
429 | "value" : "86Box gegen%1$@ (Build %2$@). Versionsstatus: aktuell."
430 | }
431 | },
432 | "el" : {
433 | "stringUnit" : {
434 | "state" : "translated",
435 | "value" : "86Box v%1$@ (Build %2$@). Κατάσταση έκδοσης: ενημερωμένη."
436 | }
437 | },
438 | "en" : {
439 | "stringUnit" : {
440 | "state" : "new",
441 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
442 | }
443 | },
444 | "en-US" : {
445 | "stringUnit" : {
446 | "state" : "new",
447 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
448 | }
449 | },
450 | "es" : {
451 | "stringUnit" : {
452 | "state" : "translated",
453 | "value" : "86Box v%1$@ (Construir %2$@). Estado de la versión: actualizado."
454 | }
455 | },
456 | "fi" : {
457 | "stringUnit" : {
458 | "state" : "new",
459 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
460 | }
461 | },
462 | "fr" : {
463 | "stringUnit" : {
464 | "state" : "translated",
465 | "value" : "86Box v%1$@ (Build %2$@). État de la version : à jour."
466 | }
467 | },
468 | "he" : {
469 | "stringUnit" : {
470 | "state" : "new",
471 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
472 | }
473 | },
474 | "hu" : {
475 | "stringUnit" : {
476 | "state" : "new",
477 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
478 | }
479 | },
480 | "it" : {
481 | "stringUnit" : {
482 | "state" : "translated",
483 | "value" : "86Box v%1$@ (Build %2$@). Stato versione: aggiornato."
484 | }
485 | },
486 | "ja" : {
487 | "stringUnit" : {
488 | "state" : "translated",
489 | "value" : "86Box v%1$@ ( %2$@をビルド) バージョンステータス: updated."
490 | }
491 | },
492 | "ko" : {
493 | "stringUnit" : {
494 | "state" : "new",
495 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
496 | }
497 | },
498 | "nb" : {
499 | "stringUnit" : {
500 | "state" : "translated",
501 | "value" : "86Box v%1$@ (Bygg %2$@). Versjon status: oppdatert."
502 | }
503 | },
504 | "nl" : {
505 | "stringUnit" : {
506 | "state" : "translated",
507 | "value" : "86Box v%1$@ (Build %2$@). Versie status: up-to-date."
508 | }
509 | },
510 | "pl" : {
511 | "stringUnit" : {
512 | "state" : "translated",
513 | "value" : "86Box v%1$@ (Build %2$@). Status wersji: aktualny."
514 | }
515 | },
516 | "pt-BR" : {
517 | "stringUnit" : {
518 | "state" : "translated",
519 | "value" : "86Box v%1$@ (Build %2$@). Status da versão: atualizada."
520 | }
521 | },
522 | "pt-PT" : {
523 | "stringUnit" : {
524 | "state" : "translated",
525 | "value" : "86Box v%1$@ (Build %2$@). Status da versão: atualizada."
526 | }
527 | },
528 | "ro" : {
529 | "stringUnit" : {
530 | "state" : "translated",
531 | "value" : "86Box v%1$@ (Build %2$@). Stare versiune: actualizată."
532 | }
533 | },
534 | "ru" : {
535 | "stringUnit" : {
536 | "state" : "translated",
537 | "value" : "86Box v%1$@ (сборка %2$@). Статус версии: актуальный."
538 | }
539 | },
540 | "sr" : {
541 | "stringUnit" : {
542 | "state" : "new",
543 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
544 | }
545 | },
546 | "sv" : {
547 | "stringUnit" : {
548 | "state" : "translated",
549 | "value" : "86Box v%1$@ (Build %2$@). Versionsstatus: aktuell."
550 | }
551 | },
552 | "tr" : {
553 | "stringUnit" : {
554 | "state" : "new",
555 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
556 | }
557 | },
558 | "uk" : {
559 | "stringUnit" : {
560 | "state" : "translated",
561 | "value" : "86Box v%1$@ (Будуйте %2$@). Стан версії: найсвіжіша версія."
562 | }
563 | },
564 | "vi" : {
565 | "stringUnit" : {
566 | "state" : "new",
567 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
568 | }
569 | },
570 | "zh-Hans" : {
571 | "stringUnit" : {
572 | "state" : "translated",
573 | "value" : "86Box v%1$@ (Building %2$@)。版本状态:最新。"
574 | }
575 | },
576 | "zh-Hant" : {
577 | "stringUnit" : {
578 | "state" : "new",
579 | "value" : "86Box v%1$@ (Build %2$@). Version status: up-to-date."
580 | }
581 | }
582 | }
583 | },
584 | "86Box v%@ (Local Build)" : {
585 | "localizations" : {
586 | "pl" : {
587 | "stringUnit" : {
588 | "state" : "translated",
589 | "value" : "86Box v%@ (Local Build)"
590 | }
591 | }
592 | }
593 | },
594 | "Add a Virtual Machine" : {
595 | "localizations" : {
596 | "pl" : {
597 | "stringUnit" : {
598 | "state" : "translated",
599 | "value" : "Dodaj maszynę wirtualną."
600 | }
601 | }
602 | }
603 | },
604 | "Cancel" : {
605 | "localizations" : {
606 | "pl" : {
607 | "stringUnit" : {
608 | "state" : "translated",
609 | "value" : "Anuluj"
610 | }
611 | }
612 | }
613 | },
614 | "Do you want to remove the selected VM?" : {
615 | "localizations" : {
616 | "pl" : {
617 | "stringUnit" : {
618 | "state" : "translated",
619 | "value" : "Czy chcesz usunąć zaznaczone VM ?"
620 | }
621 | }
622 | }
623 | },
624 | "Duplicate" : {
625 | "localizations" : {
626 | "pl" : {
627 | "stringUnit" : {
628 | "state" : "translated",
629 | "value" : "Duplikuj"
630 | }
631 | }
632 | }
633 | },
634 | "Install" : {
635 | "localizations" : {
636 | "pl" : {
637 | "stringUnit" : {
638 | "state" : "translated",
639 | "value" : "Zainstaluj"
640 | }
641 | }
642 | }
643 | },
644 | "MacBox could not find any VM on your Mac." : {
645 | "localizations" : {
646 | "pl" : {
647 | "stringUnit" : {
648 | "state" : "translated",
649 | "value" : "MacBox nie znalazł żadnej maszyny wirtualnej."
650 | }
651 | }
652 | }
653 | },
654 | "MacBox found %d VMs on your Mac, press the \"Add\" button to import them." : {
655 | "localizations" : {
656 | "pl" : {
657 | "stringUnit" : {
658 | "state" : "translated",
659 | "value" : "MacBox odnalazł %d maszyn(ę) na twoim Macu, naciśnij przycisk \"Dodaj\" aby je zaimportować."
660 | }
661 | }
662 | }
663 | },
664 | "MacBox will now restart in order to apply the update" : {
665 | "localizations" : {
666 | "pl" : {
667 | "stringUnit" : {
668 | "state" : "translated",
669 | "value" : "MacBox zostanie teraz zrestartowany aby wgrać aktualizację."
670 | }
671 | }
672 | }
673 | },
674 | "No 86Box config files was found!" : {
675 | "localizations" : {
676 | "pl" : {
677 | "stringUnit" : {
678 | "state" : "translated",
679 | "value" : "Nie znaleziono pliku konfiguracyjnego 86Box!"
680 | }
681 | }
682 | }
683 | },
684 | "OK" : {
685 | "localizations" : {
686 | "pl" : {
687 | "stringUnit" : {
688 | "state" : "translated",
689 | "value" : "OK"
690 | }
691 | }
692 | }
693 | },
694 | "Remove" : {
695 | "localizations" : {
696 | "pl" : {
697 | "stringUnit" : {
698 | "state" : "translated",
699 | "value" : "Usuń"
700 | }
701 | }
702 | }
703 | },
704 | "Restart" : {
705 | "localizations" : {
706 | "pl" : {
707 | "stringUnit" : {
708 | "state" : "translated",
709 | "value" : "Restart"
710 | }
711 | }
712 | }
713 | },
714 | "Selected 86Box file is not found. VM will open using default version." : {
715 | "localizations" : {
716 | "pl" : {
717 | "stringUnit" : {
718 | "state" : "translated",
719 | "value" : "Wybrany plik 86Box nie został odnaleziony. VM zostanie uruchomiony używając wersji domyślnej."
720 | }
721 | }
722 | }
723 | },
724 | "Selected VM is already added!" : {
725 | "localizations" : {
726 | "pl" : {
727 | "stringUnit" : {
728 | "state" : "translated",
729 | "value" : "Zaznaczona maszyna jest już dodana"
730 | }
731 | }
732 | }
733 | },
734 | "Send the selected VM and all its files to trash" : {
735 | "localizations" : {
736 | "pl" : {
737 | "stringUnit" : {
738 | "state" : "translated",
739 | "value" : "Przenieś zaznaczone maszyny oraz wszystkie ich pliki do kosza."
740 | }
741 | }
742 | }
743 | },
744 | "Show in Finder" : {
745 | "localizations" : {
746 | "pl" : {
747 | "stringUnit" : {
748 | "state" : "translated",
749 | "value" : "Pokaż w Finderze"
750 | }
751 | }
752 | }
753 | },
754 | "This will only remove it from MacBox. If you also want to remove the VM files, check the option below." : {
755 | "localizations" : {
756 | "pl" : {
757 | "stringUnit" : {
758 | "state" : "translated",
759 | "value" : "Zostanie usunięta maszyna tylko z MacBox. Jeśli chcesz usunąć pliki także z dysku, zaznacz opcję poniżej."
760 | }
761 | }
762 | }
763 | },
764 | "update" : {
765 | "localizations" : {
766 | "pl" : {
767 | "stringUnit" : {
768 | "state" : "translated",
769 | "value" : "aktualizacja"
770 | }
771 | }
772 | }
773 | },
774 | "Update" : {
775 | "localizations" : {
776 | "pl" : {
777 | "stringUnit" : {
778 | "state" : "translated",
779 | "value" : "Aktualizuj"
780 | }
781 | }
782 | }
783 | },
784 | "updates" : {
785 | "localizations" : {
786 | "pl" : {
787 | "stringUnit" : {
788 | "state" : "translated",
789 | "value" : "aktualizacje"
790 | }
791 | }
792 | }
793 | },
794 | "VM name is already taken!" : {
795 | "localizations" : {
796 | "pl" : {
797 | "stringUnit" : {
798 | "state" : "translated",
799 | "value" : "Ta nazwa VM jest już zajęta."
800 | }
801 | }
802 | }
803 | },
804 | "VM will be created at: \"%@\"." : {
805 | "localizations" : {
806 | "pl" : {
807 | "stringUnit" : {
808 | "state" : "translated",
809 | "value" : "VM zostanie stworzony w \"%@\"."
810 | }
811 | }
812 | }
813 | }
814 | },
815 | "version" : "1.0"
816 | }
--------------------------------------------------------------------------------