diff --git a/BUILD.md b/BUILD.md index 19256f70..1f90ea61 100644 --- a/BUILD.md +++ b/BUILD.md @@ -244,7 +244,7 @@ Example usage: `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DENABLE_SDL=ON - | ENABLE_SDL | | Enable SDLController controller API | ON | Currently required | | ENABLE_VCPKG | | Use VCPKG package manager to obtain dependencies | ON | | | ENABLE_VULKAN | | Enable the Vulkan graphics backend | ON | | -| ENABLE_WXWIDGETS | | Enable wxWidgets UI | ON | | +| ENABLE_WXWIDGETS | | Enable wxWidgets UI | ON | Currently required | ### Windows | Flag | Description | Default | Note | @@ -264,5 +264,4 @@ Example usage: `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DENABLE_SDL=ON - ### macOS | Flag | Description | Default | |---------------------|------------------------------------------------------|---------| -| ENABLE_SWIFTUI_MACOS | Enable experimental native macOS SwiftUI GUI backend | OFF | -| MACOS_BUNDLE | MacOS executable will be an application bundle | OFF | +| MACOS_BUNDLE | macOS executable will be an application bundle | OFF | diff --git a/CMakeLists.txt b/CMakeLists.txt index bf00c1be..4ed2d718 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ execute_process( OUTPUT_VARIABLE GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) -add_compile_definitions($<$:EMULATOR_HASH=${GIT_HASH}>) +add_definitions(-DEMULATOR_HASH=${GIT_HASH}) if (ENABLE_VCPKG) # check if vcpkg is shallow and unshallow it if necessary @@ -66,9 +66,9 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_compile_definitions($<$:CEMU_DEBUG_ASSERT>) # if build type is debug, set CEMU_DEBUG_ASSERT -add_compile_definitions($<$:EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR}>) -add_compile_definitions($<$:EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR}>) -add_compile_definitions($<$:EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}>) +add_definitions(-DEMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR}) +add_definitions(-DEMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR}) +add_definitions(-DEMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -194,7 +194,7 @@ endif() if (ENABLE_METAL) include_directories(${CMAKE_SOURCE_DIR}/dependencies/metal-cpp) - add_compile_definitions($<$:ENABLE_METAL=1>) + add_definitions(-DENABLE_METAL=1) endif() if (ENABLE_DISCORD_RPC) @@ -232,7 +232,7 @@ if (ENABLE_CUBEB) set_property(TARGET cubeb PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") add_library(cubeb::cubeb ALIAS cubeb) endif() - add_compile_definitions($<$:HAS_CUBEB=1>) + add_compile_definitions("HAS_CUBEB=1") endif() add_subdirectory("dependencies/ih264d" EXCLUDE_FROM_ALL) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37ddae52..f413fe9f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,13 +32,7 @@ elseif(UNIX) add_compile_options(-Wno-ambiguous-reversed-operator) endif() - add_compile_options( - $<$:-Wno-multichar> - $<$:-Wno-invalid-offsetof> - $<$:-Wno-switch> - $<$:-Wno-ignored-attributes> - $<$:-Wno-deprecated-enum-enum-conversion> - ) + add_compile_options(-Wno-multichar -Wno-invalid-offsetof -Wno-switch -Wno-ignored-attributes -Wno-deprecated-enum-enum-conversion) endif() add_compile_definitions(VK_NO_PROTOTYPES) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b182aa84..d66e971a 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,12 +1,7 @@ add_library(CemuGui INTERFACE) target_include_directories(CemuGui INTERFACE "interface") -if(APPLE AND ENABLE_SWIFTUI_MACOS) - add_subdirectory(swiftui) - target_link_libraries(CemuGui INTERFACE CemuSwiftUiGui) -elseif(ENABLE_WXWIDGETS) +if(ENABLE_WXWIDGETS) add_subdirectory(wxgui) target_link_libraries(CemuGui INTERFACE CemuWxGui) -else() - message(FATAL_ERROR "No GUI backend selected. Enable ENABLE_WXWIDGETS or ENABLE_SWIFTUI_MACOS on macOS.") endif() diff --git a/src/gui/swiftui/CMakeLists.txt b/src/gui/swiftui/CMakeLists.txt deleted file mode 100644 index 8e011244..00000000 --- a/src/gui/swiftui/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -enable_language(Swift) - -add_library(CemuSwiftUiGui STATIC - WindowSystemSwiftUI.mm - ContentView.swift -) - -set_target_properties(CemuSwiftUiGui PROPERTIES - Swift_LANGUAGE_VERSION 5 -) - -set_property(TARGET CemuSwiftUiGui PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - -target_include_directories(CemuSwiftUiGui PRIVATE "../../") -target_include_directories(CemuSwiftUiGui PUBLIC "../") - -target_link_libraries(CemuSwiftUiGui PRIVATE - CemuCommon - CemuConfig - CemuCafe - CemuResource -) - -find_library(COCOA_FRAMEWORK Cocoa REQUIRED) -target_link_libraries(CemuSwiftUiGui PRIVATE ${COCOA_FRAMEWORK}) - -if(ALLOW_PORTABLE) - target_compile_definitions(CemuSwiftUiGui PRIVATE CEMU_ALLOW_PORTABLE) -endif() diff --git a/src/gui/swiftui/ContentView.swift b/src/gui/swiftui/ContentView.swift deleted file mode 100644 index 2b5e247c..00000000 --- a/src/gui/swiftui/ContentView.swift +++ /dev/null @@ -1,237 +0,0 @@ -import AppKit -import SwiftUI - -@objc(CemuSwiftUIRootViewController) -final class CemuSwiftUIRootViewController: NSViewController { - override func loadView() { - self.view = NSHostingView(rootView: ContentView()) - } -} - -@_cdecl("CemuCreateSwiftUIRootViewController") -public func CemuCreateSwiftUIRootViewController() -> UnsafeMutableRawPointer { - let controller = CemuSwiftUIRootViewController() - return Unmanaged.passRetained(controller).autorelease().toOpaque() -} - -struct ContentView: View { - @State private var selectedTitleID: UInt64? - @State private var showUpdatingBanner = false - @State private var games: [GameItem] = [ - GameItem( - titleID: 0x0005_0000_101C_9400, - name: "The Legend of Zelda: Breath of the Wild", - version: "208", - dlc: "80", - played: "37 hours 42 minutes", - lastPlayed: "4/12/26", - region: "EUR" - ), - GameItem( - titleID: 0x0005_0000_1010_EC00, - name: "Mario Kart 8", - version: "64", - dlc: "48", - played: "12 hours 5 minutes", - lastPlayed: "3/28/26", - region: "USA" - ), - GameItem( - titleID: 0x0005_0000_1017_6A00, - name: "Splatoon", - version: "80", - dlc: "", - played: "1 hour 12 minutes", - lastPlayed: "never", - region: "JPN" - ), - GameItem( - titleID: 0x0005_0000_1014_4F00, - name: "Super Smash Bros. for Wii U", - version: "288", - dlc: "192", - played: "", - lastPlayed: "never", - region: "USA" - ), - ] - - var body: some View { - VStack(spacing: 0) { - GameListHeaderView() - - Divider() - - ScrollView { - LazyVStack(spacing: 0) { - ForEach(Array(games.enumerated()), id: \.element.id) { index, game in - GameListRowView( - game: game, - isSelected: selectedTitleID == game.titleID, - isAlternateRow: index.isMultiple(of: 2) - ) - .contentShape(Rectangle()) - .onTapGesture { - selectedTitleID = game.titleID - } - - Divider() - } - } - } - .background(Color(nsColor: .controlBackgroundColor)) - - if showUpdatingBanner { - GameListInfoBarView(message: "Updating game list...") { - withAnimation(.easeInOut(duration: 0.2)) { - showUpdatingBanner = false - } - } - .transition(.move(edge: .bottom).combined(with: .opacity)) - } - } - .toolbar { - ToolbarItemGroup(placement: .automatic) { - Button(action: refreshGameList) { - Image(systemName: "arrow.clockwise") - } - .help("Refresh game list") - - Button(action: openSettings) { - Image(systemName: "gear") - } - .help("Settings") - } - } - .frame(minWidth: 900, minHeight: 480) - } - - private func refreshGameList() { - withAnimation(.easeInOut(duration: 0.2)) { - showUpdatingBanner = true - } - } - - private func openSettings() { - // SwiftUI migration placeholder: the menu action exists in WindowSystemSwiftUI. - } -} - -struct GameListHeaderView: View { - var body: some View { - HStack(spacing: 0) { - headerCell("Icon", width: 66, alignment: .center) - headerCell("Game", width: 340, alignment: .leading) - headerCell("Version", width: 84, alignment: .leading) - headerCell("DLC", width: 68, alignment: .leading) - headerCell("You've played", width: 170, alignment: .leading) - headerCell("Last played", width: 136, alignment: .leading) - headerCell("Region", width: 88, alignment: .leading) - headerCell("Title ID", width: 170, alignment: .leading) - } - .padding(.vertical, 4) - .background(Color(nsColor: .windowBackgroundColor)) - } - - private func headerCell(_ title: String, width: CGFloat, alignment: Alignment) -> some View { - Text(title) - .font(.system(size: 12, weight: .semibold)) - .foregroundStyle(.primary) - .lineLimit(1) - .frame(width: width, alignment: alignment) - .padding(.horizontal, 8) - } -} - -struct GameListRowView: View { - let game: GameItem - let isSelected: Bool - let isAlternateRow: Bool - - var body: some View { - HStack(spacing: 0) { - iconCell - .frame(width: 66, alignment: .center) - - textCell(game.name, width: 340) - textCell(game.version, width: 84) - textCell(game.dlc, width: 68) - textCell(game.played, width: 170) - textCell(game.lastPlayed, width: 136) - textCell(game.region, width: 88) - textCell(String(format: "%016llx", game.titleID), width: 170) - } - .frame(maxWidth: .infinity, minHeight: 40, alignment: .leading) - .background(backgroundColor) - } - - private var iconCell: some View { - RoundedRectangle(cornerRadius: 4) - .fill(Color.accentColor.opacity(0.20)) - .frame(width: 40, height: 24) - .overlay( - Image(systemName: "photo") - .font(.system(size: 11, weight: .medium)) - .foregroundStyle(.secondary) - ) - .padding(.horizontal, 8) - } - - private func textCell(_ value: String, width: CGFloat) -> some View { - Text(value) - .font(.system(size: 12)) - .lineLimit(1) - .truncationMode(.tail) - .frame(width: width, alignment: .leading) - .padding(.horizontal, 8) - } - - private var backgroundColor: Color { - if isSelected { - return Color(nsColor: .selectedContentBackgroundColor) - } - - if isAlternateRow { - return Color(nsColor: .controlBackgroundColor) - } - - return Color(nsColor: .windowBackgroundColor) - } -} - -struct GameListInfoBarView: View { - let message: String - let onDismiss: () -> Void - - var body: some View { - HStack(spacing: 10) { - Image(systemName: "arrow.triangle.2.circlepath") - .font(.system(size: 12, weight: .semibold)) - .foregroundStyle(.secondary) - - Text(message) - .font(.system(size: 12)) - - Spacer() - - Button("Dismiss", action: onDismiss) - .buttonStyle(.plain) - .font(.system(size: 12, weight: .medium)) - } - .padding(.horizontal, 10) - .padding(.vertical, 7) - .background(Color(nsColor: .unemphasizedSelectedContentBackgroundColor)) - } -} - -struct GameItem: Identifiable { - let titleID: UInt64 - let name: String - let version: String - let dlc: String - let played: String - let lastPlayed: String - let region: String - - var id: UInt64 { titleID } -} diff --git a/src/gui/swiftui/WindowSystemSwiftUI.mm b/src/gui/swiftui/WindowSystemSwiftUI.mm deleted file mode 100644 index cdbb5cb8..00000000 --- a/src/gui/swiftui/WindowSystemSwiftUI.mm +++ /dev/null @@ -1,389 +0,0 @@ -#include "Common/precompiled.h" - -#include "interface/WindowSystem.h" - -#include "Cafe/CafeSystem.h" -#include "Cafe/TitleList/TitleInfo.h" -#include "Cafe/TitleList/TitleList.h" -#include "config/ActiveSettings.h" - -#import -#import - -extern "C" void *CemuCreateSwiftUIRootViewController(void); - -@interface CemuAppDelegate : NSObject -- (void)setupMenuBar; -- (void)quitApp:(id)sender; -- (void)openGame:(id)sender; -- (void)openPreferences:(id)sender; -- (void)toggleFullscreen:(id)sender; -- (void)showHelp:(id)sender; -- (void)showAbout:(id)sender; -@end - -namespace { -extern WindowSystem::WindowInfo g_window_info; -extern NSWindow *g_main_window; -extern CemuAppDelegate *g_app_delegate; -bool PrepareLaunchPath(const fs::path &launchPath, std::string &errorOut); -} - -@implementation CemuAppDelegate - -- (void)setupMenuBar { - NSMenu *mainMenu = [[NSMenu alloc] init]; - - // File menu - NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:@"File"]; - NSMenuItem *fileMenuItem = [mainMenu addItemWithTitle:@"File" action:nil keyEquivalent:@""]; - [mainMenu setSubmenu:fileMenu forItem:fileMenuItem]; - - NSMenuItem *openGameItem = [fileMenu addItemWithTitle:@"Open Game..." action:@selector(openGame:) keyEquivalent:@"o"]; - [openGameItem setTarget:self]; - [fileMenu addItem:[NSMenuItem separatorItem]]; - NSMenuItem *quitItem = [fileMenu addItemWithTitle:@"Quit Cemu" action:@selector(quitApp:) keyEquivalent:@"q"]; - [quitItem setTarget:self]; - - // Edit menu - NSMenu *editMenu = [[NSMenu alloc] initWithTitle:@"Edit"]; - NSMenuItem *editMenuItem = [mainMenu addItemWithTitle:@"Edit" action:nil keyEquivalent:@""]; - [mainMenu setSubmenu:editMenu forItem:editMenuItem]; - - NSMenuItem *preferencesItem = [editMenu addItemWithTitle:@"Preferences..." action:@selector(openPreferences:) keyEquivalent:@","]; - [preferencesItem setTarget:self]; - - // View menu - NSMenu *viewMenu = [[NSMenu alloc] initWithTitle:@"View"]; - NSMenuItem *viewMenuItem = [mainMenu addItemWithTitle:@"View" action:nil keyEquivalent:@""]; - [mainMenu setSubmenu:viewMenu forItem:viewMenuItem]; - - NSMenuItem *fullscreenItem = [viewMenu addItemWithTitle:@"Toggle Fullscreen" action:@selector(toggleFullscreen:) keyEquivalent:@"f"]; - [fullscreenItem setTarget:self]; - - // Help menu - NSMenu *helpMenu = [[NSMenu alloc] initWithTitle:@"Help"]; - NSMenuItem *helpMenuItem = [mainMenu addItemWithTitle:@"Help" action:nil keyEquivalent:@""]; - [mainMenu setSubmenu:helpMenu forItem:helpMenuItem]; - - NSMenuItem *helpItem = [helpMenu addItemWithTitle:@"Cemu Help" action:@selector(showHelp:) keyEquivalent:@""]; - [helpItem setTarget:self]; - NSMenuItem *aboutItem = [helpMenu addItemWithTitle:@"About Cemu" action:@selector(showAbout:) keyEquivalent:@""]; - [aboutItem setTarget:self]; - - [NSApp setMainMenu:mainMenu]; -} - -- (void)quitApp:(id)sender { - [NSApp terminate:sender]; -} - -- (void)openGame:(id)sender { - if (CafeSystem::IsTitleRunning()) { - WindowSystem::ShowErrorDialog("A title is already running.", - "Launch blocked"); - return; - } - - NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setCanChooseFiles:YES]; - [panel setCanChooseDirectories:NO]; - [panel setAllowsMultipleSelection:NO]; - [panel setAllowedContentTypes:@[ - [UTType typeWithFilenameExtension:@"wud"], - [UTType typeWithFilenameExtension:@"wux"], - [UTType typeWithFilenameExtension:@"wua"], - [UTType typeWithFilenameExtension:@"wuhb"], - [UTType typeWithFilenameExtension:@"iso"], - [UTType typeWithFilenameExtension:@"rpx"], - [UTType typeWithFilenameExtension:@"elf"], - [UTType typeWithFilenameExtension:@"tmd"] - ]]; - - if ([panel runModal] != NSModalResponseOK || panel.URL == nil) - return; - - NSString *pathString = panel.URL.path; - if (pathString.length == 0) - return; - - fs::path launchPath = _utf8ToPath(std::string(pathString.UTF8String)); - std::string errorMessage; - if (!PrepareLaunchPath(launchPath, errorMessage)) { - WindowSystem::ShowErrorDialog(errorMessage, "Failed to launch game"); - return; - } - - WindowSystem::UpdateWindowTitles(false, true, 0.0); - CafeSystem::LaunchForegroundTitle(); - WindowSystem::NotifyGameLoaded(); - - const std::string titleName = CafeSystem::GetForegroundTitleName(); - if (!titleName.empty() && g_main_window) { - [g_main_window setTitle:[NSString stringWithUTF8String:titleName.c_str()]]; - } -} - -- (void)openPreferences:(id)sender { - fs::path configPath = ActiveSettings::GetConfigPath(); - std::string configPathUtf8 = _pathToUtf8(configPath); - NSString *configNSString = - [NSString stringWithUTF8String:configPathUtf8.c_str()]; - if (configNSString.length == 0) - return; - - NSURL *configURL = [NSURL fileURLWithPath:configNSString isDirectory:YES]; - [[NSWorkspace sharedWorkspace] openURL:configURL]; -} - -- (void)toggleFullscreen:(id)sender { - if (!g_main_window) - return; - - [g_main_window toggleFullScreen:nil]; - g_window_info.is_fullscreen = !g_window_info.is_fullscreen.load(); -} - -- (void)showHelp:(id)sender { - NSURL *helpURL = [NSURL URLWithString:@"https://wiki.cemu.info"]; - if (helpURL) - [[NSWorkspace sharedWorkspace] openURL:helpURL]; -} - -- (void)showAbout:(id)sender { - NSAlert *about = [[NSAlert alloc] init]; - [about setAlertStyle:NSAlertStyleInformational]; - [about setMessageText:@"About Cemu"]; - [about setInformativeText:@"Cemu - Wii U Emulator\nSwiftUI macOS GUI"]; - [about addButtonWithTitle:@"OK"]; - [about runModal]; -} - -@end - -namespace { -WindowSystem::WindowInfo g_window_info{}; -NSWindow *g_main_window = nil; -CemuAppDelegate *g_app_delegate = nil; - -bool PrepareLaunchPath(const fs::path &launchPath, std::string &errorOut) { - TitleInfo launchTitle{launchPath}; - if (launchTitle.IsValid()) { - CafeTitleList::AddTitleFromPath(launchPath); - - TitleId baseTitleId; - if (!CafeTitleList::FindBaseTitleId(launchTitle.GetAppTitleId(), - baseTitleId)) { - errorOut = - "Unable to launch game because the base files were not found."; - return false; - } - - CafeSystem::PREPARE_STATUS_CODE status = - CafeSystem::PrepareForegroundTitle(baseTitleId); - if (status == CafeSystem::PREPARE_STATUS_CODE::UNABLE_TO_MOUNT) { - errorOut = - "Unable to mount title. Make sure your game paths are valid and " - "refresh the game list."; - return false; - } - if (status != CafeSystem::PREPARE_STATUS_CODE::SUCCESS) { - errorOut = "Failed to prepare the selected game for launch."; - return false; - } - return true; - } - - CafeTitleFileType fileType = DetermineCafeSystemFileType(launchPath); - if (fileType == CafeTitleFileType::RPX || fileType == CafeTitleFileType::ELF) { - CafeSystem::PREPARE_STATUS_CODE status = - CafeSystem::PrepareForegroundTitleFromStandaloneRPX(launchPath); - if (status != CafeSystem::PREPARE_STATUS_CODE::SUCCESS) { - errorOut = "Failed to prepare standalone RPX/ELF executable."; - return false; - } - return true; - } - - errorOut = "Unsupported or invalid Wii U title path."; - return false; -} -} // namespace - -void WindowSystem::ShowErrorDialog( - std::string_view message, std::string_view title, - std::optional /*errorCategory*/) { - @autoreleasepool { - NSAlert *alert = [[NSAlert alloc] init]; - std::string titleCopy(title); - NSString *alertTitle = - titleCopy.empty() ? @"Error" - : [NSString stringWithUTF8String:titleCopy.c_str()]; - NSString *alertMessage = - [NSString stringWithUTF8String:std::string(message).c_str()]; - [alert setAlertStyle:NSAlertStyleCritical]; - [alert setMessageText:alertTitle]; - [alert setInformativeText:alertMessage ?: @""]; - [alert addButtonWithTitle:@"OK"]; - [alert runModal]; - } -} - -void WindowSystem::Create() { - @autoreleasepool { - NSApplication *app = [NSApplication sharedApplication]; - [app setActivationPolicy:NSApplicationActivationPolicyRegular]; - - // Setup application delegate with menu bar - g_app_delegate = [[CemuAppDelegate alloc] init]; - [app setDelegate:g_app_delegate]; - [g_app_delegate setupMenuBar]; - - const NSRect frame = NSMakeRect(120.0, 120.0, 1280.0, 720.0); - const NSWindowStyleMask style = - NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | - NSWindowStyleMaskUnifiedTitleAndToolbar; - - g_main_window = [[NSWindow alloc] initWithContentRect:frame - styleMask:style - backing:NSBackingStoreBuffered - defer:NO]; - [g_main_window setTitle:@"Cemu"]; - [g_main_window setTitlebarAppearsTransparent:NO]; - - // Instantiate SwiftUI-backed root controller via explicit Swift C symbol. - NSViewController *rootViewController = nil; - if (void *swiftControllerPtr = CemuCreateSwiftUIRootViewController()) { - id swiftControllerObj = (__bridge id)swiftControllerPtr; - if ([swiftControllerObj isKindOfClass:[NSViewController class]]) { - rootViewController = (NSViewController *)swiftControllerObj; - } - } - if (!rootViewController) { - rootViewController = [[NSViewController alloc] init]; - NSView *contentView = [[NSView alloc] initWithFrame:frame]; - [contentView setWantsLayer:YES]; - contentView.layer.backgroundColor = NSColor.windowBackgroundColor.CGColor; - - NSTextField *fallbackLabel = [NSTextField labelWithString: - @"SwiftUI root view not found.\nUsing AppKit fallback view."]; - [fallbackLabel setFont:[NSFont systemFontOfSize:16 weight:NSFontWeightMedium]]; - [fallbackLabel setTextColor:NSColor.secondaryLabelColor]; - [fallbackLabel setAlignment:NSTextAlignmentCenter]; - [fallbackLabel setFrame:NSMakeRect(40, frame.size.height / 2 - 20, - frame.size.width - 80, 60)]; - [fallbackLabel setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin | NSViewMaxYMargin]; - [contentView addSubview:fallbackLabel]; - - rootViewController.view = contentView; - } - - [g_main_window setContentViewController:rootViewController]; - - [g_main_window makeKeyAndOrderFront:nil]; - [app activateIgnoringOtherApps:YES]; - - g_window_info.app_active = true; - g_window_info.width = static_cast(frame.size.width); - g_window_info.height = static_cast(frame.size.height); - g_window_info.phys_width = g_window_info.width.load(); - g_window_info.phys_height = g_window_info.height.load(); - g_window_info.dpi_scale = 1.0; - g_window_info.pad_open = false; - g_window_info.pad_width = 0; - g_window_info.pad_height = 0; - g_window_info.phys_pad_width = 0; - g_window_info.phys_pad_height = 0; - g_window_info.pad_dpi_scale = 1.0; - g_window_info.is_fullscreen = false; - g_window_info.debugger_focused = false; - g_window_info.window_main.backend = - WindowSystem::WindowHandleInfo::Backend::Cocoa; - g_window_info.window_main.display = nullptr; - g_window_info.window_main.surface = (__bridge void *)g_main_window; - - [NSApp run]; - } -} - -WindowSystem::WindowInfo &WindowSystem::GetWindowInfo() { - return g_window_info; -} - -void WindowSystem::UpdateWindowTitles(bool isIdle, bool isLoading, double fps) { - if (!g_main_window) - return; - - NSString *title = nil; - if (isIdle) - title = @"Cemu"; - else if (isLoading) - title = @"Cemu - Loading..."; - else - title = [NSString stringWithFormat:@"Cemu - FPS: %.2f", fps]; - - [g_main_window setTitle:title]; -} - -void WindowSystem::GetWindowSize(int &w, int &h) { - w = g_window_info.width; - h = g_window_info.height; -} - -void WindowSystem::GetPadWindowSize(int &w, int &h) { - w = 0; - h = 0; -} - -void WindowSystem::GetWindowPhysSize(int &w, int &h) { - w = g_window_info.phys_width; - h = g_window_info.phys_height; -} - -void WindowSystem::GetPadWindowPhysSize(int &w, int &h) { - w = 0; - h = 0; -} - -double WindowSystem::GetWindowDPIScale() { return g_window_info.dpi_scale; } - -double WindowSystem::GetPadDPIScale() { return 1.0; } - -bool WindowSystem::IsPadWindowOpen() { return false; } - -bool WindowSystem::IsKeyDown(uint32 key) { - return g_window_info.get_keystate(key); -} - -bool WindowSystem::IsKeyDown(PlatformKeyCodes key) { - switch (key) { - case PlatformKeyCodes::LCONTROL: - return IsKeyDown(0x3B); - case PlatformKeyCodes::RCONTROL: - return IsKeyDown(0x3E); - case PlatformKeyCodes::TAB: - return IsKeyDown(0x30); - case PlatformKeyCodes::ESCAPE: - return IsKeyDown(0x35); - default: - return false; - } -} - -std::string WindowSystem::GetKeyCodeName(uint32 key) { - return fmt::format("key_{}", key); -} - -bool WindowSystem::InputConfigWindowHasFocus() { return false; } - -void WindowSystem::NotifyGameLoaded() {} - -void WindowSystem::NotifyGameExited() {} - -void WindowSystem::RefreshGameList() { CafeTitleList::Refresh(); } - -void WindowSystem::CaptureInput(const ControllerState & /*currentState*/, - const ControllerState & /*lastState*/) {} - -bool WindowSystem::IsFullScreen() { return g_window_info.is_fullscreen; }