Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Use the DaemonController in the prefpane

Also name spinners more sensibly.
  • Loading branch information...
commit 7d33a5653f2aef409cd0fbb15e9196f988111a3a 1 parent 1a5c249
@mxcl authored
Showing with 106 additions and 287 deletions.
  1. +6 −7 main.h
  2. +77 −253 main.m
  3. +23 −27 main.xib
View
13 main.h
@@ -19,6 +19,8 @@
#import <PreferencePanes/PreferencePanes.h>
#import "MBSliderButton.h"
+@class DaemonController;
+
// long class name is because we get loaded into System Preferences process, so
// we are required to be ultra verbose
// http://developer.apple.com/documentation/UserExperience/Conceptual/PreferencePanes/Tasks/Conflicts.html
@@ -28,15 +30,12 @@
IBOutlet MBSliderButton* big_switch;
IBOutlet NSButton* demos;
IBOutlet NSWindow* advanced_window;
- IBOutlet NSProgressIndicator* spinner;
- IBOutlet NSProgressIndicator* scan_spinner;
+ IBOutlet NSProgressIndicator* off_spinner;
+ IBOutlet NSProgressIndicator* on_spinner;
IBOutlet NSTextField* scanning;
-
- NSTask* daemon_task;
+
NSTask* scanner_task;
- NSTimer* poll_timer;
- NSTimer* check_startup_status_timer;
- pid_t pid;
+ DaemonController* d;
}
-(void)mainViewDidLoad;
View
330 main.m
@@ -21,104 +21,17 @@
//TODO remember path that we scanned with defaults controller
#import "main.h"
-#include <Sparkle/SUUpdater.h>
-#include <sys/sysctl.h>
-
-
-/** returns the pid of the running playdar instance, or 0 if not found */
-static pid_t playdar_pid()
-{
- int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
- struct kinfo_proc *info;
- size_t N;
- pid_t pid = 0;
-
- if(sysctl(mib, 3, NULL, &N, NULL, 0) < 0)
- return 0; //wrong but unlikely
- if(!(info = NSZoneMalloc(NULL, N)))
- return 0; //wrong but unlikely
- if(sysctl(mib, 3, info, &N, NULL, 0) < 0)
- goto end;
-
- N = N / sizeof(struct kinfo_proc);
- for(size_t i = 0; i < N; i++)
- if(strcmp(info[i].kp_proc.p_comm, "playdar.smp") == 0)
- { pid = info[i].kp_proc.p_pid; break; }
-end:
- NSZoneFree(NULL, info);
- return pid;
-}
-
-static void kqueue_termination_callback(CFFileDescriptorRef f, CFOptionFlags callBackTypes, void* self)
-{
- [(id)self performSelector:@selector(daemonTerminated:) withObject:nil];
-}
-
-static inline void kqueue_watch_pid(pid_t pid, id self)
-{
- int kq;
- struct kevent changes;
- CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };
- CFRunLoopSourceRef rls;
-
- // Create the kqueue and set it up to watch for SIGCHLD. Use the
- // new-in-10.5 EV_RECEIPT flag to ensure that we get what we expect.
-
- kq = kqueue();
-
- EV_SET(&changes, pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL);
- (void) kevent(kq, &changes, 1, &changes, 1, NULL);
-
- // Wrap the kqueue in a CFFileDescriptor (new in Mac OS X 10.5!). Then
- // create a run-loop source from the CFFileDescriptor and add that to the
- // runloop.
-
- CFFileDescriptorRef ref;
- ref = CFFileDescriptorCreate(NULL, kq, true, kqueue_termination_callback, &context);
- rls = CFFileDescriptorCreateRunLoopSource(NULL, ref, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
- CFRelease(rls);
-
- CFFileDescriptorEnableCallBacks(ref, kCFFileDescriptorReadCallBack);
-}
-
-#define START_POLL poll_timer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self selector:@selector(poll:) userInfo:nil repeats:true];
+#import "Sparkle/SUUpdater.h"
+#import "DaemonController.h"
@implementation OrgPlaydarPreferencePane
--(NSString*)startScriptPath
-{
- return [[[self bundle] bundlePath] stringByAppendingPathComponent:@"Contents/MacOS/erlexec_playdar"];
-}
-
--(NSString*)playdarctl
-{
- return [[[self bundle] bundlePath] stringByAppendingPathComponent:@"bin/playdarctl"];
-}
-
--(NSString*)playdarConfDir
+-(NSString*)etc
{
return [NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Preferences/org.playdar"];
}
--(int)numFiles
-{
- NSTask* task = [[NSTask alloc] init];
- [task setLaunchPath:[self playdarctl]];
- [task setArguments:[NSArray arrayWithObject:@"numfiles"]];
- [task setStandardOutput:[NSPipe pipe]];
- [task launch];
- [task waitUntilExit];
-
- // if not zero then we library module isn't ready yet
- if (task.terminationStatus != 0)
- return -1;
-
- NSData* data = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile];
- return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] intValue];
-}
-
-(void)showTrackCount:(int)n
{
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
@@ -140,16 +53,14 @@ -(void)mainViewDidLoad
[self addFolder:[home stringByAppendingPathComponent:@"Music"] setSelected:true];
[self addFolder:home setSelected:false];
- pid = playdar_pid();
- if(pid){
- kqueue_watch_pid(pid, self); // watch the pid for termination
+ d = [[DaemonController alloc] initWithDelegate:self andRootDir:[[self bundle] bundlePath]];
+
+ if ([d isRunning]) {
[big_switch setState:NSOnState animate:false];
[demos setHidden:false];
- [self showTrackCount:[self numFiles]];
+ [self showTrackCount:[d numFiles]];
}
- else
- START_POLL;
-
+
////// Sparkle
SUUpdater* updater = [SUUpdater updaterForBundle:[self bundle]];
[updater resetUpdateCycle];
@@ -199,11 +110,11 @@ -(void)scan
{
@try {
scanner_task = [[NSTask alloc] init];
- scanner_task.launchPath = [self playdarctl];
+ scanner_task.launchPath = [d playdarctl];
scanner_task.arguments = [NSArray arrayWithObjects:@"scan", [popup titleOfSelectedItem], nil];
[scanner_task launch];
- [scan_spinner startAnimation:self];
+ [on_spinner startAnimation:self];
[scanning setStringValue:@"Scanning…"];
[scanning setHidden:NO];
@@ -212,7 +123,7 @@ -(void)scan
name:NSTaskDidTerminateNotification
object:scanner_task];
- [scan_spinner startAnimation:self];
+ [on_spinner startAnimation:self];
}
@catch (NSException* e)
{
@@ -222,107 +133,11 @@ -(void)scan
-(void)scanComplete:(NSNotification*)note
{
- [self showTrackCount:[self numFiles]];
- [scan_spinner stopAnimation:self];
+ [self showTrackCount:[d numFiles]];
+ [on_spinner stopAnimation:self];
[self fadeInDemoButton];
}
--(void)poll:(NSTimer*)_poll_timer
-{
- if(pid = playdar_pid()){
- [poll_timer invalidate];
- poll_timer = nil;
- kqueue_watch_pid(pid, self);
- [big_switch setState:NSOnState];
- }
-}
-
--(void)stop
-{
- NSTask* task = [[NSTask alloc] init];
- task.launchPath = [self playdarctl];
- task.arguments = [NSArray arrayWithObjects:@"stop", nil];
-
- [spinner startAnimation:self];
- [task launch];
- [task waitUntilExit];
-
- if (task.terminationStatus == 0) {
- daemon_task = nil;
- [spinner stopAnimation:self];
- [self fadeOutDemoButton];
- return;
- }
-
- if(daemon_task)
- [daemon_task terminate];
- else if(pid == 0)
- ; // state machine error!
- else if(kill(pid, SIGKILL) == -1 && errno != ESRCH){
- [big_switch setState:NSOnState];
- NSRunCriticalAlertPanel(@"Could not kill daemon",
- @"Perhaps you don't have the right permissions?", nil, nil, nil);
- }else{
- // the kqueue event will tell us when the process exits
- }
-}
-
--(void)start
-{
- daemon_task = [[NSTask alloc] init];
- [daemon_task setLaunchPath:[self startScriptPath]];
- [daemon_task setArguments:[NSArray arrayWithObject:@"-d"]];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(daemonTerminated:)
- name:NSTaskDidTerminateNotification
- object:daemon_task];
- [daemon_task launch];
- pid = [daemon_task processIdentifier];
-
- [scan_spinner startAnimation:self];
-
- #define CHECK_READY_FOR_SCAN \
- [self performSelector:@selector(checkReadyForScan) withObject:nil afterDelay:0.2];
-
- CHECK_READY_FOR_SCAN
-}
-
--(void)checkReadyForScan
-{
- int const n = [self numFiles];
-
- if (n < 0) {
- CHECK_READY_FOR_SCAN
- [scanning setHidden:NO];
- [scanning setStringValue:@"Playdar is starting up…"];
- } else if (n == 0) {
- [self scan];
- } else {
- [self showTrackCount:n];
- [scan_spinner stopAnimation:self];
- [self fadeInDemoButton];
- }
-}
-
--(void)startInTerminal
-{
- daemon_task = [[NSTask alloc] init];
- [daemon_task setLaunchPath:@"/usr/bin/open"];
- [daemon_task setArguments:[NSArray arrayWithObjects:[self startScriptPath], @"-aTerminal", nil]];
- [daemon_task launch];
-
- pid = -100; //HACK
- [daemon_task waitUntilExit];
- pid = playdar_pid();
- daemon_task = nil;
-
- if(pid)
- kqueue_watch_pid(pid, self);
- else
- [big_switch setState:NSOffState];
-}
-
-(NSString*)menuItemAppPath
{
return [[[self bundle] bundlePath] stringByAppendingPathComponent:@"Contents/Resources/Playdar.app"];
@@ -368,66 +183,75 @@ -(void)startAtLogin:(bool)start_at_login
CFRelease(login_items_ref);
}
--(void)onEnable:(id)sender
+-(void)playdarIsStarting
{
- if ([big_switch state] == NSOffState) {
- [self stop];
- return;
- }
+ [on_spinner startAnimation:self];
+ [big_switch setState:NSOnState];
+}
- [poll_timer invalidate];
- poll_timer=nil;
-
- pid = playdar_pid();
-
- if(!pid){
- @try{
- if(NSAlternateKeyMask & [[NSApp currentEvent] modifierFlags])
- [self startInTerminal];
- else
- [self start];
-
- [self startAtLogin:true];
- }
- @catch(NSException* e)
- {
- NSString* msg = @"The file at “";
- msg = [msg stringByAppendingString:[daemon_task launchPath]];
- msg = [msg stringByAppendingString:@"” could not be executed."];
-
- NSBeginAlertSheet(@"Could not start Playdar",
- nil, nil, nil,
- [[self mainView] window],
- self,
- nil, nil,
- nil,
- msg );
- daemon_task = nil;
- }
- }else{
- // unexpectedly there is already a playdar instance running!
- kqueue_watch_pid(pid, self);
+-(void)playdarFailedToStart:(NSString*)emsg
+{
+ NSBeginAlertSheet(@"Could not start Playdar",
+ nil, nil, nil,
+ [[self mainView] window], self,
+ nil, nil, nil,
+ emsg );
+
+ [self startAtLogin:NO];
+ [big_switch setState:NSOffState]; //TODO do both simultaneously
+ [self fadeOutDemoButton]; //TODO this one too see
+ [on_spinner stopAnimation:self];
+}
+
+-(void)playdarStarted:(NSNumber*)n
+{
+ int num_files = [n intValue];
+
+ [self startAtLogin:YES];
+ [big_switch setState:NSOnState];
+
+ if(num_files == 0)
+ [self scan];
+ else {
+ [self showTrackCount:num_files];
+ [on_spinner stopAnimation:self];
+ [self fadeInDemoButton];
}
}
--(void)daemonTerminated:(NSNotification*)note
-{
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:NSTaskDidTerminateNotification
- object:daemon_task];
-
- daemon_task = nil;
- pid = 0;
-
- [NSObject cancelPreviousPerformRequestsWithTarget:spinner];
- [NSObject cancelPreviousPerformRequestsWithTarget:self]; // FIXME a bit stupid no?
- [spinner stopAnimation:self];
- [scan_spinner stopAnimation:self];
- [self fadeOutDemoButton];
+-(void)playdarIsStopping
+{
+ [big_switch setState:NSOffState];
+ [off_spinner startAnimation:self];
+}
+
+-(void)playdarFailedToStop:(NSString*)emsg
+{
+ NSBeginAlertSheet(@"Could not stop Playdar",
+ nil, nil, nil,
+ [[self mainView] window], self,
+ nil, nil, nil,
+ emsg);
+}
+
+-(void)playdarStopped
+{
+ [NSObject cancelPreviousPerformRequestsWithTarget:off_spinner];
+
[big_switch setState:NSOffState];
- [big_switch setEnabled:true];
+ [off_spinner stopAnimation:self];
+ [self fadeOutDemoButton];
[self startAtLogin:false];
- START_POLL;
+}
+
+-(void)onEnable:(id)sender
+{
+ if ([big_switch state] == NSOffState)
+ [d stop];
+ else if (NSAlternateKeyMask & [[NSApp currentEvent] modifierFlags])
+ [d startInTerminal];
+ else
+ [d start];
}
////// Directory selector
@@ -486,7 +310,7 @@ -(NSString*)playdarModules
-(IBAction)onEditConfigFile:(id)sender;
{
NSFileManager* fm = [NSFileManager defaultManager];
- NSString* conf = [self playdarConfDir];
+ NSString* conf = [self etc];
if (![fm fileExistsAtPath:conf]) {
NSTask * task = [[NSTask alloc] init];
@@ -536,7 +360,7 @@ @implementation OrgPlaydarPreferencePane(SUUpdaterDelegateInformalProtocol)
-(void)updaterWillRelaunchApplication:(SUUpdater*)updater
{
- if(pid) kill(pid, SIGKILL);
+ [d stop];
}
-(NSString*)pathToRelaunchForUpdater:(SUUpdater*)updater
View
50 main.xib
@@ -12,8 +12,6 @@
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="324"/>
- <integer value="172"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -51,7 +49,7 @@
</object>
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
<object class="NSView" key="NSWindowView" id="1037298196">
- <reference key="NSNextResponder"/>
+ <nil key="NSNextResponder"/>
<int key="NSvFlags">272</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -365,7 +363,6 @@
</object>
</object>
<string key="NSFrameSize">{668, 344}</string>
- <reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
@@ -381,7 +378,7 @@
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
<string key="NSWindowContentMinSize">{444, 196}</string>
<object class="NSView" key="NSWindowView" id="332060182">
- <reference key="NSNextResponder"/>
+ <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -673,7 +670,6 @@
</object>
</object>
<string key="NSFrameSize">{465, 295}</string>
- <reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
<string key="NSMinSize">{444, 218}</string>
@@ -768,22 +764,6 @@
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
- <string key="label">spinner</string>
- <reference key="source" ref="294453543"/>
- <reference key="destination" ref="1047322050"/>
- </object>
- <int key="connectionID">337</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
- <string key="label">scan_spinner</string>
- <reference key="source" ref="294453543"/>
- <reference key="destination" ref="809672898"/>
- </object>
- <int key="connectionID">338</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
<string key="label">prefpane</string>
<reference key="source" ref="801010874"/>
<reference key="destination" ref="294453543"/>
@@ -838,6 +818,22 @@
</object>
<int key="connectionID">361</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">on_spinner</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="809672898"/>
+ </object>
+ <int key="connectionID">362</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">off_spinner</string>
+ <reference key="source" ref="294453543"/>
+ <reference key="destination" ref="1047322050"/>
+ </object>
+ <int key="connectionID">363</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -1390,7 +1386,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">361</int>
+ <int key="maxID">363</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -1473,20 +1469,20 @@
<string>advanced_window</string>
<string>big_switch</string>
<string>demos</string>
+ <string>off_spinner</string>
+ <string>on_spinner</string>
<string>popup</string>
- <string>scan_spinner</string>
<string>scanning</string>
- <string>spinner</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSWindow</string>
<string>MBSliderButton</string>
<string>NSButton</string>
- <string>NSPopUpButton</string>
<string>NSProgressIndicator</string>
- <string>NSTextField</string>
<string>NSProgressIndicator</string>
+ <string>NSPopUpButton</string>
+ <string>NSTextField</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
Please sign in to comment.
Something went wrong with that request. Please try again.