Drop the direct use of NSNotificationCenter for most preferences

This commit is contained in:
Lior Halphon 2023-06-09 17:42:31 +03:00
parent daf713132b
commit d61e5f248d
8 changed files with 174 additions and 205 deletions

View File

@ -1,7 +1,9 @@
#import <CoreImage/CoreImage.h>
#import "GBViewMetal.h"
#pragma clang diagnostic ignored "-Wpartial-availability"
#if !TARGET_OS_IPHONE
#import "../Cocoa/NSObject+DefaultsObserver.h"
#endif
static const vector_float2 rect[] =
{
@ -74,8 +76,13 @@ static const vector_float2 rect[] =
options:MTLResourceStorageModeShared];
output_resolution = (simd_float2){view.drawableSize.width, view.drawableSize.height};
/* TODO: NSObject+DefaultsObserver can replace the less flexible `addDefaultObserver` in iOS */
#if TARGET_OS_IPHONE
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadShader) name:@"GBFilterChanged" object:nil];
[self loadShader];
#else
[self observeStandardDefaultsKey:@"GBFilter" selector:@selector(loadShader)];
#endif
}
- (void) loadShader

View File

@ -13,6 +13,7 @@
#import "GBPaletteEditorController.h"
#import "GBObjectView.h"
#import "GBPaletteView.h"
#import "NSObject+DefaultsObserver.h"
#define likely(x) GB_likely(x)
#define unlikely(x) GB_unlikely(x)
@ -298,16 +299,6 @@ static void debuggerReloadCallback(GB_gameboy_t *gb)
GB_set_palette(&_gb, [GBPaletteEditorController userPalette]);
}
- (void) updateBorderMode
{
_borderModeChanged = true;
}
- (void) updateRumbleMode
{
GB_set_rumble_mode(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRumbleMode"]);
}
- (void) initCommon
{
GB_init(&_gb, [self internalModel]);
@ -317,22 +308,52 @@ static void debuggerReloadCallback(GB_gameboy_t *gb)
GB_set_log_callback(&_gb, (GB_log_callback_t) consoleLog);
GB_set_input_callback(&_gb, (GB_input_callback_t) consoleInput);
GB_set_async_input_callback(&_gb, (GB_input_callback_t) asyncConsoleInput);
GB_set_color_correction_mode(&_gb, (GB_color_correction_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorCorrection"]);
GB_set_light_temperature(&_gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBLightTemperature"]);
GB_set_interference_volume(&_gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBInterferenceVolume"]);
GB_set_border_mode(&_gb, (GB_border_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBBorderMode"]);
[self updatePalette];
GB_set_rgb_encode_callback(&_gb, rgbEncode);
GB_set_camera_get_pixel_callback(&_gb, cameraGetPixel);
GB_set_camera_update_request_callback(&_gb, cameraRequestUpdate);
GB_set_highpass_filter_mode(&_gb, (GB_highpass_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBHighpassFilter"]);
GB_set_rewind_length(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRewindLength"]);
GB_set_rtc_mode(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRTCMode"]);
GB_apu_set_sample_callback(&_gb, audioCallback);
GB_set_rumble_callback(&_gb, rumbleCallback);
GB_set_infrared_callback(&_gb, infraredStateChanged);
GB_set_debugger_reload_callback(&_gb, debuggerReloadCallback);
[self updateRumbleMode];
GB_gameboy_t *gb = &_gb;
__unsafe_unretained Document *weakSelf = self;
[self observeStandardDefaultsKey:@"GBColorCorrection" withBlock:^(NSNumber *value) {
GB_set_color_correction_mode(gb, value.unsignedIntValue);
}];
[self observeStandardDefaultsKey:@"GBLightTemperature" withBlock:^(NSNumber *value) {
GB_set_light_temperature(gb, value.doubleValue);
}];
[self observeStandardDefaultsKey:@"GBInterferenceVolume" withBlock:^(NSNumber *value) {
GB_set_interference_volume(gb, value.doubleValue);
}];
GB_set_border_mode(&_gb, (GB_border_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBBorderMode"]);
[self observeStandardDefaultsKey:@"GBBorderMode" withBlock:^(NSNumber *value) {
_borderModeChanged = true;
}];
[self observeStandardDefaultsKey:@"GBHighpassFilter" withBlock:^(NSNumber *value) {
GB_set_highpass_filter_mode(gb, value.unsignedIntValue);
}];
[self observeStandardDefaultsKey:@"GBRewindLength" withBlock:^(NSNumber *value) {
[weakSelf performAtomicBlock:^{
GB_set_rewind_length(gb, value.unsignedIntValue);
}];
}];
[self observeStandardDefaultsKey:@"GBRTCMode" withBlock:^(NSNumber *value) {
GB_set_rtc_mode(gb, value.unsignedIntValue);
}];
[self observeStandardDefaultsKey:@"GBRumbleMode" withBlock:^(NSNumber *value) {
GB_set_rumble_mode(gb, value.unsignedIntValue);
}];
}
- (void) updateMinSize
@ -766,82 +787,54 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
accessibilityDescription:@"Print"];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateHighpassFilter)
name:@"GBHighpassFilterChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateColorCorrectionMode)
name:@"GBColorCorrectionChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateLightTemperature)
name:@"GBLightTemperatureChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateInterferenceVolume)
name:@"GBInterferenceVolumeChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateFrameBlendingMode)
name:@"GBFrameBlendingModeChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updatePalette)
name:@"GBColorPaletteChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateBorderMode)
name:@"GBBorderModeChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateRumbleMode)
name:@"GBRumbleModeChanged"
object:nil];
__unsafe_unretained Document *weakSelf = self;
[self observeStandardDefaultsKey:@"GBFrameBlendingMode"
withBlock:^(NSNumber *value) {
weakSelf.view.frameBlendingMode = (GB_frame_blending_mode_t)value.unsignedIntValue;
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateRewindLength)
name:@"GBRewindLengthChanged"
object:nil];
[self observeStandardDefaultsKey:@"GBDMGModel" withBlock:^(id newValue) {
weakSelf->_modelsChanging = true;
if (weakSelf->_currentModel == MODEL_DMG) {
[weakSelf reset:nil];
}
weakSelf->_modelsChanging = false;
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateRTCMode)
name:@"GBRTCModeChanged"
object:nil];
[self observeStandardDefaultsKey:@"GBSGBModel" withBlock:^(id newValue) {
weakSelf->_modelsChanging = true;
if (weakSelf->_currentModel == MODEL_SGB) {
[weakSelf reset:nil];
}
weakSelf->_modelsChanging = false;
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(dmgModelChanged)
name:@"GBDMGModelChanged"
object:nil];
[self observeStandardDefaultsKey:@"GBCGBModel" withBlock:^(id newValue) {
weakSelf->_modelsChanging = true;
if (weakSelf->_currentModel == MODEL_CGB) {
[weakSelf reset:nil];
}
weakSelf->_modelsChanging = false;
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sgbModelChanged)
name:@"GBSGBModelChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cgbModelChanged)
name:@"GBCGBModelChanged"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(agbModelChanged)
name:@"GBAGBModelChanged"
object:nil];
[self observeStandardDefaultsKey:@"GBAGBModel" withBlock:^(id newValue) {
weakSelf->_modelsChanging = true;
if (weakSelf->_currentModel == MODEL_AGB) {
[weakSelf reset:nil];
}
weakSelf->_modelsChanging = false;
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateVolume)
name:@"GBVolumeChanged"
object:nil];
[self observeStandardDefaultsKey:@"GBVolume" withBlock:^(id newValue) {
weakSelf->_volume = [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBVolume"];
}];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateDMG"]) {
_currentModel = MODEL_DMG;
@ -2173,96 +2166,6 @@ static bool is_path_writeable(const char *path)
}];
}
- (void) updateVolume
{
_volume = [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBVolume"];
}
- (void) updateHighpassFilter
{
if (GB_is_inited(&_gb)) {
GB_set_highpass_filter_mode(&_gb, (GB_highpass_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBHighpassFilter"]);
}
}
- (void) updateColorCorrectionMode
{
if (GB_is_inited(&_gb)) {
GB_set_color_correction_mode(&_gb, (GB_color_correction_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorCorrection"]);
}
}
- (void) updateLightTemperature
{
if (GB_is_inited(&_gb)) {
GB_set_light_temperature(&_gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBLightTemperature"]);
}
}
- (void) updateInterferenceVolume
{
if (GB_is_inited(&_gb)) {
GB_set_interference_volume(&_gb, [[NSUserDefaults standardUserDefaults] doubleForKey:@"GBInterferenceVolume"]);
}
}
- (void) updateFrameBlendingMode
{
self.view.frameBlendingMode = (GB_frame_blending_mode_t) [[NSUserDefaults standardUserDefaults] integerForKey:@"GBFrameBlendingMode"];
}
- (void) updateRewindLength
{
[self performAtomicBlock:^{
if (GB_is_inited(&_gb)) {
GB_set_rewind_length(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRewindLength"]);
}
}];
}
- (void) updateRTCMode
{
if (GB_is_inited(&_gb)) {
GB_set_rtc_mode(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRTCMode"]);
}
}
- (void)dmgModelChanged
{
_modelsChanging = true;
if (_currentModel == MODEL_DMG) {
[self reset:nil];
}
_modelsChanging = false;
}
- (void)sgbModelChanged
{
_modelsChanging = true;
if (_currentModel == MODEL_SGB) {
[self reset:nil];
}
_modelsChanging = false;
}
- (void)cgbModelChanged
{
_modelsChanging = true;
if (_currentModel == MODEL_CGB) {
[self reset:nil];
}
_modelsChanging = false;
}
- (void)agbModelChanged
{
_modelsChanging = true;
if (_currentModel == MODEL_AGB) {
[self reset:nil];
}
_modelsChanging = false;
}
- (void)setFileURL:(NSURL *)fileURL
{
[super setFileURL:fileURL];

View File

@ -163,7 +163,7 @@ void main(void) {\n\
/* OpenGL is black magic. Closing one view causes others to be completely black unless we reload their shaders */
/* We're probably not freeing thing in the right place. */
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged$DefaultsObserver" object:nil];
}
+ (GLuint)shaderWithContents:(NSString*)contents type:(GLenum)type

View File

@ -1,5 +1,6 @@
#import "GBOpenGLView.h"
#import "GBView.h"
#import "NSObject+DefaultsObserver.h"
#import <OpenGL/gl.h>
@implementation GBOpenGLView
@ -27,13 +28,12 @@
- (instancetype)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat *)format
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(filterChanged) name:@"GBFilterChanged" object:nil];
__unsafe_unretained GBOpenGLView *weakSelf = self;
[self observeStandardDefaultsKey:@"GBFilter" withBlock:^(id newValue) {
weakSelf.shader = nil;
[weakSelf setNeedsDisplay:true];
}];
return [super initWithFrame:frameRect pixelFormat:format];
}
- (void) filterChanged
{
self.shader = nil;
[self setNeedsDisplay:true];
}
@end

View File

@ -360,14 +360,12 @@ static inline NSString *keyEquivalentString(NSMenuItem *item)
{
[[NSUserDefaults standardUserDefaults] setObject:[[self class] filterList][[sender indexOfSelectedItem]]
forKey:@"GBFilter"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged" object:nil];
}
- (IBAction)highpassFilterChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
forKey:@"GBHighpassFilter"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBHighpassFilterChanged" object:nil];
}
@ -399,43 +397,36 @@ static inline NSString *keyEquivalentString(NSMenuItem *item)
{
[[NSUserDefaults standardUserDefaults] setBool: [(NSButton *)sender state] != NSOnState
forKey:@"GBAspectRatioUnkept"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBAspectChanged" object:nil];
}
- (IBAction)colorCorrectionChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedItem].tag)
forKey:@"GBColorCorrection"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorCorrectionChanged" object:nil];
}
- (IBAction)lightTemperatureChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
forKey:@"GBLightTemperature"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBLightTemperatureChanged" object:nil];
}
- (IBAction)interferenceVolumeChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
forKey:@"GBInterferenceVolume"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBInterferenceVolumeChanged" object:nil];
}
- (IBAction)volumeChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
forKey:@"GBVolume"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBVolumeChanged" object:nil];
}
- (IBAction)franeBlendingModeChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
forKey:@"GBFrameBlendingMode"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFrameBlendingModeChanged" object:nil];
}
- (void)updatePalettesMenu
@ -490,14 +481,12 @@ static inline NSString *keyEquivalentString(NSMenuItem *item)
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedItem].tag)
forKey:@"GBBorderMode"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBBorderModeChanged" object:nil];
}
- (IBAction)rumbleModeChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedItem].tag)
forKey:@"GBRumbleMode"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBRumbleModeChanged" object:nil];
}
- (IBAction)hotkey1Changed:(id)sender
@ -516,15 +505,12 @@ static inline NSString *keyEquivalentString(NSMenuItem *item)
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
forKey:@"GBRewindLength"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBRewindLengthChanged" object:nil];
}
- (IBAction)rtcModeChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
forKey:@"GBRTCMode"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBRTCModeChanged" object:nil];
}
- (IBAction)changeAutoUpdates:(id)sender
@ -813,7 +799,6 @@ static inline NSString *keyEquivalentString(NSMenuItem *item)
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
forKey:@"GBDMGModel"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBDMGModelChanged" object:nil];
}
@ -821,21 +806,18 @@ static inline NSString *keyEquivalentString(NSMenuItem *item)
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
forKey:@"GBSGBModel"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBSGBModelChanged" object:nil];
}
- (IBAction)cgbModelChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
forKey:@"GBCGBModel"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBCGBModelChanged" object:nil];
}
- (IBAction)agbModelChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
forKey:@"GBAGBModel"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBAGBModelChanged" object:nil];
}
- (IBAction)reloadButtonsData:(id)sender

