├── Bootchoice.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── adminlocal.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── cstott.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── adminlocal.xcuserdatad │ └── xcschemes │ │ ├── Bootchoice.xcscheme │ │ └── xcschememanagement.plist │ └── cstott.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── Bootchoice.xcscheme │ └── xcschememanagement.plist ├── Bootchoice ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── bg.imageset │ │ ├── Contents.json │ │ └── bg.jpg │ ├── macos.imageset │ │ ├── Contents.json │ │ └── macos.png │ └── windows.imageset │ │ ├── Contents.json │ │ └── windows.png ├── Base.lproj │ └── MainMenu.xib ├── Info.plist ├── bootchoice.sh ├── delay_bootchoice.sh ├── init.sh └── setvals.sh ├── README.md ├── Uninstall.command ├── bootchoice.plist └── ca.ocadu.bootchoice.plist /Bootchoice.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1C11A2291D63E0100025473F /* bootchoice.sh in Resources */ = {isa = PBXBuildFile; fileRef = 1C11A2281D63E0100025473F /* bootchoice.sh */; }; 11 | 1C3039131E818EF7006FB444 /* delay_bootchoice.sh in Resources */ = {isa = PBXBuildFile; fileRef = 1C3039121E818EF7006FB444 /* delay_bootchoice.sh */; }; 12 | 1C9C227D1D6363BD00B38154 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C9C227C1D6363BD00B38154 /* AppDelegate.swift */; }; 13 | 1C9C227F1D6363BD00B38154 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1C9C227E1D6363BD00B38154 /* Assets.xcassets */; }; 14 | 1C9C22821D6363BD00B38154 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1C9C22801D6363BD00B38154 /* MainMenu.xib */; }; 15 | 606897321D6EBA5F0026F7B0 /* setvals.sh in Resources */ = {isa = PBXBuildFile; fileRef = 606897311D6EBA5F0026F7B0 /* setvals.sh */; }; 16 | 609EBC5E1D6E9DD80069AC56 /* init.sh in Resources */ = {isa = PBXBuildFile; fileRef = 609EBC5D1D6E9DD80069AC56 /* init.sh */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 1C11A2281D63E0100025473F /* bootchoice.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = bootchoice.sh; sourceTree = ""; }; 21 | 1C3039121E818EF7006FB444 /* delay_bootchoice.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = delay_bootchoice.sh; sourceTree = ""; }; 22 | 1C9C22791D6363BD00B38154 /* Bootchoice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bootchoice.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 1C9C227C1D6363BD00B38154 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Bootchoice/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 24 | 1C9C227E1D6363BD00B38154 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | 1C9C22811D6363BD00B38154 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 26 | 1C9C22831D6363BD00B38154 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | 606897311D6EBA5F0026F7B0 /* setvals.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = setvals.sh; path = ../../setvals.sh; sourceTree = ""; }; 28 | 609EBC5D1D6E9DD80069AC56 /* init.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = init.sh; path = ../../init.sh; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 1C9C22761D6363BD00B38154 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 1C9C22701D6363BD00B38154 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 1C9C227B1D6363BD00B38154 /* Bootchoice */, 46 | 1C9C227A1D6363BD00B38154 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 1C9C227A1D6363BD00B38154 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 1C9C22791D6363BD00B38154 /* Bootchoice.app */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 1C9C227B1D6363BD00B38154 /* Bootchoice */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 606897311D6EBA5F0026F7B0 /* setvals.sh */, 62 | 609EBC5D1D6E9DD80069AC56 /* init.sh */, 63 | 1C9C227C1D6363BD00B38154 /* AppDelegate.swift */, 64 | 1C11A2281D63E0100025473F /* bootchoice.sh */, 65 | 1C3039121E818EF7006FB444 /* delay_bootchoice.sh */, 66 | 1C9C227E1D6363BD00B38154 /* Assets.xcassets */, 67 | 1C9C22801D6363BD00B38154 /* MainMenu.xib */, 68 | 1C9C22831D6363BD00B38154 /* Info.plist */, 69 | ); 70 | path = Bootchoice; 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | 1C9C22781D6363BD00B38154 /* Bootchoice */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = 1C9C22861D6363BD00B38154 /* Build configuration list for PBXNativeTarget "Bootchoice" */; 79 | buildPhases = ( 80 | 1C9C22751D6363BD00B38154 /* Sources */, 81 | 1C9C22761D6363BD00B38154 /* Frameworks */, 82 | 1C9C22771D6363BD00B38154 /* Resources */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = Bootchoice; 89 | productName = Bootchoice; 90 | productReference = 1C9C22791D6363BD00B38154 /* Bootchoice.app */; 91 | productType = "com.apple.product-type.application"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | 1C9C22711D6363BD00B38154 /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastSwiftUpdateCheck = 0720; 100 | LastUpgradeCheck = 1020; 101 | ORGANIZATIONNAME = "Stott, Cameron"; 102 | TargetAttributes = { 103 | 1C9C22781D6363BD00B38154 = { 104 | CreatedOnToolsVersion = 7.2; 105 | DevelopmentTeam = 7P47UYC8V6; 106 | LastSwiftMigration = 1020; 107 | }; 108 | }; 109 | }; 110 | buildConfigurationList = 1C9C22741D6363BD00B38154 /* Build configuration list for PBXProject "Bootchoice" */; 111 | compatibilityVersion = "Xcode 3.2"; 112 | developmentRegion = en; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | Base, 117 | ); 118 | mainGroup = 1C9C22701D6363BD00B38154; 119 | productRefGroup = 1C9C227A1D6363BD00B38154 /* Products */; 120 | projectDirPath = ""; 121 | projectRoot = ""; 122 | targets = ( 123 | 1C9C22781D6363BD00B38154 /* Bootchoice */, 124 | ); 125 | }; 126 | /* End PBXProject section */ 127 | 128 | /* Begin PBXResourcesBuildPhase section */ 129 | 1C9C22771D6363BD00B38154 /* Resources */ = { 130 | isa = PBXResourcesBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | 609EBC5E1D6E9DD80069AC56 /* init.sh in Resources */, 134 | 1C11A2291D63E0100025473F /* bootchoice.sh in Resources */, 135 | 1C9C227F1D6363BD00B38154 /* Assets.xcassets in Resources */, 136 | 1C3039131E818EF7006FB444 /* delay_bootchoice.sh in Resources */, 137 | 606897321D6EBA5F0026F7B0 /* setvals.sh in Resources */, 138 | 1C9C22821D6363BD00B38154 /* MainMenu.xib in Resources */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | /* End PBXResourcesBuildPhase section */ 143 | 144 | /* Begin PBXSourcesBuildPhase section */ 145 | 1C9C22751D6363BD00B38154 /* Sources */ = { 146 | isa = PBXSourcesBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 1C9C227D1D6363BD00B38154 /* AppDelegate.swift in Sources */, 150 | ); 151 | runOnlyForDeploymentPostprocessing = 0; 152 | }; 153 | /* End PBXSourcesBuildPhase section */ 154 | 155 | /* Begin PBXVariantGroup section */ 156 | 1C9C22801D6363BD00B38154 /* MainMenu.xib */ = { 157 | isa = PBXVariantGroup; 158 | children = ( 159 | 1C9C22811D6363BD00B38154 /* Base */, 160 | ); 161 | name = MainMenu.xib; 162 | sourceTree = ""; 163 | }; 164 | /* End PBXVariantGroup section */ 165 | 166 | /* Begin XCBuildConfiguration section */ 167 | 1C9C22841D6363BD00B38154 /* Debug */ = { 168 | isa = XCBuildConfiguration; 169 | buildSettings = { 170 | ALWAYS_SEARCH_USER_PATHS = NO; 171 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 172 | CLANG_CXX_LIBRARY = "libc++"; 173 | CLANG_ENABLE_MODULES = YES; 174 | CLANG_ENABLE_OBJC_ARC = YES; 175 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 176 | CLANG_WARN_BOOL_CONVERSION = YES; 177 | CLANG_WARN_COMMA = YES; 178 | CLANG_WARN_CONSTANT_CONVERSION = YES; 179 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 180 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 181 | CLANG_WARN_EMPTY_BODY = YES; 182 | CLANG_WARN_ENUM_CONVERSION = YES; 183 | CLANG_WARN_INFINITE_RECURSION = YES; 184 | CLANG_WARN_INT_CONVERSION = YES; 185 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 186 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 187 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 189 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 190 | CLANG_WARN_STRICT_PROTOTYPES = YES; 191 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 192 | CLANG_WARN_UNREACHABLE_CODE = YES; 193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 194 | CODE_SIGN_IDENTITY = "-"; 195 | COPY_PHASE_STRIP = NO; 196 | DEBUG_INFORMATION_FORMAT = dwarf; 197 | ENABLE_STRICT_OBJC_MSGSEND = YES; 198 | ENABLE_TESTABILITY = YES; 199 | GCC_C_LANGUAGE_STANDARD = gnu99; 200 | GCC_DYNAMIC_NO_PIC = NO; 201 | GCC_NO_COMMON_BLOCKS = YES; 202 | GCC_OPTIMIZATION_LEVEL = 0; 203 | GCC_PREPROCESSOR_DEFINITIONS = ( 204 | "DEBUG=1", 205 | "$(inherited)", 206 | ); 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | MACOSX_DEPLOYMENT_TARGET = 10.10; 214 | MTL_ENABLE_DEBUG_INFO = YES; 215 | ONLY_ACTIVE_ARCH = YES; 216 | SDKROOT = macosx; 217 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 218 | SWIFT_VERSION = 2.3; 219 | }; 220 | name = Debug; 221 | }; 222 | 1C9C22851D6363BD00B38154 /* Release */ = { 223 | isa = XCBuildConfiguration; 224 | buildSettings = { 225 | ALWAYS_SEARCH_USER_PATHS = NO; 226 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 227 | CLANG_CXX_LIBRARY = "libc++"; 228 | CLANG_ENABLE_MODULES = YES; 229 | CLANG_ENABLE_OBJC_ARC = YES; 230 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 231 | CLANG_WARN_BOOL_CONVERSION = YES; 232 | CLANG_WARN_COMMA = YES; 233 | CLANG_WARN_CONSTANT_CONVERSION = YES; 234 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 241 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 242 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 243 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 244 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 245 | CLANG_WARN_STRICT_PROTOTYPES = YES; 246 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 247 | CLANG_WARN_UNREACHABLE_CODE = YES; 248 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 249 | CODE_SIGN_IDENTITY = "-"; 250 | COPY_PHASE_STRIP = NO; 251 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 252 | ENABLE_NS_ASSERTIONS = NO; 253 | ENABLE_STRICT_OBJC_MSGSEND = YES; 254 | GCC_C_LANGUAGE_STANDARD = gnu99; 255 | GCC_NO_COMMON_BLOCKS = YES; 256 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 257 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 258 | GCC_WARN_UNDECLARED_SELECTOR = YES; 259 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 260 | GCC_WARN_UNUSED_FUNCTION = YES; 261 | GCC_WARN_UNUSED_VARIABLE = YES; 262 | MACOSX_DEPLOYMENT_TARGET = 10.10; 263 | MTL_ENABLE_DEBUG_INFO = NO; 264 | SDKROOT = macosx; 265 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 266 | SWIFT_VERSION = 2.3; 267 | }; 268 | name = Release; 269 | }; 270 | 1C9C22871D6363BD00B38154 /* Debug */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 274 | CODE_SIGN_IDENTITY = "Mac Developer"; 275 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; 276 | COMBINE_HIDPI_IMAGES = YES; 277 | DEVELOPMENT_TEAM = 7P47UYC8V6; 278 | INFOPLIST_FILE = Bootchoice/Info.plist; 279 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 280 | MACOSX_DEPLOYMENT_TARGET = 10.11; 281 | PRODUCT_BUNDLE_IDENTIFIER = ca.ocadu.Bootchoice; 282 | PRODUCT_NAME = "$(TARGET_NAME)"; 283 | PROVISIONING_PROFILE = ""; 284 | SWIFT_VERSION = 5.0; 285 | }; 286 | name = Debug; 287 | }; 288 | 1C9C22881D6363BD00B38154 /* Release */ = { 289 | isa = XCBuildConfiguration; 290 | buildSettings = { 291 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 292 | CODE_SIGN_IDENTITY = "Mac Developer"; 293 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; 294 | COMBINE_HIDPI_IMAGES = YES; 295 | DEVELOPMENT_TEAM = 7P47UYC8V6; 296 | INFOPLIST_FILE = Bootchoice/Info.plist; 297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 298 | MACOSX_DEPLOYMENT_TARGET = 10.11; 299 | PRODUCT_BUNDLE_IDENTIFIER = ca.ocadu.Bootchoice; 300 | PRODUCT_NAME = "$(TARGET_NAME)"; 301 | PROVISIONING_PROFILE = ""; 302 | SWIFT_VERSION = 5.0; 303 | }; 304 | name = Release; 305 | }; 306 | /* End XCBuildConfiguration section */ 307 | 308 | /* Begin XCConfigurationList section */ 309 | 1C9C22741D6363BD00B38154 /* Build configuration list for PBXProject "Bootchoice" */ = { 310 | isa = XCConfigurationList; 311 | buildConfigurations = ( 312 | 1C9C22841D6363BD00B38154 /* Debug */, 313 | 1C9C22851D6363BD00B38154 /* Release */, 314 | ); 315 | defaultConfigurationIsVisible = 0; 316 | defaultConfigurationName = Release; 317 | }; 318 | 1C9C22861D6363BD00B38154 /* Build configuration list for PBXNativeTarget "Bootchoice" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | 1C9C22871D6363BD00B38154 /* Debug */, 322 | 1C9C22881D6363BD00B38154 /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | /* End XCConfigurationList section */ 328 | }; 329 | rootObject = 1C9C22711D6363BD00B38154 /* Project object */; 330 | } 331 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/project.xcworkspace/xcuserdata/adminlocal.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androindep/Bootchoice/c49a42a469be9969808c503e1bb3ba027e6ecbca/Bootchoice.xcodeproj/project.xcworkspace/xcuserdata/adminlocal.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/project.xcworkspace/xcuserdata/cstott.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androindep/Bootchoice/c49a42a469be9969808c503e1bb3ba027e6ecbca/Bootchoice.xcodeproj/project.xcworkspace/xcuserdata/cstott.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/xcuserdata/adminlocal.xcuserdatad/xcschemes/Bootchoice.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/xcuserdata/adminlocal.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Bootchoice.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1C9C22781D6363BD00B38154 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/xcuserdata/cstott.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/xcuserdata/cstott.xcuserdatad/xcschemes/Bootchoice.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 76 | 82 | 83 | 84 | 85 | 87 | 88 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Bootchoice.xcodeproj/xcuserdata/cstott.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Bootchoice.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1C9C22781D6363BD00B38154 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Bootchoice/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Bootchoice 4 | // 5 | // Created by C. Stott on 8/16/16. 6 | // Copyright © 2016 C. Stott. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | 13 | @NSApplicationMain 14 | 15 | 16 | 17 | class AppDelegate: NSObject, NSApplicationDelegate { 18 | 19 | func runCommand(_ cmd : String, args : String...) -> (output: [String], error: [String], exitCode: Int32) { 20 | 21 | let output : [String] = [] 22 | let error : [String] = [] 23 | 24 | let task = Process() 25 | task.launchPath = cmd 26 | task.arguments = args 27 | 28 | let outpipe = Pipe() 29 | task.standardOutput = outpipe 30 | let errpipe = Pipe() 31 | task.standardError = errpipe 32 | 33 | task.launch() 34 | 35 | 36 | task.waitUntilExit() 37 | let status = task.terminationStatus 38 | 39 | return (output, error, status) 40 | } 41 | 42 | func applicationWillFinishLaunching(_ notification: Notification) { 43 | 44 | let (output, error, status) = runCommand("/Applications/Utilities/Bootchoice.app/Contents/Resources/init.sh") 45 | print("program exited with status \(status)") 46 | let initstatus = (status) 47 | if initstatus == 1 { 48 | 49 | NSApplication.shared.terminate(self) 50 | } 51 | if output.count > 0 { 52 | print("program output:") 53 | print(output) 54 | } 55 | if error.count > 0 { 56 | 57 | NSApplication.shared.terminate(self) 58 | } 59 | 60 | 61 | 62 | } 63 | 64 | 65 | @IBOutlet var window: NSWindow! 66 | 67 | 68 | func applicationDidFinishLaunching(_ aNotification: Notification) { 69 | // Insert code here to initialize your application 70 | 71 | let setscript = "/Applications/Utilities/Bootchoice.app/Contents/Resources/setvals.sh" 72 | 73 | let settask = Process() 74 | settask.launchPath = "/bin/bash" 75 | settask.arguments = ["-c", setscript] 76 | settask.launch() 77 | settask.waitUntilExit() 78 | 79 | 80 | window.makeKeyAndOrderFront(NSWindow.self) 81 | window.orderFrontRegardless() 82 | window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.overlayWindow))) 83 | window.canBecomeVisibleWithoutLogin = true 84 | window.canHide = false 85 | 86 | NSApp.activate(ignoringOtherApps:true) 87 | 88 | if (self.window == nil){ 89 | window.setIsVisible(true) 90 | window.update() 91 | window.display() 92 | } 93 | } 94 | 95 | func applicationWillTerminate(_ aNotification: Notification) { 96 | // Insert code here to tear down your application 97 | self.window?.close() 98 | NSApplication.shared.terminate(self) 99 | } 100 | 101 | 102 | @IBAction func MacOS(_ sender: NSButton) { 103 | sender.isHighlighted = true 104 | self.window?.close() 105 | NSApplication.shared.terminate(self) 106 | 107 | } 108 | @IBAction func Windows(_ sender: NSButton) { 109 | 110 | let choicescript = "/Applications/Utilities/Bootchoice.app/Contents/Resources/bootchoice.sh" 111 | 112 | let choicetask = Process() 113 | choicetask.launchPath = "/bin/bash" 114 | choicetask.arguments = ["-c", choicescript] 115 | choicetask.launch() 116 | } 117 | } 118 | 119 | -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/bg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "bg.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/bg.imageset/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androindep/Bootchoice/c49a42a469be9969808c503e1bb3ba027e6ecbca/Bootchoice/Assets.xcassets/bg.imageset/bg.jpg -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/macos.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "macos.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/macos.imageset/macos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androindep/Bootchoice/c49a42a469be9969808c503e1bb3ba027e6ecbca/Bootchoice/Assets.xcassets/macos.imageset/macos.png -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/windows.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "windows.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Bootchoice/Assets.xcassets/windows.imageset/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androindep/Bootchoice/c49a42a469be9969808c503e1bb3ba027e6ecbca/Bootchoice/Assets.xcassets/windows.imageset/windows.png -------------------------------------------------------------------------------- /Bootchoice/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 42 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | NSIsNil 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Bootchoice/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.3.2 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | LSMultipleInstancesProhibited 30 | 31 | LSUIElement 32 | 33 | LSUIPresentationMode 34 | 0 35 | LSVisibleInClassic 36 | 37 | NSHumanReadableCopyright 38 | Written by C. Stott at OCADU 39 | NSMainNibFile 40 | MainMenu 41 | NSPrincipalClass 42 | NSApplication 43 | NSSupportsSuddenTermination 44 | 45 | UIApplicationExitsOnSuspend 46 | 47 | UIViewControllerBasedStatusBarAppearance 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Bootchoice/bootchoice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #harvest variables from plist 4 | 5 | WINPART=$(defaults read /Library/Preferences/bootchoice.plist WindowsPartition) 6 | Legacy=$(defaults read /Library/Preferences/bootchoice.plist Legacy) 7 | 8 | #set boot disk for legacy installs 9 | if [ ${Legacy} == 1 ] 10 | then 11 | bless --device "${WINPART}" --setboot --nextonly --legacy 12 | fi 13 | 14 | #set boot disk for uefi installs 15 | if [ ${Legacy} == 0 ] 16 | then 17 | bless --device "${WINPART}" --setboot --nextonly 18 | fi 19 | 20 | #reboot machine 21 | reboot -------------------------------------------------------------------------------- /Bootchoice/delay_bootchoice.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | #delay launching application 4 | sleep 1 5 | 6 | #launch 7 | /Applications/Utilities/BootChoice.app/Contents/MacOS/Bootchoice 8 | -------------------------------------------------------------------------------- /Bootchoice/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Test for presence of Windows partition 4 | if diskutil list | grep "Microsoft Basic Data" 5 | then 6 | WINPRESENCE=true 7 | else 8 | WINPRESENCE=false 9 | fi 10 | 11 | #Exit if no alternative boot partitions present 12 | if [[ ${WINPRESENCE} == false ]] 13 | then exit 1 14 | else echo "Alternate boot partitions found." 15 | fi 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /Bootchoice/setvals.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Does preference file exist? if not, create it. 4 | if ! [[ -e /Library/Preferences/bootchoice.plist ]] 5 | then 6 | defaults write /Library/Preferences/bootchoice.plist PartitionAutoDetection -bool true 7 | defaults write /Library/Preferences/bootchoice.plist WindowsPartition -string "" 8 | fi 9 | 10 | # Clean up plist values if still using strings 11 | 12 | LEGACY_FLAG=$(defaults read /Library/Preferences/bootchoice.plist Legacy) 13 | 14 | # Has Legacy support been determined? If not, then determine UEFI2 boot support level and record 15 | if ! [[ $LEGACY_FLAG ]] 16 | then 17 | MACHINE_TYPE=$(/usr/sbin/ioreg -c IOPlatformExpertDevice | grep "model" | cut -d'=' -f2 | grep -i -o '[a-z]\+') 18 | MACHINE_MODEL=$(/usr/sbin/ioreg -c IOPlatformExpertDevice | grep "model" | grep -o '[0-9]\+' | awk '{if(NR==1) print $0}') 19 | 20 | if [ "${MACHINE_TYPE}" == "MacBookPro" ]; then 21 | if [ $MACHINE_MODEL -ge 11 ]; then Legacy=false 22 | else Legacy=true ; fi 23 | fi 24 | 25 | if [ "${MACHINE_TYPE}" == "MacBook" ]; then 26 | if [ $MACHINE_MODEL -ge 7 ]; then Legacy=false 27 | else Legacy=true ; fi 28 | fi 29 | 30 | if [ "${MACHINE_TYPE}" == "MacBookAir" ]; then 31 | if [ $MACHINE_MODEL -ge 6 ]; then Legacy=false 32 | else Legacy=true ; fi 33 | fi 34 | 35 | if [ "${MACHINE_TYPE}" == "iMac" ]; then 36 | if [ $MACHINE_MODEL -ge 14 ]; then Legacy=false 37 | else Legacy=true ; fi 38 | fi 39 | 40 | if [ "${MACHINE_TYPE}" == "Macmini" ]; then 41 | if [ $MACHINE_MODEL -ge 7 ]; then Legacy=false 42 | else Legacy=true ; fi 43 | fi 44 | 45 | if [ "${MACHINE_TYPE}" == "MacPro" ]; then 46 | if [ $MACHINE_MODEL -ge 6 ]; then Legacy=false 47 | else Legacy=true ; fi 48 | fi 49 | 50 | if [ "${MACHINE_TYPE}" == "iMacPro" ]; then Legacy=false 51 | fi 52 | 53 | if [[ $Legacy == true ]]; then 54 | defaults write /Library/Preferences/bootchoice.plist Legacy -bool true 55 | else 56 | defaults write /Library/Preferences/bootchoice.plist Legacy -bool false 57 | fi 58 | else 59 | if [[ $LEGACY_FLAG == 1 ]]; then 60 | Legacy=true 61 | else 62 | Legacy=false 63 | fi 64 | fi 65 | 66 | # Is partition autodetection on? If so then do detection, set values only if autodetection plist flag is true 67 | PARDETECT=$(defaults read /Library/Preferences/bootchoice.plist PartitionAutoDetection) 68 | 69 | if [[ $PARDETECT == 1 ]]; then 70 | #Get disk windows resides on 71 | DISKQUERY=$(diskutil list | grep "Microsoft Basic Data" | awk '/disk/{for(i=1;i<=NF;++i)if($i~/disk/)print $i}') 72 | WINDISK=$($DISKQUERY | cut -c 5- | cut -f 1 -d s) 73 | 74 | #determine boot source based on EFI compatibility 75 | if [[ $Legacy == true ]]; then 76 | BOOTSOURCE="/dev/""$DISKQUERY" 77 | else 78 | BOOTSOURCE="/dev/disk""$WINDISK""s1" 79 | fi 80 | #Modify Bootchoice plist to match boot partition 81 | defaults write /Library/Preferences/bootchoice.plist WindowsPartition -string "$BOOTSOURCE" 82 | fi 83 | 84 | exit 0 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootchoice 2 | 3 | In the spirit of BootPicker, Bootchoice is a login-window application purely for the purposes of supporting a way for end-users to easily access dual-boot configurations with Windows. 4 | 5 | Not dynamically configurable with multiple boot options--currently only has two static image buttons, one for MacOS, one for Windows. 6 | However, unlike BootPicker this supports EFI and Legacy booting. 7 | 8 | **SIP/System Integrity Protection Compatibility** 9 | 10 | As of El Capitan, SIP prevents third-party programs from using the 'bless' command for booting to another partition. 11 | 12 | To effectively use this application with modern versions of MacOS, the NVRAM protections of SIP must be disabled. This can be done at install time with a script baked into an AutoDMG image, as a script task in a NetBoot imaging environment such as DeployStudio or Imagr, or from the Recovery partition. 13 | 14 | To disable only the NVRAM protections but keep all the other security that SIP brings: 15 | The command for doing this is `csrutil enable --without nvram` which produces a scary message but is fine. 16 | 17 | **How it works** 18 | 19 | Bootchoice.app is a GUI wrapper for several shell scripts and is run by a LaunchAgent when the Login Window is active. 20 | 21 | Order of operations is: 22 | 23 | -a script (init.sh) that detects the presence of a Windows installation runs, and kills the app before the window appears if there is no Windows partition detected. 24 | 25 | -a script (setvals.sh) that detects the location of the Windows partition and the boot style(Legacy/EFI) and verifies the values in the preference file /Library/Preferences/bootchoice.plist. These values contain information about the style of boot the system uses and the location of the Windows partition. If the prefs file or the values in it do not exist, they are initialized here before the window loads. 26 | 27 | -GUI loads, awaits user choice 28 | 29 | -If the Mac button is clicked, the app quits and reveals the regular login window beneath. 30 | 31 | -If the Windows button is clicked, the application executes an internal bless script(bootchoice.sh) that pulls the boot partition and the boot style from bootchoice.plist, blesses the appropriate device, and reboots the machine. 32 | 33 | **Partition Detection** 34 | 35 | Bootchoice.plist can be modified to disable automatic detection of the Windows partition by setting "PartitionAutoDetection" to "" 36 | If doing this, you should manually specify the Windows partition by modifying the "WindowsPartition" key's string to point to the appropriate boot source, eg. "/dev/disk0s4". This isn't recommended as the autodetection script will usually handle it and if you are deploying this in a mixed computer environment it's likely the values for this won't be the same on all machines. 37 | 38 | **Uninstallation** 39 | 40 | If you don't want Bootchoice on a computer anymore, you can run the `Uninstall.command` script from this repository. This script isn't included as part of the installer package. 41 | -------------------------------------------------------------------------------- /Uninstall.command: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ## Bootchoice uninstallation script 3 | 4 | sudo launchctl stop /Library/LaunchAgents/ca.ocadu.bootchoice.plist 5 | sudo killall Bootchoice 6 | 7 | sudo rm -f /Library/LaunchAgents/ca.ocadu.bootchoice.plist 8 | 9 | sudo rm -f /Library/Preferences/bootchoice.plist 10 | 11 | sudo rm -rf /Applications/Utilities/Bootchoice.app 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /bootchoice.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androindep/Bootchoice/c49a42a469be9969808c503e1bb3ba027e6ecbca/bootchoice.plist -------------------------------------------------------------------------------- /ca.ocadu.bootchoice.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | ca.ocadu.bootchoice 7 | ProgramArguments 8 | 9 | /Applications/Utilities/BootChoice.app/Contents/Resources/delay_bootchoice.sh 10 | 11 | LimitLoadToSessionType 12 | LoginWindow 13 | KeepAlive 14 | 15 | SuccessfulExit 16 | 17 | 18 | StandardErrorPath 19 | /var/log/bootchoice.log 20 | 21 | 22 | --------------------------------------------------------------------------------