From 8a7de99bcee634ef80b02f97792ab8275aff919a Mon Sep 17 00:00:00 2001 From: ad Date: Thu, 31 May 2018 13:20:18 +0300 Subject: [PATCH] + start at login --- MTMR.xcodeproj/project.pbxproj | 6 + MTMR/AppDelegate.swift | 6 + MTMR/CBridge/LaunchAtLoginController.h | 35 ++++++ MTMR/CBridge/LaunchAtLoginController.m | 128 +++++++++++++++++++++ MTMR/CBridge/TouchBarPrivateApi-Bridging.h | 1 + 5 files changed, 176 insertions(+) create mode 100644 MTMR/CBridge/LaunchAtLoginController.h create mode 100644 MTMR/CBridge/LaunchAtLoginController.m diff --git a/MTMR.xcodeproj/project.pbxproj b/MTMR.xcodeproj/project.pbxproj index 192353d..d22c61e 100644 --- a/MTMR.xcodeproj/project.pbxproj +++ b/MTMR.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 36C2ECDD207C723B003CDA33 /* ParseConfigTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECDC207C723B003CDA33 /* ParseConfigTests.swift */; }; 36C2ECDE207C82DE003CDA33 /* ItemsParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C2ECDA207C3FE7003CDA33 /* ItemsParsing.swift */; }; 36C2ECE0207CB1B0003CDA33 /* defaultPreset.json in Resources */ = {isa = PBXBuildFile; fileRef = 36C2ECDF207CB1B0003CDA33 /* defaultPreset.json */; }; + 60173D3E20C0031B002C305F /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 60173D3D20C0031B002C305F /* LaunchAtLoginController.m */; }; 6027D1B92080E52A004FFDC7 /* BrightnessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */; }; 6027D1BA2080E52A004FFDC7 /* VolumeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6027D1B82080E52A004FFDC7 /* VolumeViewController.swift */; }; 6042B6A72083E03A00C525C8 /* AppScrubberTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */; }; @@ -65,6 +66,8 @@ 36C2ECDA207C3FE7003CDA33 /* ItemsParsing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemsParsing.swift; sourceTree = ""; }; 36C2ECDC207C723B003CDA33 /* ParseConfigTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfigTests.swift; sourceTree = ""; }; 36C2ECDF207CB1B0003CDA33 /* defaultPreset.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = defaultPreset.json; sourceTree = ""; }; + 60173D3C20C0031B002C305F /* LaunchAtLoginController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = ""; }; + 60173D3D20C0031B002C305F /* LaunchAtLoginController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = ""; }; 6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrightnessViewController.swift; sourceTree = ""; }; 6027D1B82080E52A004FFDC7 /* VolumeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VolumeViewController.swift; sourceTree = ""; }; 6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppScrubberTouchBarItem.swift; sourceTree = ""; }; @@ -222,6 +225,8 @@ B0F8771B207AC92700D6E430 /* TouchBarSupport.h */, 6042B6A82083E1F500C525C8 /* DeprecatedCarbonAPI.h */, 6042B6A92083E27000C525C8 /* DeprecatedCarbonAPI.c */, + 60173D3C20C0031B002C305F /* LaunchAtLoginController.h */, + 60173D3D20C0031B002C305F /* LaunchAtLoginController.m */, ); path = CBridge; sourceTree = ""; @@ -367,6 +372,7 @@ B082B253205C7D8000BC04DC /* AppDelegate.swift in Sources */, 60C44AFD20A373A100C0EC91 /* MusicBarItem.swift in Sources */, B059D624205E04F3006E6B86 /* CustomButtonTouchBarItem.swift in Sources */, + 60173D3E20C0031B002C305F /* LaunchAtLoginController.m in Sources */, 6027D1BA2080E52A004FFDC7 /* VolumeViewController.swift in Sources */, 607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */, 6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */, diff --git a/MTMR/AppDelegate.swift b/MTMR/AppDelegate.swift index 4a9e721..1c5bb13 100644 --- a/MTMR/AppDelegate.swift +++ b/MTMR/AppDelegate.swift @@ -89,6 +89,11 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } + @objc func toggleStartAtLogin(_ sender: Any?) { + LaunchAtLoginController().setLaunchAtLogin(!LaunchAtLoginController().launchAtLogin, for: NSURL.fileURL(withPath: Bundle.main.bundlePath)) + createMenu() + } + func createMenu() { let menu = NSMenu() menu.addItem(withTitle: "Preferences", action: #selector(openPreferences(_:)), keyEquivalent: ",") @@ -96,6 +101,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { menu.addItem(withTitle: "Open Preset", action: #selector(openPreset(_:)), keyEquivalent: "O") menu.addItem(withTitle: TouchBarController.shared.controlStripState ? "Hide Control Strip" : "Show Control Strip" , action: #selector(toggleControlStrip(_:)), keyEquivalent: "T") menu.addItem(withTitle: "Toggle blackList current app" , action: #selector(toggleBlackListedApp(_:)), keyEquivalent: "B") + menu.addItem(withTitle: LaunchAtLoginController().launchAtLogin ? "Disable start at login" : "Enable start at login", action: #selector(toggleStartAtLogin(_:)), keyEquivalent: "L") menu.addItem(NSMenuItem.separator()) menu.addItem(withTitle: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q") statusItem.menu = menu diff --git a/MTMR/CBridge/LaunchAtLoginController.h b/MTMR/CBridge/LaunchAtLoginController.h new file mode 100644 index 0000000..bed7dda --- /dev/null +++ b/MTMR/CBridge/LaunchAtLoginController.h @@ -0,0 +1,35 @@ +// +// LaunchAtLoginController.h +// +// Copyright 2011 Tomáš Znamenáček +// Copyright 2010 Ben Clark-Robinson +// +// 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 Foundation; +@import CoreServices; + +@interface LaunchAtLoginController : NSObject {} + +@property(assign) BOOL launchAtLogin; + +- (BOOL) willLaunchAtLogin: (NSURL*) itemURL; +- (void) setLaunchAtLogin: (BOOL) enabled forURL: (NSURL*) itemURL; + +@end diff --git a/MTMR/CBridge/LaunchAtLoginController.m b/MTMR/CBridge/LaunchAtLoginController.m new file mode 100644 index 0000000..0374fd0 --- /dev/null +++ b/MTMR/CBridge/LaunchAtLoginController.m @@ -0,0 +1,128 @@ +// +// LaunchAtLoginController.m +// +// Copyright 2011 Tomáš Znamenáček +// Copyright 2010 Ben Clark-Robinson +// +// 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 "LaunchAtLoginController.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +static NSString *const StartAtLoginKey = @"launchAtLogin"; + +@interface LaunchAtLoginController () +@property(assign) LSSharedFileListRef loginItems; +@end + +@implementation LaunchAtLoginController +@synthesize loginItems; + +#pragma mark Change Observing + +void sharedFileListDidChange(LSSharedFileListRef inList, void *context) +{ + LaunchAtLoginController *self = (__bridge id) context; + [self willChangeValueForKey:StartAtLoginKey]; + [self didChangeValueForKey:StartAtLoginKey]; +} + +#pragma mark Initialization + +- (id) init +{ + self = [super init]; + loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + LSSharedFileListAddObserver(loginItems, CFRunLoopGetMain(), + (CFStringRef)NSDefaultRunLoopMode, sharedFileListDidChange, (voidPtr)CFBridgingRetain(self)); + return self; +} + +- (void) dealloc +{ + LSSharedFileListRemoveObserver(loginItems, CFRunLoopGetMain(), + (CFStringRef)NSDefaultRunLoopMode, sharedFileListDidChange, (__bridge void *)(self)); + CFRelease(loginItems); +} + +#pragma mark Launch List Control +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +LSSharedFileListItemRef copyItemWithURLinFileList(NSURL* wantedURL, LSSharedFileListRef fileList) { + if (wantedURL == NULL || fileList == NULL) + return NULL; + + NSArray *listSnapshot = (__bridge_transfer NSArray *)LSSharedFileListCopySnapshot(fileList, NULL); + for(NSUInteger i = 0; i< [listSnapshot count]; i++) { + LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)[listSnapshot objectAtIndex:i]; + UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; + CFURLRef currentItemURL = NULL; + LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); + if (currentItemURL && [(__bridge_transfer NSURL*)currentItemURL isEqual:wantedURL]) { + CFRetain(item); + return item; + } + } + + return NULL; +} +#pragma clang diagnostic pop + +- (BOOL) willLaunchAtLogin: (NSURL*) itemURL +{ + return !!copyItemWithURLinFileList(itemURL, loginItems); +} + +- (void) setLaunchAtLogin: (BOOL) enabled forURL: (NSURL*) itemURL +{ + LSSharedFileListItemRef appItem = copyItemWithURLinFileList(itemURL, loginItems); + if (enabled && !appItem) { + LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, + NULL, NULL, (__bridge CFURLRef)itemURL, NULL, NULL); + } else if (!enabled && appItem) { + LSSharedFileListItemRemove(loginItems, appItem); + } + if (appItem) { + CFRelease(appItem); + } +} + +#pragma mark Basic Interface + +- (NSURL*) appURL +{ + return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; +} + +- (void) setLaunchAtLogin: (BOOL) enabled +{ + [self willChangeValueForKey:StartAtLoginKey]; + [self setLaunchAtLogin:enabled forURL:[self appURL]]; + [self didChangeValueForKey:StartAtLoginKey]; +} + +- (BOOL) launchAtLogin +{ + return [self willLaunchAtLogin:[self appURL]]; +} + +@end +#pragma clang diagnostic pop diff --git a/MTMR/CBridge/TouchBarPrivateApi-Bridging.h b/MTMR/CBridge/TouchBarPrivateApi-Bridging.h index 1955001..70634c7 100644 --- a/MTMR/CBridge/TouchBarPrivateApi-Bridging.h +++ b/MTMR/CBridge/TouchBarPrivateApi-Bridging.h @@ -9,6 +9,7 @@ #import "TouchBarPrivateApi.h" #import "TouchBarSupport.h" #import "DeprecatedCarbonAPI.h" +#include "LaunchAtLoginController.h" NS_ASSUME_NONNULL_BEGIN