├── .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://img.shields.io/github/license/Moonif/MacBox)](LICENSE) [![Latest release](https://img.shields.io/github/release/Moonif/MacBox.svg)](https://github.com/Moonif/MacBox/releases) [![Downloads](https://img.shields.io/github/downloads/Moonif/MacBox/total.svg)](https://github.com/Moonif/MacBox/releases) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Moonif_MacBox&metric=alert_status)](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 | ![MacBox](https://github.com/Moonif/MacBox/raw/main/Screenshots/MacBox.png) 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 | ![MacBoxTemplates](https://github.com/Moonif/MacBox/raw/main/Screenshots/Screenshot.png) 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 | 3 | 4 | 5 | 6 | image/svg+xml 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 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 | image/svg+xml 4 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Dell_logo.imageset/Dell_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 33 | 36 | 40 | 44 | 48 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Tandy_logo.imageset/Tandy_logo 1.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 54 | 58 | 62 | 66 | 70 | 74 | 78 | 79 | 80 | 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 | 13 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 27 | 30 | 33 | 37 | 38 | 41 | 45 | 46 | 49 | 53 | 54 | 57 | 61 | 62 | 65 | 69 | 70 | 71 | 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 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/IBM_logo.imageset/IBM_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Pb_logo_old.imageset/Pb_logo_old.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | image/svg+xml 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Compaq_logo_old.imageset/Compaq_logo_old 1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml 130 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Compaq_logo.imageset/Compaq_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Pb_logo_old.imageset/Pb_logo_old 1.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 36 | 38 | 39 | 41 | image/svg+xml 42 | 44 | 45 | 46 | 47 | 48 | 51 | 54 | 59 | 64 | 68 | 72 | 76 | 81 | 86 | 91 | 96 | 100 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Commodore_logo.imageset/Commodore_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | image/svg+xml 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /MacBox/Assets.xcassets/logos/Amstrad_logo.imageset/Amstrad_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 14 | 18 | 22 | 26 | 30 | 34 | 38 | 42 | 46 | 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 | } --------------------------------------------------------------------------------