diff --git a/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj b/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj index 15ad9a85..f35b9ed5 100644 --- a/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj +++ b/Apple2Mac/Apple2Mac.xcodeproj/project.pbxproj @@ -89,6 +89,7 @@ 773B3DC019568A570085CE5F /* darwin-glue.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9119568A570085CE5F /* darwin-glue.S */; }; 773B3DC319568A570085CE5F /* zlib-helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9519568A570085CE5F /* zlib-helpers.c */; }; 773B3DCB1956903D0085CE5F /* libz.1.1.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */; }; + 773BC91619F2E6A900996893 /* EmulatorDiskController.m in Sources */ = {isa = PBXBuildFile; fileRef = 773BC91519F2E6A900996893 /* EmulatorDiskController.m */; }; 779DD827195764E200DF89E5 /* rom-shim.c in Sources */ = {isa = PBXBuildFile; fileRef = 779DD826195764E200DF89E5 /* rom-shim.c */; }; 779DD82F195BD9F900DF89E5 /* cpu.S in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D9019568A570085CE5F /* cpu.S */; }; 779DD830195BD9F900DF89E5 /* prefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 773B3D7719568A570085CE5F /* prefs.c */; }; @@ -247,6 +248,8 @@ 773B3D9519568A570085CE5F /* zlib-helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "zlib-helpers.c"; sourceTree = ""; }; 773B3D9619568A570085CE5F /* zlib-helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "zlib-helpers.h"; sourceTree = ""; }; 773B3DCA1956903D0085CE5F /* libz.1.1.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.1.3.dylib; path = usr/lib/libz.1.1.3.dylib; sourceTree = SDKROOT; }; + 773BC91419F2E6A900996893 /* EmulatorDiskController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EmulatorDiskController.h; path = Classes/OSX/EmulatorDiskController.h; sourceTree = ""; }; + 773BC91519F2E6A900996893 /* EmulatorDiskController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EmulatorDiskController.m; path = Classes/OSX/EmulatorDiskController.m; sourceTree = ""; }; 779DD826195764E200DF89E5 /* rom-shim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "rom-shim.c"; sourceTree = ""; }; 779DD850195BD9F900DF89E5 /* Apple2MacTestCPU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Apple2MacTestCPU.app; sourceTree = BUILT_PRODUCTS_DIR; }; 779DD851195BD9F900DF89E5 /* Apple2MacTestCPU-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Apple2MacTestCPU-Info.plist"; path = "/Users/aaronculliney/Documents/00web/apple2/Apple2Mac/Apple2MacTests/Apple2MacTestCPU-Info.plist"; sourceTree = ""; }; @@ -447,14 +450,16 @@ 773B3D431956897D0085CE5F /* Classes */ = { isa = PBXGroup; children = ( + 77E1C0C219D7298F004344E0 /* EmulatorFullscreenWindow.m */, + 77E1C0C319D7298F004344E0 /* EmulatorFullscreenWindow.h */, + 77E1C0C019D7298F004344E0 /* EmulatorGLView.m */, + 77E1C0C119D7298F004344E0 /* EmulatorGLView.h */, 77E1C0BE19D7298F004344E0 /* EmulatorWindowController.m */, 77E1C0BF19D7298F004344E0 /* EmulatorWindowController.h */, 4AC7A76B19ECC3FB00BCD457 /* EmulatorWindow.h */, 4AC7A76C19ECC3FB00BCD457 /* EmulatorWindow.m */, - 77E1C0C019D7298F004344E0 /* EmulatorGLView.m */, - 77E1C0C119D7298F004344E0 /* EmulatorGLView.h */, - 77E1C0C219D7298F004344E0 /* EmulatorFullscreenWindow.m */, - 77E1C0C319D7298F004344E0 /* EmulatorFullscreenWindow.h */, + 773BC91419F2E6A900996893 /* EmulatorDiskController.h */, + 773BC91519F2E6A900996893 /* EmulatorDiskController.m */, ); name = Classes; sourceTree = ""; @@ -956,6 +961,7 @@ 77E1C0B619D72700004344E0 /* matrixUtil.c in Sources */, 77E1C0C519D7298F004344E0 /* EmulatorGLView.m in Sources */, 773B3DAE19568A570085CE5F /* opcodes.c in Sources */, + 773BC91619F2E6A900996893 /* EmulatorDiskController.m in Sources */, 779F565C19EAF66E00A6F107 /* soundcore.c in Sources */, 779DD827195764E200DF89E5 /* rom-shim.c in Sources */, 773B3DC319568A570085CE5F /* zlib-helpers.c in Sources */, diff --git a/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib b/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib index a6375796..f10d9517 100644 --- a/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib +++ b/Apple2Mac/Apple2Mac/Base.lproj/MainMenu.xib @@ -114,7 +114,7 @@ CA - + @@ -124,7 +124,7 @@ CA - + @@ -171,7 +171,7 @@ CA - + @@ -257,7 +257,7 @@ CA - + @@ -285,11 +285,25 @@ CA - + + + + + + + + + + + + + + + diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h b/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h new file mode 100644 index 00000000..697113ac --- /dev/null +++ b/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h @@ -0,0 +1,13 @@ +// +// EmulatorDiskController.h +// Apple2Mac +// +// Created by Aaron Culliney on 10/18/14. +// Copyright (c) 2014 deadc0de.org. All rights reserved. +// + +#import + +@interface EmulatorDiskController : NSWindowController + +@end diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m b/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m new file mode 100644 index 00000000..fa327b2d --- /dev/null +++ b/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m @@ -0,0 +1,213 @@ +// +// EmulatorDiskController.m +// Apple2Mac +// +// Created by Aaron Culliney on 10/18/14. +// Copyright (c) 2014 deadc0de.org. All rights reserved. +// + +#import "EmulatorDiskController.h" + +#define READONLY_CHOICE_INDEX 0 +#define NO_DISK_INSERTED @"(No Disk Inserted)" +#define DSK_PROPERTIES @".dsk 143360 bytes" +#define NIB_PROPERTIES @".nib 232960 bytes" +#define GZ_EXTENSION @"gz" + +#define kApple2DisksURL @"kApple2DisksURL" + +@interface EmulatorDiskController () + +@property (assign) IBOutlet NSWindow *disksWindow; +@property (assign) IBOutlet NSTextField *diskInA; +@property (assign) IBOutlet NSTextField *diskInB; +@property (assign) IBOutlet NSTextField *diskAProperties; +@property (assign) IBOutlet NSTextField *diskBProperties; +@property (assign) IBOutlet NSMatrix *diskAProtection; +@property (assign) IBOutlet NSMatrix *diskBProtection; +@property (assign) IBOutlet NSButton *chooseDiskA; +@property (assign) IBOutlet NSButton *chooseDiskB; + +@property (nonatomic, copy) NSString *diskAPath; +@property (nonatomic, copy) NSString *diskBPath; + +@end + +@implementation EmulatorDiskController + +@synthesize diskAPath = _diskAPath; +@synthesize diskBPath = _diskBPath; + +- (void)awakeFromNib +{ + [self.diskInA setStringValue:NO_DISK_INSERTED]; + [self.diskAProperties setStringValue:@""]; + [self.diskInB setStringValue:NO_DISK_INSERTED]; + [self.diskBProperties setStringValue:@""]; + [self.chooseDiskA setKeyEquivalent:@"\r"]; + [self.chooseDiskA setBezelStyle:NSRoundedBezelStyle]; +} + +- (void)dealloc +{ +#warning TODO FIXME ... probably should exit emulator if this gets invoked ... + self.diskAPath = nil; + self.diskBPath = nil; + [super dealloc]; +} + +- (IBAction)diskAProtectionChanged:(id)sender +{ + if ([[[self diskInA] stringValue] isEqualToString:NO_DISK_INSERTED]) + { + return; + } + // HACK NOTE : dispatch so that state of outlet property is set properly + dispatch_async(dispatch_get_main_queue(), ^{ + NSButtonCell *readOnlyChoice = [[[self diskAProtection] cells] firstObject]; + NSString *path = [self diskAPath]; + [self _insertDisketteInDrive:0 path:path type:[self _extensionForPath:path] readOnly:([readOnlyChoice state] == NSOnState)]; + }); +} + +- (IBAction)diskBProtectionChanged:(id)sender +{ + if ([[[self diskInB] stringValue] isEqualToString:NO_DISK_INSERTED]) + { + return; + } + // HACK NOTE : dispatch so that state of outlet property is set properly + dispatch_async(dispatch_get_main_queue(), ^{ + NSButtonCell *readOnlyChoice = [[[self diskBProtection] cells] firstObject]; + NSString *path = [self diskBPath]; + [self _insertDisketteInDrive:1 path:path type:[self _extensionForPath:path] readOnly:([readOnlyChoice state] == NSOnState)]; + }); +} + +- (BOOL)_insertDisketteInDrive:(int)drive path:(NSString *)path type:(NSString *)type readOnly:(BOOL)readOnly +{ + c_eject_6(drive); + + const char *errMsg = c_new_diskette_6(drive, [path UTF8String], readOnly); + if (errMsg) + { + NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]]; + [alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil]; + if (!drive) + { + [[self diskInA] setStringValue:NO_DISK_INSERTED]; + [[self diskAProperties] setStringValue:@""]; + } + else + { + [[self diskInB] setStringValue:NO_DISK_INSERTED]; + [[self diskBProperties] setStringValue:@""]; + } + + return NO; + } + + NSString *imageName = [[path pathComponents] lastObject]; + + if (!drive) + { + self.diskAPath = path; + [[self diskInA] setStringValue:imageName]; + } + else + { + self.diskBPath = path; + [[self diskInB] setStringValue:imageName]; + } + + if ([type isEqualToString:@"dsk"] || [type isEqualToString:@"do"] || [type isEqualToString:@"po"]) + { + if (!drive) + { + [[self diskAProperties] setStringValue:DSK_PROPERTIES]; + } + else + { + [[self diskBProperties] setStringValue:DSK_PROPERTIES]; + } + } + else + { + if (!drive) + { + [[self diskAProperties] setStringValue:NIB_PROPERTIES]; + } + else + { + [[self diskBProperties] setStringValue:NIB_PROPERTIES]; + } + } + + return YES; +} + +- (NSString *)_extensionForPath:(NSString *)path +{ + NSString *extension0 = [path pathExtension]; + NSString *extension1 = [[path stringByDeletingPathExtension] pathExtension]; + if ([extension0 isEqualToString:GZ_EXTENSION]) + { + extension0 = extension1; + } + return extension0; +} + +- (void)_chooseDisk:(int)drive readOnly:(BOOL)readOnly +{ + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + [openPanel setTitle:@"Choose a disk image"]; + NSURL *url = [[NSUserDefaults standardUserDefaults] URLForKey:kApple2DisksURL]; + if (!url) + { + url = [[NSBundle mainBundle] URLForResource:@"blank" withExtension:@"dsk.gz"]; + url = [url URLByDeletingLastPathComponent]; + } + [[NSUserDefaults standardUserDefaults] setURL:url forKey:kApple2DisksURL]; + [openPanel setDirectoryURL:url]; + [openPanel setShowsResizeIndicator:YES]; + [openPanel setShowsHiddenFiles:NO]; + [openPanel setCanChooseFiles:YES]; + [openPanel setCanChooseDirectories:NO]; + [openPanel setCanCreateDirectories:NO]; + [openPanel setAllowsMultipleSelection:NO]; + + // NOTE : Doesn't appear to be a way to specify ".dsk.gz" ... so we may inadvertently allow files of ".foo.gz" here + NSSet *fileTypes = [NSSet setWithObjects:@"dsk", @"nib", @"do", @"po", GZ_EXTENSION, nil]; + [openPanel setAllowedFileTypes:[fileTypes allObjects]]; + [openPanel beginSheetModalForWindow:[self disksWindow] completionHandler:^(NSInteger result) { + if (result == NSOKButton) + { + NSURL *selection = [[openPanel URLs] firstObject]; + NSString *path = [[selection path] stringByResolvingSymlinksInPath]; + NSString *extension = [self _extensionForPath:path]; + + if (![fileTypes containsObject:extension]) + { + NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:@"Disk image must have file extension of .dsk, .do, .po, or .nib only" code:-1 userInfo:nil]]; + [alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil]; + return; + } + + [self _insertDisketteInDrive:drive path:path type:extension readOnly:readOnly]; + } + }]; +} + +- (IBAction)chooseDriveA:(id)sender +{ + NSButtonCell *readOnlyChoice = [[[self diskAProtection] cells] firstObject]; + [self _chooseDisk:0 readOnly:([readOnlyChoice state] == NSOnState)]; +} + +- (IBAction)chooseDriveB:(id)sender +{ + NSButtonCell *readOnlyChoice = [[[self diskBProtection] cells] firstObject]; + [self _chooseDisk:1 readOnly:([readOnlyChoice state] == NSOnState)]; +} + +@end diff --git a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m b/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m index 4d7582bb..f10f7540 100644 --- a/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m +++ b/Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m @@ -12,12 +12,6 @@ #import "EmulatorFullscreenWindow.h" #import "common.h" -#define READONLY_CHOICE_INDEX 0 -#define NO_DISK_INSERTED @"(No Disk Inserted)" -#define DSK_PROPERTIES @".dsk 143360 bytes" -#define NIB_PROPERTIES @".nib 232960 bytes" -#define GZ_EXTENSION @"gz" - #define CAPS_LOCK 0x39 #define SHIFT_LT 0x38 #define SHIFT_RT 0x3c @@ -28,23 +22,12 @@ @interface EmulatorWindowController () -@property (nonatomic, assign) IBOutlet EmulatorGLView *view; +@property (assign) IBOutlet EmulatorGLView *view; +@property (assign) IBOutlet NSWindow *disksWindow; + @property (nonatomic, retain) EmulatorFullscreenWindow *fullscreenWindow; @property (nonatomic, retain) NSWindow *standardWindow; -@property (assign) IBOutlet NSWindow *disksWindow; -@property (assign) IBOutlet NSTextField *diskInA; -@property (assign) IBOutlet NSTextField *diskInB; -@property (assign) IBOutlet NSTextField *diskAProperties; -@property (assign) IBOutlet NSTextField *diskBProperties; -@property (assign) IBOutlet NSMatrix *diskAProtection; -@property (assign) IBOutlet NSMatrix *diskBProtection; -@property (assign) IBOutlet NSButton *chooseDiskA; -@property (assign) IBOutlet NSButton *chooseDiskB; - -@property (nonatomic, copy) NSString *diskAPath; -@property (nonatomic, copy) NSString *diskBPath; - @end @@ -53,8 +36,6 @@ @synthesize view = _view; @synthesize fullscreenWindow = _fullscreenWindow; @synthesize standardWindow = _standardWindow; -@synthesize diskAPath = _diskAPath; -@synthesize diskBPath = _diskBPath; - (id)initWithWindow:(NSWindow *)window { @@ -72,22 +53,9 @@ - (void)dealloc { #warning TODO FIXME ... probably should exit emulator if this gets invoked ... - self.diskAPath = nil; - self.diskBPath = nil; [super dealloc]; } -- (void)awakeFromNib -{ - [self.diskInA setStringValue:NO_DISK_INSERTED]; - [self.diskAProperties setStringValue:@""]; - [self.diskInB setStringValue:NO_DISK_INSERTED]; - [self.diskBProperties setStringValue:@""]; - - [self.chooseDiskA setKeyEquivalent:@"\r"]; - [self.chooseDiskA setBezelStyle:NSRoundedBezelStyle]; -} - - (IBAction)reboot:(id)sender { [[self disksWindow] close]; @@ -106,156 +74,6 @@ } } -- (IBAction)diskAProtectionChanged:(id)sender -{ - if ([[[self diskInA] stringValue] isEqualToString:NO_DISK_INSERTED]) - { - return; - } - // HACK NOTE : dispatch so that state of outlet property is set properly - dispatch_async(dispatch_get_main_queue(), ^{ - NSButtonCell *readOnlyChoice = [[[self diskAProtection] cells] firstObject]; - NSString *path = [self diskAPath]; - [self _insertDisketteInDrive:0 path:path type:[self _extensionForPath:path] readOnly:([readOnlyChoice state] == NSOnState)]; - }); -} - -- (IBAction)diskBProtectionChanged:(id)sender -{ - if ([[[self diskInB] stringValue] isEqualToString:NO_DISK_INSERTED]) - { - return; - } - // HACK NOTE : dispatch so that state of outlet property is set properly - dispatch_async(dispatch_get_main_queue(), ^{ - NSButtonCell *readOnlyChoice = [[[self diskBProtection] cells] firstObject]; - NSString *path = [self diskBPath]; - [self _insertDisketteInDrive:1 path:path type:[self _extensionForPath:path] readOnly:([readOnlyChoice state] == NSOnState)]; - }); -} - -- (BOOL)_insertDisketteInDrive:(int)drive path:(NSString *)path type:(NSString *)type readOnly:(BOOL)readOnly -{ - c_eject_6(drive); - - const char *errMsg = c_new_diskette_6(drive, [path UTF8String], readOnly); - if (errMsg) - { - NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]]; - [alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil]; - if (!drive) - { - [[self diskInA] setStringValue:NO_DISK_INSERTED]; - [[self diskAProperties] setStringValue:@""]; - } - else - { - [[self diskInB] setStringValue:NO_DISK_INSERTED]; - [[self diskBProperties] setStringValue:@""]; - } - - return NO; - } - - NSString *imageName = [[path pathComponents] lastObject]; - - if (!drive) - { - self.diskAPath = path; - [[self diskInA] setStringValue:imageName]; - } - else - { - self.diskBPath = path; - [[self diskInB] setStringValue:imageName]; - } - - if ([type isEqualToString:@"dsk"] || [type isEqualToString:@"do"] || [type isEqualToString:@"po"]) - { - if (!drive) - { - [[self diskAProperties] setStringValue:DSK_PROPERTIES]; - } - else - { - [[self diskBProperties] setStringValue:DSK_PROPERTIES]; - } - } - else - { - if (!drive) - { - [[self diskAProperties] setStringValue:NIB_PROPERTIES]; - } - else - { - [[self diskBProperties] setStringValue:NIB_PROPERTIES]; - } - } - - return YES; -} - -- (NSString *)_extensionForPath:(NSString *)path -{ - NSString *extension0 = [path pathExtension]; - NSString *extension1 = [[path stringByDeletingPathExtension] pathExtension]; - if ([extension0 isEqualToString:GZ_EXTENSION]) - { - extension0 = extension1; - } - return extension0; -} - -- (void)_chooseDisk:(int)drive readOnly:(BOOL)readOnly -{ - NSOpenPanel *openPanel = [NSOpenPanel openPanel]; - [openPanel setTitle:@"Choose a disk image"]; -#warning FIXME TODO : installation default should be what it bundled, but should not always choose this ... - NSURL *url = [[NSBundle mainBundle] URLForResource:@"blank" withExtension:@"dsk.gz"]; - url = [url URLByDeletingLastPathComponent]; - [openPanel setDirectoryURL:url]; - [openPanel setShowsResizeIndicator:YES]; - [openPanel setShowsHiddenFiles:NO]; - [openPanel setCanChooseFiles:YES]; - [openPanel setCanChooseDirectories:NO]; - [openPanel setCanCreateDirectories:NO]; - [openPanel setAllowsMultipleSelection:NO]; - - // NOTE : Doesn't appear to be a way to specify ".dsk.gz" ... so we may inadvertently allow files of ".foo.gz" here - NSSet *fileTypes = [NSSet setWithObjects:@"dsk", @"nib", @"do", @"po", GZ_EXTENSION, nil]; - [openPanel setAllowedFileTypes:[fileTypes allObjects]]; - [openPanel beginSheetModalForWindow:[self disksWindow] completionHandler:^(NSInteger result) { - if (result == NSOKButton) - { - NSURL *selection = [[openPanel URLs] firstObject]; - NSString *path = [[selection path] stringByResolvingSymlinksInPath]; - NSString *extension = [self _extensionForPath:path]; - - if (![fileTypes containsObject:extension]) - { - NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:@"Disk image must have file extension of .dsk, .do, .po, or .nib only" code:-1 userInfo:nil]]; - [alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil]; - return; - } - - [self _insertDisketteInDrive:drive path:path type:extension readOnly:readOnly]; - } - }]; -} - -- (IBAction)chooseDriveA:(id)sender -{ - NSButtonCell *readOnlyChoice = [[[self diskAProtection] cells] firstObject]; - [self _chooseDisk:0 readOnly:([readOnlyChoice state] == NSOnState)]; -} - -- (IBAction)chooseDriveB:(id)sender -{ - NSButtonCell *readOnlyChoice = [[[self diskBProtection] cells] firstObject]; - [self _chooseDisk:1 readOnly:([readOnlyChoice state] == NSOnState)]; -} - - (void)goFullscreen { // If app is already fullscreen...