allow changing emulated machine without relaunching the app

This commit is contained in:
Jesús A. Álvarez 2020-09-25 00:29:30 +02:00
parent af3b2ba5b1
commit fd665a1761
12 changed files with 83 additions and 42 deletions

View File

@ -21,9 +21,11 @@ extern NSString *DocumentsChangedNotification;
@property (nonatomic, readonly) NSArray<NSBundle*> *emulatorBundles; @property (nonatomic, readonly) NSArray<NSBundle*> *emulatorBundles;
@property (nonatomic, readonly) NSString *emulatorBundlesPath; @property (nonatomic, readonly) NSString *emulatorBundlesPath;
@property (readonly, nonatomic, getter = isSandboxed) BOOL sandboxed; @property (readonly, nonatomic, getter = isSandboxed) BOOL sandboxed;
@property (readonly, nonatomic) id<Emulator> sharedEmulator;
+ (instancetype)sharedInstance; + (instancetype)sharedInstance;
+ (id<Emulator>)sharedEmulator; + (id<Emulator>)sharedEmulator;
- (void)reloadEmulator;
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message; - (void)showAlertWithTitle:(NSString *)title message:(NSString *)message;
- (IBAction)showInsertDisk:(id)sender; - (IBAction)showInsertDisk:(id)sender;

View File

