add secret listmedia/listslots options in the right-click menu

when option key pressed.
also adjust log window to use monospace font, show error/signal in red, and don't mention a successful exit.
tweaks to file handling/task complete so task complete logic is delayed until file handle is drained.
This commit is contained in:
Kelvin Sherlock 2021-06-18 21:57:46 -04:00
parent 34fcc3b3ed
commit 3889b42c14
5 changed files with 152 additions and 32 deletions

View File

@ -573,6 +573,29 @@ Gw
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="Iti-F9-p35"/> <menuItem isSeparatorItem="YES" id="Iti-F9-p35"/>
<menuItem title="List Media…" id="M5h-4W-0nV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="listMedia:" target="-2" id="IO7-MG-zud"/>
<binding destination="-2" name="hidden" keyPath="optionKey" id="LhL-2l-iss">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
</menuItem>
<menuItem title="List Slots…" id="cNj-Sb-KkE">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="listSlots:" target="-2" id="3nb-mV-eUK"/>
<binding destination="-2" name="hidden" keyPath="optionKey" id="dwp-Kn-LfC">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="yZx-W2-lZg"/>
<menuItem title="Reset All" id="PQ0-yO-SKz"> <menuItem title="Reset All" id="PQ0-yO-SKz">
<modifierMask key="keyEquivalentModifierMask"/> <modifierMask key="keyEquivalentModifierMask"/>
<connections> <connections>
@ -598,11 +621,13 @@ Gw
</connections> </connections>
</menuItem> </menuItem>
</items> </items>
<connections>
<outlet property="delegate" destination="-2" id="wqC-IG-63F"/>
</connections>
<point key="canvasLocation" x="-121" y="-2"/> <point key="canvasLocation" x="-121" y="-2"/>
</menu> </menu>
</objects> </objects>
<resources> <resources>
<image name="NSAppleMenuImage" width="11" height="14"/> <image name="NSAppleMenuImage" width="11" height="14"/>
<image name="NSAppleMenuImage" width="128" height="128"/>
</resources> </resources>
</document> </document>

View File

@ -10,7 +10,7 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface LaunchWindowController : NSWindowController <NSBrowserDelegate> @interface LaunchWindowController : NSWindowController <NSBrowserDelegate, NSMenuDelegate>
@end @end

View File

