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-2018 DeSmuME team
|
||||
Copyright (C) 2011-2021 DeSmuME team
|
||||
|
||||
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
|
||||
|
@ -79,6 +79,7 @@ typedef struct
|
|||
@property (assign) BOOL masterExecute;
|
||||
@property (assign) BOOL isFrameSkipEnabled;
|
||||
@property (assign) NSInteger coreState;
|
||||
@property (assign) BOOL emulationPaused;
|
||||
|
||||
@property (assign) BOOL isSpeedLimitEnabled;
|
||||
@property (assign) BOOL isCheatingEnabled;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -52,6 +52,7 @@ volatile bool execute = true;
|
|||
@dynamic masterExecute;
|
||||
@dynamic isFrameSkipEnabled;
|
||||
@dynamic coreState;
|
||||
@dynamic emulationPaused;
|
||||
@dynamic isSpeedLimitEnabled;
|
||||
@dynamic isCheatingEnabled;
|
||||
@dynamic speedScalar;
|
||||
|
@ -574,6 +575,8 @@ volatile bool execute = true;
|
|||
|
||||
- (void) setCoreState:(NSInteger)coreState
|
||||
{
|
||||
NSString *newFrameStatus = nil;
|
||||
|
||||
if (coreState == ExecutionBehavior_FrameJump)
|
||||
{
|
||||
uint64_t frameIndex = [self frameNumber];
|
||||
|
@ -602,9 +605,7 @@ volatile bool execute = true;
|
|||
}
|
||||
|
||||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
|
||||
execControl->SetExecutionBehavior((ExecutionBehavior)coreState);
|
||||
|
||||
pthread_rwlock_rdlock(&threadParam.rwlockOutputList);
|
||||
|
||||
switch ((ExecutionBehavior)coreState)
|
||||
|
@ -616,7 +617,7 @@ volatile bool execute = true;
|
|||
[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 = nil;
|
||||
break;
|
||||
|
@ -629,7 +630,7 @@ volatile bool execute = true;
|
|||
[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 = nil;
|
||||
break;
|
||||
|
@ -642,7 +643,7 @@ volatile bool execute = true;
|
|||
[cdsOutput setIdle:NO];
|
||||
}
|
||||
|
||||
[self setFrameStatus:@"Executing..."];
|
||||
newFrameStatus = @"Executing...";
|
||||
|
||||
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 = nil;
|
||||
break;
|
||||
|
@ -686,6 +687,22 @@ volatile bool execute = true;
|
|||
|
||||
[[self cdsGPU] respondToPauseState:(coreState == ExecutionBehavior_Pause)];
|
||||
[[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
|
||||
|
@ -694,6 +711,19 @@ volatile bool execute = true;
|
|||
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
|
||||
{
|
||||
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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -176,6 +176,11 @@
|
|||
name:@"org.desmume.DeSmuME.handleNDSError"
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleEmulatorExecutionState:)
|
||||
name:@"org.desmume.DeSmuME.handleEmulatorExecutionState"
|
||||
object:nil];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -2011,6 +2016,17 @@
|
|||
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
|
||||
{
|
||||
CocoaDSCore *cdsCore = (CocoaDSCore *)[cdsCoreController content];
|
||||
|
|
Loading…
Reference in New Issue