This commit is contained in:
relikd
2019-08-18 22:57:05 +02:00
commit c9811dd3fb
11 changed files with 946 additions and 0 deletions

89
.gitignore vendored Normal file
View File

@@ -0,0 +1,89 @@
# Created by https://www.gitignore.io/api/xcode,objective-c
# Edit at https://www.gitignore.io/?templates=xcode,objective-c
### Objective-C ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
# CocoaPods
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
# Pods/
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
# Carthage
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
# Code Injection
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/
### Objective-C Patch ###
### Xcode ###
# Xcode
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## User settings
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
## Xcode Patch
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcworkspace/contents.xcworkspacedata
/*.gcno
### Xcode Patch ###
**/xcshareddata/WorkspaceSettings.xcsettings
# End of https://www.gitignore.io/api/xcode,objective-c

7
LICENSE Normal file
View File

@@ -0,0 +1,7 @@
Copyright 2019 Oleg Geier
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.

20
README.md Normal file
View File

@@ -0,0 +1,20 @@
URL Scheme Defaults
===================
![screenshot](screenshot.png)
Simple tool to change the default macOS application for a given URL scheme (`http:`, `feed:`, etc.). The latter scheme is used for feed reader like [baRSS][1].
Usage
-----
1. Go to [releases][2] and download the tool
2. Run `URL Scheme Defaults`
3. It will list all schemes, for which **more than one** suitable application exists
4. Click on the drop-down icon and select a new application
[1]: https://github.com/relikd/baRSS
[2]: https://github.com/relikd/URL-Scheme-Defaults/releases/latest

View File

@@ -0,0 +1,343 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
5400424823072DD700958812 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5400424723072DD700958812 /* AppDelegate.m */; };
5400425023072DD700958812 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5400424F23072DD700958812 /* main.m */; };
5400425823072E5F00958812 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5400425723072E5F00958812 /* MainMenu.xib */; };
54FA660F2309DFC600A4BFAA /* AppIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 54FA660E2309DFC600A4BFAA /* AppIcon.icns */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
5400424323072DD700958812 /* URL Scheme Defaults.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "URL Scheme Defaults.app"; sourceTree = BUILT_PRODUCTS_DIR; };
5400424723072DD700958812 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
5400424E23072DD700958812 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5400424F23072DD700958812 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
5400425723072E5F00958812 /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
54FA660E2309DFC600A4BFAA /* AppIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AppIcon.icns; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5400424023072DD700958812 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
5400423A23072DD700958812 = {
isa = PBXGroup;
children = (
5400424523072DD700958812 /* source */,
5400424423072DD700958812 /* Products */,
);
sourceTree = "<group>";
};
5400424423072DD700958812 /* Products */ = {
isa = PBXGroup;
children = (
5400424323072DD700958812 /* URL Scheme Defaults.app */,
);
name = Products;
sourceTree = "<group>";
};
5400424523072DD700958812 /* source */ = {
isa = PBXGroup;
children = (
5400424723072DD700958812 /* AppDelegate.m */,
5400425723072E5F00958812 /* MainMenu.xib */,
54FA660E2309DFC600A4BFAA /* AppIcon.icns */,
5400424E23072DD700958812 /* Info.plist */,
5400424F23072DD700958812 /* main.m */,
);
path = source;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
5400424223072DD700958812 /* URL Scheme Defaults */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5400425423072DD700958812 /* Build configuration list for PBXNativeTarget "URL Scheme Defaults" */;
buildPhases = (
5400423F23072DD700958812 /* Sources */,
5400424023072DD700958812 /* Frameworks */,
5400424123072DD700958812 /* Resources */,
54FA66112309E2B600A4BFAA /* ShellScript */,
);
buildRules = (
);
dependencies = (
);
name = "URL Scheme Defaults";
productName = URLSchemeDefaults;
productReference = 5400424323072DD700958812 /* URL Scheme Defaults.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
5400423B23072DD700958812 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = relikd;
TargetAttributes = {
5400424223072DD700958812 = {
CreatedOnToolsVersion = 10.1;
SystemCapabilities = {
com.apple.HardenedRuntime = {
enabled = 1;
};
com.apple.Sandbox = {
enabled = 0;
};
};
};
};
};
buildConfigurationList = 5400423E23072DD700958812 /* Build configuration list for PBXProject "URL Scheme Defaults" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 5400423A23072DD700958812;
productRefGroup = 5400424423072DD700958812 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
5400424223072DD700958812 /* URL Scheme Defaults */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
5400424123072DD700958812 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5400425823072E5F00958812 /* MainMenu.xib in Resources */,
54FA660F2309DFC600A4BFAA /* AppIcon.icns in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
54FA66112309E2B600A4BFAA /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# https://crunchybagel.com/auto-incrementing-build-numbers-in-xcode/\nbuildNumber=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"${PROJECT_DIR}/${INFOPLIST_FILE}\")\nbuildNumber=$(($buildNumber + 1))\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $buildNumber\" \"${PROJECT_DIR}/${INFOPLIST_FILE}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
5400423F23072DD700958812 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5400425023072DD700958812 /* main.m in Sources */,
5400424823072DD700958812 /* AppDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
5400425223072DD700958812 /* 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;
CODE_SIGN_IDENTITY = "-";
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.10;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
5400425323072DD700958812 /* 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;
CODE_SIGN_IDENTITY = "-";
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.10;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
};
name = Release;
};
5400425523072DD700958812 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = UY657LKNHJ;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = source/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.URLSchemeDefaults;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
};
name = Debug;
};
5400425623072DD700958812 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = UY657LKNHJ;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = source/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.URLSchemeDefaults;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5400423E23072DD700958812 /* Build configuration list for PBXProject "URL Scheme Defaults" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5400425223072DD700958812 /* Debug */,
5400425323072DD700958812 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5400425423072DD700958812 /* Build configuration list for PBXNativeTarget "URL Scheme Defaults" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5400425523072DD700958812 /* Debug */,
5400425623072DD700958812 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 5400423B23072DD700958812 /* Project object */;
}

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5400424223072DD700958812"
BuildableName = "URL Scheme Defaults.app"
BlueprintName = "URL Scheme Defaults"
ReferencedContainer = "container:URL Scheme Defaults.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5400424223072DD700958812"
BuildableName = "URL Scheme Defaults.app"
BlueprintName = "URL Scheme Defaults"
ReferencedContainer = "container:URL Scheme Defaults.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5400424223072DD700958812"
BuildableName = "URL Scheme Defaults.app"
BlueprintName = "URL Scheme Defaults"
ReferencedContainer = "container:URL Scheme Defaults.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5400424223072DD700958812"
BuildableName = "URL Scheme Defaults.app"
BlueprintName = "URL Scheme Defaults"
ReferencedContainer = "container:URL Scheme Defaults.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

