diff --git a/MA2ME.xcodeproj/project.pbxproj b/MA2ME.xcodeproj/project.pbxproj index 60dfa77..4ea4e22 100644 --- a/MA2ME.xcodeproj/project.pbxproj +++ b/MA2ME.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + B6004DF024FB05D600D38596 /* LogWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6004DEE24FB05D600D38596 /* LogWindowController.m */; }; + B6004DF124FB05D600D38596 /* LogWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6004DEF24FB05D600D38596 /* LogWindow.xib */; }; B60A6E1424EE0AE2004B7EEF /* FlippedView.m in Sources */ = {isa = PBXBuildFile; fileRef = B60A6E1324EE0AE2004B7EEF /* FlippedView.m */; }; B61099E724F5F231005CB652 /* SlotView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B61099E324F5F230005CB652 /* SlotView.xib */; }; B61099E824F5F231005CB652 /* MediaView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B61099E524F5F230005CB652 /* MediaView.xib */; }; @@ -66,10 +68,12 @@ B6D6DE3B24FACF4F00661A5F /* Defaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = B6D6DE3A24FACF4F00661A5F /* Defaults.plist */; }; B6D6DE3E24FADF8B00661A5F /* LaunchWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6D6DE3C24FADF8B00661A5F /* LaunchWindow.xib */; }; B6D6DE4124FADFAC00661A5F /* LaunchWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6D6DE4024FADFAC00661A5F /* LaunchWindowController.m */; }; - B6D6DE4524FAF00300661A5F /* ModelsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6D6DE4324FAF00300661A5F /* ModelsView.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + B6004DED24FB05D600D38596 /* LogWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogWindowController.h; sourceTree = ""; }; + B6004DEE24FB05D600D38596 /* LogWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LogWindowController.m; sourceTree = ""; }; + B6004DEF24FB05D600D38596 /* LogWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LogWindow.xib; sourceTree = ""; }; B60A6E0B24ECE23F004B7EEF /* apple2gs.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = apple2gs.plist; sourceTree = ""; }; B60A6E1224EE0AE2004B7EEF /* FlippedView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FlippedView.h; sourceTree = ""; }; B60A6E1324EE0AE2004B7EEF /* FlippedView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlippedView.m; sourceTree = ""; }; @@ -140,7 +144,6 @@ B6D6DE3D24FADF8B00661A5F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchWindow.xib; sourceTree = ""; }; B6D6DE3F24FADFAC00661A5F /* LaunchWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LaunchWindowController.h; sourceTree = ""; }; B6D6DE4024FADFAC00661A5F /* LaunchWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LaunchWindowController.m; sourceTree = ""; }; - B6D6DE4424FAF00300661A5F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ModelsView.xib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -237,7 +240,6 @@ children = ( B6BA257E24E99BE9005FB8FF /* AppDelegate.h */, B6BA257F24E99BE9005FB8FF /* AppDelegate.m */, - B6D6DE4324FAF00300661A5F /* ModelsView.xib */, B6D6DE3F24FADFAC00661A5F /* LaunchWindowController.h */, B6D6DE4024FADFAC00661A5F /* LaunchWindowController.m */, B65593B024ECB61800722E0C /* SlotViewController.m */, @@ -248,6 +250,8 @@ B64E15A824EA1D5300E8AD3D /* MachineViewController.m */, B60A6E1324EE0AE2004B7EEF /* FlippedView.m */, B60A6E1224EE0AE2004B7EEF /* FlippedView.h */, + B6004DED24FB05D600D38596 /* LogWindowController.h */, + B6004DEE24FB05D600D38596 /* LogWindowController.m */, B6BA258124E99BEB005FB8FF /* Assets.xcassets */, B64E15AF24EA365E00E8AD3D /* Resources */, B6BA258624E99BEB005FB8FF /* Info.plist */, @@ -264,6 +268,7 @@ children = ( B6BA258324E99BEB005FB8FF /* MainMenu.xib */, B6D6DE3C24FADF8B00661A5F /* LaunchWindow.xib */, + B6004DEF24FB05D600D38596 /* LogWindow.xib */, B6D6DE3724FAC8B500661A5F /* Preferences.xib */, B61099E524F5F230005CB652 /* MediaView.xib */, B61099E324F5F230005CB652 /* SlotView.xib */, @@ -336,6 +341,7 @@ B6109A3124F5F377005CB652 /* apple1.plist in Resources */, B6109A3524F5F377005CB652 /* ace100.plist in Resources */, B6109A3424F5F377005CB652 /* am64.plist in Resources */, + B6004DF124FB05D600D38596 /* LogWindow.xib in Resources */, B6BA258224E99BEB005FB8FF /* Assets.xcassets in Resources */, B6109A1724F5F377005CB652 /* apple2e.plist in Resources */, B6109A3C24F5F377005CB652 /* am100.plist in Resources */, @@ -366,7 +372,6 @@ B6109A3B24F5F377005CB652 /* apple2gsr1.plist in Resources */, B6D6DE3B24FACF4F00661A5F /* Defaults.plist in Resources */, B6109A2224F5F377005CB652 /* models.plist in Resources */, - B6D6DE4524FAF00300661A5F /* ModelsView.xib in Resources */, B6109A4024F5F377005CB652 /* craft2p.plist in Resources */, B6109A1B24F5F377005CB652 /* uniap2pt.plist in Resources */, B6109A3724F5F377005CB652 /* las128e2.plist in Resources */, @@ -397,6 +402,7 @@ B64979C224EF6703008ABD20 /* MediaViewController.m in Sources */, B60A6E1424EE0AE2004B7EEF /* FlippedView.m in Sources */, B6BA258024E99BE9005FB8FF /* AppDelegate.m in Sources */, + B6004DF024FB05D600D38596 /* LogWindowController.m in Sources */, B65593B124ECB61800722E0C /* SlotViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -444,14 +450,6 @@ name = LaunchWindow.xib; sourceTree = ""; }; - B6D6DE4324FAF00300661A5F /* ModelsView.xib */ = { - isa = PBXVariantGroup; - children = ( - B6D6DE4424FAF00300661A5F /* Base */, - ); - name = ModelsView.xib; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ diff --git a/MA2ME/Base.lproj/ModelsView.xib b/MA2ME/Base.lproj/ModelsView.xib deleted file mode 100644 index e33e68a..0000000 --- a/MA2ME/Base.lproj/ModelsView.xib +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/MA2ME/LaunchWindowController.m b/MA2ME/LaunchWindowController.m index 98165a8..fc481b5 100644 --- a/MA2ME/LaunchWindowController.m +++ b/MA2ME/LaunchWindowController.m @@ -10,6 +10,7 @@ #import "MediaViewController.h" #import "SlotViewController.h" #import "MachineViewController.h" +#import "LogWindowController.h" static NSString *kMyContext = @"kMyContext"; static NSString *kContextMachine = @"kContextMachine"; @@ -228,6 +229,7 @@ static NSString * JoinArguments(NSArray *argv) { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *path = [defaults stringForKey: @"MamePath"]; if (![path length]) path = @"/usr/local/bin/mame"; @@ -237,15 +239,12 @@ static NSString * JoinArguments(NSArray *argv) { NSTask *task = [NSTask new]; [task setExecutableURL: url]; [task setArguments: _args]; +#if 0 [task setTerminationHandler: ^(NSTask *t){ }]; - // set stderr/stdout... - [task launchAndReturnError: &error]; - - - if (error) NSLog(@"launchAction: %@", error); - +#endif + [LogWindowController controllerForTask: task]; } diff --git a/MA2ME/LogWindow.xib b/MA2ME/LogWindow.xib new file mode 100644 index 0000000..3b02d48 --- /dev/null +++ b/MA2ME/LogWindow.xib @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MA2ME/LogWindowController.h b/MA2ME/LogWindowController.h new file mode 100644 index 0000000..c092e92 --- /dev/null +++ b/MA2ME/LogWindowController.h @@ -0,0 +1,19 @@ +// +// LogWindowController.h +// MA2ME +// +// Created by Kelvin Sherlock on 8/29/2020. +// Copyright © 2020 Kelvin Sherlock. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface LogWindowController : NSWindowController + ++(id)controllerForTask: (NSTask *)task; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MA2ME/LogWindowController.m b/MA2ME/LogWindowController.m new file mode 100644 index 0000000..8033603 --- /dev/null +++ b/MA2ME/LogWindowController.m @@ -0,0 +1,156 @@ +// +// LogWindowController.m +// MA2ME +// +// Created by Kelvin Sherlock on 8/29/2020. +// Copyright © 2020 Kelvin Sherlock. All rights reserved. +// + +#import "LogWindowController.h" + +static NSMutableSet *LogWindows; + +@interface LogWindowController () +@property (unsafe_unretained) IBOutlet NSTextView *textView; + +@end + +@implementation LogWindowController { + NSTask *_task; + NSFileHandle *_handle; +} + ++(void)initialize { + LogWindows = [NSMutableSet set]; +} + +-(NSString *)windowNibName { + return @"LogWindow"; +} + + ++(id)controllerForTask: (NSTask *)task { + LogWindowController *controller = [[LogWindowController alloc] initWithWindowNibName: @"LogWindow"]; + [controller runTask: task]; + return controller; +} + +- (void)windowDidLoad { + [super windowDidLoad]; + + [LogWindows addObject: self]; + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. +} + +-(void)appendString: (NSString *)string +{ + if ([string length]) + { + [[[_textView textStorage] mutableString] appendString: string]; + } +} + +-(NSError *)runTask: (NSTask *)task { + + + if (_task) return nil; + + NSError *error = nil; + NSPipe *pipe = [NSPipe pipe]; + + [task setStandardError: pipe]; + [task setStandardOutput: pipe]; + [task launchAndReturnError: &error]; + + + if (error) { + NSLog(@"launchAction: %@", error); + [self appendString: [error description]]; + return error; + } + _task = task; + NSString *title = [NSString stringWithFormat: @"Log Window - %u", [task processIdentifier]]; + [[self window] setTitle: title]; + _handle = [pipe fileHandleForReading]; + + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + [nc addObserver: self + selector: @selector(taskComplete:) + name: NSTaskDidTerminateNotification + object: _task]; + [nc addObserver: self + selector: @selector(readComplete:) + name: NSFileHandleReadCompletionNotification + object: _handle]; + + [_handle readInBackgroundAndNotify]; + [[self window] setDocumentEdited: YES]; + return nil; +} + + +#pragma mark - +#pragma mark Notifications +-(void)readComplete:(NSNotification *)notification +{ + // read complete, queue up another. + NSDictionary *dict = [notification userInfo]; + NSData *data = [dict objectForKey: NSFileHandleNotificationDataItem]; + + if ([data length]) + { + + NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; + + [self appendString: string]; + + [_handle readInBackgroundAndNotify]; + } + +} + +-(void)taskComplete: (NSNotification *)notification +{ + BOOL ok = NO; + NSTaskTerminationReason reason; + int status; + NSString *string = nil; + + reason = [_task terminationReason]; + status = [_task terminationStatus]; + + if (reason == NSTaskTerminationReasonExit) + { + + if (status == 0) + { + string = @"\n\n[Success]\n\n"; + ok = YES; + } + else string = @"\n\n[An error occurred]\n\n"; + } + else + { + string = @"\n\n[Caught signal]\n\n"; + + } + + [self appendString: string]; + + _handle = nil; + _task = nil; + + [[self window] setDocumentEdited: NO]; +} + +#pragma mark - NSWindowDelegate + + +-(void)windowWillClose:(NSNotification *)notification { + [LogWindows removeObject: self]; +} + +@end