From 6d474ac59de1a9365cc9759696e36e6faecc0ebf Mon Sep 17 00:00:00 2001 From: Serena Date: Mon, 6 Feb 2023 22:17:27 +0300 Subject: [PATCH 1/9] macOS bar button items --- CMakeLists.txt | 3 +- Core/Config.cpp | 9 + Core/Config.h | 5 +- SDL/MacOSBarItems.h | 21 +++ SDL/MacOSBarItems.mm | 326 +++++++++++++++++++++++++++++++++ SDL/SDLMain.cpp | 12 ++ UI/DarwinFileSystemServices.h | 10 + UI/DarwinFileSystemServices.mm | 4 + UI/GameSettingsScreen.cpp | 44 +++-- UI/MainScreen.cpp | 10 +- 10 files changed, 420 insertions(+), 24 deletions(-) create mode 100644 SDL/MacOSBarItems.h create mode 100644 SDL/MacOSBarItems.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index fa8e4914fb..82887d0a59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1231,8 +1231,9 @@ elseif(TARGET SDL2::SDL2) endif() set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) if(APPLE) - set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm SDL/SDLCocoaMetalLayer.h SDL/SDLCocoaMetalLayer.mm UI/DarwinFileSystemServices.mm UI/DarwinFileSystemServices.h Common/Battery/AppleBatteryClient.m) + set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm SDL/SDLCocoaMetalLayer.h SDL/SDLCocoaMetalLayer.mm SDL/MacOSBarItems.mm SDL/MacOSBarItems.h UI/DarwinFileSystemServices.mm UI/DarwinFileSystemServices.h Common/Battery/AppleBatteryClient.m) set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(SDL/MacOSBarItems.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc) set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY}) elseif(USING_EGL) diff --git a/Core/Config.cpp b/Core/Config.cpp index 8a6f4a9974..d55ae00703 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1301,6 +1301,15 @@ void Config::SetAppendedConfigIni(const Path &path) { appendedConfigFileName_ = path; } +void Config::updateAfterSettingAutoFrameSkip() { + if (bAutoFrameSkip && iFrameSkip == 0) { + iFrameSkip = 1; + } + + if (bAutoFrameSkip && bSkipBufferEffects) { + bSkipBufferEffects = false; + } +} void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (!bUpdatedInstanceCounter) { diff --git a/Core/Config.h b/Core/Config.h index c6f0f1673e..4e9bd0e3d2 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -572,7 +572,10 @@ public: const std::map> &GetLangValuesMapping(); bool LoadAppendedConfig(); void SetAppendedConfigIni(const Path &path); - + + + void updateAfterSettingAutoFrameSkip(); + protected: void LoadStandardControllerIni(); void LoadLangValuesMapping(); diff --git a/SDL/MacOSBarItems.h b/SDL/MacOSBarItems.h new file mode 100644 index 0000000000..379530e362 --- /dev/null +++ b/SDL/MacOSBarItems.h @@ -0,0 +1,21 @@ +// +// MacOSBarItems.h +// PPSSPP +// +// Created by Serena on 06/02/2023. +// + +#ifndef MacOSBarItems_h +#define MacOSBarItems_h + +#ifdef __cplusplus +extern "C" { +#endif + +void initBarItemsForApp(); + +#ifdef __cplusplus +} +#endif + +#endif /* MacOSBarItems_h */ diff --git a/SDL/MacOSBarItems.mm b/SDL/MacOSBarItems.mm new file mode 100644 index 0000000000..1e262a0158 --- /dev/null +++ b/SDL/MacOSBarItems.mm @@ -0,0 +1,326 @@ +// +// MacOSBarItems.mm +// PPSSPP +// +// Created by Serena on 06/02/2023. +// + +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Core/Config.h" +#include "Common/Data/Text/I18n.h" +#include "Common/StringUtils.h" +#import + +#ifdef __cplusplus +extern "C" { +#endif + +// NSMenuItem requires the use of an objective-c selector (aka the devil's greatest trick) +// So we have to make this class +@interface BarItemsManager : NSObject ++(instancetype)sharedInstance; +-(void)setupAppBarItems; +@property (assign) NSMenu *openMenu; +@property (assign) std::shared_ptr mainSettingsLocalization; +@end + +void initBarItemsForApp() { + [[BarItemsManager sharedInstance] setupAppBarItems]; +} + +// im soooooo sorry for whoever had to read this impl +@implementation BarItemsManager ++ (instancetype)sharedInstance { + static BarItemsManager *stub; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + stub = [BarItemsManager new]; + stub.mainSettingsLocalization = GetI18NCategory("MainSettings"); + }); + + return stub; +} + +-(void)setupAppBarItems { + NSMenuItem *openMenuItem = [[NSMenuItem alloc] init]; + openMenuItem.submenu = [self makeOpenSubmenu]; + + NSMenuItem *graphicsMenuItem = [[NSMenuItem alloc] init]; + graphicsMenuItem.submenu = [self makeGraphicsMenu]; + + NSMenuItem *audioMenuItem = [[NSMenuItem alloc] init]; + audioMenuItem.submenu = [self makeAudioMenu]; + + [NSApplication.sharedApplication.menu addItem:openMenuItem]; + [NSApplication.sharedApplication.menu addItem:graphicsMenuItem]; + [NSApplication.sharedApplication.menu addItem:audioMenuItem]; +} + +-(NSMenu *)makeOpenSubmenu { + NSMenu *menu = [[NSMenu alloc] initWithTitle:@"File"]; + NSMenuItem *openWithSystemFolderBrowserItem = [[NSMenuItem alloc] initWithTitle:@"Open..." action:@selector(openSystemFileBrowser) keyEquivalent:@"o"]; + openWithSystemFolderBrowserItem.keyEquivalentModifierMask = NSEventModifierFlagCommand; + openWithSystemFolderBrowserItem.enabled = YES; + openWithSystemFolderBrowserItem.target = self; + [menu addItem:openWithSystemFolderBrowserItem]; + self.openMenu = menu; + + [self addOpenRecentlyItem]; + return menu; +} + +-(NSMenu *)makeGraphicsMenu { + NSMenu *parent = [[NSMenu alloc] initWithTitle:@(self.mainSettingsLocalization->T("Graphics"))]; + NSMenu *backendsMenu = [[NSMenu alloc] init]; + + auto graphicsLocalization = GetI18NCategory("Graphics"); +#define GRAPHICS_LOCALIZED(key) @(graphicsLocalization->T(key)) + + NSMenuItem *gpuBackendItem = [[NSMenuItem alloc] initWithTitle:GRAPHICS_LOCALIZED("Backend") action:nil keyEquivalent:@""]; + + std::vector allowed = [self allowedGPUBackends]; + for (int i = 0; i < allowed.size(); i++) { + NSMenuItem *backendMenuItem = [[NSMenuItem alloc] initWithTitle:@(GPUBackendToString(allowed[i]).c_str()) action: @selector(setCurrentGPUBackend:) keyEquivalent: @""]; + backendMenuItem.tag = i; + backendMenuItem.target = self; + backendMenuItem.state = [self controlStateForBool: g_Config.iGPUBackend == (int)allowed[i]]; + [backendsMenu addItem:backendMenuItem]; + } + + gpuBackendItem.submenu = backendsMenu; + [parent addItem:gpuBackendItem]; + + [parent addItem:[NSMenuItem separatorItem]]; + +#define MENU_ITEM(variableName, localizedTitleName, SEL, ConfigurationValueName) \ +NSMenuItem *variableName = [[NSMenuItem alloc] initWithTitle:GRAPHICS_LOCALIZED(localizedTitleName) action:SEL keyEquivalent:@""]; \ +variableName.target = self; \ +variableName.state = [self controlStateForBool: ConfigurationValueName]; + + MENU_ITEM(softwareRendering, "Software Rendering", @selector(toggleSoftwareRendering:), g_Config.bSoftwareRendering) + [parent addItem:softwareRendering]; + + MENU_ITEM(vsyncItem, "VSync", @selector(toggleVSync:), g_Config.bVSync) + [parent addItem:vsyncItem]; + + MENU_ITEM(fullScreenItem, "Fullscreen", @selector(toggleFullScreen:), g_Config.bFullScreen) + [parent addItem:fullScreenItem]; + + [parent addItem:[NSMenuItem separatorItem]]; + + MENU_ITEM(autoFrameSkip, "Auto FrameSkip", @selector(toggleAutoFrameSkip:), g_Config.bAutoFrameSkip) + [parent addItem:autoFrameSkip]; + + [parent addItem:[NSMenuItem separatorItem]]; + + MENU_ITEM(fpsCounterItem, "Show FPS Counter", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) + fpsCounterItem.tag = (int)ShowStatusFlags::FPS_COUNTER; + + MENU_ITEM(speedCounterItem, "Show Speed", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) + speedCounterItem.tag = (int)ShowStatusFlags::SPEED_COUNTER; + + MENU_ITEM(batteryPercentItem, "Show battery %", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT) + batteryPercentItem.tag = (int)ShowStatusFlags::BATTERY_PERCENT; + + [parent addItem:[NSMenuItem separatorItem]]; + [parent addItem:fpsCounterItem]; + [parent addItem:speedCounterItem]; + [parent addItem:batteryPercentItem]; + + [[NSNotificationCenter defaultCenter] addObserverForName:@"ConfigDidChange" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + NSString *value = [note object]; + // NOTE: Though it may seem like it, + // the next few lines were not written by yandere dev + if ([value isEqualToString:@"VSync"]) { + vsyncItem.state = [self controlStateForBool: g_Config.bVSync]; + } else if ([value isEqualToString:@"FullScreen"]) { + fullScreenItem.state = [self controlStateForBool: g_Config.bFullScreen]; + } else if ([value isEqualToString:@"SoftwareRendering"]) { + softwareRendering.state = [self controlStateForBool: g_Config.bSoftwareRendering]; + } else if ([value isEqualToString:@"AutoFrameSkip"]) { + autoFrameSkip.state = [self controlStateForBool: g_Config.bAutoFrameSkip]; + } else if ([value isEqualToString:@"ShowFPSCounter"]) { + fpsCounterItem.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER]; + } else if ([value isEqualToString:@"ShowSpeed"]) { + speedCounterItem.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER]; + } else if ([value isEqualToString:@"BatteryPercent"]) { + batteryPercentItem.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT]; + } + }]; +#undef MENU_ITEM +#undef GRAPHICS_LOCALIZED + return parent; +} + +-(NSMenu *)makeAudioMenu { + NSMenu *parent = [[NSMenu alloc] initWithTitle:@(self.mainSettingsLocalization->T("Audio"))]; + auto audioLocalization = GetI18NCategory("Audio"); + + NSMenuItem *enableSoundItem = [[NSMenuItem alloc] initWithTitle:@(audioLocalization->T("Enable Sound")) action:@selector(toggleSound:) keyEquivalent:@""]; + enableSoundItem.target = self; + enableSoundItem.state = [self controlStateForBool: g_Config.bEnableSound]; + [parent addItem:enableSoundItem]; + + NSMenuItem *deviceListItem = [[NSMenuItem alloc] initWithTitle:@(audioLocalization->T("Device")) action:nil keyEquivalent:@""]; + deviceListItem.submenu = [self makeAudioListMenuWithItem:deviceListItem]; + [parent addItem:deviceListItem]; + + [[NSNotificationCenter defaultCenter] addObserverForName:@"AudioConfChanged" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + NSString *value = [note object]; + if ([value isEqualToString:@"EnableSound"]) { + enableSoundItem.state = [self controlStateForBool:g_Config.bEnableSound]; + } + }]; + + return parent; +} + +-(NSMenu *)makeAudioListMenuWithItem: (NSMenuItem *)callerItem { + __block NSMenu *theMenu = [[NSMenu alloc] init]; + std::vector audioDeviceList; + SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); + + for (int i = 0; i < audioDeviceList.size(); i++) { + std::string itemName = audioDeviceList[i]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@(itemName.c_str()) action:@selector(setAudioItem:) keyEquivalent:@""]; + item.tag = i; + item.target = self; + item.state = [self controlStateForBool:g_Config.sAudioDevice == itemName]; + [theMenu addItem:item]; + } + + [[NSNotificationCenter defaultCenter] addObserverForName:@"AudioConfigurationHasChanged" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + NSString *value = [note object]; + if ([value isEqualToString: @"DeviceAddedOrChanged"]) { + callerItem.submenu = [self makeAudioListMenuWithItem:callerItem]; + } else if ([value isEqualToString:@"CurrentDeviceWasChanged"]) { + // set the new item to be the selected one + dispatch_async(dispatch_get_main_queue(), ^{ + for (NSMenuItem *item in theMenu.itemArray) + item.state = [self controlStateForBool:g_Config.sAudioDevice == audioDeviceList[item.tag]]; + }); + } + }]; + + return theMenu; +} + +-(void) setAudioItem: (NSMenuItem *)sender { + std::vector audioDeviceList; + SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); + + std::string theItemSelected = audioDeviceList[sender.tag]; + if (theItemSelected == g_Config.sAudioDevice) + return; // device already selected + + g_Config.sAudioDevice = theItemSelected; + for (NSMenuItem *item in sender.menu.itemArray) { + item.state = [self controlStateForBool:g_Config.sAudioDevice == theItemSelected]; + } + + System_SendMessage("audio_resetDevice", ""); +} + +#define TOGGLE_METHOD(name, ConfigValueName, ...) \ +-(void)toggle##name: (NSMenuItem *)item { \ +ConfigValueName = !ConfigValueName; \ +__VA_ARGS__; /* for any additional updates */ \ +item.state = [self controlStateForBool: ConfigValueName]; \ +} + +TOGGLE_METHOD(Sound, g_Config.bEnableSound) +TOGGLE_METHOD(AutoFrameSkip, g_Config.bAutoFrameSkip, g_Config.updateAfterSettingAutoFrameSkip()) +TOGGLE_METHOD(SoftwareRendering, g_Config.bSoftwareRendering) +TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0")) +TOGGLE_METHOD(VSync, g_Config.bVSync) +#undef TOGGLE_METHOD + +-(void)setToggleShowCounterItem: (NSMenuItem *)item { + [self addOrRemoveInteger:(int)item.tag to:&g_Config.iShowStatusFlags]; + item.state = [self controlStateForBool:g_Config.iShowStatusFlags & item.tag]; +} + +-(void)addOrRemoveInteger: (int)integer to: (int *)r { + if (integer & *r) { + *r -= integer; + } else { + *r |= integer; + } +} + +-(void)setCurrentGPUBackend: (NSMenuItem *)sender { + std::vector allowed = [self allowedGPUBackends]; + if (allowed.size() == 1) { + printf("only one item, bailing"); + return; + } + + g_Config.iGPUBackend = (int)(allowed[sender.tag]); + sender.state = NSControlStateValueOn; + + for (NSMenuItem *item in sender.menu.itemArray) { + // deselect the previously selected item + if (item.state == NSControlStateValueOn && item.tag != sender.tag) { + item.state = NSControlStateValueOff; + break; + } + } +} + +-(NSControlStateValue) controlStateForBool: (BOOL)boolValue { + return boolValue ? NSControlStateValueOn : NSControlStateValueOff; +} + +-(std::vector)allowedGPUBackends { + std::vector allBackends = { + GPUBackend::OPENGL, GPUBackend::VULKAN, + GPUBackend::DIRECT3D11, GPUBackend::DIRECT3D9 + }; + + std::vector allowed; + + for (GPUBackend backend : allBackends) { + if (g_Config.IsBackendEnabled(backend)) { + allowed.push_back(backend); + } + } + + return allowed; +} + +-(void)addOpenRecentlyItem { + std::vector recentIsos = g_Config.RecentIsos(); + NSMenuItem *openRecent = [[NSMenuItem alloc] initWithTitle:@"Open Recent" action:nil keyEquivalent:@""]; + NSMenu *recentsMenu = [[NSMenu alloc] init]; + if (recentIsos.empty()) + openRecent.enabled = NO; + + for (int i = 0; i < recentIsos.size(); i++) { + std::string filename = Path(recentIsos[i]).GetFilename(); + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@(filename.c_str()) action:@selector(openRecentItem:) keyEquivalent:@""]; + item.target = self; + [recentsMenu addItem:item]; + } + + openRecent.submenu = recentsMenu; + [self.openMenu addItem:openRecent]; +} + +-(void)openRecentItem: (NSMenuItem *)item { + NativeMessageReceived("browse_fileSelect", g_Config.RecentIsos()[item.tag].c_str()); +} + +-(void)openSystemFileBrowser { + System_SendMessage("browse_folder", ""); +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +@end + +#ifdef __cplusplus +} +#endif diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index dea43f64f0..579f26fa80 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -62,6 +62,10 @@ SDLJoystick *joystick = NULL; #include "UI/DarwinFileSystemServices.h" #endif +#if PPSSPP_PLATFORM(MAC) +#include "MacOSBarItems.h" +#endif + GlobalUIState lastUIState = UISTATE_MENU; GlobalUIState GetUIState(); @@ -846,6 +850,12 @@ int main(int argc, char *argv[]) { int mouseWheelMovedDownFrames = 0; bool mouseCaptured = false; bool windowHidden = false; + +#if PPSSPP_PLATFORM(MAC) + // setup menu items for macOS + initBarItemsForApp(); +#endif + while (true) { double startTime = time_now_d(); @@ -1144,6 +1154,7 @@ int main(int argc, char *argv[]) { if (doAutoSwitch || g_Config.sAudioDevice == name) { StopSDLAudioDevice(); InitSDLAudioDevice(name ? name : ""); + PostDarwinNotificationIfPossible("AudioConfigurationHasChanged", "DeviceAddedOrChanged"); } } break; @@ -1151,6 +1162,7 @@ int main(int argc, char *argv[]) { if (event.adevice.iscapture == 0 && event.adevice.which == audioDev) { StopSDLAudioDevice(); InitSDLAudioDevice(); + PostDarwinNotificationIfPossible("AudioConfigurationHasChanged", "DeviceAddedOrChanged"); } break; #endif diff --git a/UI/DarwinFileSystemServices.h b/UI/DarwinFileSystemServices.h index f49d053d42..de4337aee1 100644 --- a/UI/DarwinFileSystemServices.h +++ b/UI/DarwinFileSystemServices.h @@ -32,3 +32,13 @@ private: void *__pickerDelegate = NULL; #endif // PPSSPP_PLATFORM(IOS) }; + +void PostDarwinNotification(const char *name, const char *value); + +#if PPSSPP_PLATFORM(MAC) +// Currently, this is just macOS only +// to update the top bar +#define PostDarwinNotificationIfPossible(name, value) PostDarwinNotification(name, value) +#else +#define PostDarwinNotificationIfPossible(name, value) +#endif diff --git a/UI/DarwinFileSystemServices.mm b/UI/DarwinFileSystemServices.mm index 50d9f94ec6..88987c350e 100644 --- a/UI/DarwinFileSystemServices.mm +++ b/UI/DarwinFileSystemServices.mm @@ -109,3 +109,7 @@ void DarwinFileSystemServices::setUserPreferredMemoryStickDirectory(Path path) { forKey:@(PreferredMemoryStickUserDefaultsKey)]; g_Config.memStickDirectory = path; } + +void PostDarwinNotification(const char *name, const char *value) { + [[NSNotificationCenter defaultCenter] postNotificationName:@(name) object: @(value)]; +} diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 276ee7cda3..3b0d8b7ed4 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -95,6 +95,17 @@ extern AndroidAudioState *g_audioState; #endif +#if PPSSPP_PLATFORM(MAC) +#define OnClickPostDarwinNotification(Target, NotifName, NotifValue) \ +Target->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { \ + PostDarwinNotificationIfPossible(NotifName, NotifValue); \ + return UI::EVENT_DONE; \ +}); + +#else +#define OnClickPostDarwinNotification +#endif + GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) { prevInflightFrames_ = g_Config.iInflightFrames; @@ -347,6 +358,7 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) if (deviceType != DEVICE_TYPE_VR) { CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); + OnClickPostDarwinNotification(softwareGPU, "ConfigDidChange", "SoftwareRendering") softwareGPU->SetEnabled(!PSP_IsInited()); } @@ -381,10 +393,7 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) #if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); - vSync->OnClick.Add([=](EventParams &e) { - NativeResized(); - return UI::EVENT_CONTINUE; - }); + OnClickPostDarwinNotification(vSync, "ConfigDidChange", "VSync") #endif #if PPSSPP_PLATFORM(ANDROID) @@ -601,10 +610,13 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) }); graphicsSettings->Add(new ItemHeader(gr->T("Overlay Information"))); - graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::FPS_COUNTER, gr->T("Show FPS Counter"))); - graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::SPEED_COUNTER, gr->T("Show Speed"))); + BitCheckBox *showFPSCtr = graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::FPS_COUNTER, gr->T("Show FPS Counter"))); + OnClickPostDarwinNotification(showFPSCtr, "ConfigDidChange", "ShowFPSCounter") + BitCheckBox *showSpeed = graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::SPEED_COUNTER, gr->T("Show Speed"))); + OnClickPostDarwinNotification(showSpeed, "ConfigDidChange", "ShowSpeed") #ifdef CAN_DISPLAY_CURRENT_BATTERY_CAPACITY - graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::BATTERY_PERCENT, gr->T("Show Battery %"))); + BitCheckBox *showBattery = graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::BATTERY_PERCENT, gr->T("Show Battery %"))); + OnClickPostDarwinNotification(showBattery, "ConfigDidChange", "BatteryPercent") #endif graphicsSettings->Add(new CheckBox(&g_Config.bShowDebugStats, gr->T("Show Debug Statistics")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting); @@ -617,8 +629,9 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) { auto ms = GetI18NCategory("MainSettings"); audioSettings->Add(new ItemHeader(ms->T("Audio"))); - audioSettings->Add(new CheckBox(&g_Config.bEnableSound, a->T("Enable Sound"))); - + CheckBox *enableSound = audioSettings->Add(new CheckBox(&g_Config.bEnableSound,a->T("Enable Sound"))); + OnClickPostDarwinNotification(enableSound, "AudioConfChanged", "EnableSound") + PopupSliderChoice *volume = audioSettings->Add(new PopupSliderChoice(&g_Config.iGlobalVolume, VOLUME_OFF, VOLUME_FULL, a->T("Global volume"), screenManager())); volume->SetEnabledPtr(&g_Config.bEnableSound); volume->SetZeroLabel(a->T("Mute")); @@ -1163,7 +1176,7 @@ UI::LinearLayout *GameSettingsScreen::AddTab(const char *tag, const std::string contents->SetSpacing(0); scroll->Add(contents); tabHolder_->AddTab(title, scroll); - + if (!isSearch) { settingTabContents_.push_back(contents); @@ -1176,12 +1189,8 @@ UI::LinearLayout *GameSettingsScreen::AddTab(const char *tag, const std::string } UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) { - if (g_Config.bAutoFrameSkip && g_Config.iFrameSkip == 0) { - g_Config.iFrameSkip = 1; - } - if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) { - g_Config.bSkipBufferEffects = false; - } + g_Config.updateAfterSettingAutoFrameSkip(); + PostDarwinNotificationIfPossible("ConfigChanged", "AutoFrameSkip"); return UI::EVENT_DONE; } @@ -1326,12 +1335,14 @@ UI::EventReturn GameSettingsScreen::OnChangeBackground(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnFullscreenChange(UI::EventParams &e) { + PostDarwinNotificationIfPossible("ConfigDidChange", "FullScreen"); g_Config.iForceFullScreen = -1; System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0"); return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnFullscreenMultiChange(UI::EventParams &e) { + PostDarwinNotificationIfPossible("ConfigDidChange", "FullScreen"); System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0"); return UI::EVENT_DONE; } @@ -1563,6 +1574,7 @@ UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) { g_Config.sAudioDevice.clear(); } System_SendMessage("audio_resetDevice", ""); + PostDarwinNotificationIfPossible("AudioConfigurationHasChanged", "CurrentDeviceWasChanged"); return UI::EVENT_DONE; } diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index ed600b42d3..bda898fb3b 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1260,12 +1260,10 @@ void MainScreen::sendMessage(const char *message, const char *value) { } if (!strcmp(message, "browse_folderSelect")) { std::string filename = value; - INFO_LOG(SYSTEM, "Got folder: '%s'", filename.c_str()); - int tab = tabHolder_->GetCurrentTab(); - // Don't allow browsing in the other tabs (I don't think it's possible to reach the option though) - if (tab == 1) { - gameBrowsers_[tab]->SetPath(Path(filename)); - } + INFO_LOG(SYSTEM, "Got folder: '%s'", filename.c_str());; + // switch to the 'Games' tab which has the file browser + tabHolder_->SetCurrentTab(1); + gameBrowsers_[1]->SetPath(Path(filename)); } } if (!strcmp(message, "permission_granted") && !strcmp(value, "storage")) { From cfe6ac5e03275c3d3ff17b7a25459cf23fb305d9 Mon Sep 17 00:00:00 2001 From: Serena Date: Mon, 6 Feb 2023 22:20:35 +0300 Subject: [PATCH 2/9] EMERGENCY FIX --- UI/GameSettingsScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 3b0d8b7ed4..9355fa8965 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -630,7 +630,7 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) { audioSettings->Add(new ItemHeader(ms->T("Audio"))); CheckBox *enableSound = audioSettings->Add(new CheckBox(&g_Config.bEnableSound,a->T("Enable Sound"))); - OnClickPostDarwinNotification(enableSound, "AudioConfChanged", "EnableSound") + OnClickPostDarwinNotification(enableSound, "AudioConfChanged", "EnableSound") PopupSliderChoice *volume = audioSettings->Add(new PopupSliderChoice(&g_Config.iGlobalVolume, VOLUME_OFF, VOLUME_FULL, a->T("Global volume"), screenManager())); volume->SetEnabledPtr(&g_Config.bEnableSound); From 070194ef921e2a801adb88d5143c6e8e243ff37c Mon Sep 17 00:00:00 2001 From: Serena Date: Mon, 6 Feb 2023 22:34:27 +0300 Subject: [PATCH 3/9] fix on other platforms --- SDL/SDLMain.cpp | 2 ++ UI/DarwinFileSystemServices.h | 2 -- UI/GameSettingsScreen.cpp | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 579f26fa80..68e792f7b7 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -60,6 +60,8 @@ SDLJoystick *joystick = NULL; #if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) #include "UI/DarwinFileSystemServices.h" +#else +#define PostDarwinNotificationIfPossible(name, value) #endif #if PPSSPP_PLATFORM(MAC) diff --git a/UI/DarwinFileSystemServices.h b/UI/DarwinFileSystemServices.h index de4337aee1..53f7fc655d 100644 --- a/UI/DarwinFileSystemServices.h +++ b/UI/DarwinFileSystemServices.h @@ -39,6 +39,4 @@ void PostDarwinNotification(const char *name, const char *value); // Currently, this is just macOS only // to update the top bar #define PostDarwinNotificationIfPossible(name, value) PostDarwinNotification(name, value) -#else -#define PostDarwinNotificationIfPossible(name, value) #endif diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9355fa8965..ffd82fd1fb 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -103,6 +103,7 @@ Target->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { \ }); #else +#define PostDarwinNotificationIfPossible(name, value) #define OnClickPostDarwinNotification #endif From c64aa9d19abf4530e41316c282d82e5f98706eee Mon Sep 17 00:00:00 2001 From: Serena Date: Tue, 14 Feb 2023 19:11:32 +0300 Subject: [PATCH 4/9] address concerns --- CMakeLists.txt | 4 +- Core/Config.cpp | 2 +- Core/Config.h | 4 +- SDL/MacOSBarItems.h | 21 --- SDL/MacOSBarItems.mm | 326 ---------------------------------- SDL/SDLMain.cpp | 10 +- UI/DarwinFileSystemServices.h | 7 - UI/GameSettingsScreen.cpp | 28 +-- 8 files changed, 12 insertions(+), 390 deletions(-) delete mode 100644 SDL/MacOSBarItems.h delete mode 100644 SDL/MacOSBarItems.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 82887d0a59..27dfcf93ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1231,9 +1231,9 @@ elseif(TARGET SDL2::SDL2) endif() set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) if(APPLE) - set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm SDL/SDLCocoaMetalLayer.h SDL/SDLCocoaMetalLayer.mm SDL/MacOSBarItems.mm SDL/MacOSBarItems.h UI/DarwinFileSystemServices.mm UI/DarwinFileSystemServices.h Common/Battery/AppleBatteryClient.m) + set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm SDL/SDLCocoaMetalLayer.h SDL/SDLCocoaMetalLayer.mm SDL/CocoaBarItems.mm SDL/CocoaBarItems.h UI/DarwinFileSystemServices.mm UI/DarwinFileSystemServices.h Common/Battery/AppleBatteryClient.m) set_source_files_properties(UI/DarwinFileSystemServices.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) - set_source_files_properties(SDL/MacOSBarItems.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) + set_source_files_properties(SDL/CocoaBarItems.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) set_source_files_properties(Common/Battery/AppleBatteryClient.m PROPERTIES COMPILE_FLAGS -fobjc-arc) set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${IOKIT_LIBRARY}) elseif(USING_EGL) diff --git a/Core/Config.cpp b/Core/Config.cpp index d55ae00703..bbfa50c66c 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1301,7 +1301,7 @@ void Config::SetAppendedConfigIni(const Path &path) { appendedConfigFileName_ = path; } -void Config::updateAfterSettingAutoFrameSkip() { +void Config::UpdateAfterSettingAutoFrameSkip() { if (bAutoFrameSkip && iFrameSkip == 0) { iFrameSkip = 1; } diff --git a/Core/Config.h b/Core/Config.h index 4e9bd0e3d2..e6c0dbbea1 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -573,9 +573,7 @@ public: bool LoadAppendedConfig(); void SetAppendedConfigIni(const Path &path); - - void updateAfterSettingAutoFrameSkip(); - + void UpdateAfterSettingAutoFrameSkip(); protected: void LoadStandardControllerIni(); void LoadLangValuesMapping(); diff --git a/SDL/MacOSBarItems.h b/SDL/MacOSBarItems.h deleted file mode 100644 index 379530e362..0000000000 --- a/SDL/MacOSBarItems.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// MacOSBarItems.h -// PPSSPP -// -// Created by Serena on 06/02/2023. -// - -#ifndef MacOSBarItems_h -#define MacOSBarItems_h - -#ifdef __cplusplus -extern "C" { -#endif - -void initBarItemsForApp(); - -#ifdef __cplusplus -} -#endif - -#endif /* MacOSBarItems_h */ diff --git a/SDL/MacOSBarItems.mm b/SDL/MacOSBarItems.mm deleted file mode 100644 index 1e262a0158..0000000000 --- a/SDL/MacOSBarItems.mm +++ /dev/null @@ -1,326 +0,0 @@ -// -// MacOSBarItems.mm -// PPSSPP -// -// Created by Serena on 06/02/2023. -// - -#include "Common/System/System.h" -#include "Common/System/NativeApp.h" -#include "Core/Config.h" -#include "Common/Data/Text/I18n.h" -#include "Common/StringUtils.h" -#import - -#ifdef __cplusplus -extern "C" { -#endif - -// NSMenuItem requires the use of an objective-c selector (aka the devil's greatest trick) -// So we have to make this class -@interface BarItemsManager : NSObject -+(instancetype)sharedInstance; --(void)setupAppBarItems; -@property (assign) NSMenu *openMenu; -@property (assign) std::shared_ptr mainSettingsLocalization; -@end - -void initBarItemsForApp() { - [[BarItemsManager sharedInstance] setupAppBarItems]; -} - -// im soooooo sorry for whoever had to read this impl -@implementation BarItemsManager -+ (instancetype)sharedInstance { - static BarItemsManager *stub; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - stub = [BarItemsManager new]; - stub.mainSettingsLocalization = GetI18NCategory("MainSettings"); - }); - - return stub; -} - --(void)setupAppBarItems { - NSMenuItem *openMenuItem = [[NSMenuItem alloc] init]; - openMenuItem.submenu = [self makeOpenSubmenu]; - - NSMenuItem *graphicsMenuItem = [[NSMenuItem alloc] init]; - graphicsMenuItem.submenu = [self makeGraphicsMenu]; - - NSMenuItem *audioMenuItem = [[NSMenuItem alloc] init]; - audioMenuItem.submenu = [self makeAudioMenu]; - - [NSApplication.sharedApplication.menu addItem:openMenuItem]; - [NSApplication.sharedApplication.menu addItem:graphicsMenuItem]; - [NSApplication.sharedApplication.menu addItem:audioMenuItem]; -} - --(NSMenu *)makeOpenSubmenu { - NSMenu *menu = [[NSMenu alloc] initWithTitle:@"File"]; - NSMenuItem *openWithSystemFolderBrowserItem = [[NSMenuItem alloc] initWithTitle:@"Open..." action:@selector(openSystemFileBrowser) keyEquivalent:@"o"]; - openWithSystemFolderBrowserItem.keyEquivalentModifierMask = NSEventModifierFlagCommand; - openWithSystemFolderBrowserItem.enabled = YES; - openWithSystemFolderBrowserItem.target = self; - [menu addItem:openWithSystemFolderBrowserItem]; - self.openMenu = menu; - - [self addOpenRecentlyItem]; - return menu; -} - --(NSMenu *)makeGraphicsMenu { - NSMenu *parent = [[NSMenu alloc] initWithTitle:@(self.mainSettingsLocalization->T("Graphics"))]; - NSMenu *backendsMenu = [[NSMenu alloc] init]; - - auto graphicsLocalization = GetI18NCategory("Graphics"); -#define GRAPHICS_LOCALIZED(key) @(graphicsLocalization->T(key)) - - NSMenuItem *gpuBackendItem = [[NSMenuItem alloc] initWithTitle:GRAPHICS_LOCALIZED("Backend") action:nil keyEquivalent:@""]; - - std::vector allowed = [self allowedGPUBackends]; - for (int i = 0; i < allowed.size(); i++) { - NSMenuItem *backendMenuItem = [[NSMenuItem alloc] initWithTitle:@(GPUBackendToString(allowed[i]).c_str()) action: @selector(setCurrentGPUBackend:) keyEquivalent: @""]; - backendMenuItem.tag = i; - backendMenuItem.target = self; - backendMenuItem.state = [self controlStateForBool: g_Config.iGPUBackend == (int)allowed[i]]; - [backendsMenu addItem:backendMenuItem]; - } - - gpuBackendItem.submenu = backendsMenu; - [parent addItem:gpuBackendItem]; - - [parent addItem:[NSMenuItem separatorItem]]; - -#define MENU_ITEM(variableName, localizedTitleName, SEL, ConfigurationValueName) \ -NSMenuItem *variableName = [[NSMenuItem alloc] initWithTitle:GRAPHICS_LOCALIZED(localizedTitleName) action:SEL keyEquivalent:@""]; \ -variableName.target = self; \ -variableName.state = [self controlStateForBool: ConfigurationValueName]; - - MENU_ITEM(softwareRendering, "Software Rendering", @selector(toggleSoftwareRendering:), g_Config.bSoftwareRendering) - [parent addItem:softwareRendering]; - - MENU_ITEM(vsyncItem, "VSync", @selector(toggleVSync:), g_Config.bVSync) - [parent addItem:vsyncItem]; - - MENU_ITEM(fullScreenItem, "Fullscreen", @selector(toggleFullScreen:), g_Config.bFullScreen) - [parent addItem:fullScreenItem]; - - [parent addItem:[NSMenuItem separatorItem]]; - - MENU_ITEM(autoFrameSkip, "Auto FrameSkip", @selector(toggleAutoFrameSkip:), g_Config.bAutoFrameSkip) - [parent addItem:autoFrameSkip]; - - [parent addItem:[NSMenuItem separatorItem]]; - - MENU_ITEM(fpsCounterItem, "Show FPS Counter", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER) - fpsCounterItem.tag = (int)ShowStatusFlags::FPS_COUNTER; - - MENU_ITEM(speedCounterItem, "Show Speed", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER) - speedCounterItem.tag = (int)ShowStatusFlags::SPEED_COUNTER; - - MENU_ITEM(batteryPercentItem, "Show battery %", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT) - batteryPercentItem.tag = (int)ShowStatusFlags::BATTERY_PERCENT; - - [parent addItem:[NSMenuItem separatorItem]]; - [parent addItem:fpsCounterItem]; - [parent addItem:speedCounterItem]; - [parent addItem:batteryPercentItem]; - - [[NSNotificationCenter defaultCenter] addObserverForName:@"ConfigDidChange" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { - NSString *value = [note object]; - // NOTE: Though it may seem like it, - // the next few lines were not written by yandere dev - if ([value isEqualToString:@"VSync"]) { - vsyncItem.state = [self controlStateForBool: g_Config.bVSync]; - } else if ([value isEqualToString:@"FullScreen"]) { - fullScreenItem.state = [self controlStateForBool: g_Config.bFullScreen]; - } else if ([value isEqualToString:@"SoftwareRendering"]) { - softwareRendering.state = [self controlStateForBool: g_Config.bSoftwareRendering]; - } else if ([value isEqualToString:@"AutoFrameSkip"]) { - autoFrameSkip.state = [self controlStateForBool: g_Config.bAutoFrameSkip]; - } else if ([value isEqualToString:@"ShowFPSCounter"]) { - fpsCounterItem.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER]; - } else if ([value isEqualToString:@"ShowSpeed"]) { - speedCounterItem.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER]; - } else if ([value isEqualToString:@"BatteryPercent"]) { - batteryPercentItem.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT]; - } - }]; -#undef MENU_ITEM -#undef GRAPHICS_LOCALIZED - return parent; -} - --(NSMenu *)makeAudioMenu { - NSMenu *parent = [[NSMenu alloc] initWithTitle:@(self.mainSettingsLocalization->T("Audio"))]; - auto audioLocalization = GetI18NCategory("Audio"); - - NSMenuItem *enableSoundItem = [[NSMenuItem alloc] initWithTitle:@(audioLocalization->T("Enable Sound")) action:@selector(toggleSound:) keyEquivalent:@""]; - enableSoundItem.target = self; - enableSoundItem.state = [self controlStateForBool: g_Config.bEnableSound]; - [parent addItem:enableSoundItem]; - - NSMenuItem *deviceListItem = [[NSMenuItem alloc] initWithTitle:@(audioLocalization->T("Device")) action:nil keyEquivalent:@""]; - deviceListItem.submenu = [self makeAudioListMenuWithItem:deviceListItem]; - [parent addItem:deviceListItem]; - - [[NSNotificationCenter defaultCenter] addObserverForName:@"AudioConfChanged" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { - NSString *value = [note object]; - if ([value isEqualToString:@"EnableSound"]) { - enableSoundItem.state = [self controlStateForBool:g_Config.bEnableSound]; - } - }]; - - return parent; -} - --(NSMenu *)makeAudioListMenuWithItem: (NSMenuItem *)callerItem { - __block NSMenu *theMenu = [[NSMenu alloc] init]; - std::vector audioDeviceList; - SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); - - for (int i = 0; i < audioDeviceList.size(); i++) { - std::string itemName = audioDeviceList[i]; - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@(itemName.c_str()) action:@selector(setAudioItem:) keyEquivalent:@""]; - item.tag = i; - item.target = self; - item.state = [self controlStateForBool:g_Config.sAudioDevice == itemName]; - [theMenu addItem:item]; - } - - [[NSNotificationCenter defaultCenter] addObserverForName:@"AudioConfigurationHasChanged" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { - NSString *value = [note object]; - if ([value isEqualToString: @"DeviceAddedOrChanged"]) { - callerItem.submenu = [self makeAudioListMenuWithItem:callerItem]; - } else if ([value isEqualToString:@"CurrentDeviceWasChanged"]) { - // set the new item to be the selected one - dispatch_async(dispatch_get_main_queue(), ^{ - for (NSMenuItem *item in theMenu.itemArray) - item.state = [self controlStateForBool:g_Config.sAudioDevice == audioDeviceList[item.tag]]; - }); - } - }]; - - return theMenu; -} - --(void) setAudioItem: (NSMenuItem *)sender { - std::vector audioDeviceList; - SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); - - std::string theItemSelected = audioDeviceList[sender.tag]; - if (theItemSelected == g_Config.sAudioDevice) - return; // device already selected - - g_Config.sAudioDevice = theItemSelected; - for (NSMenuItem *item in sender.menu.itemArray) { - item.state = [self controlStateForBool:g_Config.sAudioDevice == theItemSelected]; - } - - System_SendMessage("audio_resetDevice", ""); -} - -#define TOGGLE_METHOD(name, ConfigValueName, ...) \ --(void)toggle##name: (NSMenuItem *)item { \ -ConfigValueName = !ConfigValueName; \ -__VA_ARGS__; /* for any additional updates */ \ -item.state = [self controlStateForBool: ConfigValueName]; \ -} - -TOGGLE_METHOD(Sound, g_Config.bEnableSound) -TOGGLE_METHOD(AutoFrameSkip, g_Config.bAutoFrameSkip, g_Config.updateAfterSettingAutoFrameSkip()) -TOGGLE_METHOD(SoftwareRendering, g_Config.bSoftwareRendering) -TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0")) -TOGGLE_METHOD(VSync, g_Config.bVSync) -#undef TOGGLE_METHOD - --(void)setToggleShowCounterItem: (NSMenuItem *)item { - [self addOrRemoveInteger:(int)item.tag to:&g_Config.iShowStatusFlags]; - item.state = [self controlStateForBool:g_Config.iShowStatusFlags & item.tag]; -} - --(void)addOrRemoveInteger: (int)integer to: (int *)r { - if (integer & *r) { - *r -= integer; - } else { - *r |= integer; - } -} - --(void)setCurrentGPUBackend: (NSMenuItem *)sender { - std::vector allowed = [self allowedGPUBackends]; - if (allowed.size() == 1) { - printf("only one item, bailing"); - return; - } - - g_Config.iGPUBackend = (int)(allowed[sender.tag]); - sender.state = NSControlStateValueOn; - - for (NSMenuItem *item in sender.menu.itemArray) { - // deselect the previously selected item - if (item.state == NSControlStateValueOn && item.tag != sender.tag) { - item.state = NSControlStateValueOff; - break; - } - } -} - --(NSControlStateValue) controlStateForBool: (BOOL)boolValue { - return boolValue ? NSControlStateValueOn : NSControlStateValueOff; -} - --(std::vector)allowedGPUBackends { - std::vector allBackends = { - GPUBackend::OPENGL, GPUBackend::VULKAN, - GPUBackend::DIRECT3D11, GPUBackend::DIRECT3D9 - }; - - std::vector allowed; - - for (GPUBackend backend : allBackends) { - if (g_Config.IsBackendEnabled(backend)) { - allowed.push_back(backend); - } - } - - return allowed; -} - --(void)addOpenRecentlyItem { - std::vector recentIsos = g_Config.RecentIsos(); - NSMenuItem *openRecent = [[NSMenuItem alloc] initWithTitle:@"Open Recent" action:nil keyEquivalent:@""]; - NSMenu *recentsMenu = [[NSMenu alloc] init]; - if (recentIsos.empty()) - openRecent.enabled = NO; - - for (int i = 0; i < recentIsos.size(); i++) { - std::string filename = Path(recentIsos[i]).GetFilename(); - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@(filename.c_str()) action:@selector(openRecentItem:) keyEquivalent:@""]; - item.target = self; - [recentsMenu addItem:item]; - } - - openRecent.submenu = recentsMenu; - [self.openMenu addItem:openRecent]; -} - --(void)openRecentItem: (NSMenuItem *)item { - NativeMessageReceived("browse_fileSelect", g_Config.RecentIsos()[item.tag].c_str()); -} - --(void)openSystemFileBrowser { - System_SendMessage("browse_folder", ""); -} - -- (void)dealloc { - [NSNotificationCenter.defaultCenter removeObserver:self]; -} - -@end - -#ifdef __cplusplus -} -#endif diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 68e792f7b7..8e2bf12dfb 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -60,12 +60,10 @@ SDLJoystick *joystick = NULL; #if PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS) #include "UI/DarwinFileSystemServices.h" -#else -#define PostDarwinNotificationIfPossible(name, value) #endif #if PPSSPP_PLATFORM(MAC) -#include "MacOSBarItems.h" +#include "CocoaBarItems.h" #endif GlobalUIState lastUIState = UISTATE_MENU; @@ -854,8 +852,8 @@ int main(int argc, char *argv[]) { bool windowHidden = false; #if PPSSPP_PLATFORM(MAC) - // setup menu items for macOS - initBarItemsForApp(); + // setup menu items for macOS + initBarItemsForApp(); #endif while (true) { @@ -1156,7 +1154,6 @@ int main(int argc, char *argv[]) { if (doAutoSwitch || g_Config.sAudioDevice == name) { StopSDLAudioDevice(); InitSDLAudioDevice(name ? name : ""); - PostDarwinNotificationIfPossible("AudioConfigurationHasChanged", "DeviceAddedOrChanged"); } } break; @@ -1164,7 +1161,6 @@ int main(int argc, char *argv[]) { if (event.adevice.iscapture == 0 && event.adevice.which == audioDev) { StopSDLAudioDevice(); InitSDLAudioDevice(); - PostDarwinNotificationIfPossible("AudioConfigurationHasChanged", "DeviceAddedOrChanged"); } break; #endif diff --git a/UI/DarwinFileSystemServices.h b/UI/DarwinFileSystemServices.h index 53f7fc655d..bf12556a91 100644 --- a/UI/DarwinFileSystemServices.h +++ b/UI/DarwinFileSystemServices.h @@ -33,10 +33,3 @@ private: #endif // PPSSPP_PLATFORM(IOS) }; -void PostDarwinNotification(const char *name, const char *value); - -#if PPSSPP_PLATFORM(MAC) -// Currently, this is just macOS only -// to update the top bar -#define PostDarwinNotificationIfPossible(name, value) PostDarwinNotification(name, value) -#endif diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index ffd82fd1fb..9c7c6b5c5d 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -95,18 +95,6 @@ extern AndroidAudioState *g_audioState; #endif -#if PPSSPP_PLATFORM(MAC) -#define OnClickPostDarwinNotification(Target, NotifName, NotifValue) \ -Target->OnClick.Add([&](UI::EventParams &) -> UI::EventReturn { \ - PostDarwinNotificationIfPossible(NotifName, NotifValue); \ - return UI::EVENT_DONE; \ -}); - -#else -#define PostDarwinNotificationIfPossible(name, value) -#define OnClickPostDarwinNotification -#endif - GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) { prevInflightFrames_ = g_Config.iInflightFrames; @@ -359,7 +347,6 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) if (deviceType != DEVICE_TYPE_VR) { CheckBox *softwareGPU = graphicsSettings->Add(new CheckBox(&g_Config.bSoftwareRendering, gr->T("Software Rendering", "Software Rendering (slow)"))); - OnClickPostDarwinNotification(softwareGPU, "ConfigDidChange", "SoftwareRendering") softwareGPU->SetEnabled(!PSP_IsInited()); } @@ -394,7 +381,10 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) #if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS)) CheckBox *vSync = graphicsSettings->Add(new CheckBox(&g_Config.bVSync, gr->T("VSync"))); - OnClickPostDarwinNotification(vSync, "ConfigDidChange", "VSync") + vSync->OnClick.Add([=](EventParams &e) { + NativeResized(); + return UI::EVENT_CONTINUE; + }); #endif #if PPSSPP_PLATFORM(ANDROID) @@ -612,12 +602,9 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) graphicsSettings->Add(new ItemHeader(gr->T("Overlay Information"))); BitCheckBox *showFPSCtr = graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::FPS_COUNTER, gr->T("Show FPS Counter"))); - OnClickPostDarwinNotification(showFPSCtr, "ConfigDidChange", "ShowFPSCounter") BitCheckBox *showSpeed = graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::SPEED_COUNTER, gr->T("Show Speed"))); - OnClickPostDarwinNotification(showSpeed, "ConfigDidChange", "ShowSpeed") #ifdef CAN_DISPLAY_CURRENT_BATTERY_CAPACITY BitCheckBox *showBattery = graphicsSettings->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)ShowStatusFlags::BATTERY_PERCENT, gr->T("Show Battery %"))); - OnClickPostDarwinNotification(showBattery, "ConfigDidChange", "BatteryPercent") #endif graphicsSettings->Add(new CheckBox(&g_Config.bShowDebugStats, gr->T("Show Debug Statistics")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting); @@ -631,7 +618,6 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) { audioSettings->Add(new ItemHeader(ms->T("Audio"))); CheckBox *enableSound = audioSettings->Add(new CheckBox(&g_Config.bEnableSound,a->T("Enable Sound"))); - OnClickPostDarwinNotification(enableSound, "AudioConfChanged", "EnableSound") PopupSliderChoice *volume = audioSettings->Add(new PopupSliderChoice(&g_Config.iGlobalVolume, VOLUME_OFF, VOLUME_FULL, a->T("Global volume"), screenManager())); volume->SetEnabledPtr(&g_Config.bEnableSound); @@ -1190,8 +1176,7 @@ UI::LinearLayout *GameSettingsScreen::AddTab(const char *tag, const std::string } UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) { - g_Config.updateAfterSettingAutoFrameSkip(); - PostDarwinNotificationIfPossible("ConfigChanged", "AutoFrameSkip"); + g_Config.UpdateAfterSettingAutoFrameSkip(); return UI::EVENT_DONE; } @@ -1336,14 +1321,12 @@ UI::EventReturn GameSettingsScreen::OnChangeBackground(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnFullscreenChange(UI::EventParams &e) { - PostDarwinNotificationIfPossible("ConfigDidChange", "FullScreen"); g_Config.iForceFullScreen = -1; System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0"); return UI::EVENT_DONE; } UI::EventReturn GameSettingsScreen::OnFullscreenMultiChange(UI::EventParams &e) { - PostDarwinNotificationIfPossible("ConfigDidChange", "FullScreen"); System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0"); return UI::EVENT_DONE; } @@ -1575,7 +1558,6 @@ UI::EventReturn GameSettingsScreen::OnAudioDevice(UI::EventParams &e) { g_Config.sAudioDevice.clear(); } System_SendMessage("audio_resetDevice", ""); - PostDarwinNotificationIfPossible("AudioConfigurationHasChanged", "CurrentDeviceWasChanged"); return UI::EVENT_DONE; } From 6b0cec2ae0cd9e5133213c88811007dd7c71e74e Mon Sep 17 00:00:00 2001 From: Serena Date: Tue, 14 Feb 2023 19:11:44 +0300 Subject: [PATCH 5/9] i forgot this --- SDL/CocoaBarItems.h | 18 +++ SDL/CocoaBarItems.mm | 345 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 SDL/CocoaBarItems.h create mode 100644 SDL/CocoaBarItems.mm diff --git a/SDL/CocoaBarItems.h b/SDL/CocoaBarItems.h new file mode 100644 index 0000000000..b398869d58 --- /dev/null +++ b/SDL/CocoaBarItems.h @@ -0,0 +1,18 @@ +// +// CocoaBarItems.h +// PPSSPP +// +// Created by Serena on 06/02/2023. +// + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void initBarItemsForApp(); + +#ifdef __cplusplus +} +#endif diff --git a/SDL/CocoaBarItems.mm b/SDL/CocoaBarItems.mm new file mode 100644 index 0000000000..77e223041f --- /dev/null +++ b/SDL/CocoaBarItems.mm @@ -0,0 +1,345 @@ +// +// CocoaBarItems.mm +// PPSSPP +// +// Created by Serena on 06/02/2023. +// + +#import +#include "Common/System/System.h" +#include "Common/System/NativeApp.h" +#include "Core/Config.h" +#include "Common/Data/Text/I18n.h" +#include "Common/StringUtils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// NSMenuItem requires the use of an objective-c selector (aka the devil's greatest trick) +// So we have to make this class +@interface BarItemsManager : NSObject ++(instancetype)sharedInstance; +-(void)setupAppBarItems; +@property (assign) NSMenu *openMenu; +@property (assign) std::shared_ptr mainSettingsLocalization; +@property (assign) std::shared_ptr graphicsLocalization; +@end + +void initBarItemsForApp() { + [[BarItemsManager sharedInstance] setupAppBarItems]; +} + +// im soooooo sorry for whoever had to read this impl +@implementation BarItemsManager ++ (instancetype)sharedInstance { + static BarItemsManager *stub; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + stub = [BarItemsManager new]; + stub.mainSettingsLocalization = GetI18NCategory("MainSettings"); + }); + + return stub; +} + +-(void)setupAppBarItems { + NSMenuItem *openMenuItem = [[NSMenuItem alloc] init]; + openMenuItem.submenu = [self makeOpenSubmenu]; + openMenuItem.submenu.delegate = self; + + NSMenuItem *graphicsMenuItem = [[NSMenuItem alloc] init]; + graphicsMenuItem.submenu = [self makeGraphicsMenu]; + graphicsMenuItem.submenu.delegate = self; + + [NSApplication.sharedApplication.menu addItem:openMenuItem]; + [NSApplication.sharedApplication.menu addItem:graphicsMenuItem]; +} + +- (void)menuNeedsUpdate:(NSMenu *)menu { + if ([menu.title isEqualToString: [self localizedString:"Graphics" category: self.mainSettingsLocalization]]) { + for (NSMenuItem *item in menu.itemArray) { + switch (item.tag) { + case 1: + item.state = [self controlStateForBool:g_Config.bSoftwareRendering]; + break; + case 2: + item.state = [self controlStateForBool:g_Config.bVSync]; + break; + case 3: + item.state = [self controlStateForBool:g_Config.bFullScreen]; + break; + case 4: + item.state = [self controlStateForBool:g_Config.bAutoFrameSkip]; + break; + case (int)ShowStatusFlags::FPS_COUNTER + 100: + item.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER]; + break; + case (int)ShowStatusFlags::SPEED_COUNTER + 100: + item.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER]; + break; + case (int)ShowStatusFlags::BATTERY_PERCENT + 100: + item.state = [self controlStateForBool:g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT]; + break; + default: + break; + } + } + } +} + +-(NSString *)localizedString: (const char *)key category: (std::shared_ptr)cat { + return @(self.mainSettingsLocalization->T(key)); +} + +-(NSMenu *)makeOpenSubmenu { + NSMenu *menu = [[NSMenu alloc] initWithTitle:@"File"]; + NSMenuItem *openWithSystemFolderBrowserItem = [[NSMenuItem alloc] initWithTitle:@"Open..." action:@selector(openSystemFileBrowser) keyEquivalent:@"o"]; + openWithSystemFolderBrowserItem.keyEquivalentModifierMask = NSEventModifierFlagCommand; + openWithSystemFolderBrowserItem.enabled = YES; + openWithSystemFolderBrowserItem.target = self; + [menu addItem:openWithSystemFolderBrowserItem]; + self.openMenu = menu; + + [self addOpenRecentlyItem]; + return menu; +} + +-(NSMenu *)makeGraphicsMenu { + NSMenu *parent = [[NSMenu alloc] initWithTitle:@(self.mainSettingsLocalization->T("Graphics"))]; + NSMenu *backendsMenu = [[NSMenu alloc] init]; + + self.graphicsLocalization = GetI18NCategory("Graphics"); +#define GRAPHICS_LOCALIZED(key) @(self.graphicsLocalization->T(key)) + + NSMenuItem *gpuBackendItem = [[NSMenuItem alloc] initWithTitle:GRAPHICS_LOCALIZED("Backend") action:nil keyEquivalent:@""]; + + std::vector allowed = [self allowedGPUBackends]; + for (int i = 0; i < allowed.size(); i++) { + NSMenuItem *backendMenuItem = [[NSMenuItem alloc] initWithTitle:@(GPUBackendToString(allowed[i]).c_str()) action: @selector(setCurrentGPUBackend:) keyEquivalent: @""]; + backendMenuItem.tag = i; + backendMenuItem.target = self; + backendMenuItem.state = [self controlStateForBool: g_Config.iGPUBackend == (int)allowed[i]]; + [backendsMenu addItem:backendMenuItem]; + } + + gpuBackendItem.submenu = backendsMenu; + [parent addItem:gpuBackendItem]; + + [parent addItem:[NSMenuItem separatorItem]]; + +#define MENU_ITEM(variableName, localizedTitleName, SEL, ConfigurationValueName, Tag) \ +NSMenuItem *variableName = [[NSMenuItem alloc] initWithTitle:GRAPHICS_LOCALIZED(localizedTitleName) action:SEL keyEquivalent:@""]; \ +variableName.target = self; \ +variableName.tag = Tag; \ +variableName.state = [self controlStateForBool: ConfigurationValueName]; + + MENU_ITEM(softwareRendering, "Software Rendering", @selector(toggleSoftwareRendering:), g_Config.bSoftwareRendering, 1) + [parent addItem:softwareRendering]; + + MENU_ITEM(vsyncItem, "VSync", @selector(toggleVSync:), g_Config.bVSync, 2) + [parent addItem:vsyncItem]; + + MENU_ITEM(fullScreenItem, "Fullscreen", @selector(toggleFullScreen:), g_Config.bFullScreen, 3) + [parent addItem:fullScreenItem]; + + [parent addItem:[NSMenuItem separatorItem]]; + + MENU_ITEM(autoFrameSkip, "Auto FrameSkip", @selector(toggleAutoFrameSkip:), g_Config.bAutoFrameSkip, 4) + [parent addItem:autoFrameSkip]; + + [parent addItem:[NSMenuItem separatorItem]]; + + MENU_ITEM(fpsCounterItem, "Show FPS Counter", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::FPS_COUNTER, 5) + fpsCounterItem.tag = (int)ShowStatusFlags::FPS_COUNTER + 100; + + MENU_ITEM(speedCounterItem, "Show Speed", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::SPEED_COUNTER, 6) + speedCounterItem.tag = (int)ShowStatusFlags::SPEED_COUNTER + 100; // because of menuNeedsUpdate: + + MENU_ITEM(batteryPercentItem, "Show battery %", @selector(setToggleShowCounterItem:), g_Config.iShowStatusFlags & (int)ShowStatusFlags::BATTERY_PERCENT, 7) + batteryPercentItem.tag = (int)ShowStatusFlags::BATTERY_PERCENT + 100; + + [parent addItem:[NSMenuItem separatorItem]]; + [parent addItem:fpsCounterItem]; + [parent addItem:speedCounterItem]; + [parent addItem:batteryPercentItem]; + +#undef MENU_ITEM +#undef GRAPHICS_LOCALIZED + return parent; +} + +/* +-(NSMenu *)makeAudioMenu { + NSMenu *parent = [[NSMenu alloc] initWithTitle:@(self.mainSettingsLocalization->T("Audio"))]; + auto audioLocalization = GetI18NCategory("Audio"); + + NSMenuItem *enableSoundItem = [[NSMenuItem alloc] initWithTitle:@(audioLocalization->T("Enable Sound")) action:@selector(toggleSound:) keyEquivalent:@""]; + enableSoundItem.target = self; + enableSoundItem.state = [self controlStateForBool: g_Config.bEnableSound]; + [parent addItem:enableSoundItem]; + + NSMenuItem *deviceListItem = [[NSMenuItem alloc] initWithTitle:@(audioLocalization->T("Device")) action:nil keyEquivalent:@""]; + deviceListItem.submenu = [self makeAudioListMenuWithItem:deviceListItem]; + [parent addItem:deviceListItem]; + + [[NSNotificationCenter defaultCenter] addObserverForName:@"AudioConfChanged" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + NSString *value = [note object]; + if ([value isEqualToString:@"EnableSound"]) { + enableSoundItem.state = [self controlStateForBool:g_Config.bEnableSound]; + } + }]; + + return parent; +} + +-(NSMenu *)makeAudioListMenuWithItem: (NSMenuItem *)callerItem { + __block NSMenu *theMenu = [[NSMenu alloc] init]; + std::vector audioDeviceList; + SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); + + for (int i = 0; i < audioDeviceList.size(); i++) { + std::string itemName = audioDeviceList[i]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@(itemName.c_str()) action:@selector(setAudioItem:) keyEquivalent:@""]; + item.tag = i; + item.target = self; + item.state = [self controlStateForBool:g_Config.sAudioDevice == itemName]; + [theMenu addItem:item]; + } + + [[NSNotificationCenter defaultCenter] addObserverForName:@"AudioConfigurationHasChanged" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { + NSString *value = [note object]; + if ([value isEqualToString: @"DeviceAddedOrChanged"]) { + callerItem.submenu = [self makeAudioListMenuWithItem:callerItem]; + } else if ([value isEqualToString:@"CurrentDeviceWasChanged"]) { + // set the new item to be the selected one + dispatch_async(dispatch_get_main_queue(), ^{ + for (NSMenuItem *item in theMenu.itemArray) + item.state = [self controlStateForBool:g_Config.sAudioDevice == audioDeviceList[item.tag]]; + }); + } + }]; + + return theMenu; +} + */ + +/* +-(void) setAudioItem: (NSMenuItem *)sender { + std::vector audioDeviceList; + SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList); + + std::string theItemSelected = audioDeviceList[sender.tag]; + if (theItemSelected == g_Config.sAudioDevice) + return; // device already selected + + g_Config.sAudioDevice = theItemSelected; + for (NSMenuItem *item in sender.menu.itemArray) { + item.state = [self controlStateForBool:g_Config.sAudioDevice == theItemSelected]; + } + + System_SendMessage("audio_resetDevice", ""); +} + */ + +#define TOGGLE_METHOD(name, ConfigValueName, ...) \ +-(void)toggle##name: (NSMenuItem *)item { \ +ConfigValueName = !ConfigValueName; \ +__VA_ARGS__; /* for any additional updates */ \ +item.state = [self controlStateForBool: ConfigValueName]; \ +} + +TOGGLE_METHOD(Sound, g_Config.bEnableSound) +TOGGLE_METHOD(AutoFrameSkip, g_Config.bAutoFrameSkip, g_Config.UpdateAfterSettingAutoFrameSkip()) +TOGGLE_METHOD(SoftwareRendering, g_Config.bSoftwareRendering) +TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0")) +TOGGLE_METHOD(VSync, g_Config.bVSync) +#undef TOGGLE_METHOD + +-(void)setToggleShowCounterItem: (NSMenuItem *)item { + [self addOrRemoveInteger:(int)(item.tag - 100) to:&g_Config.iShowStatusFlags]; + item.state = [self controlStateForBool:g_Config.iShowStatusFlags & item.tag]; +} + +-(void)addOrRemoveInteger: (int)integer to: (int *)r { + if (integer & *r) { + *r -= integer; + } else { + *r |= integer; + } +} + +-(void)setCurrentGPUBackend: (NSMenuItem *)sender { + std::vector allowed = [self allowedGPUBackends]; + if (allowed.size() == 1) { + printf("only one item, bailing"); + return; + } + + g_Config.iGPUBackend = (int)(allowed[sender.tag]); + sender.state = NSControlStateValueOn; + + for (NSMenuItem *item in sender.menu.itemArray) { + // deselect the previously selected item + if (item.state == NSControlStateValueOn && item.tag != sender.tag) { + item.state = NSControlStateValueOff; + break; + } + } +} + +-(NSControlStateValue) controlStateForBool: (BOOL)boolValue { + return boolValue ? NSControlStateValueOn : NSControlStateValueOff; +} + +-(std::vector)allowedGPUBackends { + std::vector allBackends = { + GPUBackend::OPENGL, GPUBackend::VULKAN, + }; + + std::vector allowed; + + for (GPUBackend backend : allBackends) { + if (g_Config.IsBackendEnabled(backend)) { + allowed.push_back(backend); + } + } + + return allowed; +} + +-(void)addOpenRecentlyItem { + std::vector recentIsos = g_Config.RecentIsos(); + NSMenuItem *openRecent = [[NSMenuItem alloc] initWithTitle:@"Open Recent" action:nil keyEquivalent:@""]; + NSMenu *recentsMenu = [[NSMenu alloc] init]; + if (recentIsos.empty()) + openRecent.enabled = NO; + + for (int i = 0; i < recentIsos.size(); i++) { + std::string filename = Path(recentIsos[i]).GetFilename(); + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@(filename.c_str()) action:@selector(openRecentItem:) keyEquivalent:@""]; + item.target = self; + [recentsMenu addItem:item]; + } + + openRecent.submenu = recentsMenu; + [self.openMenu addItem:openRecent]; +} + +-(void)openRecentItem: (NSMenuItem *)item { + NativeMessageReceived("browse_fileSelect", g_Config.RecentIsos()[item.tag].c_str()); +} + +-(void)openSystemFileBrowser { + System_SendMessage("browse_folder", ""); +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +@end + +#ifdef __cplusplus +} +#endif From 84849d9d3250be6b226e46a010ea141870e28240 Mon Sep 17 00:00:00 2001 From: Serena Date: Thu, 23 Mar 2023 22:09:01 +0300 Subject: [PATCH 6/9] fixes --- SDL/CocoaBarItems.mm | 51 ++++++++++++++++++++++++++++++++-- SDL/SDLMain.cpp | 4 +-- UI/DarwinFileSystemServices.mm | 3 -- UI/GameSettingsScreen.cpp | 1 - ext/SPIRV-Cross | 2 +- ext/armips | 2 +- ext/glslang | 2 +- 7 files changed, 53 insertions(+), 12 deletions(-) diff --git a/SDL/CocoaBarItems.mm b/SDL/CocoaBarItems.mm index 77e223041f..66da05d40a 100644 --- a/SDL/CocoaBarItems.mm +++ b/SDL/CocoaBarItems.mm @@ -6,6 +6,8 @@ // #import +#include "UI/DarwinFileSystemServices.h" +#include "Common/File/Path.h" #include "Common/System/System.h" #include "Common/System/NativeApp.h" #include "Core/Config.h" @@ -30,7 +32,6 @@ void initBarItemsForApp() { [[BarItemsManager sharedInstance] setupAppBarItems]; } -// im soooooo sorry for whoever had to read this impl @implementation BarItemsManager + (instancetype)sharedInstance { static BarItemsManager *stub; @@ -52,8 +53,25 @@ void initBarItemsForApp() { graphicsMenuItem.submenu = [self makeGraphicsMenu]; graphicsMenuItem.submenu.delegate = self; + NSMenuItem *helpMenuItem = [[NSMenuItem alloc] init]; + helpMenuItem.submenu = [self makeHelpMenu]; + [NSApplication.sharedApplication.menu addItem:openMenuItem]; [NSApplication.sharedApplication.menu addItem:graphicsMenuItem]; + [NSApplication.sharedApplication.menu addItem:helpMenuItem]; + + NSString *windowMenuItemTitle = @"Window"; + // Rearrange 'Window' to be behind 'Help' + for (NSMenuItem *item in NSApplication.sharedApplication.menu.itemArray) { + if ([item.title isEqualToString:windowMenuItemTitle]) { + [NSApplication.sharedApplication.menu removeItem:item]; + // 'Help' is the last item in the bar + // so we can just use `NSApplication.sharedApplication.menu.numberOfItems - 1` + // as it's index + [NSApplication.sharedApplication.menu insertItem:item atIndex:NSApplication.sharedApplication.menu.numberOfItems - 1]; + break; + } + } } - (void)menuNeedsUpdate:(NSMenu *)menu { @@ -92,6 +110,26 @@ void initBarItemsForApp() { return @(self.mainSettingsLocalization->T(key)); } +-(NSMenu *)makeHelpMenu { + NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Help"]; + NSMenuItem *githubItem = [[NSMenuItem alloc] initWithTitle:@"Report an issue" action:@selector(reportAnIssue) keyEquivalent:@""]; + githubItem.target = self; + [menu addItem:githubItem]; + + NSMenuItem *discordItem = [[NSMenuItem alloc] initWithTitle:@"Join the Discord" action:@selector(joinTheDiscord) keyEquivalent:@""]; + discordItem.target = self; + [menu addItem:discordItem]; + return menu; +} + +-(void)reportAnIssue { + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://github.com/hrydgard/ppsspp/issues/new/choose"]]; +} + +-(void)joinTheDiscord { + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://discord.gg/5NJB6dD"]]; +} + -(NSMenu *)makeOpenSubmenu { NSMenu *menu = [[NSMenu alloc] initWithTitle:@"File"]; NSMenuItem *openWithSystemFolderBrowserItem = [[NSMenuItem alloc] initWithTitle:@"Open..." action:@selector(openSystemFileBrowser) keyEquivalent:@"o"]; @@ -252,7 +290,7 @@ item.state = [self controlStateForBool: ConfigValueName]; \ TOGGLE_METHOD(Sound, g_Config.bEnableSound) TOGGLE_METHOD(AutoFrameSkip, g_Config.bAutoFrameSkip, g_Config.UpdateAfterSettingAutoFrameSkip()) TOGGLE_METHOD(SoftwareRendering, g_Config.bSoftwareRendering) -TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_SendMessage("toggle_fullscreen", g_Config.UseFullScreen() ? "1" : "0")) +TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_MakeRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, 0, g_Config.UseFullScreen() ? "1" : "0", "", 3)) TOGGLE_METHOD(VSync, g_Config.bVSync) #undef TOGGLE_METHOD @@ -331,7 +369,14 @@ TOGGLE_METHOD(VSync, g_Config.bVSync) } -(void)openSystemFileBrowser { - System_SendMessage("browse_folder", ""); + int g = 0; + DarwinDirectoryPanelCallback callback = [g] (bool succ, Path thePathChosen) { + if (succ) + NativeMessageReceived("browse_folder", thePathChosen.c_str()); + }; + + DarwinFileSystemServices services; + services.presentDirectoryPanel(callback, /* allowFiles = */ true, /* allowDirectorites = */ true); } - (void)dealloc { diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index a35b94c8b0..d4b1200a5c 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -877,8 +877,8 @@ int main(int argc, char *argv[]) { bool windowHidden = false; #if PPSSPP_PLATFORM(MAC) - // setup menu items for macOS - initBarItemsForApp(); + // setup menu items for macOS + initBarItemsForApp(); #endif while (true) { diff --git a/UI/DarwinFileSystemServices.mm b/UI/DarwinFileSystemServices.mm index 3f81f5f8d1..1162884242 100644 --- a/UI/DarwinFileSystemServices.mm +++ b/UI/DarwinFileSystemServices.mm @@ -115,6 +115,3 @@ void DarwinFileSystemServices::setUserPreferredMemoryStickDirectory(Path path) { g_Config.memStickDirectory = path; } -void PostDarwinNotification(const char *name, const char *value) { - [[NSNotificationCenter defaultCenter] postNotificationName:@(name) object: @(value)]; -} diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9b63cede07..8d223379e2 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -620,7 +620,6 @@ void GameSettingsScreen::CreateAudioSettings(UI::ViewGroup *audioSettings) { audioSettings->Add(new ItemHeader(ms->T("Audio"))); CheckBox *enableSound = audioSettings->Add(new CheckBox(&g_Config.bEnableSound,a->T("Enable Sound"))); - PopupSliderChoice *volume = audioSettings->Add(new PopupSliderChoice(&g_Config.iGlobalVolume, VOLUME_OFF, VOLUME_FULL, a->T("Global volume"), screenManager())); volume->SetEnabledPtr(&g_Config.bEnableSound); volume->SetZeroLabel(a->T("Mute")); diff --git a/ext/SPIRV-Cross b/ext/SPIRV-Cross index 4212eef67e..c77b09b57c 160000 --- a/ext/SPIRV-Cross +++ b/ext/SPIRV-Cross @@ -1 +1 @@ -Subproject commit 4212eef67ed0ca048cb726a6767185504e7695e5 +Subproject commit c77b09b57c27837dc2d41aa371ed3d236ce9ce47 diff --git a/ext/armips b/ext/armips index 7bd1ec93d4..6719edebaa 160000 --- a/ext/armips +++ b/ext/armips @@ -1 +1 @@ -Subproject commit 7bd1ec93d4586985ba1ef420b43b5e620f68695e +Subproject commit 6719edebaae03330ee5441d9b28280672edf00d5 diff --git a/ext/glslang b/ext/glslang index b34f619e1c..77551c429f 160000 --- a/ext/glslang +++ b/ext/glslang @@ -1 +1 @@ -Subproject commit b34f619e1c85810dcb3c578107d2e48ba4ee2b37 +Subproject commit 77551c429f86c0e077f26552b7c1c0f12a9f235e From ea4e294faae460576d651b04aaa36822c9d62c46 Mon Sep 17 00:00:00 2001 From: Serena Date: Thu, 23 Mar 2023 23:28:57 +0300 Subject: [PATCH 7/9] fix openSystemFileBrowser --- SDL/CocoaBarItems.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDL/CocoaBarItems.mm b/SDL/CocoaBarItems.mm index 66da05d40a..8e36a4adad 100644 --- a/SDL/CocoaBarItems.mm +++ b/SDL/CocoaBarItems.mm @@ -372,7 +372,7 @@ TOGGLE_METHOD(VSync, g_Config.bVSync) int g = 0; DarwinDirectoryPanelCallback callback = [g] (bool succ, Path thePathChosen) { if (succ) - NativeMessageReceived("browse_folder", thePathChosen.c_str()); + NativeMessageReceived("boot", thePathChosen.c_str()); }; DarwinFileSystemServices services; From 67896bf88531808967bfa3a1b79d7816557e847a Mon Sep 17 00:00:00 2001 From: Serena Date: Tue, 28 Mar 2023 21:44:12 +0300 Subject: [PATCH 8/9] Switch to boot --- SDL/CocoaBarItems.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDL/CocoaBarItems.mm b/SDL/CocoaBarItems.mm index 8e36a4adad..349ba033c7 100644 --- a/SDL/CocoaBarItems.mm +++ b/SDL/CocoaBarItems.mm @@ -365,7 +365,7 @@ TOGGLE_METHOD(VSync, g_Config.bVSync) } -(void)openRecentItem: (NSMenuItem *)item { - NativeMessageReceived("browse_fileSelect", g_Config.RecentIsos()[item.tag].c_str()); + NativeMessageReceived("boot", g_Config.RecentIsos()[item.tag].c_str()); } -(void)openSystemFileBrowser { From 5ad830a4395c9489d3e9172cf6bb312736d255e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 28 Mar 2023 21:32:37 +0200 Subject: [PATCH 9/9] revert submodules --- ext/SPIRV-Cross | 2 +- ext/armips | 2 +- ext/glslang | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/SPIRV-Cross b/ext/SPIRV-Cross index c77b09b57c..4212eef67e 160000 --- a/ext/SPIRV-Cross +++ b/ext/SPIRV-Cross @@ -1 +1 @@ -Subproject commit c77b09b57c27837dc2d41aa371ed3d236ce9ce47 +Subproject commit 4212eef67ed0ca048cb726a6767185504e7695e5 diff --git a/ext/armips b/ext/armips index 6719edebaa..7bd1ec93d4 160000 --- a/ext/armips +++ b/ext/armips @@ -1 +1 @@ -Subproject commit 6719edebaae03330ee5441d9b28280672edf00d5 +Subproject commit 7bd1ec93d4586985ba1ef420b43b5e620f68695e diff --git a/ext/glslang b/ext/glslang index 77551c429f..b34f619e1c 160000 --- a/ext/glslang +++ b/ext/glslang @@ -1 +1 @@ -Subproject commit 77551c429f86c0e077f26552b7c1c0f12a9f235e +Subproject commit b34f619e1c85810dcb3c578107d2e48ba4ee2b37