From 67e171c48ecfdf55396ebb53bda233c17f82f513 Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Sun, 23 Jul 2023 19:20:58 +0300 Subject: [PATCH] Remove guiWrapper from gui project & replace all functions with callbacks --- src/Cafe/CMakeLists.txt | 1 - src/Cafe/CafeSystem.cpp | 25 +- src/Cafe/CafeSystem.h | 11 + src/Cafe/HW/Espresso/Debugger/Debugger.cpp | 52 +- src/Cafe/HW/Espresso/Debugger/Debugger.h | 15 + src/Cafe/HW/Latte/Core/LatteOverlay.cpp | 11 +- .../HW/Latte/Core/LattePerformanceMonitor.cpp | 9 +- src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp | 12 +- src/Cafe/HW/Latte/Core/LatteShaderCache.cpp | 6 +- src/Cafe/HW/Latte/Core/LatteThread.cpp | 7 +- .../Latte/Renderer/OpenGL/OpenGLRenderer.cpp | 9 +- src/Cafe/HW/Latte/Renderer/Renderer.cpp | 87 +--- src/Cafe/HW/Latte/Renderer/Renderer.h | 5 + .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 50 +- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 3 +- src/Cafe/OS/RPL/rpl.cpp | 7 +- src/Cafe/OS/libs/padscore/padscore.cpp | 3 +- src/Cafe/OS/libs/vpad/vpad.cpp | 3 +- src/Cemu/CMakeLists.txt | 2 + src/Cemu/GuiSystem/GuiSystem.cpp | 97 ++++ src/Cemu/GuiSystem/GuiSystem.h | 115 +++++ src/Cemu/Logging/CemuLogging.cpp | 25 +- src/Cemu/Logging/CemuLogging.h | 10 + .../Tools/DownloadManager/DownloadManager.cpp | 8 +- .../Tools/DownloadManager/DownloadManager.h | 3 + src/gui/guiWrapper.h | 144 ------ src/gui/wxGui/CMakeLists.txt | 1 - src/gui/wxGui/CemuApp.cpp | 46 +- src/gui/wxGui/LoggingWindow.cpp | 26 +- src/gui/wxGui/LoggingWindow.h | 23 +- src/gui/wxGui/MainWindow.cpp | 257 ++++++++-- src/gui/wxGui/MainWindow.h | 8 +- src/gui/wxGui/PadViewFrame.cpp | 60 +-- src/gui/wxGui/canvas/VulkanCanvas.cpp | 9 +- src/gui/wxGui/debugger/BreakpointWindow.cpp | 3 +- src/gui/wxGui/debugger/DebuggerWindow2.cpp | 40 +- src/gui/wxGui/debugger/DebuggerWindow2.h | 10 +- src/gui/wxGui/debugger/DisasmCtrl.cpp | 3 +- src/gui/wxGui/debugger/ModuleWindow.cpp | 3 +- src/gui/wxGui/debugger/SymbolCtrl.cpp | 3 +- src/gui/wxGui/debugger/SymbolWindow.cpp | 1 - src/gui/wxGui/helpers/wxHelpers.cpp | 116 ++++- src/gui/wxGui/helpers/wxHelpers.h | 8 + src/gui/wxGui/wxGuiWrapper.cpp | 464 ------------------ src/imgui/imgui_extension.cpp | 9 +- src/input/InputManager.cpp | 12 + src/input/InputManager.h | 3 + src/input/api/Controller.cpp | 2 - src/input/api/Keyboard/KeyboardController.cpp | 8 +- src/input/emulated/VPADController.cpp | 6 +- src/main.cpp | 3 +- src/mainLLE.cpp | 2 +- 52 files changed, 932 insertions(+), 914 deletions(-) create mode 100644 src/Cemu/GuiSystem/GuiSystem.cpp create mode 100644 src/Cemu/GuiSystem/GuiSystem.h delete mode 100644 src/gui/guiWrapper.h delete mode 100644 src/gui/wxGui/wxGuiWrapper.cpp diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 7e94db4e..d8e3c644 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -490,7 +490,6 @@ target_link_libraries(CemuCafe PRIVATE CemuCommon CemuComponents CemuConfig - CemuGui CemuInput CemuResource CemuUtil diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index f92911cd..4b314bb6 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -64,9 +64,6 @@ // HW interfaces #include "Cafe/HW/SI/si.h" -// dependency to be removed -#include "gui/guiWrapper.h" - std::string _pathToExecutable; std::string _pathToBaseExecutable; @@ -354,7 +351,9 @@ uint32 loadSharedData() void cemu_initForGame() { - gui_updateWindowTitles(false, true, 0.0); + auto cafeSystemCallbacks = CafeSystem::getCafeSystemCallbacks(); + if (cafeSystemCallbacks) + cafeSystemCallbacks->updateWindowTitles(false, true, 0.0); // input manager apply game profile InputManager::instance().apply_game_profile(); // log info for launched title @@ -443,6 +442,20 @@ void cemu_deinitForGame() namespace CafeSystem { + CafeSystemCallbacks* sCafeSystemCallbacks = nullptr; + void registerCafeSystemCallbacks(CafeSystemCallbacks* cafeSystemCallbacks) + { + sCafeSystemCallbacks = cafeSystemCallbacks; + } + void unregisterCafeSystemCallbacks() + { + sCafeSystemCallbacks = nullptr; + } + CafeSystemCallbacks* getCafeSystemCallbacks() + { + return sCafeSystemCallbacks; + } + void InitVirtualMlcStorage(); void MlcStorageMountTitle(TitleInfo& titleInfo); @@ -679,7 +692,9 @@ namespace CafeSystem PPCTimer_waitForInit(); // start system sSystemRunning = true; - gui_notifyGameLoaded(); + auto cafeSystemCallbacks = CafeSystem::getCafeSystemCallbacks(); + if (cafeSystemCallbacks) + cafeSystemCallbacks->notifyGameLoaded(); std::thread t(_LaunchTitleThread); t.detach(); } diff --git a/src/Cafe/CafeSystem.h b/src/Cafe/CafeSystem.h index dce0b940..130ff988 100644 --- a/src/Cafe/CafeSystem.h +++ b/src/Cafe/CafeSystem.h @@ -14,6 +14,17 @@ namespace CafeSystem //BAD_META_DATA, - the title list only stores titles with valid meta, so this error code is impossible }; + class CafeSystemCallbacks + { + public: + virtual void updateWindowTitles(bool isIdle, bool isLoading, double fps) = 0; + virtual void notifyGameLoaded() = 0; + }; + + void registerCafeSystemCallbacks(CafeSystemCallbacks* cafeSystemCallbacks); + void unregisterCafeSystemCallbacks(); + CafeSystemCallbacks* getCafeSystemCallbacks(); + void Initialize(); STATUS_CODE PrepareForegroundTitle(TitleId titleId); STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path); diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index f7361405..defb9629 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -1,4 +1,3 @@ -#include "gui/guiWrapper.h" #include "Debugger.h" #include "Cemu/PPCAssembler/ppcAssembler.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" @@ -12,6 +11,21 @@ debuggerState_t debuggerState{ }; +DebuggerCallbacks* sDebuggerCallbacks = nullptr; + +void debugger_registerDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks) +{ + sDebuggerCallbacks = debuggerCallbacks; +} +void debugger_unregisterDebuggerCallbacks() +{ + sDebuggerCallbacks = nullptr; +} +DebuggerCallbacks* debugger_getDebuggerCallbacks() +{ + return sDebuggerCallbacks; +} + DebuggerBreakpoint* debugger_getFirstBP(uint32 address) { for (auto& it : debuggerState.breakpoints) @@ -329,7 +343,8 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b { bp->enabled = state; debugger_updateExecutionBreakpoint(address); - debuggerWindow_updateViewThreadsafe2(); + if (sDebuggerCallbacks) + sDebuggerCallbacks->updateViewThreadsafe(); } else if (bpItr->isMemBP()) { @@ -351,7 +366,8 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b debugger_updateMemoryBreakpoint(bpItr); else debugger_updateMemoryBreakpoint(nullptr); - debuggerWindow_updateViewThreadsafe2(); + if (sDebuggerCallbacks) + sDebuggerCallbacks->updateViewThreadsafe(); } return; } @@ -459,8 +475,8 @@ void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true) PPCInterpreterSlim_executeInstruction(hCPU); debugger_updateExecutionBreakpoint(initialIP); debuggerState.debugSession.instructionPointer = hCPU->instructionPointer; - if(updateDebuggerWindow) - debuggerWindow_moveIP(); + if(updateDebuggerWindow && sDebuggerCallbacks) + sDebuggerCallbacks->moveIP(); ppcRecompilerEnabled = isRecEnabled; } @@ -479,7 +495,8 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) // nothing to skip, use step-into debugger_stepInto(hCPU); debugger_updateExecutionBreakpoint(initialIP); - debuggerWindow_moveIP(); + if (sDebuggerCallbacks) + sDebuggerCallbacks->moveIP(); ppcRecompilerEnabled = isRecEnabled; return false; } @@ -487,7 +504,8 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) debugger_createSingleShotExecuteBreakpoint(initialIP +4); // step over current instruction (to avoid breakpoint) debugger_stepInto(hCPU); - debuggerWindow_moveIP(); + if (sDebuggerCallbacks) + sDebuggerCallbacks->moveIP(); // restore breakpoints debugger_updateExecutionBreakpoint(initialIP); // run @@ -515,8 +533,11 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) DebuggerBreakpoint* singleshotBP = debugger_getFirstBP(debuggerState.debugSession.instructionPointer, DEBUGGER_BP_T_ONE_SHOT); if (singleshotBP) debugger_deleteBreakpoint(singleshotBP); - debuggerWindow_notifyDebugBreakpointHit2(); - debuggerWindow_updateViewThreadsafe2(); + if (sDebuggerCallbacks) + { + sDebuggerCallbacks->notifyDebugBreakpointHit(); + sDebuggerCallbacks->updateViewThreadsafe(); + } // reset step control debuggerState.debugSession.stepInto = false; debuggerState.debugSession.stepOver = false; @@ -533,14 +554,16 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) break; // if true is returned, continue with execution } debugger_createPPCStateSnapshot(hCPU); - debuggerWindow_updateViewThreadsafe2(); + if (sDebuggerCallbacks) + sDebuggerCallbacks->updateViewThreadsafe(); debuggerState.debugSession.stepOver = false; } if (debuggerState.debugSession.stepInto) { debugger_stepInto(hCPU); debugger_createPPCStateSnapshot(hCPU); - debuggerWindow_updateViewThreadsafe2(); + if (sDebuggerCallbacks) + sDebuggerCallbacks->updateViewThreadsafe(); debuggerState.debugSession.stepInto = false; continue; } @@ -557,8 +580,11 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) debuggerState.debugSession.isTrapped = false; debuggerState.debugSession.hCPU = nullptr; - debuggerWindow_updateViewThreadsafe2(); - debuggerWindow_notifyRun(); + if (sDebuggerCallbacks) + { + sDebuggerCallbacks->updateViewThreadsafe(); + sDebuggerCallbacks->notifyRun(); + } } void debugger_shouldBreak(PPCInterpreter_t* hCPU) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.h b/src/Cafe/HW/Espresso/Debugger/Debugger.h index 08cbd90a..22015a8f 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.h +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.h @@ -97,6 +97,21 @@ typedef struct extern debuggerState_t debuggerState; // new API +class DebuggerCallbacks +{ + public: + virtual void updateViewThreadsafe() = 0; + virtual void notifyDebugBreakpointHit() = 0; + virtual void notifyRun() = 0; + virtual void moveIP() = 0; + virtual void notifyModuleLoaded(void* module) = 0; + virtual void notifyModuleUnloaded(void* module) = 0; +}; + +void debugger_registerDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks); +void debugger_unregisterDebuggerCallbacks(); +DebuggerCallbacks* debugger_getDebuggerCallbacks(); + DebuggerBreakpoint* debugger_getFirstBP(uint32 address); void debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint void debugger_createExecuteBreakpoint(uint32 address); diff --git a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp index 7cc72fdb..09a8cc58 100644 --- a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp +++ b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp @@ -1,6 +1,5 @@ #include "Cafe/HW/Latte/Core/LatteOverlay.h" #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" -#include "gui/guiWrapper.h" #include "config/CemuConfig.h" @@ -14,6 +13,8 @@ #include "input/InputManager.h" #include "util/SystemInfo/SystemInfo.h" +#include "Cemu/GuiSystem/GuiSystem.h" + #include struct OverlayStats @@ -512,17 +513,17 @@ void LatteOverlay_render(bool pad_view) return; sint32 w = 0, h = 0; - if (pad_view && gui_isPadWindowOpen()) - gui_getPadWindowPhysSize(w, h); + if (pad_view && GuiSystem::isPadWindowOpen()) + GuiSystem::getPadWindowPhysSize(w, h); else - gui_getWindowPhysSize(w, h); + GuiSystem::getWindowPhysSize(w, h); if (w == 0 || h == 0) return; const Vector2f window_size{ (float)w,(float)h }; - float fontDPIScale = !pad_view ? gui_getWindowDPIScale() : gui_getPadDPIScale(); + float fontDPIScale = !pad_view ? GuiSystem::getWindowDPIScale() : GuiSystem::getPadDPIScale(); float overlayFontSize = 14.0f * (float)config.overlay.text_scale / 100.0f * fontDPIScale; diff --git a/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp b/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp index 5d6a020b..8d10765f 100644 --- a/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp +++ b/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp @@ -1,6 +1,6 @@ #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/HW/Latte/Core/LatteOverlay.h" -#include "gui/guiWrapper.h" +#include "Cafe/CafeSystem.h" performanceMonitor_t performanceMonitor{}; @@ -102,15 +102,18 @@ void LattePerformanceMonitor_frameEnd() // next update in 1 second performanceMonitor.cycle[performanceMonitor.cycleIndex].lastUpdate = GetTickCount(); + auto cafeSystemCallbacks = CafeSystem::getCafeSystemCallbacks(); if (isFirstUpdate) { LatteOverlay_updateStats(0.0, 0); - gui_updateWindowTitles(false, false, 0.0); + if (cafeSystemCallbacks) + cafeSystemCallbacks->updateWindowTitles(false, false, 0.0); } else { LatteOverlay_updateStats(fps, drawCallCounter / elapsedFrames); - gui_updateWindowTitles(false, false, fps); + if (cafeSystemCallbacks) + cafeSystemCallbacks->updateWindowTitles(false, false, fps); } } LatteOverlay_updateStatsPerFrame(); diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index 4f9d8173..0d293ecd 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -12,7 +12,7 @@ #include "Cafe/GraphicPack/GraphicPack2.h" #include "config/ActiveSettings.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h" -#include "gui/guiWrapper.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "Cafe/OS/libs/erreula/erreula.h" #include "input/InputManager.h" #include "Cafe/OS/libs/swkbd/swkbd.h" @@ -846,10 +846,10 @@ sint32 _currentOutputImageHeight = 0; void LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, sint32* height, sint32* fullWidth, sint32* fullHeight, bool padView) { int w, h; - if(padView && gui_isPadWindowOpen()) - gui_getPadWindowPhysSize(w, h); + if(padView && GuiSystem::isPadWindowOpen()) + GuiSystem::getPadWindowPhysSize(w, h); else - gui_getWindowPhysSize(w, h); + GuiSystem::getWindowPhysSize(w, h); sint32 scaledOutputX; sint32 scaledOutputY; @@ -1014,8 +1014,8 @@ void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uin return; } - const bool tabPressed = gui_isKeyDown(PlatformKeyCodes::TAB); - const bool ctrlPressed = gui_isKeyDown(PlatformKeyCodes::LCONTROL); + const bool tabPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::TAB); + const bool ctrlPressed = GuiSystem::isKeyDown(GuiSystem::PlatformKeyCodes::LCONTROL); bool showDRC = swkbd_hasKeyboardInputHook() == false && tabPressed; bool& alwaysDisplayDRC = LatteGPUState.alwaysDisplayDRC; diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index 80309140..58fdf191 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -4,9 +4,9 @@ #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h" #include "Cafe/HW/Latte/Core/FetchShader.h" -#include "Cemu/FileCache/FileCache.h" #include "Cafe/GameProfile/GameProfile.h" -#include "gui/guiWrapper.h" +#include "Cemu/FileCache/FileCache.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h" @@ -379,7 +379,7 @@ void LatteShaderCache_ShowProgress(const std::function & loadUpdateF continue; int w, h; - gui_getWindowPhysSize(w, h); + GuiSystem::getWindowPhysSize(w, h); const Vector2f window_size{ (float)w,(float)h }; ImGui_GetFont(window_size.y / 32.0f); // = 24 by default diff --git a/src/Cafe/HW/Latte/Core/LatteThread.cpp b/src/Cafe/HW/Latte/Core/LatteThread.cpp index bb5344a1..21abb284 100644 --- a/src/Cafe/HW/Latte/Core/LatteThread.cpp +++ b/src/Cafe/HW/Latte/Core/LatteThread.cpp @@ -6,7 +6,7 @@ #include "Cafe/HW/Latte/Core/LatteAsyncCommands.h" #include "Cafe/GameProfile/GameProfile.h" #include "Cafe/GraphicPack/GraphicPack2.h" -#include "gui/guiWrapper.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "Cafe/HW/Latte/Core/LatteBufferCache.h" @@ -117,7 +117,7 @@ int Latte_ThreadEntry() { SetThreadName("LatteThread"); sint32 w,h; - gui_getWindowPhysSize(w,h); + GuiSystem::getWindowPhysSize(w,h); // renderer g_renderer->Initialize(); @@ -174,8 +174,7 @@ int Latte_ThreadEntry() g_renderer->DrawEmptyFrame(true); g_renderer->DrawEmptyFrame(false); - - gui_hasScreenshotRequest(); // keep the screenshot request queue empty + g_renderer->CancelScreenshotRequest(); std::this_thread::sleep_for(std::chrono::milliseconds(1000/60)); } diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index fdeda42c..4bc451ed 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -1,5 +1,4 @@ #include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h" -#include "gui/guiWrapper.h" #include "Cafe/HW/Latte/Core/LatteRingBuffer.h" #include "Cafe/HW/Latte/Core/LatteDraw.h" @@ -19,6 +18,8 @@ #include "Cafe/HW/Latte/ISA/RegDefines.h" #include "Cafe/OS/libs/gx2/GX2.h" +#include "Cemu/GuiSystem/GuiSystem.h" + #include "GLCanvas.h" #define STRINGIFY2(X) #X @@ -478,7 +479,7 @@ void OpenGLRenderer::ClearColorbuffer(bool padView) void OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView) { - const bool hasScreenshotRequest = gui_hasScreenshotRequest(); + const bool hasScreenshotRequest = std::exchange(m_screenshot_requested, false); if(!hasScreenshotRequest && m_screenshot_state == ScreenshotState::None) return; @@ -562,9 +563,9 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu { int windowWidth, windowHeight; if (padView) - gui_getPadWindowPhysSize(windowWidth, windowHeight); + GuiSystem::getPadWindowPhysSize(windowWidth, windowHeight); else - gui_getWindowPhysSize(windowWidth, windowHeight); + GuiSystem::getWindowPhysSize(windowWidth, windowHeight); g_renderer->renderTarget_setViewport(0, 0, windowWidth, windowHeight, 0.0f, 1.0f); g_renderer->ClearColorbuffer(padView); } diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.cpp b/src/Cafe/HW/Latte/Renderer/Renderer.cpp index b8585c77..8a876157 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Renderer.cpp @@ -1,5 +1,5 @@ #include "Cafe/HW/Latte/Renderer/Renderer.h" -#include "gui/guiWrapper.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "config/CemuConfig.h" #include "Cafe/HW/Latte/Core/LatteOverlay.h" @@ -65,9 +65,9 @@ bool Renderer::ImguiBegin(bool mainWindow) { sint32 w = 0, h = 0; if(mainWindow) - gui_getWindowPhysSize(w, h); - else if(gui_isPadWindowOpen()) - gui_getPadWindowPhysSize(w, h); + GuiSystem::getWindowPhysSize(w, h); + else if(GuiSystem::isPadWindowOpen()) + GuiSystem::getPadWindowPhysSize(w, h); else return false; @@ -109,74 +109,29 @@ uint8 Renderer::RGBComponentToSRGB(uint8 cli) return (uint8)(cs * 255.0f); } -static std::optional GenerateScreenshotFilename(bool isDRC) +void Renderer::RequestScreenshot(const std::function(const std::vector&, int, int, bool)>& onSaveScreenshot) { - fs::path screendir = ActiveSettings::GetUserDataPath("screenshots"); - // build screenshot name with format Screenshot_YYYY-MM-DD_HH-MM-SS[_GamePad].png - // if the file already exists add a suffix counter (_2.png, _3.png etc) - std::time_t time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - std::tm* tm = std::localtime(&time_t); - - std::string screenshotFileName = fmt::format("Screenshot_{:04}-{:02}-{:02}_{:02}-{:02}-{:02}", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - if (isDRC) - screenshotFileName.append("_GamePad"); - - fs::path screenshotPath; - for(sint32 i=0; i<999; i++) - { - screenshotPath = screendir; - if (i == 0) - screenshotPath.append(fmt::format("{}.png", screenshotFileName)); - else - screenshotPath.append(fmt::format("{}_{}.png", screenshotFileName, i + 1)); - - std::error_code ec; - bool exists = fs::exists(screenshotPath, ec); - - if (!ec && !exists) - return screenshotPath; - } - return std::nullopt; + m_screenshot_requested = true; + m_on_save_screenshot = onSaveScreenshot; } -static void ScreenshotThread(std::vector data, bool save_screenshot, int width, int height, bool mainWindow) +void Renderer::CancelScreenshotRequest() { -#if BOOST_OS_WINDOWS - // on Windows wxWidgets uses OLE API for the clipboard - // to make this work we need to call OleInitialize() on the same thread - OleInitialize(nullptr); -#endif - - if (mainWindow) - { - if(gui_saveScreenshotToClipboard(data, width, height)) - { - if (!save_screenshot) - LatteOverlay_pushNotification("Screenshot saved to clipboard", 2500); - } - else - { - LatteOverlay_pushNotification("Failed to open clipboard", 2500); - } - } - - if (save_screenshot) - { - auto imagePath = GenerateScreenshotFilename(mainWindow); - if (imagePath.has_value() && gui_saveScreenshotToFile(imagePath.value(), data, width, height)) - { - if (mainWindow) - LatteOverlay_pushNotification("Screenshot saved", 2500); - } - else - { - LatteOverlay_pushNotification("Failed to save screenshot to file", 2500); - } - } + m_screenshot_requested = false; + m_on_save_screenshot = nullptr; } void Renderer::SaveScreenshot(const std::vector& rgb_data, int width, int height, bool mainWindow) const { - const bool save_screenshot = GetConfig().save_screenshot; - std::thread(ScreenshotThread, rgb_data, save_screenshot, width, height, mainWindow).detach(); + std::thread( + [=, this]() + { + if (m_on_save_screenshot) + { + auto notificationMessage = m_on_save_screenshot(rgb_data, width, height, mainWindow); + if (notificationMessage.has_value()) + LatteOverlay_pushNotification(notificationMessage.value(), 2500); + } + }) + .detach(); } diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.h b/src/Cafe/HW/Latte/Renderer/Renderer.h index 61ff10c8..ec2c9a36 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.h +++ b/src/Cafe/HW/Latte/Renderer/Renderer.h @@ -67,6 +67,9 @@ public: virtual void DrawEmptyFrame(bool mainWindow) = 0; virtual void SwapBuffers(bool swapTV, bool swapDRC) = 0; + void RequestScreenshot(const std::function(const std::vector&, int, int, bool)>& onSaveScreenshot); + void CancelScreenshotRequest(); + virtual void HandleScreenshotRequest(LatteTextureView* texView, bool padView){} virtual void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, @@ -172,6 +175,8 @@ protected: Pad, }; ScreenshotState m_screenshot_state = ScreenshotState::None; + bool m_screenshot_requested = false; + std::function(const std::vector&, int, int, bool)> m_on_save_screenshot; void SaveScreenshot(const std::vector& rgb_data, int width, int height, bool mainWindow) const; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index e736e0a4..e9a445ba 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -12,12 +12,12 @@ #include "Cafe/CafeSystem.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "util/helpers/helpers.h" #include "util/helpers/StringHelpers.h" #include "config/ActiveSettings.h" #include "config/CemuConfig.h" -#include "gui/guiWrapper.h" #include "imgui/imgui_extension.h" #include "imgui/imgui_impl_vulkan.h" @@ -112,11 +112,11 @@ std::vector VulkanRenderer::GetDevices() #if __ANDROID__ requiredExtensions.emplace_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); #else - auto backend = gui_getWindowInfo().window_main.backend; - if(backend == WindowHandleInfo::Backend::X11) + auto backend = GuiSystem::getWindowInfo().window_main.backend; + if(backend == GuiSystem::WindowHandleInfo::Backend::X11) requiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); #ifdef HAS_WAYLAND - else if (backend == WindowHandleInfo::Backend::WAYLAND) + else if (backend == GuiSystem::WindowHandleInfo::Backend::WAYLAND) requiredExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); #endif // HAS_WAYLAND #endif // __ANDROID__ @@ -156,7 +156,7 @@ std::vector VulkanRenderer::GetDevices() throw std::runtime_error("Failed to find a GPU with Vulkan support."); // create tmp surface to create a logical device - auto surface = CreateFramebufferSurface(instance, gui_getWindowInfo().window_main); + auto surface = CreateFramebufferSurface(instance, GuiSystem::getWindowInfo().window_main); std::vector devices(device_count); vkEnumeratePhysicalDevices(instance, &device_count, devices.data()); for (const auto& device : devices) @@ -362,7 +362,7 @@ VulkanRenderer::VulkanRenderer() throw std::runtime_error("Failed to find a GPU with Vulkan support."); // create tmp surface to create a logical device - auto surface = CreateFramebufferSurface(m_instance, gui_getWindowInfo().window_main); + auto surface = CreateFramebufferSurface(m_instance, GuiSystem::getWindowInfo().window_main); auto& config = GetConfig(); decltype(config.graphic_device_uuid) zero{}; @@ -677,7 +677,7 @@ VulkanRenderer* VulkanRenderer::GetInstance() void VulkanRenderer::InitializeSurface(const Vector2i& size, bool mainWindow) { - auto& windowHandleInfo = mainWindow ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad; + auto& windowHandleInfo = mainWindow ? GuiSystem::getWindowInfo().canvas_main : GuiSystem::getWindowInfo().canvas_pad; const auto surface = CreateFramebufferSurface(m_instance, windowHandleInfo); if (mainWindow) @@ -721,7 +721,7 @@ bool VulkanRenderer::IsPadWindowActive() void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView) { - const bool hasScreenshotRequest = gui_hasScreenshotRequest(); + const bool hasScreenshotRequest = std::exchange(m_screenshot_requested, false); if (!hasScreenshotRequest && m_screenshot_state == ScreenshotState::None) return; @@ -1187,11 +1187,11 @@ std::vector VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo #if __ANDROID__ requiredInstanceExtensions.emplace_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); #else - auto backend = gui_getWindowInfo().window_main.backend; - if(backend == WindowHandleInfo::Backend::X11) + auto backend = GuiSystem::getWindowInfo().window_main.backend; + if(backend == GuiSystem::WindowHandleInfo::Backend::X11) requiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); #if HAS_WAYLAND - else if (backend == WindowHandleInfo::Backend::WAYLAND) + else if (backend == GuiSystem::WindowHandleInfo::Backend::WAYLAND) requiredInstanceExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); #endif // HAS_WAYLAND #endif // __ANDROID__ @@ -1354,24 +1354,24 @@ VkSurfaceKHR VulkanRenderer::CreateWaylandSurface(VkInstance instance, wl_displa #endif // __ANDROID__ #endif // BOOST_OS_LINUX -VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo) +VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struct GuiSystem::WindowHandleInfo& windowInfo) { #if BOOST_OS_WINDOWS - return CreateWinSurface(instance, windowInfo.hwnd); + return CreateWinSurface(instance, reinterpret_cast(windowInfo.hwnd)); #elif BOOST_OS_LINUX #if __ANDROID__ - return CreateAndroidSurface(instance, static_cast(windowInfo.handle)); + return CreateAndroidSurface(instance, static_cast(windowInfo.surface)); #else - if(windowInfo.backend == WindowHandleInfo::Backend::X11) - return CreateXlibSurface(instance, windowInfo.xlib_display, windowInfo.xlib_window); + if(windowInfo.backend == GuiSystem::WindowHandleInfo::Backend::X11) + return CreateXlibSurface(instance, static_cast(windowInfo.display), reinterpret_cast(windowInfo.surface)); #ifdef HAS_WAYLAND - if(windowInfo.backend == WindowHandleInfo::Backend::WAYLAND) - return CreateWaylandSurface(instance, windowInfo.display, windowInfo.surface); + if(windowInfo.backend == GuiSystem::WindowHandleInfo::Backend::WAYLAND) + return CreateWaylandSurface(instance, static_cast(windowInfo.display), static_cast(windowInfo.surface)); #endif return {}; #endif // __ANDROID__ #elif BOOST_OS_MACOS - return CreateCocoaSurface(instance, windowInfo.handle); + return CreateCocoaSurface(instance, windowInfo.surface); #endif } @@ -2666,11 +2666,11 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate) if (mainWindow) { ImGui_ImplVulkan_Shutdown(); - gui_getWindowPhysSize(size.x, size.y); + GuiSystem::getWindowPhysSize(size.x, size.y); } else { - gui_getPadWindowPhysSize(size.x, size.y); + GuiSystem::getPadWindowPhysSize(size.x, size.y); } chainInfo.swapchainImageIndex = -1; @@ -2700,9 +2700,9 @@ bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow) int width, height; if (mainWindow) - gui_getWindowPhysSize(width, height); + GuiSystem::getWindowPhysSize(width, height); else - gui_getPadWindowPhysSize(width, height); + GuiSystem::getPadWindowPhysSize(width, height); auto extent = chainInfo.getExtent(); if (width != extent.width || height != extent.height) stateChanged = true; @@ -3793,9 +3793,9 @@ void VulkanRenderer::NotifySurfaceChanged(bool mainWindow) if(!chainInfo) return; if(mainWindow) - chainInfo->surface = CreateFramebufferSurface(m_instance, gui_getWindowInfo().canvas_main); + chainInfo->surface = CreateFramebufferSurface(m_instance, GuiSystem::getWindowInfo().canvas_main); else - chainInfo->surface = CreateFramebufferSurface(m_instance, gui_getWindowInfo().canvas_pad); + chainInfo->surface = CreateFramebufferSurface(m_instance, GuiSystem::getWindowInfo().canvas_pad); m_surfaceCondVar.notify_one(); } #endif // __ANDROID__ diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 07b4b25a..ad5cf15f 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -12,6 +12,7 @@ #include "util/helpers/Semaphore.h" #include "util/containers/flat_hash_map.hpp" #include "util/containers/robin_hood.h" +#include "Cemu/GuiSystem/GuiSystem.h" struct VkSupportedFormatInfo_t { @@ -213,7 +214,7 @@ public: #endif // __ANDROID__ #endif // BOOST_OS_LINUX - static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo); + static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, GuiSystem::WindowHandleInfo& windowInfo); void AppendOverlayDebugInfo() override; diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index b0aec8ae..b3c0be06 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -14,7 +14,6 @@ #include "util/crypto/crc32.h" #include "config/ActiveSettings.h" #include "Cafe/OS/libs/coreinit/coreinit_DynLoad.h" -#include "gui/guiWrapper.h" class PPCCodeHeap : public VHeap { @@ -1829,7 +1828,8 @@ void RPLLoader_UnloadModule(RPLModule* rpl) RPLLoader_decrementModuleDependencyRefs(rpl); // save module config for this module in the debugger - debuggerWindow_notifyModuleUnloaded(rpl); + auto debuggerInterface = debugger_getDebuggerCallbacks(); + if (debuggerInterface) debuggerInterface->notifyModuleLoaded(rpl); // release memory rplLoaderHeap_codeArea2.free(rpl->regionMappingBase_text.GetPtr()); @@ -1912,7 +1912,8 @@ void RPLLoader_Link() RPLLoader_LoadDebugSymbols(rplModuleList[i]); rplModuleList[i]->isLinked = true; // mark as linked GraphicPack2::NotifyModuleLoaded(rplModuleList[i]); - debuggerWindow_notifyModuleLoaded(rplModuleList[i]); + auto debuggerCallbacks = debugger_getDebuggerCallbacks(); + if (debuggerCallbacks) debuggerCallbacks->notifyModuleLoaded(rplModuleList[i]); } } diff --git a/src/Cafe/OS/libs/padscore/padscore.cpp b/src/Cafe/OS/libs/padscore/padscore.cpp index 1d447343..7ab4cd7a 100644 --- a/src/Cafe/OS/libs/padscore/padscore.cpp +++ b/src/Cafe/OS/libs/padscore/padscore.cpp @@ -1,6 +1,5 @@ #include "Cafe/OS/common/OSCommon.h" #include "Cafe/HW/Espresso/PPCCallback.h" -#include "gui/guiWrapper.h" #include "Cafe/OS/libs/padscore/padscore.h" #include "Cafe/OS/libs/coreinit/coreinit_Time.h" #include "Cafe/OS/libs/coreinit/coreinit_Alarm.h" @@ -450,7 +449,7 @@ sint32 _KPADRead(uint32 channel, KPADStatus_t* samplingBufs, uint32 length, bety samplingBufs->wpadErr = WPAD_ERR_NONE; samplingBufs->data_format = controller->get_data_format(); samplingBufs->devType = controller->get_device_type(); - if(!g_inputConfigWindowHasFocus) + if (!InputManager::input_config_window_has_focus()) { const auto btn_repeat = padscore::g_padscore.controller_data[channel].btn_repeat; controller->KPADRead(*samplingBufs, btn_repeat); diff --git a/src/Cafe/OS/libs/vpad/vpad.cpp b/src/Cafe/OS/libs/vpad/vpad.cpp index 2ac47c96..ab7d403a 100644 --- a/src/Cafe/OS/libs/vpad/vpad.cpp +++ b/src/Cafe/OS/libs/vpad/vpad.cpp @@ -1,6 +1,5 @@ #include "Cafe/OS/common/OSCommon.h" #include "Cafe/HW/Espresso/PPCCallback.h" -#include "gui/guiWrapper.h" #include "Cafe/OS/libs/vpad/vpad.h" #include "audio/IAudioAPI.h" #include "Cafe/OS/libs/coreinit/coreinit_Time.h" @@ -263,7 +262,7 @@ namespace vpad PPCCore_switchToScheduler(); } - if (!g_inputConfigWindowHasFocus) + if (!InputManager::input_config_window_has_focus()) { if (channel <= 1 && vpadDelayEnabled) { diff --git a/src/Cemu/CMakeLists.txt b/src/Cemu/CMakeLists.txt index 1fce8ec1..2166dc5d 100644 --- a/src/Cemu/CMakeLists.txt +++ b/src/Cemu/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(CemuComponents ExpressionParser/ExpressionParser.h FileCache/FileCache.cpp FileCache/FileCache.h + GuiSystem/GuiSystem.cpp + GuiSystem/GuiSystem.h Logging/CemuDebugLogging.h Logging/CemuLogging.cpp Logging/CemuLogging.h diff --git a/src/Cemu/GuiSystem/GuiSystem.cpp b/src/Cemu/GuiSystem/GuiSystem.cpp new file mode 100644 index 00000000..2d2ce5f5 --- /dev/null +++ b/src/Cemu/GuiSystem/GuiSystem.cpp @@ -0,0 +1,97 @@ +#include "GuiSystem.h" + +namespace GuiSystem +{ +std::function s_key_code_to_string; +void registerKeyCodeToStringCallback(const std::function& keyCodeToString) +{ + s_key_code_to_string = keyCodeToString; +} +void unregisterKeyCodeToStringCallback() +{ + s_key_code_to_string = {}; +} +std::string keyCodeToString(uint32 key) +{ + if (!s_key_code_to_string) + return ""; + return s_key_code_to_string(key); +} + +WindowInfo s_window_info; + +WindowInfo& getWindowInfo() +{ + return s_window_info; +} + +void getWindowSize(int& w, int& h) +{ + w = s_window_info.width; + h = s_window_info.height; +} + +void getPadWindowSize(int& w, int& h) +{ + if (s_window_info.pad_open) + { + w = s_window_info.pad_width; + h = s_window_info.pad_height; + } + else + { + w = 0; + h = 0; + } +} + +void getWindowPhysSize(int& w, int& h) +{ + w = s_window_info.phys_width; + h = s_window_info.phys_height; +} + +void getPadWindowPhysSize(int& w, int& h) +{ + if (s_window_info.pad_open) + { + w = s_window_info.phys_pad_width; + h = s_window_info.phys_pad_height; + } + else + { + w = 0; + h = 0; + } +} + +double getWindowDPIScale() +{ + return s_window_info.dpi_scale; +} + +double getPadDPIScale() +{ + return s_window_info.pad_open ? s_window_info.pad_dpi_scale.load() : 1.0; +} + +bool isPadWindowOpen() +{ + return s_window_info.pad_open; +} + +bool isKeyDown(uint32 key) +{ + return s_window_info.get_keystate(key); +} + +bool isKeyDown(PlatformKeyCodes key) +{ + return s_window_info.get_keystate(key); +} + +bool isFullScreen() +{ + return s_window_info.is_fullscreen; +} +} // namespace GuiSystem \ No newline at end of file diff --git a/src/Cemu/GuiSystem/GuiSystem.h b/src/Cemu/GuiSystem/GuiSystem.h new file mode 100644 index 00000000..3daf0435 --- /dev/null +++ b/src/Cemu/GuiSystem/GuiSystem.h @@ -0,0 +1,115 @@ +#pragma once + +namespace GuiSystem +{ + +struct WindowHandleInfo +{ + enum class Backend + { + X11, + WAYLAND, + ANDROID, + COCOA, + WINDOWS + } backend; + void* display = nullptr; + void* surface = nullptr; +}; + +enum struct PlatformKeyCodes : uint32 +{ + LCONTROL, + RCONTROL, + TAB, + MAX +}; + +struct WindowInfo +{ + std::atomic_bool app_active; // our app is active/has focus + + std::atomic_int32_t width, height; // client size of main window + std::atomic_int32_t phys_width, phys_height; // client size of main window in physical pixels + std::atomic dpi_scale; + + std::atomic_bool pad_open; // if separate pad view is open + std::atomic_int32_t pad_width, pad_height; // client size of pad window + std::atomic_int32_t phys_pad_width, phys_pad_height; // client size of pad window in physical pixels + std::atomic pad_dpi_scale; + + std::atomic_bool pad_maximized = false; + std::atomic_int32_t restored_pad_x = -1, restored_pad_y = -1; + std::atomic_int32_t restored_pad_width = -1, restored_pad_height = -1; + + std::atomic_bool has_screenshot_request; + std::atomic_bool is_fullscreen; + + inline void set_keystate(uint32 keycode, bool state) + { + const std::lock_guard lock(keycode_mutex); + m_keydown[keycode] = state; + } + + inline void set_keystate(PlatformKeyCodes keycode, bool state) + { + const std::lock_guard lock(keycode_mutex); + m_platformkeydown.at(static_cast(keycode)) = state; + } + + inline bool get_keystate(uint32 keycode) + { + const std::lock_guard lock(keycode_mutex); + auto result = m_keydown.find(keycode); + if (result == m_keydown.end()) + return false; + return result->second; + } + + inline bool get_keystate(PlatformKeyCodes keycode) + { + const std::lock_guard lock(keycode_mutex); + return m_platformkeydown.at(static_cast(keycode)); + } + + inline void set_keystates_up() + { + const std::lock_guard lock(keycode_mutex); + std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair& el) { el.second = false; }); + m_platformkeydown.fill(false); + } + + template + void iter_keystates(fn f) + { + const std::lock_guard lock(keycode_mutex); + std::for_each(m_keydown.cbegin(), m_keydown.cend(), f); + } + + WindowHandleInfo window_main; + WindowHandleInfo window_pad; + + WindowHandleInfo canvas_main; + WindowHandleInfo canvas_pad; + + private: + std::array(PlatformKeyCodes::MAX)> m_platformkeydown; + std::mutex keycode_mutex; + std::unordered_map m_keydown; +}; + +void registerKeyCodeToStringCallback(const std::function& keyCodeToString); +void unregisterKeyCodeToStringCallback(); +std::string keyCodeToString(uint32 key); +void getWindowSize(int& w, int& h); +void getPadWindowSize(int& w, int& h); +void getWindowPhysSize(int& w, int& h); +void getPadWindowPhysSize(int& w, int& h); +double getWindowDPIScale(); +double getPadDPIScale(); +bool isPadWindowOpen(); +bool isKeyDown(uint32 key); +bool isKeyDown(PlatformKeyCodes key); +bool isFullScreen(); +WindowInfo& getWindowInfo(); +} // namespace GuiSystem \ No newline at end of file diff --git a/src/Cemu/Logging/CemuLogging.cpp b/src/Cemu/Logging/CemuLogging.cpp index 8203abd7..559aa660 100644 --- a/src/Cemu/Logging/CemuLogging.cpp +++ b/src/Cemu/Logging/CemuLogging.cpp @@ -1,6 +1,5 @@ #include "CemuLogging.h" #include "config/CemuConfig.h" -#include "gui/guiWrapper.h" #include "config/ActiveSettings.h" #include "util/helpers/helpers.h" @@ -54,6 +53,19 @@ const std::map g_logging_window_mapping {LogType::VulkanValidation, "Vulkan validation layer"}, }; +LogCallbacks* g_logCallbacks = nullptr; + +void cemuLog_registerLogCallbacks(LogCallbacks* logCallbacks) +{ + g_logCallbacks = logCallbacks; +} + +void cemuLog_unregisterLogCallbacks() +{ + g_logCallbacks = nullptr; +} + + uint64 cemuLog_getFlag(LogType type) { return type <= LogType::Force ? 0 : (1ULL << ((uint64)type - 1)); @@ -157,10 +169,13 @@ bool cemuLog_log(LogType type, std::string_view text) const auto it = std::find_if(g_logging_window_mapping.cbegin(), g_logging_window_mapping.cend(), [type](const auto& entry) { return entry.first == type; }); - if (it == g_logging_window_mapping.cend()) - gui_loggingWindowLog(text); - else - gui_loggingWindowLog(it->second, text); + if (g_logCallbacks) + { + if (it == g_logging_window_mapping.cend()) + g_logCallbacks->Log("", text); + else + g_logCallbacks->Log(it->second, text); + } return true; } diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index d55256c9..f5eb9b24 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -112,6 +112,16 @@ bool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args) #endif } +class LogCallbacks +{ +public: + virtual void Log(std::string_view filter, std::string_view message) = 0; + virtual void Log(std::string_view filter, std::wstring_view message) = 0; +}; + +void cemuLog_registerLogCallbacks(LogCallbacks* logCallbacks); +void cemuLog_unregisterLogCallbacks(); + // cafe lib calls bool cemuLog_advancedPPCLoggingEnabled(); diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp index e355936b..d6f48718 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp @@ -1,7 +1,6 @@ #include "Cemu/Tools/DownloadManager/DownloadManager.h" #include "Cafe/Account/Account.h" -#include "gui/guiWrapper.h" #include "util/crypto/md5.h" #include "Cafe/TitleList/TitleId.h" #include "Common/FileStream.h" @@ -28,6 +27,11 @@ FileCache* s_nupFileCache = nullptr; std::string _(const std::string& str) { return str; } std::string from_wxString(const std::string& str){ return str; } +void DownloadManager::setOnGameListRefreshRequested(const std::function& onGameListRefreshRequested) +{ + m_onGameListRefreshRequested = onGameListRefreshRequested; +} + /* version list */ void DownloadManager::downloadTitleVersionList() { @@ -1449,7 +1453,7 @@ void DownloadManager::asyncPackageInstall(Package* package) reportPackageStatus(package); checkPackagesState(); // lastly request game list to be refreshed - gui_requestGameListRefresh(); + if (m_onGameListRefreshRequested) m_onGameListRefreshRequested(); return; } diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.h b/src/Cemu/Tools/DownloadManager/DownloadManager.h index 1693318c..8fc4e84c 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.h +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.h @@ -393,6 +393,8 @@ public: return m_userData; } + void setOnGameListRefreshRequested(const std::function& onGameListRefreshRequested); + // register/unregister callbacks // setting valid callbacks will also trigger transfer of the entire title/package state and the current status message void registerCallbacks( @@ -450,6 +452,7 @@ public: } private: + std::function m_onGameListRefreshRequested; void(*m_cbUpdateConnectStatus)(std::string statusText, DLMGR_STATUS_CODE statusCode) { nullptr }; void(*m_cbAddDownloadableTitle)(const DlMgrTitleReport& titleInfo); void(*m_cbRemoveDownloadableTitle)(uint64 titleId, uint16 version); diff --git a/src/gui/guiWrapper.h b/src/gui/guiWrapper.h deleted file mode 100644 index cfa53b68..00000000 --- a/src/gui/guiWrapper.h +++ /dev/null @@ -1,144 +0,0 @@ -#pragma once - -#include - -struct WindowHandleInfo -{ -#if BOOST_OS_WINDOWS - std::atomic hwnd; -#elif BOOST_OS_LINUX && !__ANDROID__ - enum class Backend - { - X11, - WAYLAND, - } backend; - // XLIB - Display* xlib_display{}; - Window xlib_window{}; - - // XCB (not used by GTK so we cant retrieve these without making our own window) - //xcb_connection_t* xcb_con{}; - //xcb_window_t xcb_window{}; - #ifdef HAS_WAYLAND - struct wl_display* display; - struct wl_surface* surface; - #endif // HAS_WAYLAND -#else - void* handle; -#endif -}; - -enum struct PlatformKeyCodes : uint32 -{ - LCONTROL, - RCONTROL, - TAB -}; - -struct WindowInfo -{ - std::atomic_bool app_active; // our app is active/has focus - - std::atomic_int32_t width, height; // client size of main window - std::atomic_int32_t phys_width, phys_height; // client size of main window in physical pixels - std::atomic dpi_scale; - - std::atomic_bool pad_open; // if separate pad view is open - std::atomic_int32_t pad_width, pad_height; // client size of pad window - std::atomic_int32_t phys_pad_width, phys_pad_height; // client size of pad window in physical pixels - std::atomic pad_dpi_scale; - - std::atomic_bool pad_maximized = false; - std::atomic_int32_t restored_pad_x = -1, restored_pad_y = -1; - std::atomic_int32_t restored_pad_width = -1, restored_pad_height = -1; - - std::atomic_bool has_screenshot_request; - std::atomic_bool is_fullscreen; - - void set_keystate(uint32 keycode, bool state) - { - const std::lock_guard lock(keycode_mutex); - m_keydown[keycode] = state; - } - - bool get_keystate(uint32 keycode) - { - const std::lock_guard lock(keycode_mutex); - auto result = m_keydown.find(keycode); - if (result == m_keydown.end()) - return false; - return result->second; - } - - void set_keystatesup() - { - const std::lock_guard lock(keycode_mutex); - std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair& el){ el.second = false; }); - } - - template - void iter_keystates(fn f) - { - const std::lock_guard lock(keycode_mutex); - std::for_each(m_keydown.cbegin(), m_keydown.cend(), f); - } - - WindowHandleInfo window_main; - WindowHandleInfo window_pad; - - // canvas - WindowHandleInfo canvas_main; - WindowHandleInfo canvas_pad; - private: - std::mutex keycode_mutex; - // m_keydown keys must be valid ImGuiKey values - std::unordered_map m_keydown; -}; - -extern bool g_inputConfigWindowHasFocus; - -void gui_loggingWindowLog(std::string_view filter, std::string_view message); -void gui_loggingWindowLog(std::string_view message); - -void gui_create(); - -WindowInfo& gui_getWindowInfo(); - -void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps); -void gui_getWindowSize(int& w, int& h); -void gui_getPadWindowSize(int& w, int& h); -void gui_getWindowPhysSize(int& w, int& h); -void gui_getPadWindowPhysSize(int& w, int& h); -double gui_getWindowDPIScale(); -double gui_getPadDPIScale(); -bool gui_isPadWindowOpen(); -bool gui_isKeyDown(uint32 key); -bool gui_isKeyDown(PlatformKeyCodes key); - -void gui_notifyGameLoaded(); -void gui_notifyGameExited(); - -bool gui_isFullScreen(); - -void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, class wxWindow* wxw); - -void gui_requestGameListRefresh(); - -std::string gui_RawKeyCodeToString(uint32 keyCode); - -bool gui_saveScreenshotToFile(const fs::path& imagePath, std::vector& data, int width, int height); -bool gui_saveScreenshotToClipboard(std::vector& data, int width, int height); -/* -* Returns true if a screenshot request is queued -* Once this function has returned true, it will reset back to -* false until the next time a screenshot is requested -*/ -bool gui_hasScreenshotRequest(); - -// debugger stuff -void debuggerWindow_updateViewThreadsafe2(); -void debuggerWindow_notifyDebugBreakpointHit2(); -void debuggerWindow_notifyRun(); -void debuggerWindow_moveIP(); -void debuggerWindow_notifyModuleLoaded(void* module); -void debuggerWindow_notifyModuleUnloaded(void* module); diff --git a/src/gui/wxGui/CMakeLists.txt b/src/gui/wxGui/CMakeLists.txt index 1a1b1d58..e69b928b 100644 --- a/src/gui/wxGui/CMakeLists.txt +++ b/src/gui/wxGui/CMakeLists.txt @@ -122,7 +122,6 @@ add_library(CemuwxGui wxcomponents/unchecked_mo.xpm wxcomponents/unchecked.xpm wxgui.h - wxGuiWrapper.cpp wxHelper.h ) diff --git a/src/gui/wxGui/CemuApp.cpp b/src/gui/wxGui/CemuApp.cpp index b84e6604..f23d33a2 100644 --- a/src/gui/wxGui/CemuApp.cpp +++ b/src/gui/wxGui/CemuApp.cpp @@ -3,7 +3,6 @@ #include "wxgui.h" #include "config/CemuConfig.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h" -#include "guiWrapper.h" #include "config/ActiveSettings.h" #include "GettingStartedDialog.h" #include "config/PermanentConfig.h" @@ -11,6 +10,7 @@ #include "input/InputManager.h" #include "helpers/wxHelpers.h" #include "Cemu/ncrypto/ncrypto.h" +#include "Cemu/GuiSystem/GuiSystem.h" #if BOOST_OS_LINUX && HAS_WAYLAND #include "helpers/wxWayland.h" @@ -26,10 +26,6 @@ wxIMPLEMENT_APP_NO_MAIN(CemuApp); -// defined in guiWrapper.cpp -extern WindowInfo g_window_info; -extern std::shared_mutex g_mutex; - int mainEmulatorHLE(); void HandlePostUpdate(); // Translation strings to extract for gettext: @@ -78,6 +74,7 @@ void unused_translation_dummy() bool CemuApp::OnInit() { + GuiSystem::registerKeyCodeToStringCallback(rawKeyCodeToString); fs::path user_data_path, config_path, cache_path, data_path; auto standardPaths = wxStandardPaths::Get(); fs::path exePath(standardPaths.GetExecutablePath().ToStdString()); @@ -174,8 +171,7 @@ bool CemuApp::OnInit() if (first_start) m_mainFrame->ShowGettingStartedDialog(); - std::unique_lock lock(g_mutex); - g_window_info.app_active = true; + GuiSystem::getWindowInfo().app_active = true; SetTopWindow(m_mainFrame); m_mainFrame->Show(); @@ -234,22 +230,29 @@ void CemuApp::OnAssertFailure(const wxChar* file, int line, const wxChar* func, int CemuApp::FilterEvent(wxEvent& event) { + auto& windowInfo = GuiSystem::getWindowInfo(); if(event.GetEventType() == wxEVT_KEY_DOWN) { const auto& key_event = (wxKeyEvent&)event; wxGetKeyState(wxKeyCode::WXK_F17); - g_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), true); + windowInfo.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), true); + auto platformKeyCode = rawKeyCodeToPlatformKeyCode(key_event.GetRawKeyCode()); + if (platformKeyCode.has_value()) + windowInfo.set_keystate(platformKeyCode.value(), true); } else if(event.GetEventType() == wxEVT_KEY_UP) { const auto& key_event = (wxKeyEvent&)event; - g_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), false); + windowInfo.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), false); + auto platformKeyCode = rawKeyCodeToPlatformKeyCode(key_event.GetRawKeyCode()); + if (platformKeyCode.has_value()) + windowInfo.set_keystate(platformKeyCode.value(), false); } else if(event.GetEventType() == wxEVT_ACTIVATE_APP) { const auto& activate_event = (wxActivateEvent&)event; if(!activate_event.GetActive()) - g_window_info.set_keystatesup(); + windowInfo.set_keystates_up(); } return wxApp::FilterEvent(event); @@ -460,8 +463,29 @@ bool CemuApp::SelectMLCPath(wxWindow* parent) void CemuApp::ActivateApp(wxActivateEvent& event) { - g_window_info.app_active = event.GetActive(); + GuiSystem::getWindowInfo().app_active = event.GetActive(); event.Skip(); } +#if BOOST_OS_WINDOWS +void _wxLaunch() +{ + SetThreadName("MainThread_UI"); + wxEntry(); +} +#endif +void gui_create() +{ + SetThreadName("MainThread"); +#if BOOST_OS_WINDOWS + // on Windows wxWidgets there is a bug where wxDirDialog->ShowModal will deadlock in Windows internals somehow + // moving the UI thread off the main thread fixes this + std::thread t = std::thread(_wxLaunch); + t.join(); +#else + int argc = 0; + char* argv[1]{}; + wxEntry(argc, argv); +#endif +} \ No newline at end of file diff --git a/src/gui/wxGui/LoggingWindow.cpp b/src/gui/wxGui/LoggingWindow.cpp index 4e0ae2ff..90d3acd8 100644 --- a/src/gui/wxGui/LoggingWindow.cpp +++ b/src/gui/wxGui/LoggingWindow.cpp @@ -15,6 +15,7 @@ LoggingWindow* s_instance; LoggingWindow::LoggingWindow(wxFrame* parent) : wxFrame(parent, wxID_ANY, _("Logging window"), wxDefaultPosition, wxSize(800, 600), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) { + cemuLog_registerLogCallbacks(this); auto* sizer = new wxBoxSizer( wxVERTICAL ); { auto filter_row = new wxBoxSizer( wxHORIZONTAL ); @@ -41,44 +42,25 @@ LoggingWindow::LoggingWindow(wxFrame* parent) this->Layout(); this->Bind(EVT_LOG, &LoggingWindow::OnLogMessage, this); - - std::unique_lock lock(s_mutex); - cemu_assert_debug(s_instance == nullptr); - s_instance = this; } LoggingWindow::~LoggingWindow() { + cemuLog_unregisterLogCallbacks(); this->Unbind(EVT_LOG, &LoggingWindow::OnLogMessage, this); - - std::unique_lock lock(s_mutex); - s_instance = nullptr; } void LoggingWindow::Log(std::string_view filter, std::string_view message) { - std::shared_lock lock(s_mutex); - if(!s_instance) - return; wxLogEvent event(std::string {filter}, std::string{ message }); - s_instance->OnLogMessage(event); - - //const auto log_event = new wxLogEvent(filter, message); - //wxQueueEvent(s_instance, log_event); + OnLogMessage(event); } void LoggingWindow::Log(std::string_view filter, std::wstring_view message) { - std::shared_lock lock(s_mutex); - if(!s_instance) - return; - wxLogEvent event(std::string {filter}, std::wstring{ message }); - s_instance->OnLogMessage(event); - - //const auto log_event = new wxLogEvent(filter, message); - //wxQueueEvent(s_instance, log_event); + OnLogMessage(event); } void LoggingWindow::OnLogMessage(wxLogEvent& event) diff --git a/src/gui/wxGui/LoggingWindow.h b/src/gui/wxGui/LoggingWindow.h index ee27e975..5155358b 100644 --- a/src/gui/wxGui/LoggingWindow.h +++ b/src/gui/wxGui/LoggingWindow.h @@ -7,28 +7,15 @@ class wxLogEvent; -class LoggingWindow : public wxFrame +class LoggingWindow : public wxFrame, LogCallbacks { public: LoggingWindow(wxFrame* parent); ~LoggingWindow(); - static void Log(std::string_view filter, std::string_view message); - static void Log(std::string_view message) { Log("", message); } - static void Log(std::string_view filter, std::wstring_view message); - static void Log(std::wstring_view message){ Log("", message); } + virtual void Log(std::string_view filter, std::string_view message) override; + virtual void Log(std::string_view filter, std::wstring_view message) override; - template - static void Log(std::string_view filter, std::string_view format, TArgs&&... args) - { - Log(filter, fmt::format(format, std::forward(args)...)); - } - - template - static void Log(std::string_view filter, std::wstring_view format, TArgs&&... args) - { - Log(filter, fmt::format(format, std::forward(args)...)); - } private: void OnLogMessage(wxLogEvent& event); void OnFilterChange(wxCommandEvent& event); @@ -37,8 +24,4 @@ private: wxComboBox* m_filter; wxLogCtrl* m_log_list; wxCheckBox* m_filter_message; - - inline static std::shared_mutex s_mutex; - inline static LoggingWindow* s_instance = nullptr; }; - diff --git a/src/gui/wxGui/MainWindow.cpp b/src/gui/wxGui/MainWindow.cpp index b867494b..da6ce5fc 100644 --- a/src/gui/wxGui/MainWindow.cpp +++ b/src/gui/wxGui/MainWindow.cpp @@ -1,6 +1,5 @@ #include "wxgui.h" #include "MainWindow.h" -#include "guiWrapper.h" #include #include @@ -30,6 +29,7 @@ #include "LoggingWindow.h" #include "config/ActiveSettings.h" #include "config/LaunchSettings.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "Cafe/Filesystem/FST/FST.h" @@ -70,8 +70,7 @@ #include "Cafe/TitleList/TitleList.h" #include "wxHelper.h" -extern WindowInfo g_window_info; -extern std::shared_mutex g_mutex; +MainWindow* g_mainFrame; wxDEFINE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent); @@ -290,9 +289,9 @@ private: MainWindow::MainWindow() : wxFrame(nullptr, -1, GetInitialWindowTitle(), wxDefaultPosition, wxSize(1280, 720), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER) { - gui_initHandleContextFromWxWidgetsWindow(g_window_info.window_main, this); + GuiSystem::getWindowInfo().window_main = get_window_handle_info_for_wxWindow(this); g_mainFrame = this; - + DownloadManager::GetInstance()->setOnGameListRefreshRequested([this](){RequestGameListRefresh();}); RecreateMenu(); SetClientSize(1280, 720); SetIcon(wxICON(M_WND_ICON128)); @@ -360,10 +359,12 @@ MainWindow::MainWindow() { g_gdbstub = std::make_unique(config.gdb_port); } + CafeSystem::registerCafeSystemCallbacks(this); } MainWindow::~MainWindow() { + CafeSystem::unregisterCafeSystemCallbacks(); if (m_padView) { //delete m_padView; @@ -373,10 +374,97 @@ MainWindow::~MainWindow() m_timer->Stop(); - std::unique_lock lock(g_mutex); g_mainFrame = nullptr; } +void MainWindow::updateWindowTitles(bool isIdle, bool isLoading, double fps) +{ + std::string windowText; + windowText = BUILD_VERSION_WITH_NAME_STRING; + + if (isIdle) + { + if (g_mainFrame) + g_mainFrame->AsyncSetTitle(windowText); + return; + } + if (isLoading) + { + windowText.append(" - loading..."); + if (g_mainFrame) + g_mainFrame->AsyncSetTitle(windowText); + return; + } + + const char* renderer = ""; + if(g_renderer) + { + switch(g_renderer->GetType()) + { + case RendererAPI::OpenGL: + renderer = "[OpenGL]"; + break; + case RendererAPI::Vulkan: + renderer = "[Vulkan]"; + break; + default: ; + } + } + + // get GPU vendor/mode + const char* graphicMode = "[Generic]"; + if (LatteGPUState.glVendor == GLVENDOR_AMD) + graphicMode = "[AMD GPU]"; + else if (LatteGPUState.glVendor == GLVENDOR_INTEL_LEGACY) + graphicMode = "[Intel GPU - Legacy]"; + else if (LatteGPUState.glVendor == GLVENDOR_INTEL_NOLEGACY) + graphicMode = "[Intel GPU]"; + else if (LatteGPUState.glVendor == GLVENDOR_INTEL) + graphicMode = "[Intel GPU]"; + else if (LatteGPUState.glVendor == GLVENDOR_NVIDIA) + graphicMode = "[NVIDIA GPU]"; + else if (LatteGPUState.glVendor == GLVENDOR_APPLE) + graphicMode = "[Apple GPU]"; + + const uint64 titleId = CafeSystem::GetForegroundTitleId(); + windowText.append(fmt::format(" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF))); + + if (ActiveSettings::IsOnlineEnabled()) + { + if (ActiveSettings::GetNetworkService() == NetworkService::Nintendo) + windowText.append(" [Online]"); + else if (ActiveSettings::GetNetworkService() == NetworkService::Pretendo) + windowText.append(" [Online-Pretendo]"); + else if (ActiveSettings::GetNetworkService() == NetworkService::Custom) + windowText.append(" [Online-" + GetNetworkConfig().networkname.GetValue() + "]"); + } + windowText.append(" "); + windowText.append(CafeSystem::GetForegroundTitleName()); + // append region + CafeConsoleRegion region = CafeSystem::GetForegroundTitleRegion(); + uint16 titleVersion = CafeSystem::GetForegroundTitleVersion(); + if (region == CafeConsoleRegion::JPN) + windowText.append(fmt::format(" [JP v{}]", titleVersion)); + else if (region == CafeConsoleRegion::USA) + windowText.append(fmt::format(" [US v{}]", titleVersion)); + else if (region == CafeConsoleRegion::EUR) + windowText.append(fmt::format(" [EU v{}]", titleVersion)); + else + windowText.append(fmt::format(" [v{}]", titleVersion)); + + AsyncSetTitle(windowText); + auto* pad = GetPadView(); + if (pad) + pad->AsyncSetTitle(fmt::format("GamePad View - FPS: {:.02f}", fps)); +} + +void MainWindow::notifyGameLoaded() +{ + OnGameLoaded(); + UpdateSettingsAfterGameLaunch(); +} + + wxString MainWindow::GetInitialWindowTitle() { return BUILD_VERSION_WITH_NAME_STRING; @@ -408,7 +496,7 @@ void MainWindow::OnClose(wxCloseEvent& event) if(m_game_list) m_game_list->OnClose(event); - if (!IsMaximized() && !gui_isFullScreen()) + if (!IsMaximized() && !IsFullScreen()) m_restored_size = GetSize(); SaveSettings(); @@ -1297,19 +1385,19 @@ void MainWindow::LoadSettings() if (config.window_maximized) this->Maximize(); } - + auto& windowInfo = GuiSystem::getWindowInfo(); if (config.pad_position != Vector2i{ -1,-1 }) { - g_window_info.restored_pad_x = config.pad_position.x; - g_window_info.restored_pad_y = config.pad_position.y; + windowInfo.restored_pad_x = config.pad_position.x; + windowInfo.restored_pad_y = config.pad_position.y; } if (config.pad_size != Vector2i{ -1,-1 }) { - g_window_info.restored_pad_width = config.pad_size.x; - g_window_info.restored_pad_height = config.pad_size.y; + windowInfo.restored_pad_width = config.pad_size.x; + windowInfo.restored_pad_height = config.pad_size.y; - g_window_info.pad_maximized = config.pad_maximized; + windowInfo.pad_maximized = config.pad_maximized; } this->TogglePadView(); @@ -1322,6 +1410,7 @@ void MainWindow::SaveSettings() { auto lock = g_config.Lock(); auto& config = GetConfig(); + auto& windowInfo = GuiSystem::getWindowInfo(); if (config.window_position != Vector2i{ -1,-1 }) { @@ -1341,16 +1430,16 @@ void MainWindow::SaveSettings() config.pad_open = m_padView != nullptr; - if (config.pad_position != Vector2i{ -1,-1 } && g_window_info.restored_pad_x != -1) + if (config.pad_position != Vector2i{ -1,-1 } && windowInfo.restored_pad_x != -1) { - config.pad_position.x = g_window_info.restored_pad_x; - config.pad_position.y = g_window_info.restored_pad_y; + config.pad_position.x = windowInfo.restored_pad_x; + config.pad_position.y = windowInfo.restored_pad_y; } - if (config.pad_size != Vector2i{ -1,-1 } && g_window_info.restored_pad_width != -1) + if (config.pad_size != Vector2i{ -1,-1 } && windowInfo.restored_pad_width != -1) { - config.pad_size.x = g_window_info.restored_pad_width; - config.pad_size.y = g_window_info.restored_pad_height; - config.pad_maximized = g_window_info.pad_maximized; + config.pad_size.x = windowInfo.restored_pad_width; + config.pad_size.y = windowInfo.restored_pad_height; + config.pad_maximized = windowInfo.pad_maximized; } else { @@ -1440,6 +1529,102 @@ void MainWindow::OnSetWindowTitle(wxCommandEvent& event) this->SetTitle(event.GetString()); } +static std::optional GenerateScreenshotFilename(bool isDRC) +{ + fs::path screendir = ActiveSettings::GetUserDataPath("screenshots"); + // build screenshot name with format Screenshot_YYYY-MM-DD_HH-MM-SS[_GamePad].png + // if the file already exists add a suffix counter (_2.png, _3.png etc) + std::time_t time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::tm* tm = std::localtime(&time_t); + + std::string screenshotFileName = fmt::format("Screenshot_{:04}-{:02}-{:02}_{:02}-{:02}-{:02}", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if (isDRC) + screenshotFileName.append("_GamePad"); + + fs::path screenshotPath; + for(sint32 i=0; i<999; i++) + { + screenshotPath = screendir; + if (i == 0) + screenshotPath.append(fmt::format("{}.png", screenshotFileName)); + else + screenshotPath.append(fmt::format("{}_{}.png", screenshotFileName, i + 1)); + + std::error_code ec; + bool exists = fs::exists(screenshotPath, ec); + + if (!ec && !exists) + return screenshotPath; + } + return std::nullopt; +} + +bool SaveScreenshotToFile(const fs::path& imagePath, const wxImage& image) +{ + + std::error_code ec; + fs::create_directories(imagePath.parent_path(), ec); + if (ec) return false; + + // suspend wxWidgets logging for the lifetime this object, to prevent a message box if wxImage::SaveFile fails + wxLogNull _logNo; + return image.SaveFile(imagePath.wstring()); +} + +bool SaveScreenshotToClipboard(const wxImage& image) +{ + static std::mutex s_clipboardMutex; + bool success = false; + + s_clipboardMutex.lock(); + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxImageDataObject(image)); + wxTheClipboard->Close(); + success = true; + } + s_clipboardMutex.unlock(); + + return success; +} + +std::optional SaveScreenshot(std::vector data, int width, int height, bool mainWindow) +{ +#if BOOST_OS_WINDOWS + // on Windows wxWidgets uses OLE API for the clipboard + // to make this work we need to call OleInitialize() on the same thread + OleInitialize(nullptr); +#endif + bool save_screenshot = g_config.data().save_screenshot; + wxImage image(width, height, data.data(), true); + if (mainWindow) + { + if(SaveScreenshotToClipboard(image)) + { + if (!save_screenshot) + return "Screenshot saved to clipboard"; + } + else + { + return "Failed to open clipboard"; + } + } + if (save_screenshot) + { + auto imagePath = GenerateScreenshotFilename(mainWindow); + if (imagePath.has_value() && SaveScreenshotToFile(imagePath.value(), image)) + { + if (mainWindow) + return "Screenshot saved"; + } + else + { + return "Failed to save screenshot to file"; + } + } + return std::nullopt; +} + void MainWindow::OnKeyUp(wxKeyEvent& event) { event.Skip(); @@ -1452,8 +1637,8 @@ void MainWindow::OnKeyUp(wxKeyEvent& event) SetFullScreen(false); else if (code == WXK_RETURN && event.AltDown() || code == WXK_F11) SetFullScreen(!IsFullScreen()); - else if (code == WXK_F12) - g_window_info.has_screenshot_request = true; // async screenshot request + else if (code == WXK_F12 && g_renderer) + g_renderer->RequestScreenshot(SaveScreenshot); // async screenshot request } void MainWindow::OnChar(wxKeyEvent& event) @@ -1577,15 +1762,16 @@ void MainWindow::DestroyCanvas() void MainWindow::OnSizeEvent(wxSizeEvent& event) { - if (!IsMaximized() && !gui_isFullScreen()) + if (!IsMaximized() && !IsFullScreen()) m_restored_size = GetSize(); + auto& windowInfo = GuiSystem::getWindowInfo(); const wxSize client_size = GetClientSize(); - g_window_info.width = client_size.GetWidth(); - g_window_info.height = client_size.GetHeight(); - g_window_info.phys_width = ToPhys(client_size.GetWidth()); - g_window_info.phys_height = ToPhys(client_size.GetHeight()); - g_window_info.dpi_scale = GetDPIScaleFactor(); + windowInfo.width = client_size.GetWidth(); + windowInfo.height = client_size.GetHeight(); + windowInfo.phys_width = ToPhys(client_size.GetWidth()); + windowInfo.phys_height = ToPhys(client_size.GetHeight()); + windowInfo.dpi_scale = GetDPIScaleFactor(); if (m_debugger_window && m_debugger_window->IsShown()) m_debugger_window->OnParentMove(GetPosition(), event.GetSize()); @@ -1598,17 +1784,18 @@ void MainWindow::OnSizeEvent(wxSizeEvent& event) void MainWindow::OnDPIChangedEvent(wxDPIChangedEvent& event) { event.Skip(); + auto& windowInfo = GuiSystem::getWindowInfo(); const wxSize client_size = GetClientSize(); - g_window_info.width = client_size.GetWidth(); - g_window_info.height = client_size.GetHeight(); - g_window_info.phys_width = ToPhys(client_size.GetWidth()); - g_window_info.phys_height = ToPhys(client_size.GetHeight()); - g_window_info.dpi_scale = GetDPIScaleFactor(); + windowInfo.width = client_size.GetWidth(); + windowInfo.height = client_size.GetHeight(); + windowInfo.phys_width = ToPhys(client_size.GetWidth()); + windowInfo.phys_height = ToPhys(client_size.GetHeight()); + windowInfo.dpi_scale = GetDPIScaleFactor(); } void MainWindow::OnMove(wxMoveEvent& event) { - if (!IsMaximized() && !gui_isFullScreen()) + if (!IsMaximized() && !IsFullScreen()) m_restored_position = GetPosition(); if (m_debugger_window && m_debugger_window->IsShown()) @@ -1668,7 +1855,7 @@ void MainWindow::SetFullScreen(bool state) } if (state && !m_game_launched) return; - g_window_info.is_fullscreen = state; + GuiSystem::getWindowInfo().is_fullscreen = state; m_fullscreenMenuItem->Check(state); this->ShowFullScreen(state); diff --git a/src/gui/wxGui/MainWindow.h b/src/gui/wxGui/MainWindow.h index d49b6b30..1fcc4e6b 100644 --- a/src/gui/wxGui/MainWindow.h +++ b/src/gui/wxGui/MainWindow.h @@ -15,6 +15,7 @@ #include #include "Cafe/HW/Espresso/Debugger/GDBStub.h" +#include "Cafe/CafeSystem.h" class DebuggerWindow2; struct GameEntry; @@ -50,14 +51,17 @@ private: INITIATED_BY m_initiatedBy; }; -class MainWindow : public wxFrame +class MainWindow : public wxFrame, CafeSystem::CafeSystemCallbacks { friend class CemuApp; public: MainWindow(); ~MainWindow(); - + + virtual void updateWindowTitles(bool isIdle, bool isLoading, double fps) override; + virtual void notifyGameLoaded() override; + void UpdateSettingsAfterGameLaunch(); void RestoreSettingsAfterGameExited(); diff --git a/src/gui/wxGui/PadViewFrame.cpp b/src/gui/wxGui/PadViewFrame.cpp index 83b0731e..1209a55f 100644 --- a/src/gui/wxGui/PadViewFrame.cpp +++ b/src/gui/wxGui/PadViewFrame.cpp @@ -1,5 +1,4 @@ #include "wxgui.h" -#include "guiWrapper.h" #include "PadViewFrame.h" #include @@ -12,28 +11,27 @@ #include "MainWindow.h" #include "helpers/wxHelpers.h" #include "input/InputManager.h" +#include "Cemu/GuiSystem/GuiSystem.h" #if BOOST_OS_LINUX || BOOST_OS_MACOS #include "resource/embedded/resources.h" #endif #include "wxHelper.h" -extern WindowInfo g_window_info; - PadViewFrame::PadViewFrame(wxFrame* parent) : wxFrame(nullptr, wxID_ANY, _("GamePad View"), wxDefaultPosition, wxSize(854, 480), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxCLOSE_BOX | wxWANTS_CHARS) { - gui_initHandleContextFromWxWidgetsWindow(g_window_info.window_pad, this); - + auto& windowInfo = GuiSystem::getWindowInfo(); + windowInfo.window_pad = get_window_handle_info_for_wxWindow(this); SetIcon(wxICON(M_WND_ICON128)); wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES); SetMinClientSize({ 320, 180 }); - SetPosition({ g_window_info.restored_pad_x, g_window_info.restored_pad_y }); - SetSize({ g_window_info.restored_pad_width, g_window_info.restored_pad_height }); + SetPosition({ windowInfo.restored_pad_x, windowInfo.restored_pad_y }); + SetSize({ windowInfo.restored_pad_width, windowInfo.restored_pad_height }); - if (g_window_info.pad_maximized) + if (windowInfo.pad_maximized) Maximize(); Bind(wxEVT_SIZE, &PadViewFrame::OnSizeEvent, this); @@ -43,21 +41,22 @@ PadViewFrame::PadViewFrame(wxFrame* parent) Bind(wxEVT_SET_WINDOW_TITLE, &PadViewFrame::OnSetWindowTitle, this); - g_window_info.pad_open = true; + windowInfo.pad_open = true; } PadViewFrame::~PadViewFrame() { - g_window_info.pad_open = false; + GuiSystem::getWindowInfo().pad_open = false; } bool PadViewFrame::Initialize() { + auto& windowInfo = GuiSystem::getWindowInfo(); const wxSize client_size = GetClientSize(); - g_window_info.pad_width = client_size.GetWidth(); - g_window_info.pad_height = client_size.GetHeight(); - g_window_info.phys_pad_width = ToPhys(client_size.GetWidth()); - g_window_info.phys_pad_height = ToPhys(client_size.GetHeight()); + windowInfo.pad_width = client_size.GetWidth(); + windowInfo.pad_height = client_size.GetHeight(); + windowInfo.phys_pad_width = ToPhys(client_size.GetWidth()); + windowInfo.phys_pad_height = ToPhys(client_size.GetHeight()); return true; } @@ -92,19 +91,20 @@ void PadViewFrame::InitializeRenderCanvas() void PadViewFrame::OnSizeEvent(wxSizeEvent& event) { + auto& windowInfo = GuiSystem::getWindowInfo(); if (!IsMaximized() && !IsFullScreen()) { - g_window_info.restored_pad_width = GetSize().x; - g_window_info.restored_pad_height = GetSize().y; + windowInfo.restored_pad_width = GetSize().x; + windowInfo.restored_pad_height = GetSize().y; } - g_window_info.pad_maximized = IsMaximized() && !IsFullScreen(); + windowInfo.pad_maximized = IsMaximized() && !IsFullScreen(); const wxSize client_size = GetClientSize(); - g_window_info.pad_width = client_size.GetWidth(); - g_window_info.pad_height = client_size.GetHeight(); - g_window_info.phys_pad_width = ToPhys(client_size.GetWidth()); - g_window_info.phys_pad_height = ToPhys(client_size.GetHeight()); - g_window_info.pad_dpi_scale = GetDPIScaleFactor(); + windowInfo.pad_width = client_size.GetWidth(); + windowInfo.pad_height = client_size.GetHeight(); + windowInfo.phys_pad_width = ToPhys(client_size.GetWidth()); + windowInfo.phys_pad_height = ToPhys(client_size.GetHeight()); + windowInfo.pad_dpi_scale = GetDPIScaleFactor(); event.Skip(); } @@ -112,20 +112,22 @@ void PadViewFrame::OnSizeEvent(wxSizeEvent& event) void PadViewFrame::OnDPIChangedEvent(wxDPIChangedEvent& event) { event.Skip(); + auto& windowInfo = GuiSystem::getWindowInfo(); const wxSize client_size = GetClientSize(); - g_window_info.pad_width = client_size.GetWidth(); - g_window_info.pad_height = client_size.GetHeight(); - g_window_info.phys_pad_width = ToPhys(client_size.GetWidth()); - g_window_info.phys_pad_height = ToPhys(client_size.GetHeight()); - g_window_info.pad_dpi_scale = GetDPIScaleFactor(); + windowInfo.pad_width = client_size.GetWidth(); + windowInfo.pad_height = client_size.GetHeight(); + windowInfo.phys_pad_width = ToPhys(client_size.GetWidth()); + windowInfo.phys_pad_height = ToPhys(client_size.GetHeight()); + windowInfo.pad_dpi_scale = GetDPIScaleFactor(); } void PadViewFrame::OnMoveEvent(wxMoveEvent& event) { if (!IsMaximized() && !IsFullScreen()) { - g_window_info.restored_pad_x = GetPosition().x; - g_window_info.restored_pad_y = GetPosition().y; + auto& windowInfo = GuiSystem::getWindowInfo(); + windowInfo.restored_pad_x = GetPosition().x; + windowInfo.restored_pad_y = GetPosition().y; } } diff --git a/src/gui/wxGui/canvas/VulkanCanvas.cpp b/src/gui/wxGui/canvas/VulkanCanvas.cpp index b73ce101..418f7c63 100644 --- a/src/gui/wxGui/canvas/VulkanCanvas.cpp +++ b/src/gui/wxGui/canvas/VulkanCanvas.cpp @@ -1,6 +1,7 @@ #include "canvas/VulkanCanvas.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h" -#include "guiWrapper.h" +#include "Cemu/GuiSystem/GuiSystem.h" +#include "helpers/wxHelpers.h" #if BOOST_OS_LINUX && HAS_WAYLAND #include "helpers/wxWayland.h" @@ -14,10 +15,10 @@ VulkanCanvas::VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_wi Bind(wxEVT_PAINT, &VulkanCanvas::OnPaint, this); Bind(wxEVT_SIZE, &VulkanCanvas::OnResize, this); - WindowHandleInfo& canvas = is_main_window ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad; - gui_initHandleContextFromWxWidgetsWindow(canvas, this); + auto& canvas = is_main_window ? GuiSystem::getWindowInfo().canvas_main : GuiSystem::getWindowInfo().canvas_pad; + canvas = get_window_handle_info_for_wxWindow(this); #if BOOST_OS_LINUX && HAS_WAYLAND - if (canvas.backend == WindowHandleInfo::Backend::WAYLAND) + if (canvas.backend == GuiSystem::WindowHandleInfo::Backend::WAYLAND) { m_subsurface = std::make_unique(this); canvas.surface = m_subsurface->getSurface(); diff --git a/src/gui/wxGui/debugger/BreakpointWindow.cpp b/src/gui/wxGui/debugger/BreakpointWindow.cpp index 67cd39b5..32bf3385 100644 --- a/src/gui/wxGui/debugger/BreakpointWindow.cpp +++ b/src/gui/wxGui/debugger/BreakpointWindow.cpp @@ -4,7 +4,6 @@ #include #include "debugger/DebuggerWindow2.h" -#include "guiWrapper.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h" #include "Cemu/ExpressionParser/ExpressionParser.h" @@ -176,7 +175,7 @@ void BreakpointWindow::OnLeftDClick(wxMouseEvent& event) const auto item = m_breakpoints->GetItemText(index, ColumnAddress); const auto address = std::stoul(item.ToStdString(), nullptr, 16); debuggerState.debugSession.instructionPointer = address; - debuggerWindow_moveIP(); + debugger_getDebuggerCallbacks()->moveIP(); return; } diff --git a/src/gui/wxGui/debugger/DebuggerWindow2.cpp b/src/gui/wxGui/debugger/DebuggerWindow2.cpp index 1e61397c..c9b968b0 100644 --- a/src/gui/wxGui/debugger/DebuggerWindow2.cpp +++ b/src/gui/wxGui/debugger/DebuggerWindow2.cpp @@ -70,8 +70,6 @@ wxBEGIN_EVENT_TABLE(DebuggerWindow2, wxFrame) EVT_MENU_RANGE(MENU_ID_WINDOW_REGISTERS, MENU_ID_WINDOW_MODULE, DebuggerWindow2::OnWindowMenu) wxEND_EVENT_TABLE() -DebuggerWindow2* g_debugger_window; - void DebuggerConfig::Load(XMLConfigParser& parser) { pin_to_main = parser.get("PinToMainWindow", true); @@ -326,14 +324,13 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) m_config.data().pin_to_main = true; OnParentMove(m_main_position, m_main_size); m_config.data().pin_to_main = value; - - g_debugger_window = this; + debugger_registerDebuggerCallbacks(this); } DebuggerWindow2::~DebuggerWindow2() { debuggerState.breakOnEntry = false; - g_debugger_window = nullptr; + debugger_unregisterDebuggerCallbacks(); // save configs for all modules that are still loaded // doesn't delete breakpoints since that should (in the future) be done by unloading the rpl modules when exiting the current game @@ -472,6 +469,39 @@ std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); } +void DebuggerWindow2::updateViewThreadsafe() +{ + auto* evt = new wxCommandEvent(wxEVT_UPDATE_VIEW); + wxQueueEvent(this, evt); +} +void DebuggerWindow2::notifyDebugBreakpointHit() +{ + auto* evt = new wxCommandEvent(wxEVT_BREAKPOINT_HIT); + wxQueueEvent(this, evt); +} +void DebuggerWindow2::notifyRun() +{ + auto* evt = new wxCommandEvent(wxEVT_RUN); + wxQueueEvent(this, evt); +} +void DebuggerWindow2::moveIP() +{ + auto* evt = new wxCommandEvent(wxEVT_MOVE_IP); + wxQueueEvent(this, evt); +} +void DebuggerWindow2::notifyModuleLoaded(void* module) +{ + auto* evt = new wxCommandEvent(wxEVT_NOTIFY_MODULE_LOADED); + evt->SetClientData(module); + wxQueueEvent(this, evt); +} +void DebuggerWindow2::notifyModuleUnloaded(void* module) +{ + auto* evt = new wxCommandEvent(wxEVT_NOTIFY_MODULE_UNLOADED); + evt->SetClientData(module); + wxQueueEvent(this, evt); +} + void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event) { const auto ip = debuggerState.debugSession.instructionPointer; diff --git a/src/gui/wxGui/debugger/DebuggerWindow2.h b/src/gui/wxGui/debugger/DebuggerWindow2.h index 6b452bd2..bd632fc5 100644 --- a/src/gui/wxGui/debugger/DebuggerWindow2.h +++ b/src/gui/wxGui/debugger/DebuggerWindow2.h @@ -56,7 +56,7 @@ struct DebuggerModuleStorage }; typedef XMLDataConfig XMLDebuggerModuleConfig; -class DebuggerWindow2 : public wxFrame +class DebuggerWindow2 : public wxFrame, DebuggerCallbacks { public: void CreateToolBar(); @@ -72,6 +72,14 @@ public: bool Show(bool show = true) override; std::wstring GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const; + + virtual void updateViewThreadsafe() override; + virtual void notifyDebugBreakpointHit() override; + virtual void notifyRun() override; + virtual void moveIP() override; + virtual void notifyModuleLoaded(void* module) override; + virtual void notifyModuleUnloaded(void* module) override; + private: void OnBreakpointHit(wxCommandEvent& event); void OnRunProgram(wxCommandEvent& event); diff --git a/src/gui/wxGui/debugger/DisasmCtrl.cpp b/src/gui/wxGui/debugger/DisasmCtrl.cpp index 15709ecb..884779d7 100644 --- a/src/gui/wxGui/debugger/DisasmCtrl.cpp +++ b/src/gui/wxGui/debugger/DisasmCtrl.cpp @@ -9,7 +9,6 @@ #include "Cafe/HW/Espresso/Debugger/Debugger.h" #include "debugger/DebuggerWindow2.h" #include "util/helpers/helpers.h" -#include "guiWrapper.h" #include "Cemu/ExpressionParser/ExpressionParser.h" #include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h" @@ -797,7 +796,7 @@ void DisasmCtrl::GoToAddressDialog() debug_printf("goto eval result: %x\n", result); m_lastGotoTarget = result; CenterOffset(result); - debuggerWindow_updateViewThreadsafe2(); + debugger_getDebuggerCallbacks()->updateViewThreadsafe(); } catch (const std::exception& ) { diff --git a/src/gui/wxGui/debugger/ModuleWindow.cpp b/src/gui/wxGui/debugger/ModuleWindow.cpp index 455e62d7..6fa679d1 100644 --- a/src/gui/wxGui/debugger/ModuleWindow.cpp +++ b/src/gui/wxGui/debugger/ModuleWindow.cpp @@ -1,5 +1,4 @@ #include "wxgui.h" -#include "guiWrapper.h" #include "debugger/ModuleWindow.h" #include @@ -133,5 +132,5 @@ void ModuleWindow::OnLeftDClick(wxMouseEvent& event) if (address == 0) return; debuggerState.debugSession.instructionPointer = address; - debuggerWindow_moveIP(); + debugger_getDebuggerCallbacks()->moveIP(); } diff --git a/src/gui/wxGui/debugger/SymbolCtrl.cpp b/src/gui/wxGui/debugger/SymbolCtrl.cpp index 9ca5ec49..0a2d46da 100644 --- a/src/gui/wxGui/debugger/SymbolCtrl.cpp +++ b/src/gui/wxGui/debugger/SymbolCtrl.cpp @@ -1,5 +1,4 @@ #include "debugger/SymbolCtrl.h" -#include "guiWrapper.h" #include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h" @@ -114,7 +113,7 @@ void SymbolListCtrl::OnLeftDClick(wxListEvent& event) if (address == 0) return; debuggerState.debugSession.instructionPointer = address; - debuggerWindow_moveIP(); + debugger_getDebuggerCallbacks()->moveIP(); } void SymbolListCtrl::OnRightClick(wxListEvent& event) diff --git a/src/gui/wxGui/debugger/SymbolWindow.cpp b/src/gui/wxGui/debugger/SymbolWindow.cpp index b1551af5..90771f7a 100644 --- a/src/gui/wxGui/debugger/SymbolWindow.cpp +++ b/src/gui/wxGui/debugger/SymbolWindow.cpp @@ -1,5 +1,4 @@ #include "wxgui.h" -#include "guiWrapper.h" #include "debugger/SymbolWindow.h" #include "debugger/DebuggerWindow2.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h" diff --git a/src/gui/wxGui/helpers/wxHelpers.cpp b/src/gui/wxGui/helpers/wxHelpers.cpp index 2dfca215..5d1efcaa 100644 --- a/src/gui/wxGui/helpers/wxHelpers.cpp +++ b/src/gui/wxGui/helpers/wxHelpers.cpp @@ -7,6 +7,17 @@ #include "helpers/wxControlObject.h" +#if BOOST_OS_LINUX +#include +#include +#include +#include +#include +#ifdef HAS_WAYLAND +#include +#endif +#endif + void wxAutosizeColumn(wxListCtrlBase* ctrl, int col) { ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER); @@ -14,7 +25,7 @@ void wxAutosizeColumn(wxListCtrlBase* ctrl, int col) ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE); int wc = ctrl->GetColumnWidth(col); if (wh > wc) - ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER); + ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER); } void wxAutosizeColumns(wxListCtrlBase* ctrl, int col_start, int col_end) @@ -64,3 +75,106 @@ uint32 fix_raw_keycode(uint32 keycode, uint32 raw_flags) return keycode; } + +std::string rawKeyCodeToString(uint32 keyCode) +{ +#if BOOST_OS_WINDOWS + LONG scan_code = MapVirtualKeyA((UINT)keyCode, MAPVK_VK_TO_VSC_EX); + if (HIBYTE(scan_code)) + scan_code |= 0x100; + + // because MapVirtualKey strips the extended bit for some keys + switch (keyCode) + { + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: // arrow keys + case VK_PRIOR: + case VK_NEXT: // page up and page down + case VK_END: + case VK_HOME: + case VK_INSERT: + case VK_DELETE: + case VK_DIVIDE: // numpad slash + case VK_NUMLOCK: + { + scan_code |= 0x100; // set extended bit + break; + } + } + + scan_code <<= 16; + + char key_name[128]; + if (GetKeyNameTextA(scan_code, key_name, std::size(key_name)) != 0) + return key_name; + else + return fmt::format("key_{}", keyCode); +#elif BOOST_OS_LINUX + return gdk_keyval_name(keyCode); +#else + return fmt::format("key_{}", keyCode); +#endif +} + +std::optional rawKeyCodeToPlatformKeyCode(uint32 keyCode) +{ + switch (keyCode) + { +#if BOOST_OS_WINDOWS + case VK_LCONTROL: return GuiSystem::PlatformKeyCodes::LCONTROL; + case VK_RCONTROL: return GuiSystem::PlatformKeyCodes::RCONTROL; + case VK_TAB: return GuiSystem::PlatformKeyCodes::TAB; +#elif BOOST_OS_LINUX + case GDK_KEY_Control_L: return GuiSystem::PlatformKeyCodes::LCONTROL; + case GDK_KEY_Control_R: return GuiSystem::PlatformKeyCodes::RCONTROL; + case GDK_KEY_Tab: return GuiSystem::PlatformKeyCodes::TAB; +#elif BOOST_OS_MACOS + case kVK_Control: return GuiSystem::PlatformKeyCodes::LCONTROL; + case kVK_RightControl: return GuiSystem::PlatformKeyCodes::RCONTROL; + case kVK_Tab: return GuiSystem::PlatformKeyCodes::TAB; +#endif + default: return std::nullopt; + } +} + +GuiSystem::WindowHandleInfo get_window_handle_info_for_wxWindow(wxWindow* wxw) +{ + GuiSystem::WindowHandleInfo handleInfo; +#if BOOST_OS_WINDOWS + handleInfo.backend = GuiSystem::WindowHandleInfo::Backend::WINDOWS; + handleInfo.surface = reinterpret_cast(wxw->GetHWND()); +#elif BOOST_OS_LINUX + GtkWidget* gtkWidget = (GtkWidget*)wxw->GetHandle(); // returns GtkWidget + gtk_widget_realize(gtkWidget); + GdkWindow* gdkWindow = gtk_widget_get_window(gtkWidget); + GdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow); + if (GDK_IS_X11_WINDOW(gdkWindow)) + { + handleInfo.backend = GuiSystem::WindowHandleInfo::Backend::X11; + handleInfo.surface = reinterpret_cast(gdk_x11_window_get_xid(gdkWindow)); + handleInfo.display = gdk_x11_display_get_xdisplay(gdkDisplay); + if (!handleInfo.display) + { + cemuLog_log(LogType::Force, "Unable to get xlib display"); + } + } +#ifdef HAS_WAYLAND + else if (GDK_IS_WAYLAND_WINDOW(gdkWindow)) + { + handleInfo.backend = GuiSystem::WindowHandleInfo::Backend::WAYLAND; + handleInfo.surface = gdk_wayland_window_get_wl_surface(gdkWindow); + handleInfo.display = gdk_wayland_display_get_wl_display(gdkDisplay); + } +#endif + else + { + cemuLog_log(LogType::Force, "Unsuported GTK backend"); + } +#elif BOOST_OS_MACOS + handleInfo.backend = GuiSystem::WindowHandleInfo::Backend::COCOA; + handleInfo.surface = reinterpret_cast(wxw->GetHandle()); +#endif + return handleInfo; +} diff --git a/src/gui/wxGui/helpers/wxHelpers.h b/src/gui/wxGui/helpers/wxHelpers.h index 8fd0f8a9..ab15a411 100644 --- a/src/gui/wxGui/helpers/wxHelpers.h +++ b/src/gui/wxGui/helpers/wxHelpers.h @@ -4,6 +4,8 @@ #include #include +#include "Cemu/GuiSystem/GuiSystem.h" + template <> struct fmt::formatter : formatter { @@ -124,3 +126,9 @@ T get_prev_sibling(const T element) void update_slider_text(wxCommandEvent& event, const wxFormatString& format = "%d%%"); uint32 fix_raw_keycode(uint32 keycode, uint32 raw_flags); + +std::string rawKeyCodeToString(uint32 keyCode); + +std::optional rawKeyCodeToPlatformKeyCode(uint32 keyCode); + +GuiSystem::WindowHandleInfo get_window_handle_info_for_wxWindow(wxWindow* wxw); diff --git a/src/gui/wxGui/wxGuiWrapper.cpp b/src/gui/wxGui/wxGuiWrapper.cpp deleted file mode 100644 index 0ee139ce..00000000 --- a/src/gui/wxGui/wxGuiWrapper.cpp +++ /dev/null @@ -1,464 +0,0 @@ -#include -#if BOOST_OS_LINUX -#include -#include -#include -#include -#include -#ifdef HAS_WAYLAND -#include -#endif -#endif - -#if BOOST_OS_MACOS -#include -#endif - -#include "wxgui.h" -#include "guiWrapper.h" -#include "CemuApp.h" -#include "MainWindow.h" -#include "debugger/DebuggerWindow2.h" -#include "Cafe/HW/Latte/Core/Latte.h" -#include "config/ActiveSettings.h" -#include "config/NetworkSettings.h" -#include "config/CemuConfig.h" -#include "Cafe/HW/Latte/Renderer/Renderer.h" -#include "Cafe/CafeSystem.h" -#include "LoggingWindow.h" - -#include "wxHelper.h" -#include - -WindowInfo g_window_info {}; - -std::shared_mutex g_mutex; -MainWindow* g_mainFrame = nullptr; - -#if BOOST_OS_WINDOWS -void _wxLaunch() -{ - SetThreadName("MainThread_UI"); - wxEntry(); -} -#endif - -void gui_create() -{ - SetThreadName("MainThread"); -#if BOOST_OS_WINDOWS - // on Windows wxWidgets there is a bug where wxDirDialog->ShowModal will deadlock in Windows internals somehow - // moving the UI thread off the main thread fixes this - std::thread t = std::thread(_wxLaunch); - t.join(); -#else - int argc = 0; - char* argv[1]{}; - wxEntry(argc, argv); -#endif -} - -WindowInfo& gui_getWindowInfo() -{ - return g_window_info; -} - -void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps) -{ - std::string windowText; - windowText = BUILD_VERSION_WITH_NAME_STRING; - - if (isIdle) - { - if (g_mainFrame) - g_mainFrame->AsyncSetTitle(windowText); - return; - } - if (isLoading) - { - windowText.append(" - loading..."); - if (g_mainFrame) - g_mainFrame->AsyncSetTitle(windowText); - return; - } - - const char* renderer = ""; - if(g_renderer) - { - switch(g_renderer->GetType()) - { - case RendererAPI::OpenGL: - renderer = "[OpenGL]"; - break; - case RendererAPI::Vulkan: - renderer = "[Vulkan]"; - break; - default: ; - } - } - - // get GPU vendor/mode - const char* graphicMode = "[Generic]"; - if (LatteGPUState.glVendor == GLVENDOR_AMD) - graphicMode = "[AMD GPU]"; - else if (LatteGPUState.glVendor == GLVENDOR_INTEL_LEGACY) - graphicMode = "[Intel GPU - Legacy]"; - else if (LatteGPUState.glVendor == GLVENDOR_INTEL_NOLEGACY) - graphicMode = "[Intel GPU]"; - else if (LatteGPUState.glVendor == GLVENDOR_INTEL) - graphicMode = "[Intel GPU]"; - else if (LatteGPUState.glVendor == GLVENDOR_NVIDIA) - graphicMode = "[NVIDIA GPU]"; - else if (LatteGPUState.glVendor == GLVENDOR_APPLE) - graphicMode = "[Apple GPU]"; - - const uint64 titleId = CafeSystem::GetForegroundTitleId(); - windowText.append(fmt::format(" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF))); - - if (ActiveSettings::IsOnlineEnabled()) - { - if (ActiveSettings::GetNetworkService() == NetworkService::Nintendo) - windowText.append(" [Online]"); - else if (ActiveSettings::GetNetworkService() == NetworkService::Pretendo) - windowText.append(" [Online-Pretendo]"); - else if (ActiveSettings::GetNetworkService() == NetworkService::Custom) - windowText.append(" [Online-" + GetNetworkConfig().networkname.GetValue() + "]"); - } - windowText.append(" "); - windowText.append(CafeSystem::GetForegroundTitleName()); - // append region - CafeConsoleRegion region = CafeSystem::GetForegroundTitleRegion(); - uint16 titleVersion = CafeSystem::GetForegroundTitleVersion(); - if (region == CafeConsoleRegion::JPN) - windowText.append(fmt::format(" [JP v{}]", titleVersion)); - else if (region == CafeConsoleRegion::USA) - windowText.append(fmt::format(" [US v{}]", titleVersion)); - else if (region == CafeConsoleRegion::EUR) - windowText.append(fmt::format(" [EU v{}]", titleVersion)); - else - windowText.append(fmt::format(" [v{}]", titleVersion)); - - std::shared_lock lock(g_mutex); - if (g_mainFrame) - { - g_mainFrame->AsyncSetTitle(windowText); - auto* pad = g_mainFrame->GetPadView(); - if (pad) - pad->AsyncSetTitle(fmt::format("GamePad View - FPS: {:.02f}", fps)); - } -} - -void gui_getWindowSize(int& w, int& h) -{ - w = g_window_info.width; - h = g_window_info.height; -} - -void gui_getPadWindowSize(int& w, int& h) -{ - if (g_window_info.pad_open) - { - w = g_window_info.pad_width; - h = g_window_info.pad_height; - } - else - { - w = 0; - h = 0; - } -} - -void gui_getWindowPhysSize(int& w, int& h) -{ - w = g_window_info.phys_width; - h = g_window_info.phys_height; -} - -void gui_getPadWindowPhysSize(int& w, int& h) -{ - if (g_window_info.pad_open) - { - w = g_window_info.phys_pad_width; - h = g_window_info.phys_pad_height; - } - else - { - w = 0; - h = 0; - } -} - -double gui_getWindowDPIScale() -{ - return g_window_info.dpi_scale; -} - -double gui_getPadDPIScale() -{ - return g_window_info.pad_open ? g_window_info.pad_dpi_scale.load() : 1.0; -} - -bool gui_isPadWindowOpen() -{ - return g_window_info.pad_open; -} - -std::string gui_RawKeyCodeToString(uint32 keyCode) -{ -#if BOOST_OS_WINDOWS - LONG scan_code = MapVirtualKeyA((UINT)keyCode, MAPVK_VK_TO_VSC_EX); - if(HIBYTE(scan_code)) - scan_code |= 0x100; - - // because MapVirtualKey strips the extended bit for some keys - switch (keyCode) - { - case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: // arrow keys - case VK_PRIOR: case VK_NEXT: // page up and page down - case VK_END: case VK_HOME: - case VK_INSERT: case VK_DELETE: - case VK_DIVIDE: // numpad slash - case VK_NUMLOCK: - { - scan_code |= 0x100; // set extended bit - break; - } - } - - scan_code <<= 16; - - char key_name[128]; - if (GetKeyNameTextA(scan_code, key_name, std::size(key_name)) != 0) - return key_name; - else - return fmt::format("key_{}", keyCode); -#elif BOOST_OS_LINUX - return gdk_keyval_name(keyCode); -#else - return fmt::format("key_{}", keyCode); -#endif -} - -bool gui_saveScreenshotToFile(const fs::path& imagePath, std::vector& data, int width, int height) -{ - - std::error_code ec; - fs::create_directories(imagePath.parent_path(), ec); - if (ec) return false; - - // suspend wxWidgets logging for the lifetime this object, to prevent a message box if wxImage::SaveFile fails - wxLogNull _logNo; - wxImage image(width, height, data.data(), true); - return image.SaveFile(imagePath.wstring()); -} - -bool gui_saveScreenshotToClipboard(std::vector& data, int width, int height) -{ - static std::mutex s_clipboardMutex; - bool success = false; - - s_clipboardMutex.lock(); - if (wxTheClipboard->Open()) - { - wxImage image(width, height, data.data(), true); - wxTheClipboard->SetData(new wxImageDataObject(image)); - wxTheClipboard->Close(); - success = true; - } - s_clipboardMutex.unlock(); - - return success; -} - -void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, class wxWindow* wxw) -{ -#if BOOST_OS_WINDOWS - handleInfoOut.hwnd = wxw->GetHWND(); -#elif BOOST_OS_LINUX - GtkWidget* gtkWidget = (GtkWidget*)wxw->GetHandle(); // returns GtkWidget - gtk_widget_realize(gtkWidget); - GdkWindow* gdkWindow = gtk_widget_get_window(gtkWidget); - GdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow); - if(GDK_IS_X11_WINDOW(gdkWindow)) - { - handleInfoOut.backend = WindowHandleInfo::Backend::X11; - handleInfoOut.xlib_window = gdk_x11_window_get_xid(gdkWindow); - handleInfoOut.xlib_display = gdk_x11_display_get_xdisplay(gdkDisplay); - if(!handleInfoOut.xlib_display) - { - cemuLog_log(LogType::Force, "Unable to get xlib display"); - } - } - else -#ifdef HAS_WAYLAND - if(GDK_IS_WAYLAND_WINDOW(gdkWindow)) - { - handleInfoOut.backend = WindowHandleInfo::Backend::WAYLAND; - handleInfoOut.surface = gdk_wayland_window_get_wl_surface(gdkWindow); - handleInfoOut.display = gdk_wayland_display_get_wl_display(gdkDisplay); - } - else -#endif - { - cemuLog_log(LogType::Force, "Unsuported GTK backend"); - } -#else - handleInfoOut.handle = wxw->GetHandle(); -#endif -} - -bool gui_isKeyDown(uint32 key) -{ - return g_window_info.get_keystate(key); -} - -bool gui_isKeyDown(PlatformKeyCodes key) -{ - uint32 keyCode = 0; - -#if BOOST_OS_WINDOWS - switch (key) - { - case PlatformKeyCodes::LCONTROL: - keyCode = VK_LCONTROL; - break; - case PlatformKeyCodes::RCONTROL: - keyCode = VK_RCONTROL; - break; - case PlatformKeyCodes::TAB: - keyCode = VK_TAB; - break; - } -#elif BOOST_OS_LINUX - switch (key) - { - case PlatformKeyCodes::LCONTROL: - keyCode = GDK_KEY_Control_L; - break; - case PlatformKeyCodes::RCONTROL: - keyCode = GDK_KEY_Control_R; - break; - case PlatformKeyCodes::TAB: - keyCode = GDK_KEY_Tab; - break; - } -#elif BOOST_OS_MACOS - switch (key) - { - case PlatformKeyCodes::LCONTROL: - keyCode = kVK_Control; - break; - case PlatformKeyCodes::RCONTROL: - keyCode = kVK_RightControl; - break; - case PlatformKeyCodes::TAB: - keyCode = kVK_Tab; - break; - } -#endif - - return gui_isKeyDown(keyCode); -} - - -void gui_notifyGameLoaded() -{ - std::shared_lock lock(g_mutex); - if (g_mainFrame) - { - g_mainFrame->OnGameLoaded(); - g_mainFrame->UpdateSettingsAfterGameLaunch(); - } -} - -void gui_notifyGameExited() -{ - std::shared_lock lock(g_mutex); - if(g_mainFrame) - g_mainFrame->RestoreSettingsAfterGameExited(); -} - -bool gui_isFullScreen() -{ - return g_window_info.is_fullscreen; -} - -bool gui_hasScreenshotRequest() -{ - const bool result = g_window_info.has_screenshot_request; - g_window_info.has_screenshot_request = false; - return result; -} - -extern DebuggerWindow2* g_debugger_window; -void debuggerWindow_updateViewThreadsafe2() -{ - if (g_debugger_window) - { - auto* evt = new wxCommandEvent(wxEVT_UPDATE_VIEW); - wxQueueEvent(g_debugger_window, evt); - } -} - -void debuggerWindow_moveIP() -{ - if (g_debugger_window) - { - auto* evt = new wxCommandEvent(wxEVT_MOVE_IP); - wxQueueEvent(g_debugger_window, evt); - } -} - -void debuggerWindow_notifyDebugBreakpointHit2() -{ - if (g_debugger_window) - { - auto* evt = new wxCommandEvent(wxEVT_BREAKPOINT_HIT); - wxQueueEvent(g_debugger_window, evt); - } -} - -void debuggerWindow_notifyRun() -{ - if (g_debugger_window) - { - auto* evt = new wxCommandEvent(wxEVT_RUN); - wxQueueEvent(g_debugger_window, evt); - } -} - -void debuggerWindow_notifyModuleLoaded(void* module) -{ - if (g_debugger_window) - { - auto* evt = new wxCommandEvent(wxEVT_NOTIFY_MODULE_LOADED); - evt->SetClientData(module); - wxQueueEvent(g_debugger_window, evt); - } -} - -void debuggerWindow_notifyModuleUnloaded(void* module) -{ - if (g_debugger_window) - { - auto* evt = new wxCommandEvent(wxEVT_NOTIFY_MODULE_UNLOADED); - evt->SetClientData(module); - wxQueueEvent(g_debugger_window, evt); - } -} -void gui_requestGameListRefresh() -{ - MainWindow::RequestGameListRefresh(); -} - -void gui_loggingWindowLog(std::string_view filter, std::string_view message) -{ - LoggingWindow::Log(filter, message); -} - -void gui_loggingWindowLog(std::string_view message) -{ - LoggingWindow::Log(message); -} - - diff --git a/src/imgui/imgui_extension.cpp b/src/imgui/imgui_extension.cpp index 15e0de82..33c49dd3 100644 --- a/src/imgui/imgui_extension.cpp +++ b/src/imgui/imgui_extension.cpp @@ -1,6 +1,6 @@ #include "imgui_extension.h" -#include "gui/guiWrapper.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "resource/IconsFontAwesome5.h" #include "imgui_impl_opengl3.h" #include "resource/resource.h" @@ -116,14 +116,15 @@ ImFont* ImGui_GetFont(float size) void ImGui_UpdateWindowInformation(bool mainWindow) { - extern WindowInfo g_window_info; + + auto& window_info = GuiSystem::getWindowInfo(); static std::map keyboard_mapping; static uint32 current_key = 0; ImGuiIO& io = ImGui::GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; #if BOOST_OS_WINDOWS - io.ImeWindowHandle = mainWindow ? g_window_info.window_main.hwnd : g_window_info.window_pad.hwnd; + io.ImeWindowHandle = mainWindow ? window_info.window_main.surface : window_info.window_pad.surface; #else io.ImeWindowHandle = nullptr; #endif @@ -148,7 +149,7 @@ void ImGui_UpdateWindowInformation(bool mainWindow) keyboard_mapping[key_code] = mapped_key; return mapped_key; }; - g_window_info.iter_keystates([&](auto&& el){ io.AddKeyEvent(get_mapping(el.first), el.second); }); + window_info.iter_keystates([&](auto&& el){ io.AddKeyEvent(get_mapping(el.first), el.second); }); // printf("%f %f %d\n", io.MousePos.x, io.MousePos.y, io.MouseDown[0]); diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp index d4dbea97..f429cdd4 100644 --- a/src/input/InputManager.cpp +++ b/src/input/InputManager.cpp @@ -60,6 +60,18 @@ InputManager::~InputManager() m_update_thread.join(); } +bool s_input_config_window_has_focus = false; + +bool InputManager::input_config_window_has_focus() +{ + return s_input_config_window_has_focus; +} + +void InputManager::set_input_config_window_focus(bool has_focus) +{ + s_input_config_window_has_focus = has_focus; +} + void InputManager::load() noexcept { for (size_t i = 0; i < kMaxController; ++i) diff --git a/src/input/InputManager.h b/src/input/InputManager.h index 70f283b2..91a2e80e 100644 --- a/src/input/InputManager.h +++ b/src/input/InputManager.h @@ -37,6 +37,9 @@ public: constexpr static size_t kMaxVPADControllers = 2; constexpr static size_t kMaxWPADControllers = 7; + static bool input_config_window_has_focus(); + static void set_input_config_window_focus(bool has_focus); + void load() noexcept; bool load(size_t player_index, std::string_view filename = {}); diff --git a/src/input/api/Controller.cpp b/src/input/api/Controller.cpp index b7831def..c5f1c783 100644 --- a/src/input/api/Controller.cpp +++ b/src/input/api/Controller.cpp @@ -1,7 +1,5 @@ #include "input/api/Controller.h" -#include "gui/guiWrapper.h" - ControllerBase::ControllerBase(std::string_view uuid, std::string_view display_name) : m_uuid{uuid}, m_display_name{display_name} { diff --git a/src/input/api/Keyboard/KeyboardController.cpp b/src/input/api/Keyboard/KeyboardController.cpp index 7dc1646d..7d6f8e87 100644 --- a/src/input/api/Keyboard/KeyboardController.cpp +++ b/src/input/api/Keyboard/KeyboardController.cpp @@ -1,7 +1,7 @@ #include +#include "Cemu/GuiSystem/GuiSystem.h" #include "input/api/Keyboard/KeyboardController.h" -#include "gui/guiWrapper.h" KeyboardController::KeyboardController() : base_type("keyboard", "Keyboard") @@ -11,16 +11,14 @@ KeyboardController::KeyboardController() std::string KeyboardController::get_button_name(uint64 button) const { - return gui_RawKeyCodeToString(button); + return GuiSystem::keyCodeToString(button); } -extern WindowInfo g_window_info; - ControllerState KeyboardController::raw_state() { ControllerState result{}; boost::container::small_vector pressedKeys; - g_window_info.iter_keystates([&pressedKeys](const std::pair& keyState) { if (keyState.second) pressedKeys.emplace_back(keyState.first); }); + GuiSystem::getWindowInfo().iter_keystates([&pressedKeys](const std::pair& keyState) { if (keyState.second) pressedKeys.emplace_back(keyState.first); }); result.buttons.SetPressedButtons(pressedKeys); return result; } diff --git a/src/input/emulated/VPADController.cpp b/src/input/emulated/VPADController.cpp index a8395632..90e385f1 100644 --- a/src/input/emulated/VPADController.cpp +++ b/src/input/emulated/VPADController.cpp @@ -3,7 +3,7 @@ #if HAS_SDL #include "input/api/SDL/SDLController.h" #endif // HAS_SDL -#include "gui/guiWrapper.h" +#include "Cemu/GuiSystem/GuiSystem.h" #include "input/InputManager.h" #include "Cafe/HW/Latte/Core/Latte.h" #include "Cafe/CafeSystem.h" @@ -288,9 +288,9 @@ void VPADController::update_motion(VPADStatus_t& status) int w, h; if (pad_view) - gui_getPadWindowPhysSize(w, h); + GuiSystem::getPadWindowPhysSize(w, h); else - gui_getWindowPhysSize(w, h); + GuiSystem::getWindowPhysSize(w, h); float wx = mousePos.x / w; float wy = mousePos.y / h; diff --git a/src/main.cpp b/src/main.cpp index 325a5dd7..45332109 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ -#include "gui/guiWrapper.h" #include "util/crypto/aes128.h" #include "Cafe/OS/RPL/rpl.h" #include "Cafe/OS/RPL/rpl_symbol_storage.h" @@ -301,6 +300,8 @@ void HandlePostUpdate() void ToolShaderCacheMerger(); +void gui_create(); + #if BOOST_OS_WINDOWS // entrypoint for release builds diff --git a/src/mainLLE.cpp b/src/mainLLE.cpp index ac100ccc..72b42b9d 100644 --- a/src/mainLLE.cpp +++ b/src/mainLLE.cpp @@ -1,8 +1,8 @@ #include "util/crypto/aes128.h" -#include "gui/guiWrapper.h" #include "Common/FileStream.h" void mainEmulatorCommonInit(); +void gui_create(); typedef struct {