View File

@ -5,6 +5,7 @@
#import "GBViewMetal.h"
#import "GBButtons.h"
#import "NSString+StringForKey.h"
#import "NSObject+DefaultsObserver.h"
#import "Document.h"
#define JOYSTICK_HIGH 0x4000
@ -138,7 +139,10 @@ static const uint8_t workboy_vk_to_key[] = {
{
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ratioKeepingChanged) name:@"GBAspectChanged" object:nil];
__unsafe_unretained GBView *weakSelf = self;
[self observeStandardDefaultsKey:@"GBAspectRatioUnkept" withBlock:^(id newValue) {
[weakSelf setFrame:weakSelf.superview.frame];
}];
tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){}
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect | NSTrackingMouseMoved
owner:self
@ -161,11 +165,6 @@ static const uint8_t workboy_vk_to_key[] = {
});
}
- (void) ratioKeepingChanged
{
[self setFrame:self.superview.frame];
}
- (void)dealloc
{
if (mouse_hidden) {

View File

@ -0,0 +1,6 @@
#import <AppKit/AppKit.h>
@interface NSObject (DefaultsObserver)
- (void)observeStandardDefaultsKey:(NSString *)key withBlock:(void(^)(id newValue))block;
- (void)observeStandardDefaultsKey:(NSString *)key selector:(SEL)selector;
@end

View File

@ -0,0 +1,72 @@
#import "NSObject+DefaultsObserver.h"
#import <AppKit/AppKit.h>
#import <objc/runtime.h>
@interface GBUserDefaultsObserverHelper : NSObject
@end
@implementation GBUserDefaultsObserverHelper
+ (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context
{
[[NSNotificationCenter defaultCenter] postNotificationName:[keyPath stringByAppendingString:@"Changed$DefaultsObserver"]
object:nil
userInfo:@{
@"value": change[NSKeyValueChangeNewKey]
}];
}
+ (void)startObservingKey:(NSString *)key
{
if (!NSThread.isMainThread) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self startObservingKey:key];
});
return;
}
static NSMutableSet *set = nil;
if (!set) {
set = [NSMutableSet set];
}
if ([set containsObject:key]) return;
[set addObject:key];
[[NSUserDefaults standardUserDefaults] addObserver:(id)self
forKeyPath:key
options:NSKeyValueObservingOptionNew
context:nil];
}
@end
@implementation NSObject (DefaultsObserver)
- (void)observeStandardDefaultsKey:(NSString *)key selector:(SEL)selector
{
__weak id weakSelf = self;
[self observeStandardDefaultsKey:key
withBlock:^(id newValue) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[weakSelf performSelector:selector withObject:newValue];
#pragma clang diagnostic pop
}];
}
- (void)observeStandardDefaultsKey:(NSString *)key withBlock:(void(^)(id newValue))block
{
NSString *notificationName = [key stringByAppendingString:@"Changed$DefaultsObserver"];
objc_setAssociatedObject(self, sel_registerName(notificationName.UTF8String), block, OBJC_ASSOCIATION_RETAIN);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(standardDefaultsKeyChanged:)
name:notificationName
object:nil];
[GBUserDefaultsObserverHelper startObservingKey:key];
block([[NSUserDefaults standardUserDefaults] objectForKey:key]);
}
- (void)standardDefaultsKeyChanged:(NSNotification *)notification
{
SEL selector = sel_registerName(notification.name.UTF8String);
((void(^)(id))objc_getAssociatedObject(self, selector))(notification.userInfo[@"value"]);
}
@end