commit 906cec6cc5d865410f76728b4e4e5283121713f9 Author: David Wernhart Date: Sun Feb 16 03:28:55 2020 +0100 first commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..789a08e Binary files /dev/null and b/.DS_Store differ diff --git a/AlDente.xcodeproj/project.pbxproj b/AlDente.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9b30ce6 --- /dev/null +++ b/AlDente.xcodeproj/project.pbxproj @@ -0,0 +1,596 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 9224A08723F1F70600961AC4 /* com.davidwernhart.Helper in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 927DBFC923F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */; }; + 927DBFCA23F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */; }; + 9283741B23F1F34400B8AE7A /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9283741A23F1F34400B8AE7A /* main.swift */; }; + 9286FB4923F84C2B00BEB15B /* LaunchAtLogin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9286FB4823F84C2B00BEB15B /* LaunchAtLogin.framework */; }; + 9286FB4A23F84C2B00BEB15B /* LaunchAtLogin.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9286FB4823F84C2B00BEB15B /* LaunchAtLogin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 92981EDB23F08D9B00C05424 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92981EDA23F08D9B00C05424 /* AppDelegate.swift */; }; + 92981EDD23F08D9B00C05424 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92981EDC23F08D9B00C05424 /* ContentView.swift */; }; + 92981EDF23F08D9C00C05424 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92981EDE23F08D9C00C05424 /* Assets.xcassets */; }; + 92981EE223F08D9C00C05424 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92981EE123F08D9C00C05424 /* Preview Assets.xcassets */; }; + 92981EE523F08D9C00C05424 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92981EE323F08D9C00C05424 /* Main.storyboard */; }; + 92ACA12B23F5F822003512DC /* HelperTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927DBFCB23F54C2C00F8BF0D /* HelperTool.swift */; }; + 92ACA12E23F5F861003512DC /* SMC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92ACA12D23F5F861003512DC /* SMC.swift */; }; + 92E24B4123F6DC0D00BE41ED /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92E24B4023F6DC0D00BE41ED /* Helper.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9224A08623F1F6E300961AC4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 12; + dstPath = Contents/Library/LaunchServices; + dstSubfolderSpec = 1; + files = ( + 9224A08723F1F70600961AC4 /* com.davidwernhart.Helper in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9258163B23F5CBD500AB7387 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 9283741623F1F34400B8AE7A /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = ""; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 9286FB4B23F84C2B00BEB15B /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 9286FB4A23F84C2B00BEB15B /* LaunchAtLogin.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 927DBFC623F533FB00F8BF0D /* Helper-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Helper-Launchd.plist"; sourceTree = ""; }; + 927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelperToolProtocol.swift; sourceTree = ""; }; + 927DBFCB23F54C2C00F8BF0D /* HelperTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelperTool.swift; sourceTree = ""; }; + 9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.davidwernhart.Helper; sourceTree = BUILT_PRODUCTS_DIR; }; + 9283741A23F1F34400B8AE7A /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 9283741F23F1F38100B8AE7A /* Helper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Helper-Info.plist"; sourceTree = ""; }; + 9286FB4823F84C2B00BEB15B /* LaunchAtLogin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LaunchAtLogin.framework; path = Carthage/Build/Mac/LaunchAtLogin.framework; sourceTree = ""; }; + 92981ED723F08D9B00C05424 /* AlDente.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AlDente.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 92981EDA23F08D9B00C05424 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 92981EDC23F08D9B00C05424 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 92981EDE23F08D9C00C05424 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 92981EE123F08D9C00C05424 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 92981EE423F08D9C00C05424 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 92981EE623F08D9C00C05424 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 92981EE723F08D9C00C05424 /* AlDente.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AlDente.entitlements; sourceTree = ""; }; + 92ACA12D23F5F861003512DC /* SMC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMC.swift; sourceTree = ""; }; + 92E24B4023F6DC0D00BE41ED /* Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9283741523F1F34400B8AE7A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 92981ED423F08D9B00C05424 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9286FB4923F84C2B00BEB15B /* LaunchAtLogin.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9258163723F5CBD400AB7387 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9286FB4823F84C2B00BEB15B /* LaunchAtLogin.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 927DBFC723F545AF00F8BF0D /* Common */ = { + isa = PBXGroup; + children = ( + 927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */, + ); + path = Common; + sourceTree = ""; + }; + 9283741923F1F34400B8AE7A /* com.davidwernhart.Helper */ = { + isa = PBXGroup; + children = ( + 9283741A23F1F34400B8AE7A /* main.swift */, + 9283741F23F1F38100B8AE7A /* Helper-Info.plist */, + 927DBFC623F533FB00F8BF0D /* Helper-Launchd.plist */, + 927DBFCB23F54C2C00F8BF0D /* HelperTool.swift */, + 92ACA12D23F5F861003512DC /* SMC.swift */, + ); + path = com.davidwernhart.Helper; + sourceTree = ""; + }; + 92981ECE23F08D9B00C05424 = { + isa = PBXGroup; + children = ( + 927DBFC723F545AF00F8BF0D /* Common */, + 92981ED923F08D9B00C05424 /* AlDente */, + 9283741923F1F34400B8AE7A /* com.davidwernhart.Helper */, + 92981ED823F08D9B00C05424 /* Products */, + 9258163723F5CBD400AB7387 /* Frameworks */, + ); + sourceTree = ""; + }; + 92981ED823F08D9B00C05424 /* Products */ = { + isa = PBXGroup; + children = ( + 92981ED723F08D9B00C05424 /* AlDente.app */, + 9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */, + ); + name = Products; + sourceTree = ""; + }; + 92981ED923F08D9B00C05424 /* AlDente */ = { + isa = PBXGroup; + children = ( + 92E24B4023F6DC0D00BE41ED /* Helper.swift */, + 92981EDA23F08D9B00C05424 /* AppDelegate.swift */, + 92981EDC23F08D9B00C05424 /* ContentView.swift */, + 92981EDE23F08D9C00C05424 /* Assets.xcassets */, + 92981EE323F08D9C00C05424 /* Main.storyboard */, + 92981EE623F08D9C00C05424 /* Info.plist */, + 92981EE723F08D9C00C05424 /* AlDente.entitlements */, + 92981EE023F08D9C00C05424 /* Preview Content */, + ); + path = AlDente; + sourceTree = ""; + }; + 92981EE023F08D9C00C05424 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 92981EE123F08D9C00C05424 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 9283741723F1F34400B8AE7A /* com.davidwernhart.Helper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9283741C23F1F34400B8AE7A /* Build configuration list for PBXNativeTarget "com.davidwernhart.Helper" */; + buildPhases = ( + 9283741423F1F34400B8AE7A /* Sources */, + 9283741523F1F34400B8AE7A /* Frameworks */, + 9283741623F1F34400B8AE7A /* CopyFiles */, + 9258163B23F5CBD500AB7387 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = com.davidwernhart.Helper; + productName = com.davidwernhart.Helper; + productReference = 9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */; + productType = "com.apple.product-type.tool"; + }; + 92981ED623F08D9B00C05424 /* AlDente */ = { + isa = PBXNativeTarget; + buildConfigurationList = 92981EEA23F08D9C00C05424 /* Build configuration list for PBXNativeTarget "AlDente" */; + buildPhases = ( + 92981ED323F08D9B00C05424 /* Sources */, + 92981ED423F08D9B00C05424 /* Frameworks */, + 92981ED523F08D9B00C05424 /* Resources */, + 9224A08623F1F6E300961AC4 /* CopyFiles */, + 92E24B4423F847B500BE41ED /* ShellScript */, + 9286FB4B23F84C2B00BEB15B /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AlDente; + productName = AlDente; + productReference = 92981ED723F08D9B00C05424 /* AlDente.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 92981ECF23F08D9B00C05424 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = "David Wernhart"; + TargetAttributes = { + 9283741723F1F34400B8AE7A = { + CreatedOnToolsVersion = 11.3.1; + }; + 92981ED623F08D9B00C05424 = { + CreatedOnToolsVersion = 11.3.1; + }; + }; + }; + buildConfigurationList = 92981ED223F08D9B00C05424 /* Build configuration list for PBXProject "AlDente" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 92981ECE23F08D9B00C05424; + productRefGroup = 92981ED823F08D9B00C05424 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 92981ED623F08D9B00C05424 /* AlDente */, + 9283741723F1F34400B8AE7A /* com.davidwernhart.Helper */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 92981ED523F08D9B00C05424 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 92981EE523F08D9C00C05424 /* Main.storyboard in Resources */, + 92981EE223F08D9C00C05424 /* Preview Assets.xcassets in Resources */, + 92981EDF23F08D9C00C05424 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 92E24B4423F847B500BE41ED /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "${PROJECT_DIR}/Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 9283741423F1F34400B8AE7A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9283741B23F1F34400B8AE7A /* main.swift in Sources */, + 92ACA12B23F5F822003512DC /* HelperTool.swift in Sources */, + 927DBFCA23F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */, + 92ACA12E23F5F861003512DC /* SMC.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 92981ED323F08D9B00C05424 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 927DBFC923F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */, + 92981EDD23F08D9B00C05424 /* ContentView.swift in Sources */, + 92981EDB23F08D9B00C05424 /* AppDelegate.swift in Sources */, + 92E24B4123F6DC0D00BE41ED /* Helper.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 92981EE323F08D9C00C05424 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 92981EE423F08D9C00C05424 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 9283741D23F1F34400B8AE7A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2.0; + DEVELOPMENT_TEAM = 56C2L92EKW; + ENABLE_HARDENED_RUNTIME = YES; + "FRAMEWORK_SEARCH_PATHS[arch=*]" = "$(PROJECT_DIR)/Frameworks"; + INFOPLIST_FILE = "com.davidwernhart.Helper/Helper-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MARKETING_VERSION = 2.0; + OTHER_LDFLAGS = ( + "-sectcreate", + __TEXT, + __info_plist, + "$(SRCROOT)/com.davidwernhart.Helper/Helper-Info.plist", + "-sectcreate", + __TEXT, + __launchd_plist, + "$(SRCROOT)/com.davidwernhart.Helper/Helper-Launchd.plist", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.Helper; + PRODUCT_MODULE_NAME = AlDenteHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Frameworks"; + }; + name = Debug; + }; + 9283741E23F1F34400B8AE7A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2.0; + DEVELOPMENT_TEAM = 56C2L92EKW; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = "com.davidwernhart.Helper/Helper-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MARKETING_VERSION = 2.0; + OTHER_LDFLAGS = ( + "-sectcreate", + __TEXT, + __info_plist, + "$(SRCROOT)/com.davidwernhart.Helper/Helper-Info.plist", + "-sectcreate", + __TEXT, + __launchd_plist, + "$(SRCROOT)/com.davidwernhart.Helper/Helper-Launchd.plist", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.Helper; + PRODUCT_MODULE_NAME = AlDenteHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Frameworks"; + }; + name = Release; + }; + 92981EE823F08D9C00C05424 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 92981EE923F08D9C00C05424 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 92981EEB23F08D9C00C05424 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = AlDente/AlDente.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"AlDente/Preview Content\""; + DEVELOPMENT_TEAM = 56C2L92EKW; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); + INFOPLIST_FILE = AlDente/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.AlDente; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 92981EEC23F08D9C00C05424 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = AlDente/AlDente.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"AlDente/Preview Content\""; + DEVELOPMENT_TEAM = 56C2L92EKW; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/Mac", + ); + INFOPLIST_FILE = AlDente/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.AlDente; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 9283741C23F1F34400B8AE7A /* Build configuration list for PBXNativeTarget "com.davidwernhart.Helper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9283741D23F1F34400B8AE7A /* Debug */, + 9283741E23F1F34400B8AE7A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 92981ED223F08D9B00C05424 /* Build configuration list for PBXProject "AlDente" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 92981EE823F08D9C00C05424 /* Debug */, + 92981EE923F08D9C00C05424 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 92981EEA23F08D9C00C05424 /* Build configuration list for PBXNativeTarget "AlDente" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 92981EEB23F08D9C00C05424 /* Debug */, + 92981EEC23F08D9C00C05424 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 92981ECF23F08D9B00C05424 /* Project object */; +} diff --git a/AlDente.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AlDente.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..eaf971d --- /dev/null +++ b/AlDente.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/AlDente.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AlDente.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/AlDente.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/AlDente.xcodeproj/project.xcworkspace/xcuserdata/davidwernhart.xcuserdatad/UserInterfaceState.xcuserstate b/AlDente.xcodeproj/project.xcworkspace/xcuserdata/davidwernhart.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..c697e47 Binary files /dev/null and b/AlDente.xcodeproj/project.xcworkspace/xcuserdata/davidwernhart.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcschemes/xcschememanagement.plist b/AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..94042ec --- /dev/null +++ b/AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,29 @@ + + + + + SchemeUserState + + AlDente.xcscheme_^#shared#^_ + + orderHint + 0 + + Hall.xcscheme_^#shared#^_ + + orderHint + 0 + + Helper.xcscheme_^#shared#^_ + + orderHint + 2 + + com.davidwernhart.Helper.xcscheme_^#shared#^_ + + orderHint + 1 + + + + diff --git a/AlDente/.DS_Store b/AlDente/.DS_Store new file mode 100644 index 0000000..8a5ef45 Binary files /dev/null and b/AlDente/.DS_Store differ diff --git a/AlDente/AlDente.entitlements b/AlDente/AlDente.entitlements new file mode 100644 index 0000000..51a7cc5 --- /dev/null +++ b/AlDente/AlDente.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/AlDente/AppDelegate.swift b/AlDente/AppDelegate.swift new file mode 100644 index 0000000..4b244a8 --- /dev/null +++ b/AlDente/AppDelegate.swift @@ -0,0 +1,64 @@ +// +// AppDelegate.swift +// AlDente +// +// Created by David Wernhart on 09.02.20. +// Copyright © 2020 David Wernhart. All rights reserved. +// + +import Cocoa +import SwiftUI +import ServiceManagement +import Foundation + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + //var window: NSWindow! + var statusBarItem: NSStatusItem! + var popover: NSPopover! + + func applicationDidFinishLaunching(_ aNotification: Notification) { + + let contentView = ContentView() + + // Create the popover + let popover = NSPopover() + popover.contentSize = NSSize(width: 400, height: 600) + popover.behavior = .transient + popover.contentViewController = NSHostingController(rootView: contentView) + self.popover = popover + + + let statusBar = NSStatusBar.system + statusBarItem = statusBar.statusItem( + withLength: NSStatusItem.squareLength) + statusBarItem.button?.title = "🍝" + + if let button = self.statusBarItem.button { + button.action = #selector(togglePopover(_:)) + } + + Helper.instance.checkHelperVersion() + + } + + @objc func togglePopover(_ sender: AnyObject?) { + self.popover.contentViewController?.view.window?.becomeKey() + if let button = self.statusBarItem.button { + if self.popover.isShown { + self.popover.performClose(sender) + } else { + self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY) + } + } + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } + + + +} + diff --git a/AlDente/Assets.xcassets/.DS_Store b/AlDente/Assets.xcassets/.DS_Store new file mode 100644 index 0000000..f8c1b43 Binary files /dev/null and b/AlDente/Assets.xcassets/.DS_Store differ diff --git a/AlDente/Assets.xcassets/AppIcon.appiconset/Contents.json b/AlDente/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d517fae --- /dev/null +++ b/AlDente/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,61 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "spaghetti-2.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "spaghetti-1.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "spaghetti.png", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti-1.png b/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti-1.png new file mode 100644 index 0000000..ed07e60 Binary files /dev/null and b/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti-1.png differ diff --git a/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti-2.png b/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti-2.png new file mode 100644 index 0000000..ed07e60 Binary files /dev/null and b/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti-2.png differ diff --git a/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti.png b/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti.png new file mode 100644 index 0000000..ed07e60 Binary files /dev/null and b/AlDente/Assets.xcassets/AppIcon.appiconset/spaghetti.png differ diff --git a/AlDente/Assets.xcassets/Contents.json b/AlDente/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AlDente/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AlDente/Assets.xcassets/SettingsColor.colorset/Contents.json b/AlDente/Assets.xcassets/SettingsColor.colorset/Contents.json new file mode 100644 index 0000000..f8a3261 --- /dev/null +++ b/AlDente/Assets.xcassets/SettingsColor.colorset/Contents.json @@ -0,0 +1,56 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "1.000", + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.800", + "alpha" : "1.000", + "blue" : "0.800", + "green" : "0.800" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.100", + "alpha" : "1.000", + "blue" : "0.100", + "green" : "0.100" + } + } + } + ] +} \ No newline at end of file diff --git a/AlDente/Base.lproj/Main.storyboard b/AlDente/Base.lproj/Main.storyboard new file mode 100644 index 0000000..a6ad7ba --- /dev/null +++ b/AlDente/Base.lproj/Main.storyboard @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AlDente/ContentView.swift b/AlDente/ContentView.swift new file mode 100644 index 0000000..48d6c6a --- /dev/null +++ b/AlDente/ContentView.swift @@ -0,0 +1,213 @@ +// +// ContentView.swift +// AlDente +// +// Created by David Wernhart on 09.02.20. +// Copyright © 2020 David Wernhart. All rights reserved. +// + +import SwiftUI +import ServiceManagement +import Foundation +import LaunchAtLogin +import Combine + +struct BlueButtonStyle: ButtonStyle { + func makeBody(configuration: Self.Configuration) -> some View { + configuration.label + .foregroundColor(configuration.isPressed ? Color.blue : Color.white) + .background(configuration.isPressed ? Color.white : Color.blue) + .cornerRadius(6.0) + .padding() + } +} + +struct RedButtonStyle: ButtonStyle { + func makeBody(configuration: Self.Configuration) -> some View { + configuration.label + .foregroundColor(configuration.isPressed ? Color.red : Color.white) + .background(configuration.isPressed ? Color.white : Color.red) + .cornerRadius(6.0) + .padding() + } +} + +struct settings: View { + + + var content: () -> Content + @State var launchOnLogin = LaunchAtLogin.isEnabled + + init(@ViewBuilder _ content: @escaping () -> Content) { + self.content = content + + //Helper.instance.delegate = self + } + + var body: some View { + VStack(alignment: .center){ + HStack(alignment: .center) { + Toggle(isOn: Binding( + get: { + self.launchOnLogin + }, + set: {(newValue) in + self.launchOnLogin = newValue + if(newValue){ + print("launch on login turned on!") + LaunchAtLogin.isEnabled = true + } + else{ + print("launch on login turned off!") + LaunchAtLogin.isEnabled = false + } + } + )) { + Text("Launch on Login") + }.padding() + + Spacer() + Button( action: { + Helper.instance.installHelper() + } + ) { + Text("Reinstall Helper") + .frame(maxWidth: 120, maxHeight: 30) + }.buttonStyle(BlueButtonStyle()) + } + + + HStack(alignment: .center) { + Spacer() + VStack(alignment: .leading){ + Text("AlDente 🍝").font(.subheadline) + Text("github.com/davidwernhart/AlDente").foregroundColor(Color.blue) + Text("Created with 🤍 by David Wernhart in 2020") +// Text("AlDente 🍝").font(.title) +// Text("Keep your battery just right").font(.subheadline) + } + Spacer() + Button(action: { + let url = URL(string: "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6PLR7D9ZCZGGC&source=url")! + if NSWorkspace.shared.open(url) { + print("default browser was successfully opened") + } + }) { + Text("Donate") + .frame(maxWidth: 60, maxHeight: 50) + } + .buttonStyle(BlueButtonStyle()) + } + }.background(Color("SettingsColor")).cornerRadius(5) + } +} + +struct ContentView: View{ + @State var adaptableHeight = CGFloat(100) + @State var showSettings = false + + @ObservedObject var presenter = SMCPresenter() + + init() { + Helper.instance.delegate = presenter + Helper.instance.readMaxBatteryCharge() + } + + + + var body: some View { + let vstack = VStack{ + VStack(alignment: .leading) { + //Text("Value is: \(presenter.value)") + HStack(alignment: .center){ + Text(" Max. Battery Charge:").padding(.leading) + TextField("Number", value: Binding( + get: { + Float(self.presenter.value) + }, + set: {(newValue) in + if(newValue >= 20 && newValue <= 100){ + self.presenter.setValue(value: newValue) + } + } + ), formatter: NumberFormatter()) + .multilineTextAlignment(.center) + .frame(maxWidth:50) + .textFieldStyle(RoundedBorderTextFieldStyle()) + + Spacer() + Button( action: { + self.showSettings = !self.showSettings + if(self.showSettings){ + self.adaptableHeight = 235 + } + else{ + self.adaptableHeight = 100 + } + }) { + Text("Settings") + .frame(maxWidth: 70, maxHeight: 30) + }.buttonStyle(BlueButtonStyle()).padding(.leading,-30) + + Button( action: { + NSApplication.shared.terminate(self) + }) { + Text("Exit") + .frame(maxWidth: 50, maxHeight: 30) + }.buttonStyle(RedButtonStyle()).padding(.leading,-30) + } + + + HStack(alignment: .center){ + + Slider(value: Binding( + get: { + Float(self.presenter.value) + }, + set: {(newValue) in + if(newValue >= 20 && newValue <= 100){ + self.presenter.setValue(value: newValue) + } + } + ), in: 20...100).padding(.horizontal).padding(.top,-20) + } + + Spacer() + if(self.showSettings){ + settings{Text("")} + } + + }.frame(width: 400, height: adaptableHeight) + + } + + return vstack + } +} + +class SMCPresenter: ObservableObject, HelperDelegate{ + + @Published var value: UInt8 = 0 + private var timer: Timer? + + func OnMaxBatRead(value: UInt8){ + DispatchQueue.main.async { + self.value = value + } + } + + func setValue(value: Float){ + DispatchQueue.main.async { + self.value = UInt8(value) + } + self.timer?.invalidate() + self.timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { timer in + print("Setting Max Battery To: ",value) + Helper.instance.writeMaxBatteryCharge(setVal: UInt8(value)) + Helper.instance.readMaxBatteryCharge() + self.timer = nil + }) + } + +} + diff --git a/AlDente/Helper.swift b/AlDente/Helper.swift new file mode 100644 index 0000000..a79fb38 --- /dev/null +++ b/AlDente/Helper.swift @@ -0,0 +1,124 @@ +// +// Helper.swift +// AlDente +// +// Created by David Wernhart on 14.02.20. +// Copyright © 2020 David Wernhart. All rights reserved. +// + +import Cocoa +import SwiftUI +import ServiceManagement +import Foundation + +protocol HelperDelegate { + func OnMaxBatRead(value: UInt8) +} + +class Helper{ + + static let instance = Helper() + + public var delegate: HelperDelegate? + +// var receiveMessage = "" { +// didSet { +// DispatchQueue.main.async { +// print(self.receiveMessage) +// // if self.receiveMessage.isEmpty { +// // self.clearButton.isEnabled = false +// // } else { +// // self.clearButton.isEnabled = true +// // } +// } +// } +// } + + lazy var helperToolConnection: NSXPCConnection = { + let connection = NSXPCConnection(machServiceName: "com.davidwernhart.Helper.mach", options: .privileged) + connection.remoteObjectInterface = NSXPCInterface(with: HelperToolProtocol.self) + + connection.resume() + return connection + }() + + @objc func installHelper() { + print("trying to install helper!") + var status: OSStatus = noErr + let helperID = "com.davidwernhart.Helper" as CFString//Prefs.helperID as CFString + + var authItem = AuthorizationItem(name: kSMRightBlessPrivilegedHelper, valueLength: 0, value: nil, flags: 0) + var authRights = AuthorizationRights(count: 1, items: &authItem) + let authFlags: AuthorizationFlags = [.interactionAllowed, .preAuthorize, .extendRights] + var authRef: AuthorizationRef? = nil + status = AuthorizationCreate(&authRights, nil, authFlags, &authRef) + if status != errAuthorizationSuccess { + print(SecCopyErrorMessageString(status,nil)) + print("Error:", String(status)) + } + var error: Unmanaged? = nil + SMJobBless(kSMDomainSystemLaunchd, helperID, authRef, &error) + if let e = error?.takeRetainedValue() { + print("Domain:", CFErrorGetDomain(e)) + print("Code:", CFErrorGetCode(e)) + print("UserInfo:", CFErrorCopyUserInfo(e)) + print("Description:", CFErrorCopyDescription(e)) + print("Reason:", CFErrorCopyFailureReason(e)) + print("Suggestion:", CFErrorCopyRecoverySuggestion(e)) + } + } + + + @objc func writeMaxBatteryCharge(setVal: UInt8){ + SMCWriteByte(key: "BCLM", value: setVal) + + + } + + @objc func readMaxBatteryCharge(){ + SMCReadByte(key:"BCLM",withReply: { (value) in + print(String(value)) + self.delegate?.OnMaxBatRead(value: value) + }) + } + + @objc func checkHelperVersion() { + print("checking helper version") + if let helper = helperToolConnection.remoteObjectProxyWithErrorHandler({ (error) in + let e = error as NSError + print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")") + self.installHelper() + //self.receiveMessage.append("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")") + }) as? HelperToolProtocol { + helper.getVersion(withReply: { (version) in + print("helperVersion:", helperVersion, " version from helper:",version) + if(!helperVersion.elementsEqual(version)){ + self.installHelper() + } + //self.receiveMessage.append("Version: \(version)\n") + }) + } + } + + @objc func SMCReadByte(key:String, withReply reply: @escaping (UInt8) -> Void){ + if let helper = helperToolConnection.remoteObjectProxyWithErrorHandler({ (error) in + let e = error as NSError + print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")") + //self.receiveMessage.append("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")") + }) as? HelperToolProtocol { + helper.readSMCByte(key: key) { (value) in + reply (value) + } + } + } + + @objc func SMCWriteByte(key:String,value:UInt8){ + if let helper = helperToolConnection.remoteObjectProxyWithErrorHandler({ (error) in + let e = error as NSError + print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")") + //self.receiveMessage.append("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")") + }) as? HelperToolProtocol { + helper.setSMCByte(key: key,value: value) + } + } +} diff --git a/AlDente/Info.plist b/AlDente/Info.plist new file mode 100644 index 0000000..60ece97 --- /dev/null +++ b/AlDente/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + LSUIElement + + NSHumanReadableCopyright + Copyright © 2020 David Wernhart. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + NSSupportsAutomaticTermination + + NSSupportsSuddenTermination + + SMPrivilegedExecutables + + com.davidwernhart.Helper + identifier "com.davidwernhart.Helper" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: david.wernhart96@gmail.com (GSDX9BQ584)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ + + + diff --git a/AlDente/Preview Content/Preview Assets.xcassets/Contents.json b/AlDente/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/AlDente/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Cartfile b/Cartfile new file mode 100644 index 0000000..bfb4e39 --- /dev/null +++ b/Cartfile @@ -0,0 +1,2 @@ +github "sindresorhus/LaunchAtLogin" + diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 0000000..bc0bf77 --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "sindresorhus/LaunchAtLogin" "v3.0.0" diff --git a/Carthage/.DS_Store b/Carthage/.DS_Store new file mode 100644 index 0000000..eb65868 Binary files /dev/null and b/Carthage/.DS_Store differ diff --git a/Carthage/Build/.DS_Store b/Carthage/Build/.DS_Store new file mode 100644 index 0000000..d1c74c1 Binary files /dev/null and b/Carthage/Build/.DS_Store differ diff --git a/Carthage/Build/.LaunchAtLogin.version b/Carthage/Build/.LaunchAtLogin.version new file mode 100644 index 0000000..cda06c5 --- /dev/null +++ b/Carthage/Build/.LaunchAtLogin.version @@ -0,0 +1,19 @@ +{ + "Mac" : [ + { + "name" : "LaunchAtLogin", + "hash" : "3aa89276b3b2caf4499607f2f8edc08acaa6b1ea55a5e9b42f7ca47c595f41d1", + "swiftToolchainVersion" : "5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)" + } + ], + "watchOS" : [ + + ], + "tvOS" : [ + + ], + "commitish" : "v3.0.0", + "iOS" : [ + + ] +} \ No newline at end of file diff --git a/Carthage/Build/Mac/.DS_Store b/Carthage/Build/Mac/.DS_Store new file mode 100644 index 0000000..796e95e Binary files /dev/null and b/Carthage/Build/Mac/.DS_Store differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework.dSYM/Contents/Info.plist b/Carthage/Build/Mac/LaunchAtLogin.framework.dSYM/Contents/Info.plist new file mode 100644 index 0000000..bc6eb76 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.com.sindresorhus.LaunchAtLogin + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 3.0.0 + CFBundleVersion + 1 + + diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework.dSYM/Contents/Resources/DWARF/LaunchAtLogin b/Carthage/Build/Mac/LaunchAtLogin.framework.dSYM/Contents/Resources/DWARF/LaunchAtLogin new file mode 100644 index 0000000..d1dcf26 Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework.dSYM/Contents/Resources/DWARF/LaunchAtLogin differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Headers b/Carthage/Build/Mac/LaunchAtLogin.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/LaunchAtLogin b/Carthage/Build/Mac/LaunchAtLogin.framework/LaunchAtLogin new file mode 120000 index 0000000..f0b8733 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/LaunchAtLogin @@ -0,0 +1 @@ +Versions/Current/LaunchAtLogin \ No newline at end of file diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Modules b/Carthage/Build/Mac/LaunchAtLogin.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Resources b/Carthage/Build/Mac/LaunchAtLogin.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Headers/LaunchAtLogin-Swift.h b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Headers/LaunchAtLogin-Swift.h new file mode 100644 index 0000000..a96006d --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Headers/LaunchAtLogin-Swift.h @@ -0,0 +1,204 @@ +// Generated by Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif + +#if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +#else +# define SWIFT_METHOD_FAMILY(X) +#endif +#if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +#else +# define SWIFT_NOESCAPE +#endif +#if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SWIFT_WARN_UNUSED_RESULT +#endif +#if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +#else +# define SWIFT_NORETURN +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if defined(__has_attribute) && __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +#else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +#endif +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#if __has_feature(modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="LaunchAtLogin",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#pragma clang diagnostic pop diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Headers/LaunchAtLogin.h b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Headers/LaunchAtLogin.h new file mode 100644 index 0000000..f801178 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Headers/LaunchAtLogin.h @@ -0,0 +1,4 @@ +#import + +FOUNDATION_EXPORT double LaunchAtLoginVersionNumber; +FOUNDATION_EXPORT const unsigned char LaunchAtLoginVersionString[]; diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/LaunchAtLogin b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/LaunchAtLogin new file mode 100755 index 0000000..4ffa9e2 Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/LaunchAtLogin differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64-apple-macos.swiftdoc b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64-apple-macos.swiftdoc new file mode 100644 index 0000000..ad316cb Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64-apple-macos.swiftdoc differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64-apple-macos.swiftmodule b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64-apple-macos.swiftmodule new file mode 100644 index 0000000..9e946ea Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64-apple-macos.swiftmodule differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64.swiftdoc b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64.swiftdoc new file mode 100644 index 0000000..ad316cb Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64.swiftmodule b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64.swiftmodule new file mode 100644 index 0000000..9e946ea Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/LaunchAtLogin.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/module.modulemap b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..3753816 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,11 @@ +framework module LaunchAtLogin { + umbrella header "LaunchAtLogin.h" + + export * + module * { export * } +} + +module LaunchAtLogin.Swift { + header "LaunchAtLogin-Swift.h" + requires objc +} diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/Info.plist b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..748d9cd --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,44 @@ + + + + + BuildMachineOSBuild + 19D76 + CFBundleExecutable + LaunchAtLogin + CFBundleIdentifier + com.sindresorhus.LaunchAtLogin + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + LaunchAtLogin + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.0.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 11C504 + DTPlatformVersion + GM + DTSDKBuild + 19B90 + DTSDKName + macosx10.15 + DTXcode + 1130 + DTXcodeBuild + 11C504 + LSMinimumSystemVersion + 10.12 + NSHumanReadableCopyright + MIT © Sindre Sorhus + + diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCore.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCore.dylib new file mode 100755 index 0000000..fddff1e Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCore.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCoreFoundation.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCoreFoundation.dylib new file mode 100755 index 0000000..df2d8fd Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCoreFoundation.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCoreGraphics.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCoreGraphics.dylib new file mode 100755 index 0000000..708867a Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftCoreGraphics.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftDarwin.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftDarwin.dylib new file mode 100755 index 0000000..aabc8f6 Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftDarwin.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftDispatch.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftDispatch.dylib new file mode 100755 index 0000000..bdc7829 Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftDispatch.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftFoundation.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftFoundation.dylib new file mode 100755 index 0000000..eca45ca Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftFoundation.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftIOKit.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftIOKit.dylib new file mode 100755 index 0000000..3dee2a5 Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftIOKit.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftObjectiveC.dylib b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftObjectiveC.dylib new file mode 100755 index 0000000..f7eb84f Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Frameworks/libswiftObjectiveC.dylib differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Info.plist b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Info.plist new file mode 100644 index 0000000..384d68b --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/Info.plist @@ -0,0 +1,48 @@ + + + + + BuildMachineOSBuild + 19D76 + CFBundleExecutable + LaunchAtLoginHelper + CFBundleIdentifier + com.sindresorhus.LaunchAtLoginHelper + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + LaunchAtLoginHelper + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 11C504 + DTPlatformVersion + GM + DTSDKBuild + 19B90 + DTSDKName + macosx10.15 + DTXcode + 1130 + DTXcodeBuild + 11C504 + LSBackgroundOnly + + LSMinimumSystemVersion + 10.12 + NSHumanReadableCopyright + MIT © Sindre Sorhus + NSPrincipalClass + NSApplication + + diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/MacOS/LaunchAtLoginHelper b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/MacOS/LaunchAtLoginHelper new file mode 100755 index 0000000..4d19f46 Binary files /dev/null and b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/MacOS/LaunchAtLoginHelper differ diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/PkgInfo b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/PkgInfo new file mode 100644 index 0000000..bd04210 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/LaunchAtLoginHelper.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/copy-helper.sh b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/copy-helper.sh new file mode 100755 index 0000000..52af101 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/A/Resources/copy-helper.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +origin_helper_path="$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH/LaunchAtLogin.framework/Resources/LaunchAtLoginHelper.app" +helper_dir="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/LoginItems" +helper_path="$helper_dir/LaunchAtLoginHelper.app" + +rm -rf "$helper_path" +mkdir -p "$helper_dir" +cp -rf "$origin_helper_path" "$helper_dir/" + +defaults write "$helper_path/Contents/Info" CFBundleIdentifier -string "$PRODUCT_BUNDLE_IDENTIFIER-LaunchAtLoginHelper" + +if [[ -n $CODE_SIGN_ENTITLEMENTS ]]; then + codesign --force --entitlements="$CODE_SIGN_ENTITLEMENTS" --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path" +else + codesign --force --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path" +fi + +if [[ $CONFIGURATION == "Release" ]]; then + rm -rf "$origin_helper_path" + rm "$(dirname "$origin_helper_path")/copy-helper.sh" +fi diff --git a/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/Current b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Carthage/Build/Mac/LaunchAtLogin.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Carthage/Checkouts/LaunchAtLogin/.editorconfig b/Carthage/Checkouts/LaunchAtLogin/.editorconfig new file mode 100644 index 0000000..aaac325 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/Carthage/Checkouts/LaunchAtLogin/.gitattributes b/Carthage/Checkouts/LaunchAtLogin/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/Carthage/Checkouts/LaunchAtLogin/.github/funding.yml b/Carthage/Checkouts/LaunchAtLogin/.github/funding.yml new file mode 100644 index 0000000..15edf6e --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/.github/funding.yml @@ -0,0 +1,4 @@ +github: sindresorhus +open_collective: sindresorhus +patreon: sindresorhus +custom: https://sindresorhus.com/donate diff --git a/Carthage/Checkouts/LaunchAtLogin/.gitignore b/Carthage/Checkouts/LaunchAtLogin/.gitignore new file mode 100644 index 0000000..8b53cbf --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/.gitignore @@ -0,0 +1,2 @@ +xcuserdata +project.xcworkspace diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/project.pbxproj b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/project.pbxproj new file mode 100644 index 0000000..851ca84 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/project.pbxproj @@ -0,0 +1,494 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 52; + objects = { + +/* Begin PBXBuildFile section */ + E32E9B681EB87D7B000FEEE9 /* LaunchAtLogin.h in Headers */ = {isa = PBXBuildFile; fileRef = E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E32E9B6F1EB87DC5000FEEE9 /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32E9B6E1EB87DC5000FEEE9 /* LaunchAtLogin.swift */; }; + E32E9B771EB87EA3000FEEE9 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32E9B761EB87EA3000FEEE9 /* main.swift */; }; + E32E9B861EB8845E000FEEE9 /* LaunchAtLoginHelper.app in Resources */ = {isa = PBXBuildFile; fileRef = E32E9B741EB87EA3000FEEE9 /* LaunchAtLoginHelper.app */; }; + E32E9B931EB889AE000FEEE9 /* copy-helper.sh in Resources */ = {isa = PBXBuildFile; fileRef = E32E9B921EB889AE000FEEE9 /* copy-helper.sh */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + E32E9B871EB88462000FEEE9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E32E9B5A1EB87D7B000FEEE9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E32E9B731EB87EA3000FEEE9; + remoteInfo = LaunchAtLoginHelper; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + E32E9B631EB87D7B000FEEE9 /* LaunchAtLogin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LaunchAtLogin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = LaunchAtLogin.h; sourceTree = ""; usesTabs = 1; }; + E32E9B671EB87D7B000FEEE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E32E9B6E1EB87DC5000FEEE9 /* LaunchAtLogin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = LaunchAtLogin.swift; sourceTree = ""; usesTabs = 1; }; + E32E9B741EB87EA3000FEEE9 /* LaunchAtLoginHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LaunchAtLoginHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E32E9B761EB87EA3000FEEE9 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = main.swift; sourceTree = ""; usesTabs = 1; }; + E32E9B7F1EB87EA3000FEEE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E32E9B921EB889AE000FEEE9 /* copy-helper.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; lineEnding = 0; path = "copy-helper.sh"; sourceTree = ""; usesTabs = 1; }; + E3B8C38A20C0003300272EC0 /* LaunchAtLoginHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LaunchAtLoginHelper.entitlements; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E32E9B5F1EB87D7B000FEEE9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E32E9B711EB87EA3000FEEE9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E32E9B591EB87D7B000FEEE9 = { + isa = PBXGroup; + children = ( + E32E9B651EB87D7B000FEEE9 /* LaunchAtLogin */, + E32E9B751EB87EA3000FEEE9 /* LaunchAtLoginHelper */, + E32E9B641EB87D7B000FEEE9 /* Products */, + ); + sourceTree = ""; + usesTabs = 1; + }; + E32E9B641EB87D7B000FEEE9 /* Products */ = { + isa = PBXGroup; + children = ( + E32E9B631EB87D7B000FEEE9 /* LaunchAtLogin.framework */, + E32E9B741EB87EA3000FEEE9 /* LaunchAtLoginHelper.app */, + ); + name = Products; + sourceTree = ""; + }; + E32E9B651EB87D7B000FEEE9 /* LaunchAtLogin */ = { + isa = PBXGroup; + children = ( + E32E9B6E1EB87DC5000FEEE9 /* LaunchAtLogin.swift */, + E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */, + E32E9B921EB889AE000FEEE9 /* copy-helper.sh */, + E32E9B671EB87D7B000FEEE9 /* Info.plist */, + ); + path = LaunchAtLogin; + sourceTree = ""; + }; + E32E9B751EB87EA3000FEEE9 /* LaunchAtLoginHelper */ = { + isa = PBXGroup; + children = ( + E32E9B761EB87EA3000FEEE9 /* main.swift */, + E32E9B7F1EB87EA3000FEEE9 /* Info.plist */, + E3B8C38A20C0003300272EC0 /* LaunchAtLoginHelper.entitlements */, + ); + path = LaunchAtLoginHelper; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + E32E9B601EB87D7B000FEEE9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E32E9B681EB87D7B000FEEE9 /* LaunchAtLogin.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + E32E9B621EB87D7B000FEEE9 /* LaunchAtLogin */ = { + isa = PBXNativeTarget; + buildConfigurationList = E32E9B6B1EB87D7B000FEEE9 /* Build configuration list for PBXNativeTarget "LaunchAtLogin" */; + buildPhases = ( + E32E9B5E1EB87D7B000FEEE9 /* Sources */, + E32E9B5F1EB87D7B000FEEE9 /* Frameworks */, + E32E9B601EB87D7B000FEEE9 /* Headers */, + E32E9B611EB87D7B000FEEE9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + E32E9B881EB88462000FEEE9 /* PBXTargetDependency */, + ); + name = LaunchAtLogin; + productName = LaunchAtLogin; + productReference = E32E9B631EB87D7B000FEEE9 /* LaunchAtLogin.framework */; + productType = "com.apple.product-type.framework"; + }; + E32E9B731EB87EA3000FEEE9 /* LaunchAtLoginHelper */ = { + isa = PBXNativeTarget; + buildConfigurationList = E32E9B801EB87EA3000FEEE9 /* Build configuration list for PBXNativeTarget "LaunchAtLoginHelper" */; + buildPhases = ( + E32E9B701EB87EA3000FEEE9 /* Sources */, + E32E9B711EB87EA3000FEEE9 /* Frameworks */, + E32E9B721EB87EA3000FEEE9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = LaunchAtLoginHelper; + productName = LaunchAtLoginHelper; + productReference = E32E9B741EB87EA3000FEEE9 /* LaunchAtLoginHelper.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E32E9B5A1EB87D7B000FEEE9 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = "Sindre Sorhus"; + TargetAttributes = { + E32E9B621EB87D7B000FEEE9 = { + CreatedOnToolsVersion = 8.3.2; + LastSwiftMigration = 1020; + }; + E32E9B731EB87EA3000FEEE9 = { + CreatedOnToolsVersion = 8.3.2; + LastSwiftMigration = 1020; + SystemCapabilities = { + com.apple.HardenedRuntime = { + enabled = 1; + }; + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + }; + }; + buildConfigurationList = E32E9B5D1EB87D7B000FEEE9 /* Build configuration list for PBXProject "LaunchAtLogin" */; + compatibilityVersion = "Xcode 11.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E32E9B591EB87D7B000FEEE9; + productRefGroup = E32E9B641EB87D7B000FEEE9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E32E9B621EB87D7B000FEEE9 /* LaunchAtLogin */, + E32E9B731EB87EA3000FEEE9 /* LaunchAtLoginHelper */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E32E9B611EB87D7B000FEEE9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E32E9B861EB8845E000FEEE9 /* LaunchAtLoginHelper.app in Resources */, + E32E9B931EB889AE000FEEE9 /* copy-helper.sh in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E32E9B721EB87EA3000FEEE9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E32E9B5E1EB87D7B000FEEE9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E32E9B6F1EB87DC5000FEEE9 /* LaunchAtLogin.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E32E9B701EB87EA3000FEEE9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E32E9B771EB87EA3000FEEE9 /* main.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + E32E9B881EB88462000FEEE9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E32E9B731EB87EA3000FEEE9 /* LaunchAtLoginHelper */; + targetProxy = E32E9B871EB88462000FEEE9 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + E32E9B691EB87D7B000FEEE9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_COMPILATION_MODE = singlefile; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VALID_ARCHS = x86_64; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + E32E9B6A1EB87D7B000FEEE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + VALID_ARCHS = x86_64; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + E32E9B6C1EB87D7B000FEEE9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = LaunchAtLogin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 3.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLogin; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_COMPILATION_MODE = singlefile; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + E32E9B6D1EB87D7B000FEEE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = LaunchAtLogin/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 3.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLogin; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + }; + name = Release; + }; + E32E9B811EB87EA3000FEEE9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = LaunchAtLoginHelper/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLoginHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + E32E9B821EB87EA3000FEEE9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = LaunchAtLoginHelper/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLoginHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E32E9B5D1EB87D7B000FEEE9 /* Build configuration list for PBXProject "LaunchAtLogin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E32E9B691EB87D7B000FEEE9 /* Debug */, + E32E9B6A1EB87D7B000FEEE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E32E9B6B1EB87D7B000FEEE9 /* Build configuration list for PBXNativeTarget "LaunchAtLogin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E32E9B6C1EB87D7B000FEEE9 /* Debug */, + E32E9B6D1EB87D7B000FEEE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E32E9B801EB87EA3000FEEE9 /* Build configuration list for PBXNativeTarget "LaunchAtLoginHelper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E32E9B811EB87EA3000FEEE9 /* Debug */, + E32E9B821EB87EA3000FEEE9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E32E9B5A1EB87D7B000FEEE9 /* Project object */; +} diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/xcshareddata/xcschemes/LaunchAtLogin.xcscheme b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/xcshareddata/xcschemes/LaunchAtLogin.xcscheme new file mode 100644 index 0000000..d8b20f0 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/xcshareddata/xcschemes/LaunchAtLogin.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/xcshareddata/xcschemes/LaunchAtLoginHelper.xcscheme b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/xcshareddata/xcschemes/LaunchAtLoginHelper.xcscheme new file mode 100644 index 0000000..0742f95 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj/xcshareddata/xcschemes/LaunchAtLoginHelper.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/Info.plist b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/Info.plist new file mode 100644 index 0000000..d6021a3 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + MIT © Sindre Sorhus + + diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/LaunchAtLogin.h b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/LaunchAtLogin.h new file mode 100644 index 0000000..f801178 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/LaunchAtLogin.h @@ -0,0 +1,4 @@ +#import + +FOUNDATION_EXPORT double LaunchAtLoginVersionNumber; +FOUNDATION_EXPORT const unsigned char LaunchAtLoginVersionString[]; diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/LaunchAtLogin.swift b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/LaunchAtLogin.swift new file mode 100644 index 0000000..6c77ee6 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/LaunchAtLogin.swift @@ -0,0 +1,21 @@ +import Foundation +import ServiceManagement + +public struct LaunchAtLogin { + private static let id = "\(Bundle.main.bundleIdentifier!)-LaunchAtLoginHelper" + + public static var isEnabled: Bool { + get { + guard let jobs = (SMCopyAllJobDictionaries(kSMDomainUserLaunchd).takeRetainedValue() as? [[String: AnyObject]]) else { + return false + } + + let job = jobs.first { $0["Label"] as! String == id } + + return job?["OnDemand"] as? Bool ?? false + } + set { + SMLoginItemSetEnabled(id as CFString, newValue) + } + } +} diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/copy-helper.sh b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/copy-helper.sh new file mode 100755 index 0000000..52af101 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin/copy-helper.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +origin_helper_path="$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH/LaunchAtLogin.framework/Resources/LaunchAtLoginHelper.app" +helper_dir="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/LoginItems" +helper_path="$helper_dir/LaunchAtLoginHelper.app" + +rm -rf "$helper_path" +mkdir -p "$helper_dir" +cp -rf "$origin_helper_path" "$helper_dir/" + +defaults write "$helper_path/Contents/Info" CFBundleIdentifier -string "$PRODUCT_BUNDLE_IDENTIFIER-LaunchAtLoginHelper" + +if [[ -n $CODE_SIGN_ENTITLEMENTS ]]; then + codesign --force --entitlements="$CODE_SIGN_ENTITLEMENTS" --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path" +else + codesign --force --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path" +fi + +if [[ $CONFIGURATION == "Release" ]]; then + rm -rf "$origin_helper_path" + rm "$(dirname "$origin_helper_path")/copy-helper.sh" +fi diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/Info.plist b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/Info.plist new file mode 100644 index 0000000..a075677 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + MIT © Sindre Sorhus + LSBackgroundOnly + + NSPrincipalClass + NSApplication + + diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/main.swift b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/main.swift new file mode 100644 index 0000000..ad7fd4f --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/LaunchAtLoginHelper/main.swift @@ -0,0 +1,25 @@ +import Cocoa + +final class AppDelegate: NSObject, NSApplicationDelegate { + func applicationDidFinishLaunching(_ notification: Notification) { + let bundleId = Bundle.main.bundleIdentifier! + // TODO: Make this more strict by only replacing at the end + let mainBundleId = bundleId.replacingOccurrences(of: "-LaunchAtLoginHelper", with: "") + + // Ensure the app is not already running + guard NSRunningApplication.runningApplications(withBundleIdentifier: mainBundleId).isEmpty else { + NSApp.terminate(nil) + return + } + + let pathComponents = (Bundle.main.bundlePath as NSString).pathComponents + let mainPath = NSString.path(withComponents: Array(pathComponents[0...(pathComponents.count - 5)])) + NSWorkspace.shared.launchApplication(mainPath) + NSApp.terminate(nil) + } +} + +private let app = NSApplication.shared +private let delegate = AppDelegate() +app.delegate = delegate +app.run() diff --git a/Carthage/Checkouts/LaunchAtLogin/before-after.md b/Carthage/Checkouts/LaunchAtLogin/before-after.md new file mode 100644 index 0000000..91cbe70 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/before-after.md @@ -0,0 +1,21 @@ +# Before and after + +With `LaunchAtLogin`, you only have to do 2 steps instead of 13! + +```diff +- 1. Create a new target that will be the helper app that launches your app +- 2. Set `LSBackgroundOnly` to true in the `Info.plist` file +- 3. Set `Skip Install` to `YES` in the build settings for the helper app +- 4. Enable sandboxing for the helper app +- 5. Add a new `Copy Files` build phase to the main app +- 6. Select `Wrapper` as destination +- 7. Enter `Contents/Library/LoginItems` as subpath +- 8. Add the helper build product to the build phase +- 9. Copy-paste some boilerplate code into the helper app +- 10. Remember to replace `bundleid.of.main.app` and `MainExectuableName` with your own values +- 11. Copy-paste some code to register the helper app into your main app +- 12. Make sure the main app and helper app use the same code signing certificate +- 13. Manually verify that you did everything correctly ++ 1. Install this package ++ 2. Add a new "Run Script Phase" +``` diff --git a/Carthage/Checkouts/LaunchAtLogin/license b/Carthage/Checkouts/LaunchAtLogin/license new file mode 100644 index 0000000..e7af2f7 --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Carthage/Checkouts/LaunchAtLogin/readme.md b/Carthage/Checkouts/LaunchAtLogin/readme.md new file mode 100644 index 0000000..6505bda --- /dev/null +++ b/Carthage/Checkouts/LaunchAtLogin/readme.md @@ -0,0 +1,88 @@ +# LaunchAtLogin + +> Add “Launch at Login” functionality to your macOS app in seconds + +It's usually quite a [convoluted and error-prone process](before-after.md) to add this. **No more!** + +This package works with both sandboxed and non-sandboxed apps and it's App Store compatible and used in apps like [Plash](https://github.com/sindresorhus/Plash), [Dato](https://sindresorhus.com/dato), [Lungo](https://sindresorhus.com/lungo), and [Battery Indicator](https://sindresorhus.com/battery-indicator). + +## Requirements + +- macOS 10.12+ +- Xcode 11+ +- Swift 5+ + +## Install + +#### Carthage + +``` +github "sindresorhus/LaunchAtLogin" +``` + +## Usage + +Add a new ["Run Script Phase"](http://stackoverflow.com/a/39633955/64949) below "Embed Frameworks" in "Build Phases" with the following: + +```sh +"${PROJECT_DIR}/Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh" +``` + +Use it in your app: + +```swift +import LaunchAtLogin + +print(LaunchAtLogin.isEnabled) +//=> false + +LaunchAtLogin.isEnabled = true + +print(LaunchAtLogin.isEnabled) +//=> true +``` + +No need to store any state to UserDefaults. + +*Note that the [Mac App Store guidelines](https://developer.apple.com/app-store/review/guidelines/) requires “launch at login” functionality to be enabled in response to a user action. This is usually solved by making it a preference that is disabled by default. Many apps also let the user activate it in a welcome screen.* + +## How does it work? + +The framework bundles the helper app needed to launch your app and copies it into your app at build time. + +## FAQ + +#### My app doesn't show up in “System Preferences › Users & Groups › Login Items” + +[This is the expected behavior](https://stackoverflow.com/a/15104481/64949), unfortunately. + +#### My app doesn't launch at login when testing + +This is usually caused by having one or more older builds of your app laying around somewhere on the system, and macOS picking one of those instead, which doesn't have the launch helper, and thus fails to start. + +Some things you can try: +- Bump the version & build of your app so macOS is more likely to pick it. +- Delete the [`DerivedData` directory](https://mgrebenets.github.io/mobile%20ci/2015/02/01/xcode-derived-data). +- Ensure you don't have any other builds laying around somewhere. + +Some helpful Stack Overflow answers: +- https://stackoverflow.com/a/43281810/64949 +- https://stackoverflow.com/a/51683190/64949 +- https://stackoverflow.com/a/53110832/64949 +- https://stackoverflow.com/a/53110852/64949 + +#### Can you support CocoaPods? + +CocoaPods used to be supported, but [it did not work well](https://github.com/sindresorhus/LaunchAtLogin/issues/22) and there was no easy way to fix it, so support was dropped. Even though you mainly use CocoaPods, you can still use Carthage just for this package without any problems. + +#### I'm getting a `'SMCopyAllJobDictionaries' was deprecated in OS X 10.10` warning + +Apple deprecated that API without providing an alternative. Apple engineers have [stated that it's still the preferred API to use](https://github.com/alexzielenski/StartAtLoginController/issues/12#issuecomment-307525807). I plan to use it as long as it's available. There are workarounds I can implement if Apple ever removes the API, so rest assured, this module will be made to work even then. If you want to see this resolved, submit a [Feedback Assistant](https://feedbackassistant.apple.com) report with [the following text](https://github.com/feedback-assistant/reports/issues/16). There's unfortunately still [no way to suppress warnings in Swift](https://stackoverflow.com/a/32861678/64949). + +## Related + +- [Defaults](https://github.com/sindresorhus/Defaults) - Swifty and modern UserDefaults +- [Preferences](https://github.com/sindresorhus/Preferences) - Add a preferences window to your macOS app in minutes +- [DockProgress](https://github.com/sindresorhus/DockProgress) - Show progress in your app's Dock icon +- [create-dmg](https://github.com/sindresorhus/create-dmg) - Create a good-looking DMG for your macOS app in seconds +- [More…](https://github.com/search?q=user%3Asindresorhus+language%3Aswift) diff --git a/Common/HelperToolProtocol.swift b/Common/HelperToolProtocol.swift new file mode 100644 index 0000000..c8a667c --- /dev/null +++ b/Common/HelperToolProtocol.swift @@ -0,0 +1,21 @@ +// +// HelperToolProtocol.swift +// AlDente +// +// Created by David Wernhart on 13.02.20. +// Copyright © 2020 David Wernhart. All rights reserved. +// + +import Foundation + +let helperVersion: String = "4" //for some reason the integrated version check does not work, so I use this one + +@objc(HelperToolProtocol) protocol HelperToolProtocol { +//protocol HelperToolProtocol { + func getVersion(withReply reply: @escaping (String) -> Void) + + //TODO: more functions for other data types, altough this is sufficient for battery max charge level + func setSMCByte(key: String, value: UInt8) + func readSMCByte(key: String, withReply reply: @escaping (UInt8) -> Void) + +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..fb09fe9 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# AlDente diff --git a/SMJobBlessUtil.py b/SMJobBlessUtil.py new file mode 100755 index 0000000..c041363 --- /dev/null +++ b/SMJobBlessUtil.py @@ -0,0 +1,437 @@ +#! /usr/bin/python +# +# File: SMJobBlessUtil.py +# +# Contains: Tool for checking and correcting apps that use SMJobBless. +# +# Written by: DTS +# +# Copyright: Copyright (c) 2012 Apple Inc. All Rights Reserved. +# +# Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. +# ("Apple") in consideration of your agreement to the following +# terms, and your use, installation, modification or +# redistribution of this Apple software constitutes acceptance of +# these terms. If you do not agree with these terms, please do +# not use, install, modify or redistribute this Apple software. +# +# In consideration of your agreement to abide by the following +# terms, and subject to these terms, Apple grants you a personal, +# non-exclusive license, under Apple's copyrights in this +# original Apple software (the "Apple Software"), to use, +# reproduce, modify and redistribute the Apple Software, with or +# without modifications, in source and/or binary forms; provided +# that if you redistribute the Apple Software in its entirety and +# without modifications, you must retain this notice and the +# following text and disclaimers in all such redistributions of +# the Apple Software. Neither the name, trademarks, service marks +# or logos of Apple Inc. may be used to endorse or promote +# products derived from the Apple Software without specific prior +# written permission from Apple. Except as expressly stated in +# this notice, no other rights or licenses, express or implied, +# are granted by Apple herein, including but not limited to any +# patent rights that may be infringed by your derivative works or +# by other works in which the Apple Software may be incorporated. +# +# The Apple Software is provided by Apple on an "AS IS" basis. +# APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING +# WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING +# THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN +# COMBINATION WITH YOUR PRODUCTS. +# +# IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, +# INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY +# OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION +# OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY +# OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR +# OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +import sys +import os +import getopt +import subprocess +import plistlib +import operator + +class UsageException (Exception): + """ + Raised when the progam detects a usage issue; the top-level code catches this + and prints a usage message. + """ + pass + +class CheckException (Exception): + """ + Raised when the "check" subcommand detects a problem; the top-level code catches + this and prints a nice error message. + """ + def __init__(self, message, path=None): + self.message = message + self.path = path + +def checkCodeSignature(programPath, programType): + """Checks the code signature of the referenced program.""" + + # Use the codesign tool to check the signature. The second "-v" is required to enable + # verbose mode, which causes codesign to do more checking. By default it does the minimum + # amount of checking ("Is the program properly signed?"). If you enabled verbose mode it + # does other sanity checks, which we definitely want. The specific thing I'd like to + # detect is "Does the code satisfy its own designated requirement?" and I need to enable + # verbose mode to get that. + + args = [ + # "false", + "codesign", + "-v", + "-v", + programPath + ] + try: + subprocess.check_call(args, stderr=open("/dev/null")) + except subprocess.CalledProcessError, e: + raise CheckException("%s code signature invalid" % programType, programPath) + +def readDesignatedRequirement(programPath, programType): + """Returns the designated requirement of the program as a string.""" + args = [ + # "false", + "codesign", + "-d", + "-r", + "-", + programPath + ] + try: + req = subprocess.check_output(args, stderr=open("/dev/null")) + except subprocess.CalledProcessError, e: + raise CheckException("%s designated requirement unreadable" % programType, programPath) + + reqLines = req.splitlines() + if len(reqLines) != 1 or not req.startswith("designated => "): + raise CheckException("%s designated requirement malformed" % programType, programPath) + return reqLines[0][len("designated => "):] + +def readInfoPlistFromPath(infoPath): + """Reads an "Info.plist" file from the specified path.""" + try: + info = plistlib.readPlist(infoPath) + except: + raise CheckException("'Info.plist' not readable", infoPath) + if not isinstance(info, dict): + raise CheckException("'Info.plist' root must be a dictionary", infoPath) + return info + +def readPlistFromToolSection(toolPath, segmentName, sectionName): + """Reads a dictionary property list from the specified section within the specified executable.""" + + # Run otool -s to get a hex dump of the section. + + args = [ + # "false", + "otool", + "-s", + segmentName, + sectionName, + toolPath + ] + try: + plistDump = subprocess.check_output(args) + except subprocess.CalledProcessError, e: + raise CheckException("tool %s / %s section unreadable" % (segmentName, sectionName), toolPath) + + # Convert that hex dump to an property list. + + plistLines = plistDump.splitlines() + if len(plistLines) < 3 or plistLines[1] != ("Contents of (%s,%s) section" % (segmentName, sectionName)): + raise CheckException("tool %s / %s section dump malformed (1)" % (segmentName, sectionName), toolPath) + del plistLines[0:2] + + try: + bytes = [] + for line in plistLines: + # line looks like this: + # + # '0000000100000b80\t3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 ' + columns = line.split("\t") + assert len(columns) == 2 + for hexStr in columns[1].split(): + bytes.append(int(hexStr, 16)) + plist = plistlib.readPlistFromString(bytearray(bytes)) + except: + raise CheckException("tool %s / %s section dump malformed (2)" % (segmentName, sectionName), toolPath) + + # Check the root of the property list. + + if not isinstance(plist, dict): + raise CheckException("tool %s / %s property list root must be a dictionary" % (segmentName, sectionName), toolPath) + + return plist + +def checkStep1(appPath): + """Checks that the app and the tool are both correctly code signed.""" + + if not os.path.isdir(appPath): + raise CheckException("app not found", appPath) + + # Check the app's code signature. + + checkCodeSignature(appPath, "app") + + # Check the tool directory. + + toolDirPath = os.path.join(appPath, "Contents", "Library", "LaunchServices") + if not os.path.isdir(toolDirPath): + raise CheckException("tool directory not found", toolDirPath) + + # Check each tool's code signature. + + toolPathList = [] + for toolName in os.listdir(toolDirPath): + if toolName != ".DS_Store": + toolPath = os.path.join(toolDirPath, toolName) + if not os.path.isfile(toolPath): + raise CheckException("tool directory contains a directory", toolPath) + checkCodeSignature(toolPath, "tool") + toolPathList.append(toolPath) + + # Check that we have at least one tool. + + if len(toolPathList) == 0: + raise CheckException("no tools found", toolDirPath) + + return toolPathList + +def checkStep2(appPath, toolPathList): + """Checks the SMPrivilegedExecutables entry in the app's "Info.plist".""" + + # Create a map from the tool name (not path) to its designated requirement. + + toolNameToReqMap = dict() + for toolPath in toolPathList: + req = readDesignatedRequirement(toolPath, "tool") + toolNameToReqMap[os.path.basename(toolPath)] = req + + # Read the Info.plist for the app and extract the SMPrivilegedExecutables value. + + infoPath = os.path.join(appPath, "Contents", "Info.plist") + info = readInfoPlistFromPath(infoPath) + if not info.has_key("SMPrivilegedExecutables"): + raise CheckException("'SMPrivilegedExecutables' not found", infoPath) + infoToolDict = info["SMPrivilegedExecutables"] + if not isinstance(infoToolDict, dict): + raise CheckException("'SMPrivilegedExecutables' must be a dictionary", infoPath) + + # Check that the list of tools matches the list of SMPrivilegedExecutables entries. + + if sorted(infoToolDict.keys()) != sorted(toolNameToReqMap.keys()): + raise CheckException("'SMPrivilegedExecutables' and tools in 'Contents/Library/LaunchServices' don't match") + + # Check that all the requirements match. + + # This is an interesting policy choice. Technically the tool just needs to match + # the requirement listed in SMPrivilegedExecutables, and we can check that by + # putting the requirement into tmp.req and then running + # + # $ codesign -v -R tmp.req /path/to/tool + # + # However, for a Developer ID signed tool we really want to have the SMPrivilegedExecutables + # entry contain the tool's designated requirement because Xcode has built a + # more complex DR that does lots of useful and important checks. So, as a matter + # of policy we require that the value in SMPrivilegedExecutables match the tool's DR. + + for toolName in infoToolDict: + if infoToolDict[toolName] != toolNameToReqMap[toolName]: + raise CheckException("tool designated requirement (%s) doesn't match entry in 'SMPrivilegedExecutables' (%s)" % (toolNameToReqMap[toolName], infoToolDict[toolName])) + +def checkStep3(appPath, toolPathList): + """Checks the "Info.plist" embedded in each helper tool.""" + + # First get the app's designated requirement. + + appReq = readDesignatedRequirement(appPath, "app") + + # Then check that the tool's SMAuthorizedClients value matches it. + + for toolPath in toolPathList: + info = readPlistFromToolSection(toolPath, "__TEXT", "__info_plist") + + if not info.has_key("CFBundleInfoDictionaryVersion") or info["CFBundleInfoDictionaryVersion"] != "6.0": + raise CheckException("'CFBundleInfoDictionaryVersion' in tool __TEXT / __info_plist section must be '6.0'", toolPath) + + if not info.has_key("CFBundleIdentifier") or info["CFBundleIdentifier"] != os.path.basename(toolPath): + raise CheckException("'CFBundleIdentifier' in tool __TEXT / __info_plist section must match tool name", toolPath) + + if not info.has_key("SMAuthorizedClients"): + raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section not found", toolPath) + infoClientList = info["SMAuthorizedClients"] + if not isinstance(infoClientList, list): + raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section must be an array", toolPath) + if len(infoClientList) != 1: + raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section must have one entry", toolPath) + + # Again, as a matter of policy we require that the SMAuthorizedClients entry must + # match exactly the designated requirement of the app. + + if infoClientList[0] != appReq: + raise CheckException("app designated requirement (%s) doesn't match entry in 'SMAuthorizedClients' (%s)" % (appReq, infoClientList[0]), toolPath) + +def checkStep4(appPath, toolPathList): + """Checks the "launchd.plist" embedded in each helper tool.""" + + for toolPath in toolPathList: + launchd = readPlistFromToolSection(toolPath, "__TEXT", "__launchd_plist") + + if not launchd.has_key("Label") or launchd["Label"] != os.path.basename(toolPath): + raise CheckException("'Label' in tool __TEXT / __launchd_plist section must match tool name", toolPath) + + # We don't need to check that the label matches the bundle identifier because + # we know it matches the tool name and step 4 checks that the tool name matches + # the bundle identifier. + +def checkStep5(appPath): + """There's nothing to do here; we effectively checked for this is steps 1 and 2.""" + pass + +def check(appPath): + """Checks the SMJobBless setup of the specified app.""" + + # Each of the following steps matches a bullet point in the SMJobBless header doc. + + toolPathList = checkStep1(appPath) + + checkStep2(appPath, toolPathList) + + checkStep3(appPath, toolPathList) + + checkStep4(appPath, toolPathList) + + checkStep5(appPath) + +def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths): + """ + Reads information from the built app and uses it to set the SMJobBless setup + in the specified app and tool Info.plist source files. + """ + + if not os.path.isdir(appPath): + raise CheckException("app not found", appPath) + + if not os.path.isfile(appInfoPlistPath): + raise CheckException("app 'Info.plist' not found", appInfoPlistPath) + for toolInfoPlistPath in toolInfoPlistPaths: + if not os.path.isfile(toolInfoPlistPath): + raise CheckException("app 'Info.plist' not found", toolInfoPlistPath) + + # Get the designated requirement for the app and each of the tools. + + appReq = readDesignatedRequirement(appPath, "app") + + toolDirPath = os.path.join(appPath, "Contents", "Library", "LaunchServices") + if not os.path.isdir(toolDirPath): + raise CheckException("tool directory not found", toolDirPath) + + toolNameToReqMap = {} + for toolName in os.listdir(toolDirPath): + req = readDesignatedRequirement(os.path.join(toolDirPath, toolName), "tool") + toolNameToReqMap[toolName] = req + + if len(toolNameToReqMap) > len(toolInfoPlistPaths): + raise CheckException("tool directory has more tools (%d) than you've supplied tool 'Info.plist' paths (%d)" % (len(toolNameToReqMap), len(toolInfoPlistPaths)), toolDirPath) + if len(toolNameToReqMap) < len(toolInfoPlistPaths): + raise CheckException("tool directory has fewer tools (%d) than you've supplied tool 'Info.plist' paths (%d)" % (len(toolNameToReqMap), len(toolInfoPlistPaths)), toolDirPath) + + # Build the new value for SMPrivilegedExecutables. + + appToolDict = {} + toolInfoPlistPathToToolInfoMap = {} + for toolInfoPlistPath in toolInfoPlistPaths: + toolInfo = readInfoPlistFromPath(toolInfoPlistPath) + toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] = toolInfo + if not toolInfo.has_key("CFBundleIdentifier"): + raise CheckException("'CFBundleIdentifier' not found", toolInfoPlistPath) + bundleID = toolInfo["CFBundleIdentifier"] + if not isinstance(bundleID, basestring): + raise CheckException("'CFBundleIdentifier' must be a string", toolInfoPlistPath) + appToolDict[bundleID] = toolNameToReqMap[bundleID] + + # Set the SMPrivilegedExecutables value in the app "Info.plist". + + appInfo = readInfoPlistFromPath(appInfoPlistPath) + needsUpdate = not appInfo.has_key("SMPrivilegedExecutables") + if not needsUpdate: + oldAppToolDict = appInfo["SMPrivilegedExecutables"] + if not isinstance(oldAppToolDict, dict): + raise CheckException("'SMPrivilegedExecutables' must be a dictionary", appInfoPlistPath) + appToolDictSorted = sorted(appToolDict.iteritems(), key=operator.itemgetter(0)) + oldAppToolDictSorted = sorted(oldAppToolDict.iteritems(), key=operator.itemgetter(0)) + needsUpdate = (appToolDictSorted != oldAppToolDictSorted) + + if needsUpdate: + appInfo["SMPrivilegedExecutables"] = appToolDict + plistlib.writePlist(appInfo, appInfoPlistPath) + print >> sys.stdout, "%s: updated" % appInfoPlistPath + + # Set the SMAuthorizedClients value in each tool's "Info.plist". + + toolAppListSorted = [ appReq ] # only one element, so obviously sorted (-: + for toolInfoPlistPath in toolInfoPlistPaths: + toolInfo = toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] + + needsUpdate = not toolInfo.has_key("SMAuthorizedClients") + if not needsUpdate: + oldToolAppList = toolInfo["SMAuthorizedClients"] + if not isinstance(oldToolAppList, list): + raise CheckException("'SMAuthorizedClients' must be an array", toolInfoPlistPath) + oldToolAppListSorted = sorted(oldToolAppList) + needsUpdate = (toolAppListSorted != oldToolAppListSorted) + + if needsUpdate: + toolInfo["SMAuthorizedClients"] = toolAppListSorted + plistlib.writePlist(toolInfo, toolInfoPlistPath) + print >> sys.stdout, "%s: updated" % toolInfoPlistPath + +def main(): + options, appArgs = getopt.getopt(sys.argv[1:], "d") + + debug = False + for opt, val in options: + if opt == "-d": + debug = True + else: + raise UsageException() + + if len(appArgs) == 0: + raise UsageException() + command = appArgs[0] + if command == "check": + if len(appArgs) != 2: + raise UsageException() + check(appArgs[1]) + elif command == "setreq": + if len(appArgs) < 4: + raise UsageException() + setreq(appArgs[1], appArgs[2], appArgs[3:]) + else: + raise UsageException() + +if __name__ == "__main__": + try: + main() + except CheckException, e: + if e.path is None: + print >> sys.stderr, "%s: %s" % (os.path.basename(sys.argv[0]), e.message) + else: + path = e.path + if path.endswith("/"): + path = path[:-1] + print >> sys.stderr, "%s: %s" % (path, e.message) + sys.exit(1) + except UsageException, e: + print >> sys.stderr, "usage: %s check /path/to/app" % os.path.basename(sys.argv[0]) + print >> sys.stderr, " %s setreq /path/to/app /path/to/app/Info.plist /path/to/tool/Info.plist..." % os.path.basename(sys.argv[0]) + sys.exit(1) diff --git a/com.davidwernhart.Helper/Helper-Info.plist b/com.davidwernhart.Helper/Helper-Info.plist new file mode 100644 index 0000000..0c1129b --- /dev/null +++ b/com.davidwernhart.Helper/Helper-Info.plist @@ -0,0 +1,18 @@ + + + + + CFBundleIdentifier + com.davidwernhart.Helper + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + com.davidwernhart.Helper + CFBundleVersion + 4 + SMAuthorizedClients + + identifier "com.davidwernhart.AlDente" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: david.wernhart96@gmail.com (GSDX9BQ584)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ + + + diff --git a/com.davidwernhart.Helper/Helper-Launchd.plist b/com.davidwernhart.Helper/Helper-Launchd.plist new file mode 100644 index 0000000..e3fbf9d --- /dev/null +++ b/com.davidwernhart.Helper/Helper-Launchd.plist @@ -0,0 +1,13 @@ + + + + + Label + com.davidwernhart.Helper + MachServices + + com.davidwernhart.Helper.mach + + + + diff --git a/com.davidwernhart.Helper/HelperTool.swift b/com.davidwernhart.Helper/HelperTool.swift new file mode 100644 index 0000000..2709df3 --- /dev/null +++ b/com.davidwernhart.Helper/HelperTool.swift @@ -0,0 +1,57 @@ +// +// HelperTool.swift +// com.davidwernhart.Helper +// +// Created by David Wernhart on 13.02.20. +// Copyright © 2020 David Wernhart. All rights reserved. +// + +import Foundation + +class HelperTool: NSObject, HelperToolProtocol { + func getVersion(withReply reply: (String) -> Void) { +// let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString" as String) as? String ?? "(unknown version)" +// let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String ?? "(unknown build)" +// reply("v\(version) (\(build))") + reply(helperVersion) + + } + + func setSMCByte(key: String, value: UInt8){ + do { + try SMCKit.open() + } catch { + print(error) + exit(EX_UNAVAILABLE) + } + + var key = SMCKit.getKey(key, type: DataTypes.UInt8) + let bytes: SMCBytes = (value, UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0)) + + do { + let status = try SMCKit.writeData(key,data: bytes) + } catch { + } + } + func readSMCByte(key: String, withReply reply: @escaping (UInt8) -> Void){ + do { + try SMCKit.open() + } catch { + print(error) + exit(EX_UNAVAILABLE) + } + + var key = SMCKit.getKey(key, type: DataTypes.UInt8) + do { + let status = try SMCKit.readData(key).0 + reply(status) + } catch { + reply(0) + } + } +} diff --git a/com.davidwernhart.Helper/SMC.swift b/com.davidwernhart.Helper/SMC.swift new file mode 100644 index 0000000..635bf8c --- /dev/null +++ b/com.davidwernhart.Helper/SMC.swift @@ -0,0 +1,792 @@ +// +// SMC.swift +// SMCKit +// +// The MIT License +// +// Copyright (C) 2014-2017 beltex +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import IOKit +import Foundation + +//------------------------------------------------------------------------------ +// MARK: Type Aliases +//------------------------------------------------------------------------------ + +// http://stackoverflow.com/a/22383661 + +/// Floating point, unsigned, 14 bits exponent, 2 bits fraction +public typealias FPE2 = (UInt8, UInt8) + +/// Floating point, signed, 7 bits exponent, 8 bits fraction +public typealias SP78 = (UInt8, UInt8) + +public typealias SMCBytes = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8) + +//------------------------------------------------------------------------------ +// MARK: Standard Library Extensions +//------------------------------------------------------------------------------ + +extension UInt32 { + + init(fromBytes bytes: (UInt8, UInt8, UInt8, UInt8)) { + // TODO: Broken up due to "Expression was too complex" error as of + // Swift 4. + + let byte0 = UInt32(bytes.0) << 24 + let byte1 = UInt32(bytes.1) << 16 + let byte2 = UInt32(bytes.2) << 8 + let byte3 = UInt32(bytes.3) + + self = byte0 | byte1 | byte2 | byte3 + } +} + +extension Bool { + + init(fromByte byte: UInt8) { + self = byte == 1 ? true : false + } +} + +public extension Int { + + init(fromFPE2 bytes: FPE2) { + self = (Int(bytes.0) << 6) + (Int(bytes.1) >> 2) + } + + func toFPE2() -> FPE2 { + return (UInt8(self >> 6), UInt8((self << 2) ^ ((self >> 6) << 8))) + } +} + +extension Double { + + init(fromSP78 bytes: SP78) { + // FIXME: Handle second byte + let sign = bytes.0 & 0x80 == 0 ? 1.0 : -1.0 + self = sign * Double(bytes.0 & 0x7F) // AND to mask sign bit + } +} + +// Thanks to Airspeed Velocity for the great idea! +// http://airspeedvelocity.net/2015/05/22/my-talk-at-swift-summit/ +public extension FourCharCode { + + init(fromString str: String) { + precondition(str.count == 4) + + self = str.utf8.reduce(0) { sum, character in + return sum << 8 | UInt32(character) + } + } + + init(fromStaticString str: StaticString) { + precondition(str.utf8CodeUnitCount == 4) + + self = str.withUTF8Buffer { buffer in + // TODO: Broken up due to "Expression was too complex" error as of + // Swift 4. + + let byte0 = UInt32(buffer[0]) << 24 + let byte1 = UInt32(buffer[1]) << 16 + let byte2 = UInt32(buffer[2]) << 8 + let byte3 = UInt32(buffer[3]) + + return byte0 | byte1 | byte2 | byte3 + } + } + + func toString() -> String { + return String(describing: UnicodeScalar(self >> 24 & 0xff)!) + + String(describing: UnicodeScalar(self >> 16 & 0xff)!) + + String(describing: UnicodeScalar(self >> 8 & 0xff)!) + + String(describing: UnicodeScalar(self & 0xff)!) + } +} + +//------------------------------------------------------------------------------ +// MARK: Defined by AppleSMC.kext +//------------------------------------------------------------------------------ + +/// Defined by AppleSMC.kext +/// +/// This is the predefined struct that must be passed to communicate with the +/// AppleSMC driver. While the driver is closed source, the definition of this +/// struct happened to appear in the Apple PowerManagement project at around +/// version 211, and soon after disappeared. It can be seen in the PrivateLib.c +/// file under pmconfigd. Given that it is C code, this is the closest +/// translation to Swift from a type perspective. +/// +/// ### Issues +/// +/// * Padding for struct alignment when passed over to C side +/// * Size of struct must be 80 bytes +/// * C array's are bridged as tuples +/// +/// http://www.opensource.apple.com/source/PowerManagement/PowerManagement-211/ +public struct SMCParamStruct { + + /// I/O Kit function selector + public enum Selector: UInt8 { + case kSMCHandleYPCEvent = 2 + case kSMCReadKey = 5 + case kSMCWriteKey = 6 + case kSMCGetKeyFromIndex = 8 + case kSMCGetKeyInfo = 9 + } + + /// Return codes for SMCParamStruct.result property + public enum Result: UInt8 { + case kSMCSuccess = 0 + case kSMCError = 1 + case kSMCKeyNotFound = 132 + } + + public struct SMCVersion { + var major: CUnsignedChar = 0 + var minor: CUnsignedChar = 0 + var build: CUnsignedChar = 0 + var reserved: CUnsignedChar = 0 + var release: CUnsignedShort = 0 + } + + public struct SMCPLimitData { + var version: UInt16 = 0 + var length: UInt16 = 0 + var cpuPLimit: UInt32 = 0 + var gpuPLimit: UInt32 = 0 + var memPLimit: UInt32 = 0 + } + + public struct SMCKeyInfoData { + /// How many bytes written to SMCParamStruct.bytes + var dataSize: IOByteCount = 0 + + /// Type of data written to SMCParamStruct.bytes. This lets us know how + /// to interpret it (translate it to human readable) + var dataType: UInt32 = 0 + + var dataAttributes: UInt8 = 0 + } + + /// FourCharCode telling the SMC what we want + var key: UInt32 = 0 + + var vers = SMCVersion() + + var pLimitData = SMCPLimitData() + + var keyInfo = SMCKeyInfoData() + + /// Padding for struct alignment when passed over to C side + var padding: UInt16 = 0 + + /// Result of an operation + var result: UInt8 = 0 + + var status: UInt8 = 0 + + /// Method selector + var data8: UInt8 = 0 + + var data32: UInt32 = 0 + + /// Data returned from the SMC + var bytes: SMCBytes = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0)) +} + +//------------------------------------------------------------------------------ +// MARK: SMC Client +//------------------------------------------------------------------------------ + +/// SMC data type information +public struct DataTypes { + + /// Fan information struct + public static let FDS = + DataType(type: FourCharCode(fromStaticString: "{fds"), size: 16) + public static let Flag = + DataType(type: FourCharCode(fromStaticString: "flag"), size: 1) + /// See type aliases + public static let FPE2 = + DataType(type: FourCharCode(fromStaticString: "fpe2"), size: 2) + /// See type aliases + public static let SP78 = + DataType(type: FourCharCode(fromStaticString: "sp78"), size: 2) + public static let UInt8 = + DataType(type: FourCharCode(fromStaticString: "ui8 "), size: 1) + public static let UInt32 = + DataType(type: FourCharCode(fromStaticString: "ui32"), size: 4) +} + +public struct SMCKey { + let code: FourCharCode + let info: DataType +} + +public struct DataType: Equatable { + let type: FourCharCode + let size: UInt32 +} + +public func ==(lhs: DataType, rhs: DataType) -> Bool { + return lhs.type == rhs.type && lhs.size == rhs.size +} + +/// Apple System Management Controller (SMC) user-space client for Intel-based +/// Macs. Works by talking to the AppleSMC.kext (kernel extension), the closed +/// source driver for the SMC. +public struct SMCKit { + + public enum SMCError: Error { + + /// AppleSMC driver not found + case driverNotFound + + /// Failed to open a connection to the AppleSMC driver + case failedToOpen + + /// This SMC key is not valid on this machine + case keyNotFound(code: String) + + /// Requires root privileges + case notPrivileged + + /// Fan speed must be > 0 && <= fanMaxSpeed + case unsafeFanSpeed + + /// https://developer.apple.com/library/mac/qa/qa1075/_index.html + /// + /// - parameter kIOReturn: I/O Kit error code + /// - parameter SMCResult: SMC specific return code + case unknown(kIOReturn: kern_return_t, SMCResult: UInt8) + } + + /// Connection to the SMC driver + fileprivate static var connection: io_connect_t = 0 + + /// Open connection to the SMC driver. This must be done first before any + /// other calls + public static func open() throws { + let service = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("AppleSMC")) + + if service == 0 { throw SMCError.driverNotFound } + + let result = IOServiceOpen(service, mach_task_self_, 0, + &SMCKit.connection) + IOObjectRelease(service) + + if result != kIOReturnSuccess { throw SMCError.failedToOpen } + } + + /// Close connection to the SMC driver + @discardableResult + public static func close() -> Bool { + let result = IOServiceClose(SMCKit.connection) + return result == kIOReturnSuccess ? true : false + } + + /// Get information about a key + public static func keyInformation(_ key: FourCharCode) throws -> DataType { + var inputStruct = SMCParamStruct() + + inputStruct.key = key + inputStruct.data8 = SMCParamStruct.Selector.kSMCGetKeyInfo.rawValue + + let outputStruct = try callDriver(&inputStruct) + + return DataType(type: outputStruct.keyInfo.dataType, + size: outputStruct.keyInfo.dataSize) + } + + /// Get information about the key at index + public static func keyInformationAtIndex(_ index: Int) throws -> + FourCharCode { + var inputStruct = SMCParamStruct() + + inputStruct.data8 = SMCParamStruct.Selector.kSMCGetKeyFromIndex.rawValue + inputStruct.data32 = UInt32(index) + + let outputStruct = try callDriver(&inputStruct) + + return outputStruct.key + } + + public static func getKey(_ code:String,type:DataType) -> SMCKey{ + let key = SMCKey(code: FourCharCode(fromString: code),info: type) + return key + } + + /// Read data of a key + public static func readData(_ key: SMCKey) throws -> SMCBytes { + var inputStruct = SMCParamStruct() + + inputStruct.key = key.code + inputStruct.keyInfo.dataSize = UInt32(key.info.size) + inputStruct.data8 = SMCParamStruct.Selector.kSMCReadKey.rawValue + + let outputStruct = try callDriver(&inputStruct) + + return outputStruct.bytes + } + + /// Write data for a key + public static func writeData(_ key: SMCKey, data: SMCBytes) throws { + var inputStruct = SMCParamStruct() + + inputStruct.key = key.code + inputStruct.bytes = data + inputStruct.keyInfo.dataSize = UInt32(key.info.size) + inputStruct.data8 = SMCParamStruct.Selector.kSMCWriteKey.rawValue + + _ = try callDriver(&inputStruct) + } + + /// Make an actual call to the SMC driver + public static func callDriver(_ inputStruct: inout SMCParamStruct, + selector: SMCParamStruct.Selector = .kSMCHandleYPCEvent) + throws -> SMCParamStruct { + assert(MemoryLayout.stride == 80, "SMCParamStruct size is != 80") + + var outputStruct = SMCParamStruct() + let inputStructSize = MemoryLayout.stride + var outputStructSize = MemoryLayout.stride + + let result = IOConnectCallStructMethod(SMCKit.connection, + UInt32(selector.rawValue), + &inputStruct, + inputStructSize, + &outputStruct, + &outputStructSize) + + switch (result, outputStruct.result) { + case (kIOReturnSuccess, SMCParamStruct.Result.kSMCSuccess.rawValue): + return outputStruct + case (kIOReturnSuccess, SMCParamStruct.Result.kSMCKeyNotFound.rawValue): + throw SMCError.keyNotFound(code: inputStruct.key.toString()) + case (kIOReturnNotPrivileged, _): + throw SMCError.notPrivileged + default: + throw SMCError.unknown(kIOReturn: result, + SMCResult: outputStruct.result) + } + } +} + +//------------------------------------------------------------------------------ +// MARK: General +//------------------------------------------------------------------------------ + +extension SMCKit { + + /// Get all valid SMC keys for this machine + public static func allKeys() throws -> [SMCKey] { + let count = try keyCount() + var keys = [SMCKey]() + + for i in 0 ..< count { + let key = try keyInformationAtIndex(i) + let info = try keyInformation(key) + keys.append(SMCKey(code: key, info: info)) + } + + return keys + } + + /// Get the number of valid SMC keys for this machine + public static func keyCount() throws -> Int { + let key = SMCKey(code: FourCharCode(fromStaticString: "#KEY"), + info: DataTypes.UInt32) + + let data = try readData(key) + return Int(UInt32(fromBytes: (data.0, data.1, data.2, data.3))) + } + + /// Is this key valid on this machine? + public static func isKeyFound(_ code: FourCharCode) throws -> Bool { + do { + _ = try keyInformation(code) + } catch SMCError.keyNotFound { return false } + + return true + } +} + +//------------------------------------------------------------------------------ +// MARK: Temperature +//------------------------------------------------------------------------------ + +/// The list is NOT exhaustive. In addition, the names of the sensors may not be +/// mapped to the correct hardware component. +/// +/// ### Sources +/// +/// * powermetrics(1) +/// * https://www.apple.com/downloads/dashboard/status/istatpro.html +/// * https://github.com/hholtmann/smcFanControl +/// * https://github.com/jedda/OSX-Monitoring-Tools +/// * http://www.opensource.apple.com/source/net_snmp/ +/// * http://www.parhelia.ch/blog/statics/k3_keys.html +public struct TemperatureSensors { + + public static let AMBIENT_AIR_0 = TemperatureSensor(name: "AMBIENT_AIR_0", + code: FourCharCode(fromStaticString: "TA0P")) + public static let AMBIENT_AIR_1 = TemperatureSensor(name: "AMBIENT_AIR_1", + code: FourCharCode(fromStaticString: "TA1P")) + // Via powermetrics(1) + public static let CPU_0_DIE = TemperatureSensor(name: "CPU_0_DIE", + code: FourCharCode(fromStaticString: "TC0F")) + public static let CPU_0_DIODE = TemperatureSensor(name: "CPU_0_DIODE", + code: FourCharCode(fromStaticString: "TC0D")) + public static let CPU_0_HEATSINK = TemperatureSensor(name: "CPU_0_HEATSINK", + code: FourCharCode(fromStaticString: "TC0H")) + public static let CPU_0_PROXIMITY = + TemperatureSensor(name: "CPU_0_PROXIMITY", + code: FourCharCode(fromStaticString: "TC0P")) + public static let ENCLOSURE_BASE_0 = + TemperatureSensor(name: "ENCLOSURE_BASE_0", + code: FourCharCode(fromStaticString: "TB0T")) + public static let ENCLOSURE_BASE_1 = + TemperatureSensor(name: "ENCLOSURE_BASE_1", + code: FourCharCode(fromStaticString: "TB1T")) + public static let ENCLOSURE_BASE_2 = + TemperatureSensor(name: "ENCLOSURE_BASE_2", + code: FourCharCode(fromStaticString: "TB2T")) + public static let ENCLOSURE_BASE_3 = + TemperatureSensor(name: "ENCLOSURE_BASE_3", + code: FourCharCode(fromStaticString: "TB3T")) + public static let GPU_0_DIODE = TemperatureSensor(name: "GPU_0_DIODE", + code: FourCharCode(fromStaticString: "TG0D")) + public static let GPU_0_HEATSINK = TemperatureSensor(name: "GPU_0_HEATSINK", + code: FourCharCode(fromStaticString: "TG0H")) + public static let GPU_0_PROXIMITY = + TemperatureSensor(name: "GPU_0_PROXIMITY", + code: FourCharCode(fromStaticString: "TG0P")) + public static let HDD_PROXIMITY = TemperatureSensor(name: "HDD_PROXIMITY", + code: FourCharCode(fromStaticString: "TH0P")) + public static let HEATSINK_0 = TemperatureSensor(name: "HEATSINK_0", + code: FourCharCode(fromStaticString: "Th0H")) + public static let HEATSINK_1 = TemperatureSensor(name: "HEATSINK_1", + code: FourCharCode(fromStaticString: "Th1H")) + public static let HEATSINK_2 = TemperatureSensor(name: "HEATSINK_2", + code: FourCharCode(fromStaticString: "Th2H")) + public static let LCD_PROXIMITY = TemperatureSensor(name: "LCD_PROXIMITY", + code: FourCharCode(fromStaticString: "TL0P")) + public static let MEM_SLOT_0 = TemperatureSensor(name: "MEM_SLOT_0", + code: FourCharCode(fromStaticString: "TM0S")) + public static let MEM_SLOTS_PROXIMITY = + TemperatureSensor(name: "MEM_SLOTS_PROXIMITY", + code: FourCharCode(fromStaticString: "TM0P")) + public static let MISC_PROXIMITY = TemperatureSensor(name: "MISC_PROXIMITY", + code: FourCharCode(fromStaticString: "Tm0P")) + public static let NORTHBRIDGE = TemperatureSensor(name: "NORTHBRIDGE", + code: FourCharCode(fromStaticString: "TN0H")) + public static let NORTHBRIDGE_DIODE = + TemperatureSensor(name: "NORTHBRIDGE_DIODE", + code: FourCharCode(fromStaticString: "TN0D")) + public static let NORTHBRIDGE_PROXIMITY = + TemperatureSensor(name: "NORTHBRIDGE_PROXIMITY", + code: FourCharCode(fromStaticString: "TN0P")) + public static let ODD_PROXIMITY = TemperatureSensor(name: "ODD_PROXIMITY", + code: FourCharCode(fromStaticString: "TO0P")) + public static let PALM_REST = TemperatureSensor(name: "PALM_REST", + code: FourCharCode(fromStaticString: "Ts0P")) + public static let PWR_SUPPLY_PROXIMITY = + TemperatureSensor(name: "PWR_SUPPLY_PROXIMITY", + code: FourCharCode(fromStaticString: "Tp0P")) + public static let THUNDERBOLT_0 = TemperatureSensor(name: "THUNDERBOLT_0", + code: FourCharCode(fromStaticString: "TI0P")) + public static let THUNDERBOLT_1 = TemperatureSensor(name: "THUNDERBOLT_1", + code: FourCharCode(fromStaticString: "TI1P")) + + public static let all = [AMBIENT_AIR_0.code : AMBIENT_AIR_0, + AMBIENT_AIR_1.code : AMBIENT_AIR_1, + CPU_0_DIE.code : CPU_0_DIE, + CPU_0_DIODE.code : CPU_0_DIODE, + CPU_0_HEATSINK.code : CPU_0_HEATSINK, + CPU_0_PROXIMITY.code : CPU_0_PROXIMITY, + ENCLOSURE_BASE_0.code : ENCLOSURE_BASE_0, + ENCLOSURE_BASE_1.code : ENCLOSURE_BASE_1, + ENCLOSURE_BASE_2.code : ENCLOSURE_BASE_2, + ENCLOSURE_BASE_3.code : ENCLOSURE_BASE_3, + GPU_0_DIODE.code : GPU_0_DIODE, + GPU_0_HEATSINK.code : GPU_0_HEATSINK, + GPU_0_PROXIMITY.code : GPU_0_PROXIMITY, + HDD_PROXIMITY.code : HDD_PROXIMITY, + HEATSINK_0.code : HEATSINK_0, + HEATSINK_1.code : HEATSINK_1, + HEATSINK_2.code : HEATSINK_2, + MEM_SLOT_0.code : MEM_SLOT_0, + MEM_SLOTS_PROXIMITY.code: MEM_SLOTS_PROXIMITY, + PALM_REST.code : PALM_REST, + LCD_PROXIMITY.code : LCD_PROXIMITY, + MISC_PROXIMITY.code : MISC_PROXIMITY, + NORTHBRIDGE.code : NORTHBRIDGE, + NORTHBRIDGE_DIODE.code : NORTHBRIDGE_DIODE, + NORTHBRIDGE_PROXIMITY.code : NORTHBRIDGE_PROXIMITY, + ODD_PROXIMITY.code : ODD_PROXIMITY, + PWR_SUPPLY_PROXIMITY.code : PWR_SUPPLY_PROXIMITY, + THUNDERBOLT_0.code : THUNDERBOLT_0, + THUNDERBOLT_1.code : THUNDERBOLT_1] +} + +public struct TemperatureSensor { + public let name: String + public let code: FourCharCode +} + +public enum TemperatureUnit { + case celius + case fahrenheit + case kelvin + + public static func toFahrenheit(_ celius: Double) -> Double { + // https://en.wikipedia.org/wiki/Fahrenheit#Definition_and_conversions + return (celius * 1.8) + 32 + } + + public static func toKelvin(_ celius: Double) -> Double { + // https://en.wikipedia.org/wiki/Kelvin + return celius + 273.15 + } +} + +extension SMCKit { + + public static func allKnownTemperatureSensors() throws -> + [TemperatureSensor] { + var sensors = [TemperatureSensor]() + + for sensor in TemperatureSensors.all.values { + if try isKeyFound(sensor.code) { sensors.append(sensor) } + } + + return sensors + } + + public static func allUnknownTemperatureSensors() throws -> [TemperatureSensor] { + let keys = try allKeys() + + return keys.filter { $0.code.toString().hasPrefix("T") && + $0.info == DataTypes.SP78 && + TemperatureSensors.all[$0.code] == nil } + .map { TemperatureSensor(name: "Unknown", code: $0.code) } + } + + /// Get current temperature of a sensor + public static func temperature(_ sensorCode: FourCharCode, + unit: TemperatureUnit = .celius) throws -> Double { + let data = try readData(SMCKey(code: sensorCode, info: DataTypes.SP78)) + + let temperatureInCelius = Double(fromSP78: (data.0, data.1)) + + switch unit { + case .celius: + return temperatureInCelius + case .fahrenheit: + return TemperatureUnit.toFahrenheit(temperatureInCelius) + case .kelvin: + return TemperatureUnit.toKelvin(temperatureInCelius) + } + } +} + +//------------------------------------------------------------------------------ +// MARK: Fan +//------------------------------------------------------------------------------ + +public struct Fan { + // TODO: Should we start the fan id from 1 instead of 0? + public let id: Int + public let name: String + public let minSpeed: Int + public let maxSpeed: Int +} + +extension SMCKit { + + public static func allFans() throws -> [Fan] { + let count = try fanCount() + var fans = [Fan]() + + for i in 0 ..< count { + fans.append(try SMCKit.fan(i)) + } + + return fans + } + + public static func fan(_ id: Int) throws -> Fan { + let name = try fanName(id) + let minSpeed = try fanMinSpeed(id) + let maxSpeed = try fanMaxSpeed(id) + return Fan(id: id, name: name, minSpeed: minSpeed, maxSpeed: maxSpeed) + } + + /// Number of fans this machine has. All Intel based Macs, except for the + /// 2015 MacBook (8,1), have at least 1 + public static func fanCount() throws -> Int { + let key = SMCKey(code: FourCharCode(fromStaticString: "FNum"), + info: DataTypes.UInt8) + + let data = try readData(key) + return Int(data.0) + } + + public static func fanName(_ id: Int) throws -> String { + let key = SMCKey(code: FourCharCode(fromString: "F\(id)ID"), + info: DataTypes.FDS) + let data = try readData(key) + + // The last 12 bytes of '{fds' data type, a custom struct defined by the + // AppleSMC.kext that is 16 bytes, contains the fan name + let c1 = String(UnicodeScalar(data.4)) + let c2 = String(UnicodeScalar(data.5)) + let c3 = String(UnicodeScalar(data.6)) + let c4 = String(UnicodeScalar(data.7)) + let c5 = String(UnicodeScalar(data.8)) + let c6 = String(UnicodeScalar(data.9)) + let c7 = String(UnicodeScalar(data.10)) + let c8 = String(UnicodeScalar(data.11)) + let c9 = String(UnicodeScalar(data.12)) + let c10 = String(UnicodeScalar(data.13)) + let c11 = String(UnicodeScalar(data.14)) + let c12 = String(UnicodeScalar(data.15)) + + let name = c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11 + c12 + + let characterSet = CharacterSet.whitespaces + return name.trimmingCharacters(in: characterSet) + } + + public static func fanCurrentSpeed(_ id: Int) throws -> Int { + let key = SMCKey(code: FourCharCode(fromString: "F\(id)Ac"), + info: DataTypes.FPE2) + + let data = try readData(key) + return Int(fromFPE2: (data.0, data.1)) + } + + public static func fanMinSpeed(_ id: Int) throws -> Int { + let key = SMCKey(code: FourCharCode(fromString: "F\(id)Mn"), + info: DataTypes.FPE2) + + let data = try readData(key) + return Int(fromFPE2: (data.0, data.1)) + } + + public static func fanMaxSpeed(_ id: Int) throws -> Int { + let key = SMCKey(code: FourCharCode(fromString: "F\(id)Mx"), + info: DataTypes.FPE2) + + let data = try readData(key) + return Int(fromFPE2: (data.0, data.1)) + } + + /// Requires root privileges. By minimum we mean that OS X can interject and + /// raise the fan speed if needed, however it will not go below this. + /// + /// WARNING: You are playing with hardware here, BE CAREFUL. + /// + /// - Throws: Of note, `SMCKit.SMCError`'s `UnsafeFanSpeed` and `NotPrivileged` + public static func fanSetMinSpeed(_ id: Int, speed: Int) throws { + let maxSpeed = try fanMaxSpeed(id) + if speed <= 0 || speed > maxSpeed { throw SMCError.unsafeFanSpeed } + + let data = speed.toFPE2() + let bytes: SMCBytes = (data.0, data.1, UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0)) + + let key = SMCKey(code: FourCharCode(fromString: "F\(id)Mn"), + info: DataTypes.FPE2) + + try writeData(key, data: bytes) + } +} + +//------------------------------------------------------------------------------ +// MARK: Miscellaneous +//------------------------------------------------------------------------------ + +public struct batteryInfo { + public let batteryCount: Int + public let isACPresent: Bool + public let isBatteryPowered: Bool + public let isBatteryOk: Bool + public let isCharging: Bool +} + +extension SMCKit { + + public static func isOpticalDiskDriveFull() throws -> Bool { + // TODO: Should we catch key not found? That just means the machine + // doesn't have an ODD. Returning false though is not fully correct. + // Maybe we could throw a no ODD error instead? + let key = SMCKey(code: FourCharCode(fromStaticString: "MSDI"), + info: DataTypes.Flag) + + let data = try readData(key) + return Bool(fromByte: data.0) + } + + public static func batteryInformation() throws -> batteryInfo { + let batteryCountKey = + SMCKey(code: FourCharCode(fromStaticString: "BNum"), + info: DataTypes.UInt8) + let batteryPoweredKey = + SMCKey(code: FourCharCode(fromStaticString: "BATP"), + info: DataTypes.Flag) + let batteryInfoKey = + SMCKey(code: FourCharCode(fromStaticString: "BSIn"), + info: DataTypes.UInt8) + + let batteryCountData = try readData(batteryCountKey) + let batteryCount = Int(batteryCountData.0) + + let isBatteryPoweredData = try readData(batteryPoweredKey) + let isBatteryPowered = Bool(fromByte: isBatteryPoweredData.0) + + let batteryInfoData = try readData(batteryInfoKey) + let isCharging = batteryInfoData.0 & 1 == 1 ? true : false + let isACPresent = (batteryInfoData.0 >> 1) & 1 == 1 ? true : false + let isBatteryOk = (batteryInfoData.0 >> 6) & 1 == 1 ? true : false + + return batteryInfo(batteryCount: batteryCount, isACPresent: isACPresent, + isBatteryPowered: isBatteryPowered, + isBatteryOk: isBatteryOk, + isCharging: isCharging) + } +} diff --git a/com.davidwernhart.Helper/main.swift b/com.davidwernhart.Helper/main.swift new file mode 100644 index 0000000..332bc0e --- /dev/null +++ b/com.davidwernhart.Helper/main.swift @@ -0,0 +1,25 @@ +// +// main.swift +// com.davidwernhart.Helper +// +// Created by David Wernhart on 10.02.20. +// Copyright © 2020 David Wernhart. All rights reserved. +// + +import Foundation + +class HelperDelegate: NSObject, NSXPCListenerDelegate { + func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { + newConnection.exportedInterface = NSXPCInterface(with: HelperToolProtocol.self) + newConnection.exportedObject = HelperTool() + newConnection.resume() + return true + } +} + +let delegate = HelperDelegate() +let listener = NSXPCListener(machServiceName: "com.davidwernhart.Helper.mach") +listener.delegate = delegate +listener.resume() +RunLoop.current.run() +