@ -108,6 +108,24 @@ NSString *DocumentsChangedNotification = @"documentsChanged";
return sharedEmulator != nil; return sharedEmulator != nil;
} }
- (void)reloadEmulator {
NSBundle *bundle = sharedEmulator.bundle;
[self willChangeValueForKey:@"sharedEmulator"];
id<Emulator> 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<Emulator>)sharedEmulator {
return sharedEmulator;
}
- (void)applicationDidEnterBackground:(UIApplication *)application { - (void)applicationDidEnterBackground:(UIApplication *)application {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize]; [defaults synchronize];

View File

@ -38,11 +38,10 @@ typedef enum : NSInteger {
@property (nonatomic, readonly) BOOL anyDiskInserted; @property (nonatomic, readonly) BOOL anyDiskInserted;
@property (nonatomic, readonly) NSString *currentApplication; @property (nonatomic, readonly) NSString *currentApplication;
+ (instancetype)sharedEmulator;
- (void)run; - (void)run;
- (void)reset; - (void)reset;
- (void)interrupt; - (void)interrupt;
- (void)shutdown;
- (void)keyDown:(int)scancode; - (void)keyDown:(int)scancode;
- (void)keyUp:(int)scancode; - (void)keyUp:(int)scancode;

View File

@ -36,14 +36,14 @@ EXPORTVAR(ui3p, RAM)
EXPORTVAR(ui3p, VidROM) EXPORTVAR(ui3p, VidROM)
EXPORTVAR(ui3p, VidMem) EXPORTVAR(ui3p, VidMem)
@interface Emulator : NSObject <Emulator, UIAlertViewDelegate> @interface MNVMBundleClassName : NSObject <Emulator, UIAlertViewDelegate>
- (void)makeNewDisk:(NSString*)name size:(NSInteger)size; - (void)makeNewDisk:(NSString*)name size:(NSInteger)size;
- (void)updateScreen:(CGImageRef)screenImage; - (void)updateScreen:(CGImageRef)screenImage;
@end @end
static Emulator *sharedEmulator = nil; static __weak MNVMBundleClassName *sharedEmulator = nil;
#pragma mark - some simple utilities #pragma mark - some simple utilities
@ -405,7 +405,7 @@ LOCALFUNC tMacErr vSonyEject0(tDrive Drive_No, blnr deleteit) {
} }
#endif #endif
[[NSNotificationCenter defaultCenter] postNotificationName:[Emulator sharedEmulator].ejectDiskNotification object:[Emulator sharedEmulator] userInfo:userInfo]; [[NSNotificationCenter defaultCenter] postNotificationName:sharedEmulator.ejectDiskNotification object:sharedEmulator userInfo:userInfo];
return mnvm_noErr; return mnvm_noErr;
} }
@ -455,7 +455,7 @@ LOCALFUNC blnr Sony_Insert0(FILE *refnum, blnr locked, NSString *filePath) {
} else { } else {
NSDictionary *userInfo = @{@"path": filePath, NSDictionary *userInfo = @{@"path": filePath,
@"drive": @(Drive_No)}; @"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); */ /* printf("Sony_Insert0 %d\n", (int)Drive_No); */
@ -787,7 +787,7 @@ LOCALPROC HaveChangedScreenBuff(ui4r top, ui4r left, ui4r bottom, ui4r right) {
if (colorSpace) { if (colorSpace) {
CGImageRef screenImage = CGImageCreate(vMacScreenWidth, vMacScreenHeight, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, options, screenDataProvider, NULL, false, kCGRenderingIntentDefault); CGImageRef screenImage = CGImageCreate(vMacScreenWidth, vMacScreenHeight, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, options, screenDataProvider, NULL, false, kCGRenderingIntentDefault);
[[Emulator sharedEmulator] updateScreen:screenImage]; [sharedEmulator updateScreen:screenImage];
CGImageRelease(screenImage); CGImageRelease(screenImage);
} }
} }
@ -1644,31 +1644,24 @@ GLOBALPROC WaitForNextTick(void) {
#pragma mark - Objective-C Interface #pragma mark - Objective-C Interface
static dispatch_once_t onceToken; @implementation MNVMBundleClassName
@implementation Emulator
{ {
__block __weak UITextField *nameTextField; __block __weak UITextField *nameTextField;
} }
@synthesize dataPath; @synthesize dataPath;
+ (instancetype)sharedEmulator {
dispatch_once(&onceToken, ^{
sharedEmulator = [self new];
});
return sharedEmulator;
}
- (instancetype)init { - (instancetype)init {
if ((self = [super init])) { if ((self = [super init])) {
dispatch_once(&onceToken, ^{ sharedEmulator = self;
sharedEmulator = self;
});
} }
return self; return self;
} }
- (void)shutdown {
RequestMacOff = trueblnr;
}
- (void)run { - (void)run {
ZapOSGLUVars(); ZapOSGLUVars();
if (InitOSGLU()) { if (InitOSGLU()) {

View File

@ -39,6 +39,8 @@
#define AutoLocation 1 #define AutoLocation 1
#define AutoTimeZone 1 #define AutoTimeZone 1
#define MNVMBundleClassName Mac128KEmulator
#ifdef PLIST_PREPROCESSOR #ifdef PLIST_PREPROCESSOR
#define MNVMBundleDisplayName Mac 128K #define MNVMBundleDisplayName Mac 128K
#define MNVMBundleGetInfoString 128K, 512×342 #define MNVMBundleGetInfoString 128K, 512×342

View File

@ -39,6 +39,8 @@
#define AutoLocation 1 #define AutoLocation 1
#define AutoTimeZone 1 #define AutoTimeZone 1
#define MNVMBundleClassName MacIIEmulator640x480
#ifdef PLIST_PREPROCESSOR #ifdef PLIST_PREPROCESSOR
#define MNVMBundleDisplayName Mac II #define MNVMBundleDisplayName Mac II
#define MNVMBundleGetInfoString 8M, 640×480 #define MNVMBundleGetInfoString 8M, 640×480

View File

@ -39,6 +39,8 @@
#define AutoLocation 1 #define AutoLocation 1
#define AutoTimeZone 1 #define AutoTimeZone 1
#define MNVMBundleClassName MacIIEmulator
#ifdef PLIST_PREPROCESSOR #ifdef PLIST_PREPROCESSOR
#define MNVMBundleDisplayName Mac II #define MNVMBundleDisplayName Mac II
#define MNVMBundleGetInfoString 8M, 1024×768 #define MNVMBundleGetInfoString 8M, 1024×768

View File

@ -40,6 +40,8 @@
#define AutoLocation 1 #define AutoLocation 1
#define AutoTimeZone 1 #define AutoTimeZone 1
#define MNVMBundleClassName MacPlus4MEmulator
#ifdef PLIST_PREPROCESSOR #ifdef PLIST_PREPROCESSOR
#define MNVMBundleDisplayName Mac Plus #define MNVMBundleDisplayName Mac Plus
#define MNVMBundleGetInfoString 4M, 512×342 #define MNVMBundleGetInfoString 4M, 512×342

View File

@ -25,6 +25,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string>Emulator</string> <string>MNVMBundleClassName</string>
</dict> </dict>
</plist> </plist>

View File

@ -26,13 +26,9 @@ static ScreenView *sharedScreenView = nil;
NSString *screenFilter = [[NSUserDefaults standardUserDefaults] stringForKey:@"screenFilter"]; NSString *screenFilter = [[NSUserDefaults standardUserDefaults] stringForKey:@"screenFilter"];
videoLayer.magnificationFilter = screenFilter; videoLayer.magnificationFilter = screenFilter;
videoLayer.minificationFilter = screenFilter; videoLayer.minificationFilter = screenFilter;
[AppDelegate sharedEmulator].screenLayer = videoLayer; [self updateVideoLayer];
if ([AppDelegate sharedEmulator]) {
screenSize = [AppDelegate sharedEmulator].screenSize;
} else {
screenSize = CGSizeMake(1, 1);
}
[self.layer addSublayer:videoLayer]; [self.layer addSublayer:videoLayer];
[[AppDelegate sharedInstance] addObserver:self forKeyPath:@"sharedEmulator" options:NSKeyValueObservingOptionNew context:NULL];
[[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"screenFilter" options:NSKeyValueObservingOptionNew context:NULL]; [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"screenFilter" options:NSKeyValueObservingOptionNew context:NULL];
} }
@ -48,6 +44,15 @@ static ScreenView *sharedScreenView = nil;
return screenSize; return screenSize;
} }
- (void)updateVideoLayer {
if ([AppDelegate sharedEmulator]) {
[AppDelegate sharedEmulator].screenLayer = videoLayer;
screenSize = [AppDelegate sharedEmulator].screenSize;
} else {
screenSize = CGSizeMake(1, 1);
}
}
- (void)layoutSubviews { - (void)layoutSubviews {
[super layoutSubviews]; [super layoutSubviews];
CGRect viewBounds = self.bounds; CGRect viewBounds = self.bounds;
@ -73,10 +78,14 @@ static ScreenView *sharedScreenView = nil;
videoLayer.magnificationFilter = value; videoLayer.magnificationFilter = value;
videoLayer.minificationFilter = value; videoLayer.minificationFilter = value;
} }
} else if (object == [AppDelegate sharedInstance] && [keyPath isEqualToString:@"sharedEmulator"]) {
[self updateVideoLayer];
[self layoutSubviews];
} }
} }
- (void)dealloc { - (void)dealloc {
[[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"screenFilter" context:NULL]; [[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"screenFilter" context:NULL];
} }
@end @end

View File

@ -108,6 +108,9 @@ typedef enum : NSInteger {
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[AppDelegate sharedEmulator].running = YES; [AppDelegate sharedEmulator].running = YES;
if (![selectedEmulatorBundle isEqual:[AppDelegate sharedEmulator].bundle] && ![AppDelegate sharedEmulator].anyDiskInserted) {
[[AppDelegate sharedInstance] reloadEmulator];
}
} }
- (void)showInsertDisk:(id)sender { - (void)showInsertDisk:(id)sender {
@ -209,8 +212,8 @@ typedef enum : NSInteger {
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
if (section == SettingsSectionSpeed) { if (section == SettingsSectionSpeed) {
return NSLocalizedString(@"Faster speeds and running in background drain the battery faster", nil); return NSLocalizedString(@"Faster speeds and running in background drain the battery faster", nil);
} else if (section == SettingsSectionMachine) { } else if (section == SettingsSectionMachine && [AppDelegate sharedEmulator].anyDiskInserted) {
return NSLocalizedString(@"Changing the emulated machine requires to relaunch Mini vMac", nil); return NSLocalizedString(@"The emulated machine cannot be changed while disks are inserted.", nil);
} else { } else {
return nil; return nil;
} }
@ -328,6 +331,13 @@ typedef enum : NSInteger {
return cell; 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 { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];

View File

@ -208,19 +208,21 @@ API_AVAILABLE(ios(13.4))
} }
- (void)emulatorDidShutDown:(NSNotification*)notification { - (void)emulatorDidShutDown:(NSNotification*)notification {
UILabel *shutdownLabel = [[UILabel alloc] initWithFrame:self.view.bounds]; if (notification.object == [AppDelegate sharedEmulator]) {
shutdownLabel.text = NSLocalizedString(@"the emulated Mac has shut down\ntap to restart", nil); UILabel *shutdownLabel = [[UILabel alloc] initWithFrame:self.view.bounds];
shutdownLabel.textColor = [UIColor whiteColor]; shutdownLabel.text = NSLocalizedString(@"the emulated Mac has shut down\ntap to restart", nil);
[self.view addSubview:shutdownLabel]; shutdownLabel.textColor = [UIColor whiteColor];
shutdownLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.view addSubview:shutdownLabel];
[shutdownLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(restartEmulator:)]]; shutdownLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
shutdownLabel.numberOfLines = -1; [shutdownLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(restartEmulator:)]];
shutdownLabel.textAlignment = NSTextAlignmentCenter; shutdownLabel.numberOfLines = -1;
shutdownLabel.userInteractionEnabled = YES; shutdownLabel.textAlignment = NSTextAlignmentCenter;
[UIView animateWithDuration:0.5 animations:^{ shutdownLabel.userInteractionEnabled = YES;
self.screenView.alpha = 0.5; [UIView animateWithDuration:0.5 animations:^{
}]; self.screenView.alpha = 0.5;
[self hideKeyboard:notification]; }];
[self hideKeyboard:notification];
}
} }
- (void)restartEmulator:(UITapGestureRecognizer*)gestureRecognizer { - (void)restartEmulator:(UITapGestureRecognizer*)gestureRecognizer {