173
source/AppDelegate.m Normal file
View File

@@ -0,0 +1,173 @@
@import Cocoa;
@interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDataSource, NSComboBoxCellDataSource>
@end
static NSMutableDictionary<NSString*, NSString*> *nameCache;
// ################################################################
// #
// # MARK: - AppId -
// #
// ################################################################
@interface AppId : NSObject
@property (copy) NSString *bundleId;
@property (copy) NSString *name;
@end
@implementation AppId
+ (instancetype)bundleId:(NSString*)bundleId {
AppId *a = [AppId new];
a.bundleId = bundleId;
[a updateAppName];
return a;
}
/// First query name cache for available names. If not set, add new name to cache
- (void)updateAppName {
self.name = nameCache[self.bundleId];
if (!self.name) {
self.name = [self applicationNameForBundleId:self.bundleId];
if (!self.name) self.name = self.bundleId;
[nameCache setValue:self.name forKey:self.bundleId];
}
}
/// Returns application name for given identifier
- (NSString*)applicationNameForBundleId:(NSString*)bundleID {
NSArray<NSURL*> *urls = CFBridgingRelease(LSCopyApplicationURLsForBundleIdentifier((__bridge CFStringRef)bundleID, NULL));
if (urls.count > 0) {
NSDictionary *info = CFBridgingRelease(CFBundleCopyInfoDictionaryForURL((CFURLRef)urls.firstObject));
return info[(NSString*)kCFBundleExecutableKey];
}
return nil;
}
@end
// ################################################################
// #
// # MARK: - Scheme -
// #
// ################################################################
@interface Scheme : NSObject
@property (copy) NSString *name;
@property (weak) AppId *registered;
@property (strong) NSArray<AppId*> *available;
@end
@implementation Scheme
+ (instancetype)name:(NSString*)name {
Scheme *s = [Scheme new];
s.name = name;
[s prepareAvailable];
return s;
}
/// Select app at index and set it default. Checks whether set successful. Ignores setting same id.
- (void)setDefault:(NSUInteger)index {
AppId *app = self.available[index];
if (app == self.registered) return;
OSStatus s = LSSetDefaultHandlerForURLScheme((__bridge CFStringRef)self.name, (__bridge CFStringRef)app.bundleId);
if (s == 0) self.registered = app;
}
/// Gathers all registered application for scheme and inserts to available
- (void)prepareAvailable {
NSMutableArray *list = [NSMutableArray array];
NSString *defaultId = CFBridgingRelease(LSCopyDefaultHandlerForURLScheme((__bridge CFStringRef)self.name));
NSArray<NSString*> *ids = CFBridgingRelease(LSCopyAllHandlersForURLScheme((__bridge CFStringRef)self.name));
// LSCopyDefaultRoleHandlerForContentType, LSCopyAllRoleHandlersForContentType, kLSRolesAll
for (NSString *bundleId in ids) {
[list addObject:[AppId bundleId:bundleId]];
if ([bundleId isEqualToString:defaultId])
self.registered = list.lastObject;
}
self.available = [list sortedArrayUsingComparator:^NSComparisonResult(AppId *a, AppId *b) {
return [[a.name lowercaseString] compare:[b.name lowercaseString]];
}];
}
@end
// ################################################################
// #
// # MARK: - Main -
// #
// ################################################################
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTableView *table;
@property (strong) NSMutableArray<Scheme*> *data;
@end
@implementation AppDelegate
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
nameCache = [NSMutableDictionary dictionary];
self.data = [NSMutableArray array];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
for (NSString *urlScheme in [self readLaunchServicesSchemes]) {
Scheme *s = [Scheme name:urlScheme];
if (s.available.count > 1)
[self.data addObject:s];
}
[self.data sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];
[self.table reloadData];
}
- (NSSet*)readLaunchServicesSchemes {
NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.LaunchServices/com.apple.launchservices.secure"];
NSMutableSet<NSString*> *allSchemes = [NSMutableSet set];
for (NSDictionary *handler in [ud arrayForKey:@"LSHandlers"]) {
NSString *scheme = handler[@"LSHandlerURLScheme"]; // LSHandlerContentType
if (scheme) [allSchemes addObject:scheme];
}
return allSchemes;
}
#pragma mark - TableView & ComboBox data source
// table view data source
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.data.count;
}
// table view data source
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
if ([tableColumn.identifier isEqualToString:@"colScheme"])
return self.data[row].name;
return self.data[row].registered.name;
}
// table view data source
- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors {
[self.data sortUsingDescriptors:tableView.sortDescriptors];
[tableView setNeedsDisplay];
}
// table view data source
- (void)tableView:(NSTableView *)tableView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row {
NSInteger idx = [[tableView selectedCell] indexOfSelectedItem];
[self.data[row] setDefault:idx];
}
// combo box data source
- (NSInteger)numberOfItemsInComboBoxCell:(NSComboBoxCell *)comboBoxCell {
Scheme *s = self.data[self.table.selectedRow];
comboBoxCell.representedObject = s.available;
return s.available.count;
}
// combo box data source
- (id)comboBoxCell:(NSComboBoxCell *)comboBoxCell objectValueForItemAtIndex:(NSInteger)index {
NSArray<AppId*> *apps = comboBoxCell.representedObject;
return apps[index].name;
}
@end
// Rebuild Launch Services cache
// https://eclecticlight.co/2017/08/11/launch-services-database-problems-correcting-and-rebuilding/
// /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -v -apps u

