2015-10-22 05:13:26 +00:00
/ *
* Apple // emulator for * ix
*
* This software package is subject to the GNU General Public License
* version 3 or later ( your choice ) as published by the Free Software
* Foundation .
*
* Copyright 2014 , 2015 Aaron Culliney
*
* /
2014-10-18 19:02:02 +00:00
# import "EmulatorDiskController.h"
2014-10-19 19:56:30 +00:00
# import "EmulatorPrefsController.h"
# import "common.h"
2014-10-18 19:02:02 +00:00
# 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 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 ;
2014-10-25 20:52:46 +00:00
@ property ( assign ) IBOutlet NSButton * startupLoadDiskA ;
@ property ( assign ) IBOutlet NSButton * startupLoadDiskB ;
2014-10-18 19:02:02 +00:00
@ end
@ implementation EmulatorDiskController
- ( void ) awakeFromNib
{
2014-11-29 21:31:21 +00:00
# if CRASH_APP _ON _LOAD _BECAUSE _YAY _GJ _APPLE
glGetError ( ) ;
# endif
2014-10-18 19:02:02 +00:00
[ 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 ] ;
2014-10-25 20:52:46 +00:00
[ self . startupLoadDiskA setState : NSOffState ] ;
[ self . startupLoadDiskB setState : NSOffState ] ;
2014-10-19 19:56:30 +00:00
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
NSString * startupDiskA = [ defaults stringForKey : kApple2PrefStartupDiskA ] ;
2014-10-25 20:52:46 +00:00
BOOL readOnlyA = [ defaults boolForKey : kApple2PrefStartupDiskAProtected ] ;
2014-10-19 19:56:30 +00:00
if ( startupDiskA )
{
2015-11-14 07:13:21 +00:00
const char * err = disk6_insert ( 0 , [ [ NSString stringWithFormat : @ "%@.gz" , startupDiskA ] UTF8String ] , readOnlyA ) ;
2014-10-19 19:56:30 +00:00
if ( ! err )
{
[ self . diskInA setStringValue : [ [ startupDiskA pathComponents ] lastObject ] ] ;
2014-10-25 20:52:46 +00:00
[ self . startupLoadDiskA setState : NSOnState ] ;
[ self . diskAProtection setState : ( readOnlyA ? NSOnState : NSOffState ) atRow : 0 column : 0 ] ;
[ self . diskAProtection setState : ( ! readOnlyA ? NSOnState : NSOffState ) atRow : 0 column : 1 ] ;
2014-10-19 19:56:30 +00:00
}
}
NSString * startupDiskB = [ defaults stringForKey : kApple2PrefStartupDiskB ] ;
2014-10-25 20:52:46 +00:00
BOOL readOnlyB = [ defaults boolForKey : kApple2PrefStartupDiskBProtected ] ;
2014-10-19 19:56:30 +00:00
if ( startupDiskB )
{
2015-11-14 07:13:21 +00:00
const char * err = disk6_insert ( 1 , [ [ NSString stringWithFormat : @ "%@.gz" , startupDiskB ] UTF8String ] , readOnlyB ) ;
2014-10-19 19:56:30 +00:00
if ( ! err )
{
[ self . diskInB setStringValue : [ [ startupDiskB pathComponents ] lastObject ] ] ;
2014-10-25 20:52:46 +00:00
[ self . startupLoadDiskB setState : NSOnState ] ;
[ self . diskBProtection setState : ( readOnlyB ? NSOnState : NSOffState ) atRow : 0 column : 0 ] ;
[ self . diskBProtection setState : ( ! readOnlyB ? NSOnState : NSOffState ) atRow : 0 column : 1 ] ;
2014-10-19 19:56:30 +00:00
}
}
2014-10-18 19:02:02 +00:00
}
2014-10-25 20:52:46 +00:00
- ( void ) _savePrefs
2014-10-18 19:02:02 +00:00
{
2014-10-25 20:52:46 +00:00
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
[ defaults removeObjectForKey : kApple2PrefStartupDiskA ] ;
[ defaults removeObjectForKey : kApple2PrefStartupDiskB ] ;
[ defaults removeObjectForKey : kApple2PrefStartupDiskAProtected ] ;
[ defaults removeObjectForKey : kApple2PrefStartupDiskBProtected ] ;
if ( [ self . startupLoadDiskA state ] = = NSOnState )
{
2015-11-14 07:13:21 +00:00
if ( disk6 . disk [ 0 ] . fd >= 0 )
2014-10-25 20:52:46 +00:00
{
NSString * diskA = [ NSString stringWithUTF8String : disk6 . disk [ 0 ] . file_name ] ;
[ defaults setObject : diskA forKey : kApple2PrefStartupDiskA ] ;
2015-11-14 07:13:21 +00:00
NSButtonCell * readOnlyChoice = ( NSButtonCell * ) [ [ [ self diskAProtection ] cells ] firstObject ] ;
2014-10-25 20:52:46 +00:00
[ defaults setBool : ( [ readOnlyChoice state ] = = NSOnState ) forKey : kApple2PrefStartupDiskAProtected ] ;
}
}
if ( [ self . startupLoadDiskB state ] = = NSOnState )
{
2015-11-14 07:13:21 +00:00
if ( disk6 . disk [ 1 ] . fd >= 0 )
2014-10-25 20:52:46 +00:00
{
NSString * diskB = [ NSString stringWithUTF8String : disk6 . disk [ 1 ] . file_name ] ;
[ defaults setObject : diskB forKey : kApple2PrefStartupDiskB ] ;
2015-11-14 07:13:21 +00:00
NSButtonCell * readOnlyChoice = ( NSButtonCell * ) [ [ [ self diskBProtection ] cells ] firstObject ] ;
2014-10-25 20:52:46 +00:00
[ defaults setBool : ( [ readOnlyChoice state ] = = NSOnState ) forKey : kApple2PrefStartupDiskBProtected ] ;
}
}
2014-10-18 19:02:02 +00:00
}
2014-10-25 20:52:46 +00:00
- ( void ) _protectionChangedForDrive : ( int ) drive
2014-10-18 19:02:02 +00:00
{
2015-11-14 07:13:21 +00:00
if ( disk6 . disk [ drive ] . fd < 0 )
2014-10-18 19:02:02 +00:00
{
return ;
}
// HACK NOTE : dispatch so that state of outlet property is set properly
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2015-11-14 07:13:21 +00:00
NSButtonCell * readOnlyChoice = ( NSButtonCell * ) [ [ ( drive = = 0 ? [ self diskAProtection ] : [ self diskBProtection ] ) cells ] firstObject ] ;
2014-10-25 20:52:46 +00:00
NSString * path = [ NSString stringWithUTF8String : disk6 . disk [ drive ] . file_name ] ;
[ self _insertDisketteInDrive : drive path : path type : [ EmulatorDiskController extensionForPath : path ] readOnly : ( [ readOnlyChoice state ] = = NSOnState ) ] ;
[ self _savePrefs ] ;
2014-10-18 19:02:02 +00:00
} ) ;
}
2014-10-25 20:52:46 +00:00
- ( IBAction ) diskAProtectionChanged : ( id ) sender
{
[ self _protectionChangedForDrive : 0 ] ;
}
2014-10-18 19:02:02 +00:00
- ( IBAction ) diskBProtectionChanged : ( id ) sender
{
2014-10-25 20:52:46 +00:00
[ self _protectionChangedForDrive : 1 ] ;
2014-10-18 19:02:02 +00:00
}
- ( BOOL ) _insertDisketteInDrive : ( int ) drive path : ( NSString * ) path type : ( NSString * ) type readOnly : ( BOOL ) readOnly
{
2015-11-14 07:13:21 +00:00
disk6_eject ( drive ) ;
2014-10-18 19:02:02 +00:00
2015-11-14 07:13:21 +00:00
const char * errMsg = disk6_insert ( drive , [ path UTF8String ] , readOnly ) ;
2014-10-18 19:02:02 +00:00
if ( errMsg )
{
2014-10-25 20:52:46 +00:00
path = [ NSString stringWithFormat : @ "%@.gz" , path ] ;
2015-11-14 07:13:21 +00:00
errMsg = disk6_insert ( drive , [ path UTF8String ] , readOnly ) ;
2014-10-25 20:52:46 +00:00
if ( errMsg )
2014-10-18 19:02:02 +00:00
{
2014-10-25 20:52:46 +00:00
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 ;
2014-10-18 19:02:02 +00:00
}
}
2014-10-25 20:52:46 +00:00
path = [ NSString stringWithUTF8String : disk6 . disk [ drive ] . file_name ] ;
2014-10-18 19:02:02 +00:00
NSString * imageName = [ [ path pathComponents ] lastObject ] ;
2014-10-25 20:52:46 +00:00
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
2014-10-18 19:02:02 +00:00
2014-10-25 20:52:46 +00:00
if ( drive = = 0 )
2014-10-18 19:02:02 +00:00
{
[ [ self diskInA ] setStringValue : imageName ] ;
2014-10-25 20:52:46 +00:00
if ( [ [ defaults stringForKey : kApple2PrefStartupDiskA ] isEqualToString : path ] )
{
[ self . startupLoadDiskA setState : NSOnState ] ;
// [ self . diskAProtection setState : ( readOnly ? NSOnState : NSOffState ) atRow : 0 column : 0 ] ;
// [ self . diskAProtection setState : ( ! readOnly ? NSOnState : NSOffState ) atRow : 0 column : 1 ] ;
}
2014-10-18 19:02:02 +00:00
}
else
{
[ [ self diskInB ] setStringValue : imageName ] ;
2014-10-25 20:52:46 +00:00
if ( [ [ defaults stringForKey : kApple2PrefStartupDiskB ] isEqualToString : path ] )
{
[ self . startupLoadDiskB setState : NSOnState ] ;
// [ self . diskBProtection setState : ( readOnly ? NSOnState : NSOffState ) atRow : 0 column : 0 ] ;
// [ self . diskBProtection setState : ( ! readOnly ? NSOnState : NSOffState ) atRow : 0 column : 1 ] ;
}
2014-10-18 19:02:02 +00:00
}
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 ;
}
2014-10-19 19:56:30 +00:00
+ ( NSSet * ) emulatorFileTypes
{
static NSSet * set = nil ;
static dispatch_once _t onceToken = 0 L ;
dispatch_once ( & onceToken , ^ {
2014-10-25 20:52:46 +00:00
set = [ [ NSSet alloc ] initWithObjects : @ "dsk" , @ "nib" , @ "do" , @ "po" , @ "gz" , nil ] ;
2014-10-19 19:56:30 +00:00
} ) ;
return [ [ set retain ] autorelease ] ;
}
+ ( NSString * ) extensionForPath : ( NSString * ) path
2014-10-18 19:02:02 +00:00
{
NSString * extension0 = [ path pathExtension ] ;
NSString * extension1 = [ [ path stringByDeletingPathExtension ] pathExtension ] ;
2014-10-25 20:52:46 +00:00
if ( [ extension0 isEqualToString : @ "gz" ] )
2014-10-18 19:02:02 +00:00
{
extension0 = extension1 ;
}
return extension0 ;
}
2014-10-19 19:56:30 +00:00
+ ( void ) chooseDiskForWindow : ( NSWindow * ) window completionHandler : ( DiskCompletionHandler ) handler
2014-10-18 19:02:02 +00:00
{
2014-10-19 19:56:30 +00:00
NSOpenPanel * openPanel = [ [ NSOpenPanel openPanel ] retain ] ;
2014-10-18 19:02:02 +00:00
[ openPanel setTitle : @ "Choose a disk image" ] ;
NSURL * url = [ [ NSUserDefaults standardUserDefaults ] URLForKey : kApple2DisksURL ] ;
if ( ! url )
{
2014-12-07 01:07:58 +00:00
url = [ [ NSBundle mainBundle ] URLForResource : @ "images" withExtension : nil ] ;
2014-10-18 19:02:02 +00:00
}
[ 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
2014-10-19 19:56:30 +00:00
NSSet * fileTypes = [ EmulatorDiskController emulatorFileTypes ] ;
2014-10-18 19:02:02 +00:00
[ openPanel setAllowedFileTypes : [ fileTypes allObjects ] ] ;
2014-10-19 19:56:30 +00:00
handler = Block_copy ( handler ) ;
[ openPanel beginSheetModalForWindow : window completionHandler : ^ ( NSInteger result ) {
handler ( openPanel , result ) ;
Block_release ( handler ) ;
[ openPanel autorelease ] ;
} ] ;
}
- ( void ) _chooseDisk : ( int ) drive readOnly : ( BOOL ) readOnly
{
[ EmulatorDiskController chooseDiskForWindow : [ self disksWindow ] completionHandler : ^ ( NSOpenPanel * openPanel , NSInteger result ) {
2014-10-18 19:02:02 +00:00
if ( result = = NSOKButton )
{
NSURL * selection = [ [ openPanel URLs ] firstObject ] ;
NSString * path = [ [ selection path ] stringByResolvingSymlinksInPath ] ;
2014-10-19 19:56:30 +00:00
NSString * extension = [ EmulatorDiskController extensionForPath : path ] ;
NSSet * fileTypes = [ EmulatorDiskController emulatorFileTypes ] ;
NSString * directory = [ path stringByDeletingLastPathComponent ] ;
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
[ defaults setURL : [ NSURL URLWithString : directory ] forKey : kApple2DisksURL ] ;
2014-10-18 19:02:02 +00:00
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 ;
}
2014-10-19 19:56:30 +00:00
2014-10-25 20:52:46 +00:00
[ ( drive = = 0 ) ? self . startupLoadDiskA : self . startupLoadDiskB setState : NSOffState ] ;
2014-10-18 19:02:02 +00:00
[ self _insertDisketteInDrive : drive path : path type : extension readOnly : readOnly ] ;
}
} ] ;
}
- ( IBAction ) chooseDriveA : ( id ) sender
{
2015-11-14 07:13:21 +00:00
NSButtonCell * readOnlyChoice = ( NSButtonCell * ) [ [ [ self diskAProtection ] cells ] firstObject ] ;
2014-10-18 19:02:02 +00:00
[ self _chooseDisk : 0 readOnly : ( [ readOnlyChoice state ] = = NSOnState ) ] ;
}
- ( IBAction ) chooseDriveB : ( id ) sender
{
2015-11-14 07:13:21 +00:00
NSButtonCell * readOnlyChoice = ( NSButtonCell * ) [ [ [ self diskBProtection ] cells ] firstObject ] ;
2014-10-18 19:02:02 +00:00
[ self _chooseDisk : 1 readOnly : ( [ readOnlyChoice state ] = = NSOnState ) ] ;
}
2014-10-25 20:52:46 +00:00
- ( IBAction ) startupDiskAChoiceChanged : ( id ) sender
2014-10-19 19:56:30 +00:00
{
2014-10-25 20:52:46 +00:00
[ self _savePrefs ] ;
}
- ( IBAction ) startupDiskBChoiceChanged : ( id ) sender
{
[ self _savePrefs ] ;
}
- ( IBAction ) disksOK : ( id ) sender
{
[ [ self disksWindow ] close ] ;
2014-10-19 19:56:30 +00:00
}
2014-10-18 19:02:02 +00:00
@ end