Cocoa Port: Fix a bug where the Frame Advance and Frame Jump buttons in the Execution Control panel would cause the other buttons to enable/disable themselves inconsistently, but only if the .app was built on Xcode 10 or later.
- Apparently, KVO-based UI updates being made across threads are a big no-no in the macOS v10.14 SDK and later. So now we need to make sure that ALL KVO-based UI updates are done on the main thread only.
This commit is contained in:
parent
c7f85ba00a
commit
b7c9b6b614
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2011 Roger Manuel
|
Copyright (C) 2011 Roger Manuel
|
||||||
Copyright (C) 2011-2018 DeSmuME team
|
Copyright (C) 2011-2021 DeSmuME team
|
||||||
|
|
||||||
This file is free software: you can redistribute it and/or modify
|
This file is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -79,6 +79,7 @@ typedef struct
|
||||||
@property (assign) BOOL masterExecute;
|
@property (assign) BOOL masterExecute;
|
||||||
@property (assign) BOOL isFrameSkipEnabled;
|
@property (assign) BOOL isFrameSkipEnabled;
|
||||||
@property (assign) NSInteger coreState;
|
@property (assign) NSInteger coreState;
|
||||||
|
@property (assign) BOOL emulationPaused;
|
||||||
|
|
||||||
@property (assign) BOOL isSpeedLimitEnabled;
|
@property (assign) BOOL isSpeedLimitEnabled;
|
||||||
@property (assign) BOOL isCheatingEnabled;
|
@property (assign) BOOL isCheatingEnabled;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2011 Roger Manuel
|
Copyright (C) 2011 Roger Manuel
|
||||||
Copyright (C) 2011-2018 DeSmuME team
|
Copyright (C) 2011-2021 DeSmuME team
|
||||||
|
|
||||||
This file is free software: you can redistribute it and/or modify
|
This file is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -52,6 +52,7 @@ volatile bool execute = true;
|
||||||
@dynamic masterExecute;
|
@dynamic masterExecute;
|
||||||
@dynamic isFrameSkipEnabled;
|
@dynamic isFrameSkipEnabled;
|
||||||
@dynamic coreState;
|
@dynamic coreState;
|
||||||
|
@dynamic emulationPaused;
|
||||||
@dynamic isSpeedLimitEnabled;
|
@dynamic isSpeedLimitEnabled;
|
||||||
@dynamic isCheatingEnabled;
|
@dynamic isCheatingEnabled;
|
||||||
@dynamic speedScalar;
|
@dynamic speedScalar;
|
||||||
|
@ -574,6 +575,8 @@ volatile bool execute = true;
|
||||||
|
|
||||||
- (void) setCoreState:(NSInteger)coreState
|
- (void) setCoreState:(NSInteger)coreState
|
||||||
{
|
{
|
||||||
|
NSString *newFrameStatus = nil;
|
||||||
|
|
||||||
if (coreState == ExecutionBehavior_FrameJump)
|
if (coreState == ExecutionBehavior_FrameJump)
|
||||||
{
|
{
|
||||||
uint64_t frameIndex = [self frameNumber];
|
uint64_t frameIndex = [self frameNumber];
|
||||||
|
@ -602,9 +605,7 @@ volatile bool execute = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||||
|
|
||||||
execControl->SetExecutionBehavior((ExecutionBehavior)coreState);
|
execControl->SetExecutionBehavior((ExecutionBehavior)coreState);
|
||||||
|
|
||||||
pthread_rwlock_rdlock(&threadParam.rwlockOutputList);
|
pthread_rwlock_rdlock(&threadParam.rwlockOutputList);
|
||||||
|
|
||||||
switch ((ExecutionBehavior)coreState)
|
switch ((ExecutionBehavior)coreState)
|
||||||
|
@ -616,7 +617,7 @@ volatile bool execute = true;
|
||||||
[cdsOutput setIdle:YES];
|
[cdsOutput setIdle:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setFrameStatus:[NSString stringWithFormat:@"%llu", (unsigned long long)[self frameNumber]]];
|
newFrameStatus = [NSString stringWithFormat:@"%llu", (unsigned long long)[self frameNumber]];
|
||||||
[_fpsTimer invalidate];
|
[_fpsTimer invalidate];
|
||||||
_fpsTimer = nil;
|
_fpsTimer = nil;
|
||||||
break;
|
break;
|
||||||
|
@ -629,7 +630,7 @@ volatile bool execute = true;
|
||||||
[cdsOutput setIdle:NO];
|
[cdsOutput setIdle:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setFrameStatus:[NSString stringWithFormat:@"%llu", (unsigned long long)[self frameNumber]]];
|
newFrameStatus = [NSString stringWithFormat:@"%llu", (unsigned long long)[self frameNumber]];
|
||||||
[_fpsTimer invalidate];
|
[_fpsTimer invalidate];
|
||||||
_fpsTimer = nil;
|
_fpsTimer = nil;
|
||||||
break;
|
break;
|
||||||
|
@ -642,7 +643,7 @@ volatile bool execute = true;
|
||||||
[cdsOutput setIdle:NO];
|
[cdsOutput setIdle:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setFrameStatus:@"Executing..."];
|
newFrameStatus = @"Executing...";
|
||||||
|
|
||||||
if (_fpsTimer == nil)
|
if (_fpsTimer == nil)
|
||||||
{
|
{
|
||||||
|
@ -669,7 +670,7 @@ volatile bool execute = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setFrameStatus:[NSString stringWithFormat:@"Jumping to frame %llu.", (unsigned long long)execControl->GetFrameJumpTarget()]];
|
newFrameStatus = [NSString stringWithFormat:@"Jumping to frame %llu.", (unsigned long long)execControl->GetFrameJumpTarget()];
|
||||||
[_fpsTimer invalidate];
|
[_fpsTimer invalidate];
|
||||||
_fpsTimer = nil;
|
_fpsTimer = nil;
|
||||||
break;
|
break;
|
||||||
|
@ -686,6 +687,22 @@ volatile bool execute = true;
|
||||||
|
|
||||||
[[self cdsGPU] respondToPauseState:(coreState == ExecutionBehavior_Pause)];
|
[[self cdsGPU] respondToPauseState:(coreState == ExecutionBehavior_Pause)];
|
||||||
[[self cdsController] setHardwareMicPause:(coreState != ExecutionBehavior_Run)];
|
[[self cdsController] setHardwareMicPause:(coreState != ExecutionBehavior_Run)];
|
||||||
|
|
||||||
|
// This method affects UI updates, but can also be called from a thread that is different from
|
||||||
|
// the main thread. When compiling against the macOS v10.13 SDK and earlier, UI updates were allowed
|
||||||
|
// when doing KVO changes on other threads. However, the macOS v10.14 SDK and later now require that
|
||||||
|
// any KVO changes that affect UI updates MUST be performed on the main thread. Therefore, we need
|
||||||
|
// to push the UI-related stuff to the main thread here.
|
||||||
|
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||||
|
[NSNumber numberWithInteger:coreState], @"ExecutionState",
|
||||||
|
newFrameStatus, @"FrameStatusString",
|
||||||
|
nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:@"org.desmume.DeSmuME.handleEmulatorExecutionState" object:self userInfo:userInfo];
|
||||||
|
[userInfo release];
|
||||||
|
|
||||||
|
[tempPool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger) coreState
|
- (NSInteger) coreState
|
||||||
|
@ -694,6 +711,19 @@ volatile bool execute = true;
|
||||||
return behavior;
|
return behavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) setEmulationPaused:(BOOL)theState
|
||||||
|
{
|
||||||
|
// Do nothing. This is for KVO-compliance only.
|
||||||
|
// This method (actually its corresponding getter method) is really intended for
|
||||||
|
// UI updates only. If you want to pause the emulator, call setCoreState: and pass
|
||||||
|
// to it a value of ExecutionBehavior_Pause.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) emulationPaused
|
||||||
|
{
|
||||||
|
return (execControl->GetExecutionBehavior() == ExecutionBehavior_Pause) ? YES : NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) setArm9ImageURL:(NSURL *)fileURL
|
- (void) setArm9ImageURL:(NSURL *)fileURL
|
||||||
{
|
{
|
||||||
const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
|
const char *filePath = (fileURL != NULL) ? [[fileURL path] cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2013-2018 DeSmuME Team
|
Copyright (C) 2013-2021 DeSmuME Team
|
||||||
|
|
||||||
This file is free software: you can redistribute it and/or modify
|
This file is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -176,6 +176,11 @@
|
||||||
name:@"org.desmume.DeSmuME.handleNDSError"
|
name:@"org.desmume.DeSmuME.handleNDSError"
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(handleEmulatorExecutionState:)
|
||||||
|
name:@"org.desmume.DeSmuME.handleEmulatorExecutionState"
|
||||||
|
object:nil];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2011,6 +2016,17 @@
|
||||||
contextInfo:nil];
|
contextInfo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) handleEmulatorExecutionState:(NSNotification *)aNotification
|
||||||
|
{
|
||||||
|
CocoaDSCore *cdsCore = [aNotification object];
|
||||||
|
NSDictionary *userInfo = [aNotification userInfo];
|
||||||
|
ExecutionBehavior execState = (ExecutionBehavior)[(NSNumber *)[userInfo valueForKey:@"ExecutionState"] integerValue];
|
||||||
|
NSString *frameStatusString = (NSString *)[userInfo valueForKey:@"FrameStatusString"];
|
||||||
|
|
||||||
|
[cdsCore setEmulationPaused:(execState == ExecutionBehavior_Pause)];
|
||||||
|
[cdsCore setFrameStatus:frameStatusString];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) addOutputToCore:(CocoaDSOutput *)theOutput
|
- (void) addOutputToCore:(CocoaDSOutput *)theOutput
|
||||||
{
|
{
|
||||||
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
|
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
|
||||||
|
|
Loading…
Reference in New Issue