BIN
source/AppIcon.icns Normal file

Binary file not shown.

34
source/Info.plist Normal file
View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>189</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 relikd. Public Domain.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

184
source/MainMenu.xib Normal file
View File

@@ -0,0 +1,184 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate">
<connections>
<outlet property="table" destination="VIj-4u-Ayb" id="zxl-IS-Ykc"/>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="URL Scheme Defaults" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="URL Scheme Defaults" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About URL Scheme Defaults" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide URL Scheme Defaults" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit URL Scheme Defaults" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="-67" y="-341"/>
</menu>
<window title="URL Scheme Defaults" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" animationBehavior="default" tabbingMode="disallowed" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenNone="YES" fullScreenDisallowsTiling="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="400" height="200"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<value key="minSize" type="size" width="320" height="200"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="400" height="200"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AWT-SO-eMg">
<rect key="frame" x="-1" y="21" width="402" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="Jyi-ee-N8g">
<rect key="frame" x="1" y="0.0" width="400" height="179"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" selectionHighlightStyle="sourceList" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="19" headerView="d5x-hJ-iGB" id="VIj-4u-Ayb">
<rect key="frame" x="0.0" y="0.0" width="400" height="156"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="10" height="1"/>
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
<tableViewGridLines key="gridStyleMask" vertical="YES"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="colScheme" editable="NO" width="135" minWidth="60" maxWidth="10000" id="xAk-fJ-vg3">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="URL Scheme">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingMiddle" selectable="YES" allowsUndo="NO" alignment="right" title="Text Cell" usesSingleLineMode="YES" id="Chb-uW-rMg">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<sortDescriptor key="sortDescriptorPrototype" selector="compare:" sortKey="name"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
<tableColumn identifier="colApp" width="245" minWidth="100" maxWidth="10000" id="e5d-gJ-zc9">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Application">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<comboBoxCell key="dataCell" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="left" usesSingleLineMode="YES" buttonBordered="NO" completes="NO" usesDataSource="YES" numberOfVisibleItems="400" id="PSB-WY-9EH">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<connections>
<outlet property="dataSource" destination="Voe-Tx-rLC" id="yYb-j9-gSe"/>
</connections>
</comboBoxCell>
<sortDescriptor key="sortDescriptorPrototype" selector="compare:" sortKey="registered.name"/>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="Voe-Tx-rLC" id="1RG-C6-RKI"/>
</connections>
</tableView>
</subviews>
<nil key="backgroundColor"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="QVc-od-33H">
<rect key="frame" x="1" y="163" width="400" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="JXh-pC-WcA">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="d5x-hJ-iGB">
<rect key="frame" x="0.0" y="0.0" width="400" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
</subviews>
</view>
<contentBorderThickness minY="22"/>
<point key="canvasLocation" x="-2" y="-136"/>
</window>
</objects>
</document>

5
source/main.m Normal file
View File

@@ -0,0 +1,5 @@
@import AppKit.NSApplication;
int main(int argc, const char * argv[]) {
return NSApplicationMain(argc, argv);
}