diff --git a/Application/JitouchAppDelegate.m b/Application/JitouchAppDelegate.m
index bc4dfd2..123a9dc 100644
--- a/Application/JitouchAppDelegate.m
+++ b/Application/JitouchAppDelegate.m
@@ -3,6 +3,7 @@
*
* Copyright 2021 Sukolsak Sakshuwong
* Copyright 2021 Supasorn Suwajanakorn
+ * Copyright 2021 Aaron Kollasch
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
@@ -34,63 +35,18 @@ @implementation JitouchAppDelegate
@synthesize window;
-- (void)addJitouchToLoginItems{
- NSString *jitouchPath = [[NSString stringWithFormat:@"file://%@",[[NSBundle mainBundle] bundlePath]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSURL *jitouchURL = [NSURL URLWithString:jitouchPath];
-
-
- LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
- if (loginListRef) {
- // delete all shortcuts to jitouch in the login items
- UInt32 seedValue;
- NSArray *loginItemsArray = (NSArray *)CFBridgingRelease(LSSharedFileListCopySnapshot(loginListRef, &seedValue));
- for (id item in loginItemsArray) {
- LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
- CFURLRef thePath;
- if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
- NSRange range = [[(__bridge NSURL*)thePath path] rangeOfString:@"Jitouch"];
- if (range.location != NSNotFound)
- LSSharedFileListItemRemove(loginListRef, itemRef);
- }
- }
-
- if (![settings objectForKey:@"StartAtLogin"] || [[settings objectForKey:@"StartAtLogin"] intValue]) {
- // add shortcut to jitouch in the login items (there should be only one shortcut)
- LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef, kLSSharedFileListItemLast, NULL, NULL, (__bridge CFURLRef)jitouchURL, NULL, NULL);
-
- if (loginItemRef) {
- CFRelease(loginItemRef);
- }
- }
-
- CFRelease(loginListRef);
- }
-}
-
-- (void)removeJitouchFromLoginItems{
- LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
- if (loginListRef) {
- // delete all shortcuts to jitouch in the login items
- UInt32 seedValue;
- NSArray *loginItemsArray = (NSArray *)CFBridgingRelease(LSSharedFileListCopySnapshot(loginListRef, &seedValue));
- for (id item in loginItemsArray) {
- LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
- CFURLRef thePath;
- if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
- NSRange range = [[(__bridge NSURL*)thePath path] rangeOfString:@"Jitouch"];
- if (range.location != NSNotFound)
- LSSharedFileListItemRemove(loginListRef, itemRef);
- }
- }
- CFRelease(loginListRef);
- }
+- (void)unloadJitouchLaunchAgent {
+ NSString *plistPath = [@"~/Library/LaunchAgents/com.jitouch.Jitouch.plist" stringByStandardizingPath];
+ NSArray *unloadArgs = [NSArray arrayWithObjects:@"unload",
+ plistPath,
+ nil];
+ NSTask *unloadTask = [NSTask launchedTaskWithLaunchPath:@"/bin/launchctl" arguments:unloadArgs];
+ [unloadTask waitUntilExit];
}
#pragma mark - Menu
- (BOOL)validateMenuItem:(NSMenuItem *)item {
- if ([item action] == @selector(switchChange:))
- return NO;
return YES;
}
@@ -151,8 +107,7 @@ - (void)preferences:(id)sender {
- (void)quit:(id)sender {
- // Remove from login item
- [self removeJitouchFromLoginItems];
+ [self unloadJitouchLaunchAgent];
// Quit
[NSApp terminate: sender];
diff --git a/PreferencePane/JitouchPref.m b/PreferencePane/JitouchPref.m
index b3d2911..244f300 100644
--- a/PreferencePane/JitouchPref.m
+++ b/PreferencePane/JitouchPref.m
@@ -4,6 +4,7 @@
* Copyright 2021 Daniel Herrmann
* Copyright 2021 Sukolsak Sakshuwong
* Copyright 2021 Supasorn Suwajanakorn
+ * Copyright 2021 Aaron Kollasch
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
@@ -53,6 +54,9 @@ - (IBAction)change:(id)sender {
[Settings setKey:@"enAll" withInt:value];
[self enUpdated];
+ if (enAll) {
+ [self loadJitouchLaunchAgent];
+ }
} else if (sender == cbShowIcon) {
int value = [sender state] == NSOnState ? 1: 0;
[Settings setKey:@"ShowIcon" withInt:value];
@@ -119,15 +123,12 @@ static CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEve
}
-- (void)addJitouchToLoginItems{
- NSString *jitouchPath = [NSString stringWithFormat:@"file://%@", [[self bundle] pathForResource:@"Jitouch" ofType:@"app"]];
- NSURL *jitouchURL = [NSURL URLWithString:jitouchPath];
-
+- (void)removeJitouchFromLoginItems{
LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginListRef) {
// delete all shortcuts to jitouch in the login items
UInt32 seedValue;
- NSArray *loginItemsArray = (NSArray *)CFBridgingRelease(LSSharedFileListCopySnapshot(loginListRef, &seedValue));
+ NSArray *loginItemsArray = (NSArray *)CFBridgingRelease(LSSharedFileListCopySnapshot(loginListRef, &seedValue));
for (id item in loginItemsArray) {
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
CFURLRef thePath;
@@ -137,19 +138,106 @@ - (void)addJitouchToLoginItems{
LSSharedFileListItemRemove(loginListRef, itemRef);
}
}
+ }
+}
+- (NSData *)generateJitouchLaunchAgent:(NSError**)error {
+ if (error) { *error = nil; }
+ NSString *pathToUs = [[self bundle] bundlePath];
+ NSString *plistPath = [[self bundle]
+ pathForResource:@"io.github.jitouchproject.Jitouch" ofType:@"plist"];
+ NSData *launchAgentXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
+ NSString *home = NSHomeDirectory();
+
+ NSMutableDictionary *launchAgent = [NSPropertyListSerialization
+ propertyListWithData:launchAgentXML
+ options:NSPropertyListMutableContainersAndLeaves
+ format:NULL
+ error:error];
+ if (error && *error) {
+ return launchAgentXML;
+ }
- if (![settings objectForKey:@"StartAtLogin"] || [[settings objectForKey:@"StartAtLogin"] intValue]) {
- // add shortcut to jitouch in the login items (there should be only one shortcut)
- LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef, kLSSharedFileListItemLast, NULL, NULL, (__bridge CFURLRef)jitouchURL, NULL, NULL);
+ NSString *jitouchPath = [NSString
+ stringWithFormat:@"%@/Contents/Resources/Jitouch.app/Contents/MacOS/Jitouch",
+ pathToUs];
+ if ([launchAgent[@"ProgramArguments"] count] == 0) {
+ [launchAgent[@"ProgramArguments"] addObject:jitouchPath];
+ } else {
+ [launchAgent[@"ProgramArguments"] replaceObjectAtIndex:0 withObject:jitouchPath];
+ }
+ launchAgent[@"StandardErrorPath"] = [NSString stringWithFormat:@"%@/Library/Logs/com.jitouch.Jitouch.log", home];
+ launchAgent[@"KeepAlive"][@"PathState"] = @{ pathToUs: [NSNumber numberWithBool:TRUE] };
+ launchAgentXML = [NSPropertyListSerialization
+ dataWithPropertyList:launchAgent format:NSPropertyListXMLFormat_v1_0 options:0 error:error];
+ return launchAgentXML;
+}
- if (loginItemRef) {
- CFRelease(loginItemRef);
- }
+- (void)loadJitouchLaunchAgent {
+ NSString *plistPath = [@"~/Library/LaunchAgents/com.jitouch.Jitouch.plist" stringByStandardizingPath];
+ NSArray *loadArgs = [NSArray arrayWithObjects:@"load",
+ plistPath,
+ nil];
+ NSTask *loadTask = [NSTask launchedTaskWithLaunchPath:@"/bin/launchctl" arguments:loadArgs];
+ [loadTask waitUntilExit];
+}
+
+- (void)unloadJitouchLaunchAgent {
+ NSString *plistPath = [@"~/Library/LaunchAgents/com.jitouch.Jitouch.plist" stringByStandardizingPath];
+ NSArray *unloadArgs = [NSArray arrayWithObjects:@"unload",
+ plistPath,
+ nil];
+ NSTask *unloadTask = [NSTask launchedTaskWithLaunchPath:@"/bin/launchctl" arguments:unloadArgs];
+ [unloadTask waitUntilExit];
+}
+
+- (void)addJitouchLaunchAgent {
+ NSError *error;
+ NSData *launchAgent = [self generateJitouchLaunchAgent:&error];
+ if (error) {
+ NSLog(@"Error generating LaunchAgent: %@", [error localizedDescription]);
+ return;
+ }
+ NSString *plistPath = [@"~/Library/LaunchAgents/com.jitouch.Jitouch.plist" stringByStandardizingPath];
+ NSString *launchAgentPath = [@"~/Library/LaunchAgents" stringByStandardizingPath];
+ NSFileManager *fm = [NSFileManager defaultManager];
+ // exit if the LaunchAgent plist already matches
+ if ([fm fileExistsAtPath:plistPath] &&
+ [launchAgent isEqualToData:[fm contentsAtPath:plistPath]]) {
+ return;
+ }
+ // create the LaunchAgents directory
+ BOOL isDir;
+ BOOL exists = [fm fileExistsAtPath:launchAgentPath isDirectory:&isDir];
+ if (!exists) {
+ BOOL success = [fm createDirectoryAtPath:launchAgentPath withIntermediateDirectories:NO attributes:nil error:&error];
+ if (!success || error) {
+ NSLog(@"Error creating LaunchAgents directory at %@: %@", launchAgentPath, [error localizedDescription]);
+ } else {
+ NSLog(@"Created the LaunchAgents directory at %@", launchAgentPath);
}
+ } else if (!isDir) {
+ NSLog(@"Error creating LaunchAgent at %@: ~/Library/LaunchAgents is not a directory.", plistPath);
+ }
+ // unload the LaunchAgent
+ [self unloadJitouchLaunchAgent];
- CFRelease(loginListRef);
+ // write the new LaunchAgent plist
+ [launchAgent writeToFile:plistPath options:NSDataWritingAtomic error:&error];
+ if (error) {
+ NSLog(@"Error creating LaunchAgent at %@: %@", plistPath, [error localizedDescription]);
+ }
+ else {
+ NSLog(@"Updated LaunchAgent at %@", plistPath);
}
+
+ // in case an older Jitouch is still around
+ [self removeJitouchFromLoginItems];
+ [self killAllJitouchs];
+
+ [self loadJitouchLaunchAgent];
+
+ NSLog(@"Reloaded LaunchAgent at %@", plistPath);
}
- (void)mainViewDidLoad {
@@ -174,11 +262,7 @@ - (void)mainViewDidLoad {
[self killAllJitouchs];
running = NO;
}
- [self addJitouchToLoginItems];
- //if (!running) {
- NSString *pathToJitouchInBundle = [[self bundle] pathForResource:@"Jitouch" ofType:@"app"];
- [[NSWorkspace sharedWorkspace] openFile:pathToJitouchInBundle];
- //}
+ [self addJitouchLaunchAgent];
NSInteger tabIndex = 0;
diff --git a/PreferencePane/io.github.jitouchproject.Jitouch.plist b/PreferencePane/io.github.jitouchproject.Jitouch.plist
index aeb573c..0866d76 100644
--- a/PreferencePane/io.github.jitouchproject.Jitouch.plist
+++ b/PreferencePane/io.github.jitouchproject.Jitouch.plist
@@ -22,5 +22,11 @@
SuccessfulExit
+ ProcessType
+ Interactive
+ StandardErrorPath
+ /dev/null
+ StandardOutPath
+ /dev/null