diff --git a/Mini vMac/AppDelegate.h b/Mini vMac/AppDelegate.h index 4c1cfe5..95b3c4b 100644 --- a/Mini vMac/AppDelegate.h +++ b/Mini vMac/AppDelegate.h @@ -21,9 +21,11 @@ extern NSString *DocumentsChangedNotification; @property (nonatomic, readonly) NSArray *emulatorBundles; @property (nonatomic, readonly) NSString *emulatorBundlesPath; @property (readonly, nonatomic, getter = isSandboxed) BOOL sandboxed; +@property (readonly, nonatomic) id sharedEmulator; + (instancetype)sharedInstance; + (id)sharedEmulator; +- (void)reloadEmulator; - (void)showAlertWithTitle:(NSString *)title message:(NSString *)message; - (IBAction)showInsertDisk:(id)sender; diff --git a/Mini vMac/AppDelegate.m b/Mini vMac/AppDelegate.m index 087c522..08334c2 100644 --- a/Mini vMac/AppDelegate.m +++ b/Mini vMac/AppDelegate.m @@ -108,6 +108,24 @@ NSString *DocumentsChangedNotification = @"documentsChanged"; return sharedEmulator != nil; } +- (void)reloadEmulator { + NSBundle *bundle = sharedEmulator.bundle; + [self willChangeValueForKey:@"sharedEmulator"]; + id oldEmulator = sharedEmulator; + sharedEmulator = nil; + [oldEmulator shutdown]; + [bundle unload]; + if (![self loadEmulator:[[NSUserDefaults standardUserDefaults] stringForKey:@"machine"]]) { + [self loadEmulator:@"MacPlus4M"]; + } + [self didChangeValueForKey:@"sharedEmulator"]; + [sharedEmulator performSelector:@selector(run) withObject:nil afterDelay:0.1]; +} + +- (id)sharedEmulator { + return sharedEmulator; +} + - (void)applicationDidEnterBackground:(UIApplication *)application { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize]; diff --git a/Mini vMac/EmulatorProtocol.h b/Mini vMac/EmulatorProtocol.h index eb3c01d..057edd0 100644 --- a/Mini vMac/EmulatorProtocol.h +++ b/Mini vMac/EmulatorProtocol.h @@ -38,11 +38,10 @@ typedef enum : NSInteger { @property (nonatomic, readonly) BOOL anyDiskInserted; @property (nonatomic, readonly) NSString *currentApplication; -+ (instancetype)sharedEmulator; - - (void)run; - (void)reset; - (void)interrupt; +- (void)shutdown; - (void)keyDown:(int)scancode; - (void)keyUp:(int)scancode; diff --git a/Mini vMac/MYOSGLUE.m b/Mini vMac/MYOSGLUE.m index 9485003..08f4e45 100644 --- a/Mini vMac/MYOSGLUE.m +++ b/Mini vMac/MYOSGLUE.m @@ -36,14 +36,14 @@ EXPORTVAR(ui3p, RAM) EXPORTVAR(ui3p, VidROM) EXPORTVAR(ui3p, VidMem) -@interface Emulator : NSObject +@interface MNVMBundleClassName : NSObject - (void)makeNewDisk:(NSString*)name size:(NSInteger)size; - (void)updateScreen:(CGImageRef)screenImage; @end -static Emulator *sharedEmulator = nil; +static __weak MNVMBundleClassName *sharedEmulator = nil; #pragma mark - some simple utilities @@ -405,7 +405,7 @@ LOCALFUNC tMacErr vSonyEject0(tDrive Drive_No, blnr deleteit) { } #endif - [[NSNotificationCenter defaultCenter] postNotificationName:[Emulator sharedEmulator].ejectDiskNotification object:[Emulator sharedEmulator] userInfo:userInfo]; + [[NSNotificationCenter defaultCenter] postNotificationName:sharedEmulator.ejectDiskNotification object:sharedEmulator userInfo:userInfo]; return mnvm_noErr; } @@ -455,7 +455,7 @@ LOCALFUNC blnr Sony_Insert0(FILE *refnum, blnr locked, NSString *filePath) { } else { NSDictionary *userInfo = @{@"path": filePath, @"drive": @(Drive_No)}; - [[NSNotificationCenter defaultCenter] postNotificationName:[Emulator sharedEmulator].insertDiskNotification object:[Emulator sharedEmulator] userInfo:userInfo]; + [[NSNotificationCenter defaultCenter] postNotificationName:sharedEmulator.insertDiskNotification object:sharedEmulator userInfo:userInfo]; /* printf("Sony_Insert0 %d\n", (int)Drive_No); */ @@ -787,7 +787,7 @@ LOCALPROC HaveChangedScreenBuff(ui4r top, ui4r left, ui4r bottom, ui4r right) { if (colorSpace) { CGImageRef screenImage = CGImageCreate(vMacScreenWidth, vMacScreenHeight, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, options, screenDataProvider, NULL, false, kCGRenderingIntentDefault); - [[Emulator sharedEmulator] updateScreen:screenImage]; + [sharedEmulator updateScreen:screenImage]; CGImageRelease(screenImage); } } @@ -1644,31 +1644,24 @@ GLOBALPROC WaitForNextTick(void) { #pragma mark - Objective-C Interface -static dispatch_once_t onceToken; - -@implementation Emulator +@implementation MNVMBundleClassName { __block __weak UITextField *nameTextField; } @synthesize dataPath; -+ (instancetype)sharedEmulator { - dispatch_once(&onceToken, ^{ - sharedEmulator = [self new]; - }); - return sharedEmulator; -} - - (instancetype)init { if ((self = [super init])) { - dispatch_once(&onceToken, ^{ - sharedEmulator = self; - }); + sharedEmulator = self; } return self; } +- (void)shutdown { + RequestMacOff = trueblnr; +} + - (void)run { ZapOSGLUVars(); if (InitOSGLU()) { diff --git a/Mini vMac/Mac128K/CNFUDALL.h b/Mini vMac/Mac128K/CNFUDALL.h index 27e8762..a951850 100644 --- a/Mini vMac/Mac128K/CNFUDALL.h +++ b/Mini vMac/Mac128K/CNFUDALL.h @@ -39,6 +39,8 @@ #define AutoLocation 1 #define AutoTimeZone 1 +#define MNVMBundleClassName Mac128KEmulator + #ifdef PLIST_PREPROCESSOR #define MNVMBundleDisplayName Mac 128K #define MNVMBundleGetInfoString 128K, 512×342 diff --git a/Mini vMac/MacII-640x480/CNFUDALL.h b/Mini vMac/MacII-640x480/CNFUDALL.h index f7b35a5..a652bd0 100644 --- a/Mini vMac/MacII-640x480/CNFUDALL.h +++ b/Mini vMac/MacII-640x480/CNFUDALL.h @@ -39,6 +39,8 @@ #define AutoLocation 1 #define AutoTimeZone 1 +#define MNVMBundleClassName MacIIEmulator640x480 + #ifdef PLIST_PREPROCESSOR #define MNVMBundleDisplayName Mac II #define MNVMBundleGetInfoString 8M, 640×480 diff --git a/Mini vMac/MacII/CNFUDALL.h b/Mini vMac/MacII/CNFUDALL.h index 9286dbf..659b0a7 100644 --- a/Mini vMac/MacII/CNFUDALL.h +++ b/Mini vMac/MacII/CNFUDALL.h @@ -39,6 +39,8 @@ #define AutoLocation 1 #define AutoTimeZone 1 +#define MNVMBundleClassName MacIIEmulator + #ifdef PLIST_PREPROCESSOR #define MNVMBundleDisplayName Mac II #define MNVMBundleGetInfoString 8M, 1024×768 diff --git a/Mini vMac/MacPlus4M/CNFUDALL.h b/Mini vMac/MacPlus4M/CNFUDALL.h index 8853b63..63a0147 100644 --- a/Mini vMac/MacPlus4M/CNFUDALL.h +++ b/Mini vMac/MacPlus4M/CNFUDALL.h @@ -40,6 +40,8 @@ #define AutoLocation 1 #define AutoTimeZone 1 +#define MNVMBundleClassName MacPlus4MEmulator + #ifdef PLIST_PREPROCESSOR #define MNVMBundleDisplayName Mac Plus #define MNVMBundleGetInfoString 4M, 512×342 diff --git a/Mini vMac/PlugIn-Info.plist b/Mini vMac/PlugIn-Info.plist index 059fc63..e47a059 100644 --- a/Mini vMac/PlugIn-Info.plist +++ b/Mini vMac/PlugIn-Info.plist @@ -25,6 +25,6 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass - Emulator + MNVMBundleClassName diff --git a/Mini vMac/ScreenView.m b/Mini vMac/ScreenView.m index 778db24..7eda81b 100644 --- a/Mini vMac/ScreenView.m +++ b/Mini vMac/ScreenView.m @@ -26,13 +26,9 @@ static ScreenView *sharedScreenView = nil; NSString *screenFilter = [[NSUserDefaults standardUserDefaults] stringForKey:@"screenFilter"]; videoLayer.magnificationFilter = screenFilter; videoLayer.minificationFilter = screenFilter; - [AppDelegate sharedEmulator].screenLayer = videoLayer; - if ([AppDelegate sharedEmulator]) { - screenSize = [AppDelegate sharedEmulator].screenSize; - } else { - screenSize = CGSizeMake(1, 1); - } + [self updateVideoLayer]; [self.layer addSublayer:videoLayer]; + [[AppDelegate sharedInstance] addObserver:self forKeyPath:@"sharedEmulator" options:NSKeyValueObservingOptionNew context:NULL]; [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"screenFilter" options:NSKeyValueObservingOptionNew context:NULL]; } @@ -48,6 +44,15 @@ static ScreenView *sharedScreenView = nil; return screenSize; } +- (void)updateVideoLayer { + if ([AppDelegate sharedEmulator]) { + [AppDelegate sharedEmulator].screenLayer = videoLayer; + screenSize = [AppDelegate sharedEmulator].screenSize; + } else { + screenSize = CGSizeMake(1, 1); + } +} + - (void)layoutSubviews { [super layoutSubviews]; CGRect viewBounds = self.bounds; @@ -73,10 +78,14 @@ static ScreenView *sharedScreenView = nil; videoLayer.magnificationFilter = value; videoLayer.minificationFilter = value; } + } else if (object == [AppDelegate sharedInstance] && [keyPath isEqualToString:@"sharedEmulator"]) { + [self updateVideoLayer]; + [self layoutSubviews]; } } - (void)dealloc { [[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"screenFilter" context:NULL]; } + @end diff --git a/Mini vMac/SettingsViewController.m b/Mini vMac/SettingsViewController.m index cd53447..3e00ffb 100644 --- a/Mini vMac/SettingsViewController.m +++ b/Mini vMac/SettingsViewController.m @@ -108,6 +108,9 @@ typedef enum : NSInteger { - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [AppDelegate sharedEmulator].running = YES; + if (![selectedEmulatorBundle isEqual:[AppDelegate sharedEmulator].bundle] && ![AppDelegate sharedEmulator].anyDiskInserted) { + [[AppDelegate sharedInstance] reloadEmulator]; + } } - (void)showInsertDisk:(id)sender { @@ -209,8 +212,8 @@ typedef enum : NSInteger { - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { if (section == SettingsSectionSpeed) { return NSLocalizedString(@"Faster speeds and running in background drain the battery faster", nil); - } else if (section == SettingsSectionMachine) { - return NSLocalizedString(@"Changing the emulated machine requires to relaunch Mini vMac", nil); + } else if (section == SettingsSectionMachine && [AppDelegate sharedEmulator].anyDiskInserted) { + return NSLocalizedString(@"The emulated machine cannot be changed while disks are inserted.", nil); } else { return nil; } @@ -328,6 +331,13 @@ typedef enum : NSInteger { return cell; } +- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section == SettingsSectionMachine && [AppDelegate sharedEmulator].anyDiskInserted) { + return nil; + } + return indexPath; +} + - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; diff --git a/Mini vMac/ViewController.m b/Mini vMac/ViewController.m index c67688b..dbe392e 100644 --- a/Mini vMac/ViewController.m +++ b/Mini vMac/ViewController.m @@ -208,19 +208,21 @@ API_AVAILABLE(ios(13.4)) } - (void)emulatorDidShutDown:(NSNotification*)notification { - UILabel *shutdownLabel = [[UILabel alloc] initWithFrame:self.view.bounds]; - shutdownLabel.text = NSLocalizedString(@"the emulated Mac has shut down\ntap to restart", nil); - shutdownLabel.textColor = [UIColor whiteColor]; - [self.view addSubview:shutdownLabel]; - shutdownLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [shutdownLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(restartEmulator:)]]; - shutdownLabel.numberOfLines = -1; - shutdownLabel.textAlignment = NSTextAlignmentCenter; - shutdownLabel.userInteractionEnabled = YES; - [UIView animateWithDuration:0.5 animations:^{ - self.screenView.alpha = 0.5; - }]; - [self hideKeyboard:notification]; + if (notification.object == [AppDelegate sharedEmulator]) { + UILabel *shutdownLabel = [[UILabel alloc] initWithFrame:self.view.bounds]; + shutdownLabel.text = NSLocalizedString(@"the emulated Mac has shut down\ntap to restart", nil); + shutdownLabel.textColor = [UIColor whiteColor]; + [self.view addSubview:shutdownLabel]; + shutdownLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [shutdownLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(restartEmulator:)]]; + shutdownLabel.numberOfLines = -1; + shutdownLabel.textAlignment = NSTextAlignmentCenter; + shutdownLabel.userInteractionEnabled = YES; + [UIView animateWithDuration:0.5 animations:^{ + self.screenView.alpha = 0.5; + }]; + [self hideKeyboard:notification]; + } } - (void)restartEmulator:(UITapGestureRecognizer*)gestureRecognizer {