@ -79,6 +79,9 @@ static NSString *kContextMachine = @"kContextMachine";
@property (strong) IBOutlet NSWindow *addBookmarkWindow; @property (strong) IBOutlet NSWindow *addBookmarkWindow;
@property (strong) NSString *bookmarkName; @property (strong) NSString *bookmarkName;
@property (weak) IBOutlet NSTextField *bookmarkTextField; @property (weak) IBOutlet NSTextField *bookmarkTextField;
@property BOOL optionKey;
@end @end
@interface LaunchWindowController (SoftwareList) @interface LaunchWindowController (SoftwareList)
@ -600,6 +603,62 @@ static NSString *ShellQuote(NSString *s) {
} }
- (IBAction)listMedia:(id)sender {
[[self window] makeFirstResponder: nil]; // in case text is being edited...
if (!_machine) return;
NSMutableArray *argv = [NSMutableArray new];
[argv addObject: _machine];
[argv addObject: @"-listmedia"];
NSArray *tmp;
tmp = [_slotController args];
if ([tmp count]) {
[argv addObjectsFromArray: tmp];
}
#if 0
tmp = [_mediaController args];
if ([tmp count]) {
[argv addObjectsFromArray: tmp];
}
#endif
[LogWindowController controllerForArgs: argv close: NO];
}
- (IBAction)listSlots:(id)sender {
[[self window] makeFirstResponder: nil]; // in case text is being edited...
if (!_machine) return;
NSMutableArray *argv = [NSMutableArray new];
[argv addObject: _machine];
[argv addObject: @"-listslots"];
NSArray *tmp;
tmp = [_slotController args];
if ([tmp count]) {
[argv addObjectsFromArray: tmp];
}
#if 0
tmp = [_mediaController args];
if ([tmp count]) {
[argv addObjectsFromArray: tmp];
}
#endif
[LogWindowController controllerForArgs: argv close: NO];
}
-(IBAction)exportShellScript: (id)sender { -(IBAction)exportShellScript: (id)sender {
NSSavePanel *p = [NSSavePanel savePanel]; NSSavePanel *p = [NSSavePanel savePanel];
@ -924,4 +983,12 @@ static NSString *ShellQuote(NSString *s) {
} }
#pragma mark - NSMenuDelegate
-(void)menuNeedsUpdate:(NSMenu *)menu {
NSEventModifierFlags modifiers = [NSEvent modifierFlags];
[self setOptionKey: modifiers & NSEventModifierFlagOption ? YES : NO];
}
@end @end

View File

@ -12,8 +12,13 @@ NS_ASSUME_NONNULL_BEGIN
@interface LogWindowController : NSWindowController <NSWindowDelegate> @interface LogWindowController : NSWindowController <NSWindowDelegate>
#if 0
+(id)controllerForTask: (NSTask *)task; +(id)controllerForTask: (NSTask *)task;
+(id)controllerForTask: (NSTask *)task close: (BOOL)close;
#endif
+(id)controllerForArgs: (NSArray *)args; +(id)controllerForArgs: (NSArray *)args;
+(id)controllerForArgs: (NSArray *)args close: (BOOL)close;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -19,6 +19,10 @@ static NSMutableSet *LogWindows;
@implementation LogWindowController { @implementation LogWindowController {
NSTask *_task; NSTask *_task;
NSFileHandle *_handle; NSFileHandle *_handle;
NSFont *_font;
BOOL _close;
BOOL _eof;
} }
+(void)initialize { +(void)initialize {
@ -30,17 +34,14 @@ static NSMutableSet *LogWindows;
} }
+(id)controllerForTask: (NSTask *)task { +(id)controllerForTask: (NSTask *)task close: (BOOL)close{
LogWindowController *controller = [[LogWindowController alloc] initWithWindowNibName: @"LogWindow"]; LogWindowController *controller = [[LogWindowController alloc] initWithWindowNibName: @"LogWindow"];
[controller runTask: task]; [controller runTask: task close: close];
return controller; return controller;
} }
+(id)controllerForArgs: (NSArray *)args close: (BOOL)close {
+(id)controllerForArgs: (NSArray *)args {
// NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSURL *url = MameURL(); NSURL *url = MameURL();
@ -64,15 +65,24 @@ static NSMutableSet *LogWindows;
[task setArguments: args]; [task setArguments: args];
return [LogWindowController controllerForTask: task]; return [LogWindowController controllerForTask: task close: close];
}
+(id)controllerForArgs: (NSArray *)args {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL close = [defaults boolForKey: kAutoCloseLogWindow];
return [self controllerForArgs: args close: close];
} }
- (void)windowDidLoad { - (void)windowDidLoad {
[super windowDidLoad]; [super windowDidLoad];
[LogWindows addObject: self]; [LogWindows addObject: self];
_font = [NSFont userFixedPitchFontOfSize: 0];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
} }
-(void)appendString: (NSString *)string -(void)appendString: (NSString *)string
@ -80,7 +90,10 @@ static NSMutableSet *LogWindows;
if ([string length]) if ([string length])
{ {
// needs explicit color attribute for proper dark mode support. // needs explicit color attribute for proper dark mode support.
NSDictionary *attr = @{ NSForegroundColorAttributeName: [NSColor textColor] }; NSDictionary *attr = @{
NSForegroundColorAttributeName: [NSColor textColor],
NSFontAttributeName: _font,
};
NSAttributedString *astr = [[NSAttributedString alloc] initWithString: string attributes: attr]; NSAttributedString *astr = [[NSAttributedString alloc] initWithString: string attributes: attr];
[[_textView textStorage] appendAttributedString: astr]; [[_textView textStorage] appendAttributedString: astr];
} }
@ -93,10 +106,12 @@ static NSMutableSet *LogWindows;
} }
} }
-(NSError *)runTask: (NSTask *)task { -(NSError *)runTask: (NSTask *)task close: (BOOL)close {
if (_task) return nil; if (_task) return nil;
_close = close;
_eof = NO;
NSPipe *pipe = [NSPipe pipe]; NSPipe *pipe = [NSPipe pipe];
@ -130,16 +145,6 @@ static NSMutableSet *LogWindows;
} }
} }
#if 0
if (error) {
// NSURL *url = [task executableURL];
// NSString *path = [NSString stringWithCString: [url fileSystemRepresentation] encoding: NSUTF8StringEncoding];
NSLog(@"NSTask error. Path = %s error = %@", path, error);
// [self appendString: path];
// [self appendString: [error description]];
return error;
}
#endif
_task = task; _task = task;
NSString *title = [NSString stringWithFormat: @"Ample Log - %u", [task processIdentifier]]; NSString *title = [NSString stringWithFormat: @"Ample Log - %u", [task processIdentifier]];
[[self window] setTitle: title]; [[self window] setTitle: title];
@ -150,6 +155,7 @@ static NSMutableSet *LogWindows;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self [nc addObserver: self
selector: @selector(taskComplete:) selector: @selector(taskComplete:)
name: NSTaskDidTerminateNotification name: NSTaskDidTerminateNotification
@ -160,6 +166,7 @@ static NSMutableSet *LogWindows;
object: _handle]; object: _handle];
[_handle readInBackgroundAndNotify]; [_handle readInBackgroundAndNotify];
[[self window] setDocumentEdited: YES]; [[self window] setDocumentEdited: YES];
return nil; return nil;
} }
@ -172,21 +179,33 @@ static NSMutableSet *LogWindows;
// read complete, queue up another. // read complete, queue up another.
NSDictionary *dict = [notification userInfo]; NSDictionary *dict = [notification userInfo];
NSData *data = [dict objectForKey: NSFileHandleNotificationDataItem]; NSData *data = [dict objectForKey: NSFileHandleNotificationDataItem];
if ([data length]) if ([data length])
{ {
NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
[self appendString: string]; [self appendString: string];
[_handle readInBackgroundAndNotify]; [_handle readInBackgroundAndNotify];
} else {
[self appendString: @"\n"]; // -listmedia sometimes causes display issues.
_eof = YES;
//[_textView setNeedsDisplay: YES]; // -listmedia sometimes weird.
} }
} }
-(void)taskCompleteHack {
}
/* hask! task complete may occur while output still being processed. add a delay to compensate. */
-(void)taskComplete: (NSNotification *)notification -(void)taskComplete: (NSNotification *)notification
{ {
if (!_eof) {
[self performSelector: @selector(taskComplete:) withObject: notification afterDelay: 0.5];
return;
}
BOOL ok = NO; BOOL ok = NO;
NSTaskTerminationReason reason; NSTaskTerminationReason reason;
int status; int status;
@ -200,7 +219,7 @@ static NSMutableSet *LogWindows;
if (status == 0) if (status == 0)
{ {
string = @"\n\n[Success]\n\n"; //string = @"\n\n[Success]\n\n";
ok = YES; ok = YES;
} }
else string = @"\n\n[An error occurred]\n\n"; else string = @"\n\n[An error occurred]\n\n";
@ -209,18 +228,22 @@ static NSMutableSet *LogWindows;
{ {
string = [NSString stringWithFormat: @"\n\n[Caught signal %d (%s)]\n\n", status, strsignal(status)]; string = [NSString stringWithFormat: @"\n\n[Caught signal %d (%s)]\n\n", status, strsignal(status)];
} }
if (string) {
[self appendString: string]; NSDictionary *attr = @{
NSForegroundColorAttributeName: [NSColor systemRedColor],
NSFontAttributeName: _font,
};
NSAttributedString *astr = [[NSAttributedString alloc] initWithString: string attributes: attr];
[self appendAttributedString: astr];
}
_handle = nil; _handle = nil;
_task = nil; _task = nil;
[[self window] setDocumentEdited: NO]; [[self window] setDocumentEdited: NO];
if (ok && [[NSUserDefaults standardUserDefaults] boolForKey: kAutoCloseLogWindow]) { if (ok && _close) {
[[self window] close]; [[self window] close];
//[LogWindows removeObject: self]; // close sends WindowWillClose notification.
} }
} }