UI+build: Isolate wxWidgets code from non-GUI code (#1633)

This commit is contained in:
SSimco
2025-07-15 05:28:41 +03:00
committed by GitHub
parent 5f3c2816ec
commit 67de63bed6
199 changed files with 2414 additions and 2091 deletions

View File

@@ -31,6 +31,7 @@ jobs:
find src -name *.cpp -o -name *.hpp -o -name *.h |
xargs xgettext --from-code=utf-8 -w 100
--keyword="_" --keyword="wxTRANSLATE" --keyword="wxPLURAL:1,2"
--keyword="_tr" --keyword="TR_NOOP"
--check=space-ellipsis --omit-header
-o cemu.pot

View File

@@ -150,7 +150,3 @@ if(UNIX AND NOT APPLE)
# most likely not helpful in debugging problems with cemu code
target_link_options(CemuBin PRIVATE "$<$<CONFIG:Release>:-Xlinker;--strip-debug>")
endif()
if (ENABLE_WXWIDGETS)
target_link_libraries(CemuBin PRIVATE wx::base wx::core)
endif()

View File

@@ -597,10 +597,6 @@ else ()
target_link_libraries(CemuCafe PRIVATE libusb::libusb)
endif ()
if (ENABLE_WXWIDGETS)
target_link_libraries(CemuCafe PRIVATE wx::base wx::core)
endif()
if(WIN32)
target_link_libraries(CemuCafe PRIVATE iphlpapi)
endif()

View File

@@ -1,5 +1,5 @@
#include "Cafe/OS/common/OSCommon.h"
#include "gui/wxgui.h"
#include "WindowSystem.h"
#include "Cafe/OS/libs/gx2/GX2.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
@@ -65,9 +65,6 @@
// HW interfaces
#include "Cafe/HW/SI/si.h"
// dependency to be removed
#include "gui/guiWrapper.h"
#include <time.h>
#if BOOST_OS_LINUX
@@ -172,7 +169,7 @@ void LoadMainExecutable()
applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str());
if (!applicationRPX)
{
wxMessageBox(_("Failed to run this title because the executable is damaged"));
WindowSystem::ShowErrorDialog(_tr("Failed to run this title because the executable is damaged"));
cemuLog_createLogFile(false);
cemuLog_waitForFlush();
exit(0);
@@ -357,7 +354,7 @@ uint32 LoadSharedData()
void cemu_initForGame()
{
gui_updateWindowTitles(false, true, 0.0);
WindowSystem::UpdateWindowTitles(false, true, 0.0);
// input manager apply game profile
InputManager::instance().apply_game_profile();
// log info for launched title
@@ -855,7 +852,7 @@ namespace CafeSystem
PPCTimer_waitForInit();
// start system
sSystemRunning = true;
gui_notifyGameLoaded();
WindowSystem::NotifyGameLoaded();
std::thread t(_LaunchTitleThread);
t.detach();
}

View File

@@ -1,7 +1,7 @@
#include <wx/msgdlg.h>
#include <mutex>
#include <gui/helpers/wxHelpers.h>
#include "Cemu/Logging/CemuLogging.h"
#include "WindowSystem.h"
#include "config/ActiveSettings.h"
#include "util/crypto/aes128.h"
#include "Common/FileStream.h"
@@ -75,7 +75,7 @@ void KeyCache_Prepare()
}
else
{
wxMessageBox(_("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
WindowSystem::ShowErrorDialog(_tr("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _tr("Error"), WindowSystem::ErrorCategory::KEYS_TXT_CREATION);
}
mtxKeyCache.unlock();
return;
@@ -108,8 +108,8 @@ void KeyCache_Prepare()
continue;
if( strishex(line) == false )
{
auto errorMsg = formatWxString(_("Error in keys.txt at line {}"), lineNumber);
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
auto errorMsg = _tr("Error in keys.txt at line {}", lineNumber);
WindowSystem::ShowErrorDialog(errorMsg, WindowSystem::ErrorCategory::KEYS_TXT_CREATION);
continue;
}
if(line.size() == 32 )

View File

@@ -85,7 +85,7 @@ bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules)
auto gp = std::make_shared<GraphicPack2>(rulesPath, rules);
// check if enabled and preset set
const auto& config_entries = g_config.data().graphic_pack_entries;
const auto& config_entries = GetConfigHandle().data().graphic_pack_entries;
// legacy absolute path checking for not breaking compatibility
auto file = gp->GetRulesPath();

View File

@@ -1,13 +1,12 @@
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "Cemu/Logging/CemuLogging.h"
#include "Common/FileStream.h"
#include "WindowSystem.h"
#include "util/helpers/StringParser.h"
#include "Cemu/PPCAssembler/ppcAssembler.h"
#include "Cafe/OS/RPL/rpl_structs.h"
#include "boost/algorithm/string.hpp"
#include "gui/wxgui.h" // for wxMessageBox
#include "gui/helpers/wxHelpers.h"
// error handler
void PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumber, std::string_view errorMsg)
{
@@ -40,13 +39,13 @@ void PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumb
void PatchErrorHandler::showStageErrorMessageBox()
{
wxString errorMsg;
std::string errorMsg;
if (m_gp)
{
if (m_stage == STAGE::PARSER)
errorMsg.assign(formatWxString(_("Failed to load patches for graphic pack \'{}\'"), m_gp->GetName()));
errorMsg.assign(_tr("Failed to load patches for graphic pack \'{}\'", m_gp->GetName()));
else
errorMsg.assign(formatWxString(_("Failed to apply patches for graphic pack \'{}\'"), m_gp->GetName()));
errorMsg.assign(_tr("Failed to apply patches for graphic pack \'{}\'", m_gp->GetName()));
}
else
{
@@ -55,7 +54,7 @@ void PatchErrorHandler::showStageErrorMessageBox()
if (cemuLog_isLoggingEnabled(LogType::Patches))
{
errorMsg.append("\n \n")
.append(_("Details:"))
.append(_tr("Details:"))
.append("\n");
for (auto& itr : errorMessages)
{
@@ -64,7 +63,7 @@ void PatchErrorHandler::showStageErrorMessageBox()
}
}
wxMessageBox(errorMsg, _("Graphic pack error"));
WindowSystem::ShowErrorDialog(errorMsg, _tr("Graphic pack error"), WindowSystem::ErrorCategory::GRAPHIC_PACKS);
}
// loads Cemu-style patches (patch_<anything>.asm)

View File

@@ -1,19 +1,20 @@
#include "gui/guiWrapper.h"
#include "Common/precompiled.h"
#include "Debugger.h"
#include "Cafe/OS/RPL/rpl_structs.h"
#include "Cemu/PPCAssembler/ppcAssembler.h"
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
#include "Cemu/ExpressionParser/ExpressionParser.h"
#include "gui/debugger/DebuggerWindow2.h"
#include "Cafe/OS/libs/coreinit/coreinit.h"
#include "OS/RPL/rpl.h"
#include "util/helpers/helpers.h"
#if BOOST_OS_WINDOWS
#include <Windows.h>
#endif
DebuggerDispatcher g_debuggerDispatcher;
debuggerState_t debuggerState{ };
DebuggerBreakpoint* debugger_getFirstBP(uint32 address)
@@ -337,7 +338,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b
{
bp->enabled = state;
debugger_updateExecutionBreakpoint(address);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
}
else if (bpItr->isMemBP())
{
@@ -359,7 +360,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b
debugger_updateMemoryBreakpoint(bpItr);
else
debugger_updateMemoryBreakpoint(nullptr);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
}
return;
}
@@ -496,7 +497,7 @@ void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true)
debugger_updateExecutionBreakpoint(initialIP);
debuggerState.debugSession.instructionPointer = hCPU->instructionPointer;
if(updateDebuggerWindow)
debuggerWindow_moveIP();
g_debuggerDispatcher.MoveIP();
ppcRecompilerEnabled = isRecEnabled;
}
@@ -515,7 +516,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU)
// nothing to skip, use step-into
debugger_stepInto(hCPU);
debugger_updateExecutionBreakpoint(initialIP);
debuggerWindow_moveIP();
g_debuggerDispatcher.MoveIP();
ppcRecompilerEnabled = isRecEnabled;
return false;
}
@@ -523,7 +524,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU)
debugger_createCodeBreakpoint(initialIP + 4, DEBUGGER_BP_T_ONE_SHOT);
// step over current instruction (to avoid breakpoint)
debugger_stepInto(hCPU);
debuggerWindow_moveIP();
g_debuggerDispatcher.MoveIP();
// restore breakpoints
debugger_updateExecutionBreakpoint(initialIP);
// run
@@ -621,8 +622,8 @@ 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();
g_debuggerDispatcher.NotifyDebugBreakpointHit();
g_debuggerDispatcher.UpdateViewThreadsafe();
// reset step control
debuggerState.debugSession.stepInto = false;
debuggerState.debugSession.stepOver = false;
@@ -639,14 +640,14 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
break; // if true is returned, continue with execution
}
debugger_createPPCStateSnapshot(hCPU);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
debuggerState.debugSession.stepOver = false;
}
if (debuggerState.debugSession.stepInto)
{
debugger_stepInto(hCPU);
debugger_createPPCStateSnapshot(hCPU);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
debuggerState.debugSession.stepInto = false;
continue;
}
@@ -663,8 +664,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
debuggerState.debugSession.isTrapped = false;
debuggerState.debugSession.hCPU = nullptr;
debuggerWindow_updateViewThreadsafe2();
debuggerWindow_notifyRun();
g_debuggerDispatcher.UpdateViewThreadsafe();
g_debuggerDispatcher.NotifyRun();
}
void debugger_shouldBreak(PPCInterpreter_t* hCPU)

View File

@@ -15,6 +15,69 @@
#define DEBUGGER_BP_T_GDBSTUB_TW 0x7C010008
#define DEBUGGER_BP_T_DEBUGGER_TW 0x7C020008
class DebuggerCallbacks
{
public:
virtual void UpdateViewThreadsafe() {}
virtual void NotifyDebugBreakpointHit() {}
virtual void NotifyRun() {}
virtual void MoveIP() {}
virtual void NotifyModuleLoaded(void* module) {}
virtual void NotifyModuleUnloaded(void* module) {}
virtual ~DebuggerCallbacks() = default;
};
class DebuggerDispatcher
{
private:
static inline class DefaultDebuggerCallbacks : public DebuggerCallbacks
{
} s_defaultDebuggerCallbacks;
DebuggerCallbacks* m_callbacks = &s_defaultDebuggerCallbacks;
public:
void SetDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks)
{
cemu_assert_debug(m_callbacks == &s_defaultDebuggerCallbacks);
m_callbacks = debuggerCallbacks;
}
void ClearDebuggerCallbacks()
{
cemu_assert_debug(m_callbacks != &s_defaultDebuggerCallbacks);
m_callbacks = &s_defaultDebuggerCallbacks;
}
void UpdateViewThreadsafe()
{
m_callbacks->UpdateViewThreadsafe();
}
void NotifyDebugBreakpointHit()
{
m_callbacks->NotifyDebugBreakpointHit();
}
void NotifyRun()
{
m_callbacks->NotifyRun();
}
void MoveIP()
{
m_callbacks->MoveIP();
}
void NotifyModuleLoaded(void* module)
{
m_callbacks->NotifyModuleLoaded(module);
}
void NotifyModuleUnloaded(void* module)
{
m_callbacks->NotifyModuleUnloaded(module);
}
} extern g_debuggerDispatcher;
struct DebuggerBreakpoint
{

View File

@@ -1,6 +1,6 @@
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "config/CemuConfig.h"
@@ -519,17 +519,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 && WindowSystem::IsPadWindowOpen())
WindowSystem::GetPadWindowPhysSize(w, h);
else
gui_getWindowPhysSize(w, h);
WindowSystem::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 ? WindowSystem::GetWindowDPIScale() : WindowSystem::GetPadDPIScale();
float overlayFontSize = 14.0f * (float)config.overlay.text_scale / 100.0f * fontDPIScale;

View File

@@ -1,6 +1,6 @@
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
performanceMonitor_t performanceMonitor{};
@@ -106,12 +106,12 @@ void LattePerformanceMonitor_frameEnd()
if (isFirstUpdate)
{
LatteOverlay_updateStats(0.0, 0, 0);
gui_updateWindowTitles(false, false, 0.0);
WindowSystem::UpdateWindowTitles(false, false, 0.0);
}
else
{
LatteOverlay_updateStats(fps, drawCallCounter / elapsedFrames, fastDrawCallCounter / elapsedFrames);
gui_updateWindowTitles(false, false, fps);
WindowSystem::UpdateWindowTitles(false, false, fps);
}
}
}

View File

@@ -11,7 +11,7 @@
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "config/ActiveSettings.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/OS/libs/erreula/erreula.h"
#include "input/InputManager.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
@@ -838,10 +838,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 && WindowSystem::IsPadWindowOpen())
WindowSystem::GetPadWindowPhysSize(w, h);
else
gui_getWindowPhysSize(w, h);
WindowSystem::GetWindowPhysSize(w, h);
sint32 scaledOutputX;
sint32 scaledOutputY;
@@ -999,8 +999,8 @@ void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uin
return {pressed && !toggle, pressed && toggle};
};
const bool tabPressed = gui_isKeyDown(PlatformKeyCodes::TAB);
const bool ctrlPressed = gui_isKeyDown(PlatformKeyCodes::LCONTROL);
const bool tabPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::TAB);
const bool ctrlPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::LCONTROL);
const auto [vpad0Active, vpad0Toggle] = getVPADScreenActive(0);
const auto [vpad1Active, vpad1Toggle] = getVPADScreenActive(1);

View File

@@ -6,7 +6,7 @@
#include "Cafe/HW/Latte/Core/FetchShader.h"
#include "Cemu/FileCache/FileCache.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h"
@@ -24,7 +24,6 @@
#include "Cafe/HW/Latte/Common/ShaderSerializer.h"
#include "util/helpers/Serializer.h"
#include <wx/msgdlg.h>
#include <audio/IAudioAPI.h>
#include <util/bootSound/BootSoundReader.h>
#include <thread>
@@ -69,8 +68,6 @@ void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId);
bool LatteShaderCache_updatePipelineLoadingProgress();
void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines);
void LatteShaderCache_handleDeprecatedCacheFiles(fs::path pathGeneric, fs::path pathGenericPre1_25_0, fs::path pathGenericPre1_16_0);
struct
{
struct
@@ -360,10 +357,7 @@ void LatteShaderCache_Load()
RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);
// get cache file name
const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId);
const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0
const auto pathGenericPre1_16_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0
LatteShaderCache_handleDeprecatedCacheFiles(pathGeneric, pathGenericPre1_25_0, pathGenericPre1_16_0);
// calculate extraVersion for transferable and precompiled shader cache
uint32 transferableExtraVersion = SHADER_CACHE_GENERIC_EXTRA_VERSION;
s_shaderCacheGeneric = FileCache::Open(pathGeneric, false, transferableExtraVersion); // legacy extra version (1.25.0 - 1.25.1b)
@@ -511,7 +505,7 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
continue;
int w, h;
gui_getWindowPhysSize(w, h);
WindowSystem::GetWindowPhysSize(w, h);
const Vector2f window_size{ (float)w,(float)h };
ImGui_GetFont(window_size.y / 32.0f); // = 24 by default
@@ -900,30 +894,3 @@ void LatteShaderCache_Close()
if (g_renderer->GetType() == RendererAPI::Vulkan)
VulkanPipelineStableCache::GetInstance().Close();
}
#include <wx/msgdlg.h>
void LatteShaderCache_handleDeprecatedCacheFiles(fs::path pathGeneric, fs::path pathGenericPre1_25_0, fs::path pathGenericPre1_16_0)
{
std::error_code ec;
bool hasOldCacheFiles = fs::exists(pathGenericPre1_25_0, ec) || fs::exists(pathGenericPre1_16_0, ec);
bool hasNewCacheFiles = fs::exists(pathGeneric, ec);
if (hasOldCacheFiles && !hasNewCacheFiles)
{
// ask user if they want to delete or keep the old cache file
auto infoMsg = _("Cemu detected that the shader cache for this game is outdated.\nOnly shader caches generated with Cemu 1.25.0 or above are supported.\n\nWe recommend deleting the outdated cache file as it will no longer be used by Cemu.");
wxMessageDialog dialog(nullptr, infoMsg, _("Outdated shader cache"),
wxYES_NO | wxCENTRE | wxICON_EXCLAMATION);
dialog.SetYesNoLabels(_("Delete outdated cache file [recommended]"), _("Keep outdated cache file"));
const auto result = dialog.ShowModal();
if (result == wxID_YES)
{
fs::remove(pathGenericPre1_16_0, ec);
fs::remove(pathGenericPre1_25_0, ec);
}
}
}

View File

@@ -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 "WindowSystem.h"
#include "Cafe/HW/Latte/Core/LatteBufferCache.h"
@@ -115,7 +115,7 @@ int Latte_ThreadEntry()
{
SetThreadName("LatteThread");
sint32 w,h;
gui_getWindowPhysSize(w,h);
WindowSystem::GetWindowPhysSize(w,h);
// renderer
g_renderer->Initialize();
@@ -166,8 +166,7 @@ int Latte_ThreadEntry()
g_renderer->DrawEmptyFrame(true);
g_renderer->DrawEmptyFrame(false);
gui_hasScreenshotRequest(); // keep the screenshot request queue empty
g_renderer->CancelScreenshotRequest(); // keep the screenshot request queue empty
std::this_thread::sleep_for(std::chrono::milliseconds(1000/60));
}

View File

@@ -1,5 +1,5 @@
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Core/LatteRingBuffer.h"
#include "Cafe/HW/Latte/Core/LatteDraw.h"
@@ -19,7 +19,38 @@
#include "Cafe/HW/Latte/ISA/RegDefines.h"
#include "Cafe/OS/libs/gx2/GX2.h"
#include "gui/canvas/OpenGLCanvas.h"
class DefaultOpenGLCanvasCallbacks : public OpenGLCanvasCallbacks
{
} g_defaultOpenGLCanvasCallbacks;
OpenGLCanvasCallbacks* g_openGLCanvasCallbacks = &g_defaultOpenGLCanvasCallbacks;
void SetOpenGLCanvasCallbacks(OpenGLCanvasCallbacks* callbacks)
{
cemu_assert_debug(g_openGLCanvasCallbacks == &g_defaultOpenGLCanvasCallbacks);
g_openGLCanvasCallbacks = callbacks;
}
void ClearOpenGLCanvasCallbacks()
{
cemu_assert_debug(g_openGLCanvasCallbacks != &g_defaultOpenGLCanvasCallbacks);
g_openGLCanvasCallbacks = &g_defaultOpenGLCanvasCallbacks;
}
bool GLCanvas_HasPadViewOpen()
{
return g_openGLCanvasCallbacks->HasPadViewOpen();
}
bool GLCanvas_MakeCurrent(bool padView)
{
return g_openGLCanvasCallbacks->MakeCurrent(padView);
}
void GLCanvas_SwapBuffers(bool swapTV, bool swapDRC)
{
g_openGLCanvasCallbacks->SwapBuffers(swapTV, swapDRC);
}
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
@@ -479,8 +510,7 @@ void OpenGLRenderer::ClearColorbuffer(bool padView)
void OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView)
{
const bool hasScreenshotRequest = gui_hasScreenshotRequest();
if(!hasScreenshotRequest && m_screenshot_state == ScreenshotState::None)
if(!m_screenshot_requested && m_screenshot_state == ScreenshotState::None)
return;
if (IsPadWindowActive())
@@ -563,9 +593,9 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
{
int windowWidth, windowHeight;
if (padView)
gui_getPadWindowPhysSize(windowWidth, windowHeight);
WindowSystem::GetPadWindowPhysSize(windowWidth, windowHeight);
else
gui_getWindowPhysSize(windowWidth, windowHeight);
WindowSystem::GetWindowPhysSize(windowWidth, windowHeight);
g_renderer->renderTarget_setViewport(0, 0, windowWidth, windowHeight, 0.0f, 1.0f);
g_renderer->ClearColorbuffer(padView);
}

View File

@@ -6,6 +6,28 @@
#define GPU_GL_MAX_NUM_ATTRIBUTE (16) // Wii U GPU supports more than 16 but not all desktop GPUs do. Have to keep this at 16 until we find a better solution
class OpenGLCanvasCallbacks
{
public:
virtual bool HasPadViewOpen() const
{
return false;
}
virtual bool MakeCurrent(bool padView)
{
return false;
}
virtual void SwapBuffers(bool swapTV, bool swapDRC) {}
virtual ~OpenGLCanvasCallbacks() = default;
};
void SetOpenGLCanvasCallbacks(OpenGLCanvasCallbacks* callbacks);
void ClearOpenGLCanvasCallbacks();
bool GLCanvas_HasPadViewOpen();
bool GLCanvas_MakeCurrent(bool padView);
void GLCanvas_SwapBuffers(bool swapTV, bool swapDRC);
class OpenGLRenderer : public Renderer
{
friend class OpenGLCanvas;

View File

@@ -1,5 +1,5 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "config/CemuConfig.h"
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
@@ -10,11 +10,6 @@
#include "config/ActiveSettings.h"
#include <wx/image.h>
#include <wx/dataobj.h>
#include <wx/clipbrd.h>
#include <wx/log.h>
std::unique_ptr<Renderer> g_renderer;
bool Renderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const
@@ -69,10 +64,10 @@ void Renderer::Shutdown()
bool Renderer::ImguiBegin(bool mainWindow)
{
sint32 w = 0, h = 0;
if(mainWindow)
gui_getWindowPhysSize(w, h);
else if(gui_isPadWindowOpen())
gui_getPadWindowPhysSize(w, h);
if (mainWindow)
WindowSystem::GetWindowPhysSize(w, h);
else if (WindowSystem::IsPadWindowOpen())
WindowSystem::GetPadWindowPhysSize(w, h);
else
return false;
@@ -82,9 +77,9 @@ bool Renderer::ImguiBegin(bool mainWindow)
// select the right context
ImGui::SetCurrentContext(mainWindow ? imguiTVContext : imguiPadContext);
const Vector2f window_size{ (float)w,(float)h };
const Vector2f window_size{(float)w, (float)h};
auto& io = ImGui::GetIO();
io.DisplaySize = { window_size.x, window_size.y }; // should be only updated in the renderer and only when needed
io.DisplaySize = {window_size.x, window_size.y}; // should be only updated in the renderer and only when needed
ImGui_PrecacheFonts();
return true;
@@ -114,107 +109,29 @@ uint8 Renderer::RGBComponentToSRGB(uint8 cli)
return (uint8)(cs * 255.0f);
}
static std::optional<fs::path> GenerateScreenshotFilename(bool isDRC)
void Renderer::RequestScreenshot(ScreenshotSaveFunction 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;
}
std::mutex s_clipboardMutex;
static bool SaveScreenshotToClipboard(const wxImage &image)
void Renderer::CancelScreenshotRequest()
{
bool success = false;
s_clipboardMutex.lock();
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxImageDataObject(image));
wxTheClipboard->Close();
success = true;
}
s_clipboardMutex.unlock();
return success;
m_screenshot_requested = false;
m_on_save_screenshot = {};
}
static bool SaveScreenshotToFile(const wxImage &image, bool mainWindow)
void Renderer::SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow)
{
auto path = GenerateScreenshotFilename(!mainWindow);
if (!path) return false;
std::error_code ec;
fs::create_directories(path->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(path->wstring());
}
static void ScreenshotThread(std::vector<uint8> data, bool save_screenshot, 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
wxImage image(width, height, data.data(), true);
if (mainWindow)
{
if(SaveScreenshotToClipboard(image))
{
if (!save_screenshot)
LatteOverlay_pushNotification("Screenshot saved to clipboard", 2500);
}
else
{
LatteOverlay_pushNotification("Failed to open clipboard", 2500);
}
}
if (save_screenshot)
{
if (SaveScreenshotToFile(image, mainWindow))
{
if (mainWindow)
LatteOverlay_pushNotification("Screenshot saved", 2500);
}
else
{
LatteOverlay_pushNotification("Failed to save screenshot to file", 2500);
}
}
}
void Renderer::SaveScreenshot(const std::vector<uint8>& 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(
[=, screenshotRequested = std::exchange(m_screenshot_requested, false), onSaveScreenshot = std::exchange(m_on_save_screenshot, {})]() {
if (screenshotRequested && onSaveScreenshot)
{
auto notificationMessage = onSaveScreenshot(rgb_data, width, height, mainWindow);
if (notificationMessage.has_value())
LatteOverlay_pushNotification(notificationMessage.value(), 2500);
}
})
.detach();
}

View File

@@ -65,6 +65,10 @@ public:
virtual void DrawEmptyFrame(bool mainWindow) = 0;
virtual void SwapBuffers(bool swapTV, bool swapDRC) = 0;
using ScreenshotSaveFunction = std::function<std::optional<std::string>(const std::vector<uint8>&, int, int, bool)>;
void RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot);
void CancelScreenshotRequest();
virtual void HandleScreenshotRequest(LatteTextureView* texView, bool padView){}
virtual void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
@@ -168,7 +172,10 @@ protected:
Pad,
};
ScreenshotState m_screenshot_state = ScreenshotState::None;
void SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow) const;
bool m_screenshot_requested = false;
ScreenshotSaveFunction m_on_save_screenshot;
void SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow);
ImFontAtlas* imguiFontAtlas{};

View File

@@ -1,7 +1,7 @@
#include "SwapchainInfoVk.h"
#include "config/CemuConfig.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Core/Latte.h"
#include "Cafe/HW/Latte/Core/LatteTiming.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
@@ -9,7 +9,7 @@
SwapchainInfoVk::SwapchainInfoVk(bool mainWindow, Vector2i size) : mainWindow(mainWindow), m_desiredExtent(size)
{
auto& windowHandleInfo = mainWindow ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad;
auto& windowHandleInfo = mainWindow ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;
auto renderer = VulkanRenderer::GetInstance();
m_instance = renderer->GetVkInstance();
m_logicalDevice = renderer->GetLogicalDevice();

View File

@@ -1,9 +1,9 @@
#include "gui/MainWindow.h"
#if BOOST_OS_WINDOWS
#include <Windows.h>
#include "WindowSystem.h"
typedef LONG NTSTATUS;
typedef UINT32 D3DKMT_HANDLE;
@@ -53,7 +53,7 @@ public:
private:
bool HasMonitorChanged()
{
HWND hWnd = (HWND)g_mainFrame->GetRenderCanvasHWND();
HWND hWnd = (HWND)WindowSystem::GetWindowInfo().canvas_main.surface;
if (hWnd == 0)
return true;
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
@@ -71,9 +71,7 @@ private:
HRESULT GetAdapterHandleFromHwnd(D3DKMT_HANDLE* phAdapter, UINT* pOutput)
{
if (!g_mainFrame)
return E_FAIL;
HWND hWnd = (HWND)g_mainFrame->GetRenderCanvasHWND();
HWND hWnd = (HWND)WindowSystem::GetWindowInfo().canvas_main.surface;
if (hWnd == 0)
return E_FAIL;

View File

@@ -18,7 +18,7 @@
#include "config/ActiveSettings.h"
#include "config/CemuConfig.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "imgui/imgui_extension.h"
#include "imgui/imgui_impl_vulkan.h"
@@ -27,11 +27,9 @@
#include "Cafe/HW/Latte/Core/LatteTiming.h" // vsync control
#include <cstdint>
#include <glslang/Public/ShaderLang.h>
#include <wx/msgdlg.h>
#include <wx/intl.h> // for localization
#ifndef VK_API_VERSION_MAJOR
#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU)
#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU)
@@ -113,11 +111,11 @@ std::vector<VulkanRenderer::DeviceInfo> VulkanRenderer::GetDevices()
#if BOOST_OS_WINDOWS
requiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#elif BOOST_OS_LINUX
auto backend = gui_getWindowInfo().window_main.backend;
if(backend == WindowHandleInfo::Backend::X11)
auto backend = WindowSystem::GetWindowInfo().window_main.backend;
if(backend == WindowSystem::WindowHandleInfo::Backend::X11)
requiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
#ifdef HAS_WAYLAND
else if (backend == WindowHandleInfo::Backend::WAYLAND)
else if (backend == WindowSystem::WindowHandleInfo::Backend::Wayland)
requiredExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
#elif BOOST_OS_MACOS
@@ -156,7 +154,7 @@ std::vector<VulkanRenderer::DeviceInfo> 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, WindowSystem::GetWindowInfo().window_main);
std::vector<VkPhysicalDevice> devices(device_count);
vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
for (const auto& device : devices)
@@ -309,7 +307,7 @@ void VulkanRenderer::GetDeviceFeatures()
cemuLog_log(LogType::Force, "VK_EXT_pipeline_creation_cache_control not supported. Cannot use asynchronous shader and pipeline compilation");
// if async shader compilation is enabled show warning message
if (GetConfig().async_compile)
LatteOverlay_pushNotification(_("Async shader compile is enabled but not supported by the graphics driver\nCemu will use synchronous compilation which can cause additional stutter").utf8_string(), 10000);
LatteOverlay_pushNotification(_tr("Async shader compile is enabled but not supported by the graphics driver\nCemu will use synchronous compilation which can cause additional stutter"), 10000);
}
if (!m_featureControl.deviceExtensions.custom_border_color_without_format)
{
@@ -402,7 +400,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, WindowSystem::GetWindowInfo().window_main);
auto& config = GetConfig();
decltype(config.graphic_device_uuid) zero{};
@@ -810,8 +808,7 @@ bool VulkanRenderer::IsPadWindowActive()
void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView)
{
const bool hasScreenshotRequest = gui_hasScreenshotRequest();
if (!hasScreenshotRequest && m_screenshot_state == ScreenshotState::None)
if (!m_screenshot_requested && m_screenshot_state == ScreenshotState::None)
return;
if (IsSwapchainInfoValid(false))
@@ -1311,11 +1308,11 @@ std::vector<const char*> VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo
#if BOOST_OS_WINDOWS
requiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#elif BOOST_OS_LINUX
auto backend = gui_getWindowInfo().window_main.backend;
if(backend == WindowHandleInfo::Backend::X11)
auto backend = WindowSystem::GetWindowInfo().window_main.backend;
if(backend == WindowSystem::WindowHandleInfo::Backend::X11)
requiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
#if HAS_WAYLAND
else if (backend == WindowHandleInfo::Backend::WAYLAND)
else if (backend == WindowSystem::WindowHandleInfo::Backend::Wayland)
requiredInstanceExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
#endif
#elif BOOST_OS_MACOS
@@ -1457,20 +1454,21 @@ VkSurfaceKHR VulkanRenderer::CreateWaylandSurface(VkInstance instance, wl_displa
#endif // HAS_WAYLAND
#endif // BOOST_OS_LINUX
VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo)
VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, WindowSystem::WindowHandleInfo& windowInfo)
{
#if BOOST_OS_WINDOWS
return CreateWinSurface(instance, windowInfo.hwnd);
return CreateWinSurface(instance, static_cast<HWND>(windowInfo.surface));
#elif BOOST_OS_LINUX
if(windowInfo.backend == WindowHandleInfo::Backend::X11)
return CreateXlibSurface(instance, windowInfo.xlib_display, windowInfo.xlib_window);
if(windowInfo.backend == WindowSystem::WindowHandleInfo::Backend::X11)
return CreateXlibSurface(instance, static_cast<Display*>(windowInfo.display), reinterpret_cast<Window>(windowInfo.surface));
#ifdef HAS_WAYLAND
if(windowInfo.backend == WindowHandleInfo::Backend::WAYLAND)
return CreateWaylandSurface(instance, windowInfo.display, windowInfo.surface);
if(windowInfo.backend == WindowSystem::WindowHandleInfo::Backend::Wayland)
return CreateWaylandSurface(instance, static_cast<wl_display*>(windowInfo.display), static_cast<wl_surface*>(windowInfo.surface));
#endif
return {};
#elif BOOST_OS_MACOS
return CreateCocoaSurface(instance, windowInfo.handle);
return CreateCocoaSurface(instance, windowInfo.surface);
#endif
}
@@ -2746,11 +2744,11 @@ void VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)
if (mainWindow)
{
ImGui_ImplVulkan_Shutdown();
gui_getWindowPhysSize(size.x, size.y);
WindowSystem::GetWindowPhysSize(size.x, size.y);
}
else
{
gui_getPadWindowPhysSize(size.x, size.y);
WindowSystem::GetPadWindowPhysSize(size.x, size.y);
}
chainInfo.swapchainImageIndex = -1;
@@ -2780,9 +2778,9 @@ bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
int width, height;
if (mainWindow)
gui_getWindowPhysSize(width, height);
WindowSystem::GetWindowPhysSize(width, height);
else
gui_getPadWindowPhysSize(width, height);
WindowSystem::GetPadWindowPhysSize(width, height);
auto extent = chainInfo.getExtent();
if (width != extent.width || height != extent.height)
stateChanged = true;

View File

@@ -120,6 +120,11 @@ public:
bool neverSkipAccurateBarrier{false};
};
namespace WindowSystem
{
struct WindowHandleInfo;
};
class VulkanRenderer : public Renderer
{
friend class LatteQueryObjectVk;
@@ -204,7 +209,7 @@ public:
#endif
#endif
static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo);
static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowSystem::WindowHandleInfo& windowInfo);
void AppendOverlayDebugInfo() override;

View File

@@ -1,7 +1,8 @@
#include "Cafe/HW/MMU/MMU.h"
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "Cemu/Logging/CemuLogging.h"
#include "WindowSystem.h"
#include "util/MemMapper/MemMapper.h"
#include <wx/msgdlg.h>
#include "config/ActiveSettings.h"
uint8* memory_base = NULL; // base address of the reserved 4GB space
@@ -90,8 +91,8 @@ void MMURange::mapMem()
cemu_assert_debug(!m_isMapped);
if (MemMapper::AllocateMemory(memory_base + baseAddress, size, MemMapper::PAGE_PERMISSION::P_RW, true) == nullptr)
{
std::string errorMsg = fmt::format("Unable to allocate {} memory", name);
wxMessageBox(errorMsg.c_str(), "Error", wxOK | wxCENTRE | wxICON_ERROR);
std::string errorMsg = _tr("Unable to allocate {} memory", name);
WindowSystem::ShowErrorDialog(errorMsg, _tr("Error"));
#if BOOST_OS_WINDOWS
ExitProcess(-1);
#else
@@ -133,7 +134,7 @@ void memory_init()
{
debug_printf("memory_init(): Unable to reserve 4GB of memory\n");
debugBreakpoint();
wxMessageBox("Unable to reserve 4GB of memory\n", "Error", wxOK | wxCENTRE | wxICON_ERROR);
WindowSystem::ShowErrorDialog(_tr("Unable to reserve 4GB of memory"), _tr("Error"));
exit(-1);
}
for (auto& itr : g_mmuRanges)

View File

@@ -2,7 +2,6 @@
#include "iosu_ioctl.h"
#include "Cafe/OS/libs/nn_common.h"
#include "gui/CemuApp.h"
#include <algorithm>
#include <mutex>

View File

@@ -14,7 +14,7 @@
#include "util/crypto/crc32.h"
#include "config/ActiveSettings.h"
#include "Cafe/OS/libs/coreinit/coreinit_DynLoad.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
class PPCCodeHeap : public VHeap
{
@@ -1795,7 +1795,7 @@ void RPLLoader_UnloadModule(RPLModule* rpl)
RPLLoader_decrementModuleDependencyRefs(rpl);
// save module config for this module in the debugger
debuggerWindow_notifyModuleUnloaded(rpl);
g_debuggerDispatcher.NotifyModuleUnloaded(rpl);
// release memory
rplLoaderHeap_codeArea2.free(rpl->regionMappingBase_text.GetPtr());
@@ -1878,7 +1878,7 @@ void RPLLoader_Link()
RPLLoader_LoadDebugSymbols(rplModuleList[i]);
rplModuleList[i]->isLinked = true; // mark as linked
GraphicPack2::NotifyModuleLoaded(rplModuleList[i]);
debuggerWindow_notifyModuleLoaded(rplModuleList[i]);
g_debuggerDispatcher.NotifyModuleLoaded(rplModuleList[i]);
}
}

View File

@@ -6,8 +6,6 @@
#include <imgui.h>
#include "imgui/imgui_extension.h"
#include <wx/msgdlg.h>
#include "Cafe/OS/libs/coreinit/coreinit_FS.h"
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
#include "Cafe/OS/libs/vpad/vpad.h"

View File

@@ -1,5 +1,4 @@
#include "Cafe/OS/common/OSCommon.h"
#include "gui/wxgui.h"
#include "nn_save.h"
#include "Cafe/OS/libs/nn_acp/nn_acp.h"
@@ -229,78 +228,6 @@ namespace save
return ConvertACPToSaveStatus(acp::ACPUnmountSaveDir());
}
void _CheckAndMoveLegacySaves()
{
const uint64 titleId = CafeSystem::GetForegroundTitleId();
fs::path targetPath, sourcePath;
try
{
bool copiedUser = false, copiedCommon = false;
const auto sourceSavePath = ActiveSettings::GetMlcPath("emulatorSave/{:08x}", CafeSystem::GetRPXHashBase());
sourcePath = sourceSavePath;
if (fs::exists(sourceSavePath) && is_directory(sourceSavePath))
{
targetPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/user/{:08x}", GetTitleIdHigh(titleId), GetTitleIdLow(titleId), 0x80000001);
fs::create_directories(targetPath);
copy(sourceSavePath, targetPath, fs::copy_options::overwrite_existing | fs::copy_options::recursive);
copiedUser = true;
}
const auto sourceCommonPath = ActiveSettings::GetMlcPath("emulatorSave/{:08x}_255", CafeSystem::GetRPXHashBase());
sourcePath = sourceCommonPath;
if (fs::exists(sourceCommonPath) && is_directory(sourceCommonPath))
{
targetPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/user/common", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
fs::create_directories(targetPath);
copy(sourceCommonPath, targetPath, fs::copy_options::overwrite_existing | fs::copy_options::recursive);
copiedCommon = true;
}
if (copiedUser)
fs::remove_all(sourceSavePath);
if (copiedCommon)
fs::remove_all(sourceCommonPath);
}
catch (const std::exception& ex)
{
#if BOOST_OS_WINDOWS
std::wstringstream errorMsg;
errorMsg << L"Couldn't move your save files!" << std::endl << std::endl;
errorMsg << L"Error: " << ex.what() << std::endl << std::endl;
errorMsg << L"From:" << std::endl << sourcePath << std::endl << std::endl << "To:" << std::endl << targetPath;
const DWORD lastError = GetLastError();
if (lastError != ERROR_SUCCESS)
{
LPTSTR lpMsgBuf = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, lastError, 0, (LPTSTR)&lpMsgBuf, 0, nullptr);
if (lpMsgBuf)
{
errorMsg << std::endl << std::endl << L"Details: " << lpMsgBuf;
LocalFree(lpMsgBuf);
}
else
{
errorMsg << std::endl << std::endl << L"Error Code: 0x" << std::hex << lastError;
}
}
errorMsg << std::endl << std::endl << "Continuing will create a new save at the target location." << std::endl << "Do you want to continue?";
int result = wxMessageBox(errorMsg.str(), "Save Migration - Error", wxCENTRE | wxYES_NO | wxICON_ERROR);
if (result != wxYES)
{
exit(0);
return;
}
#endif
}
}
SAVEStatus SAVEInit()
{
@@ -321,8 +248,6 @@ namespace save
SAVEMountSaveDir();
g_nn_save->initialized = true;
_CheckAndMoveLegacySaves();
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
uint32 low = GetTitleIdLow(titleId);

View File

@@ -1,10 +1,10 @@
#include "Cafe/OS/common/OSCommon.h"
#include "Cafe/HW/Espresso/PPCCallback.h"
#include "gui/wxgui.h"
#include "Cafe/OS/libs/padscore/padscore.h"
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
#include "Cafe/OS/libs/coreinit/coreinit_Alarm.h"
#include "Cafe/OS/libs/coreinit/coreinit_SystemInfo.h"
#include "WindowSystem.h"
#include "input/InputManager.h"
// KPAD
@@ -470,7 +470,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(!WindowSystem::InputConfigWindowHasFocus())
{
const auto btn_repeat = padscore::g_padscore.controller_data[channel].btn_repeat;
controller->KPADRead(*samplingBufs, btn_repeat);

View File

@@ -1,12 +1,12 @@
#include "Cafe/OS/common/OSCommon.h"
#include "Cafe/HW/Espresso/PPCCallback.h"
#include "gui/wxgui.h"
#include "Cafe/OS/libs/vpad/vpad.h"
#include "audio/IAudioAPI.h"
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
#include "config/ActiveSettings.h"
#include "Cafe/OS/libs/coreinit/coreinit_Alarm.h"
#include "input/InputManager.h"
#include "WindowSystem.h"
#ifdef PUBLIC_RELASE
#define vpadbreak()
@@ -263,7 +263,7 @@ namespace vpad
PPCCore_switchToScheduler();
}
if (!g_inputConfigWindowHasFocus)
if (!WindowSystem::InputConfigWindowHasFocus())
{
if (channel <= 1 && vpadDelayEnabled)
{

View File

@@ -1,5 +1,5 @@
#include "CemuLogging.h"
#include "gui/LoggingWindow.h"
#include "Common/precompiled.h"
#include "util/helpers/helpers.h"
#include "config/CemuConfig.h"
#include "config/ActiveSettings.h"
@@ -13,6 +13,64 @@
uint64 s_loggingFlagMask = cemuLog_getFlag(LogType::Force);
class LoggingDispatcher
{
private:
static inline class DefaultLoggingCallbacks : public LoggingCallbacks
{
} s_defaultCallbacks;
LoggingCallbacks* m_loggingCallbacks = &s_defaultCallbacks;
std::shared_mutex m_mutex;
public:
void Log(std::string_view filter, std::string_view message)
{
std::shared_lock lock(m_mutex);
m_loggingCallbacks->Log(filter, message);
}
void Log(std::string_view message)
{
Log("", message);
}
void Log(std::string_view filter, std::wstring_view message)
{
std::shared_lock lock(m_mutex);
m_loggingCallbacks->Log(filter, message);
}
void Log(std::wstring_view message)
{
Log("", message);
}
void setCallbacks(LoggingCallbacks* loggingCallbacks)
{
std::unique_lock lock(m_mutex);
cemu_assert_debug(m_loggingCallbacks == &s_defaultCallbacks);
m_loggingCallbacks = loggingCallbacks;
}
void clearCallbacks()
{
std::unique_lock lock(m_mutex);
cemu_assert_debug(m_loggingCallbacks != &s_defaultCallbacks);
m_loggingCallbacks = &s_defaultCallbacks;
}
} s_loggingDispatcher;
void cemuLog_setCallbacks(LoggingCallbacks* loggingCallbacks)
{
s_loggingDispatcher.setCallbacks(loggingCallbacks);
}
void cemuLog_clearCallbacks()
{
s_loggingDispatcher.clearCallbacks();
}
struct _LogContext
{
std::condition_variable_any log_condition;
@@ -153,9 +211,9 @@ 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())
LoggingWindow::Log(text);
s_loggingDispatcher.Log(text);
else
LoggingWindow::Log(it->second, text);
s_loggingDispatcher.Log(it->second, text);
return true;
}

View File

@@ -133,3 +133,14 @@ uint64 cemuLog_getFlag(LogType type);
fs::path cemuLog_GetLogFilePath();
void cemuLog_createLogFile(bool triggeredByCrash);
[[nodiscard]] std::unique_lock<std::recursive_mutex> cemuLog_acquire(); // used for logging multiple lines at once
class LoggingCallbacks
{
public:
virtual void Log(std::string_view filter, std::string_view message) {};
virtual void Log(std::string_view filter, std::wstring_view message) {};
virtual ~LoggingCallbacks() = default;
};
void cemuLog_setCallbacks(LoggingCallbacks* loggingCallbacks);
void cemuLog_clearCallbacks();

View File

@@ -1,7 +1,6 @@
#include "Cemu/Tools/DownloadManager/DownloadManager.h"
#include "Cafe/Account/Account.h"
#include "gui/CemuApp.h"
#include "util/crypto/md5.h"
#include "Cafe/TitleList/TitleId.h"
#include "Common/FileStream.h"
@@ -10,7 +9,6 @@
#include "config/ActiveSettings.h"
#include "util/ThreadPool/ThreadPool.h"
#include "util/helpers/enum_array.hpp"
#include "gui/MainWindow.h"
#include "Cafe/Filesystem/FST/FST.h"
#include "Cafe/TitleList/TitleList.h"
@@ -20,7 +18,7 @@
#include <curl/curl.h>
#include <pugixml.hpp>
#include "gui/helpers/wxHelpers.h"
#include "WindowSystem.h"
#include "Cemu/napi/napi.h"
#include "util/helpers/Serializer.h"
@@ -333,7 +331,7 @@ bool DownloadManager::syncAccountTickets()
for (auto& tiv : resultTicketIds.tivs)
{
index++;
std::string msg = _("Downloading account ticket").utf8_string();
std::string msg = _tr("Downloading account ticket");
msg.append(fmt::format(" {0}/{1}", index, count));
setStatusMessage(msg, DLMGR_STATUS_CODE::CONNECTING);
// skip if already cached
@@ -386,7 +384,7 @@ bool DownloadManager::syncAccountTickets()
bool DownloadManager::syncSystemTitleTickets()
{
setStatusMessage(_("Downloading system tickets...").utf8_string(), DLMGR_STATUS_CODE::CONNECTING);
setStatusMessage(_tr("Downloading system tickets..."), DLMGR_STATUS_CODE::CONNECTING);
NAPI::AuthInfo authInfo = GetAuthInfo(true);
auto querySystemTitleTicket = [&](uint64 titleId) -> void
{
@@ -436,7 +434,7 @@ bool DownloadManager::syncSystemTitleTickets()
// build list of updates for which either an installed game exists or the base title ticket is cached
bool DownloadManager::syncUpdateTickets()
{
setStatusMessage(_("Retrieving update information...").utf8_string(), DLMGR_STATUS_CODE::CONNECTING);
setStatusMessage(_tr("Retrieving update information..."), DLMGR_STATUS_CODE::CONNECTING);
// download update version list
downloadTitleVersionList();
if (!m_hasTitleVersionList)
@@ -458,7 +456,7 @@ bool DownloadManager::syncUpdateTickets()
if (titleIdParser.GetType() != TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)
continue;
std::string msg = _("Downloading ticket").utf8_string();
std::string msg = _tr("Downloading ticket");
msg.append(fmt::format(" {0}/{1}", updateIndex, numUpdates));
updateIndex++;
setStatusMessage(msg, DLMGR_STATUS_CODE::CONNECTING);
@@ -510,12 +508,12 @@ bool DownloadManager::syncTicketCache()
for (auto& ticketInfo : m_ticketCache)
{
index++;
std::string msg = _("Downloading meta data").utf8_string();
std::string msg = _tr("Downloading meta data");
msg.append(fmt::format(" {0}/{1}", index, count));
setStatusMessage(msg, DLMGR_STATUS_CODE::CONNECTING);
prepareIDBE(ticketInfo.titleId);
}
setStatusMessage(_("Connected. Right click entries in the list to start downloading").utf8_string(), DLMGR_STATUS_CODE::CONNECTED);
setStatusMessage(_tr("Connected. Right click entries in the list to start downloading"), DLMGR_STATUS_CODE::CONNECTED);
return true;
}
@@ -601,7 +599,7 @@ void DownloadManager::_handle_connect()
// reset login state
m_iasToken.serviceAccountId.clear();
m_iasToken.deviceToken.clear();
setStatusMessage(_("Logging in...").utf8_string(), DLMGR_STATUS_CODE::CONNECTING);
setStatusMessage(_tr("Logging in..."), DLMGR_STATUS_CODE::CONNECTING);
// retrieve ECS AccountId + DeviceToken from cache
if (s_nupFileCache)
{
@@ -624,7 +622,7 @@ void DownloadManager::_handle_connect()
cemuLog_log(LogType::Force, "Failed to request IAS token");
cemu_assert_debug(false);
m_connectState.store(CONNECT_STATE::FAILED);
setStatusMessage(_("Login failed. Outdated or incomplete online files?").utf8_string(), DLMGR_STATUS_CODE::FAILED);
setStatusMessage(_tr("Login failed. Outdated or incomplete online files?"), DLMGR_STATUS_CODE::FAILED);
return;
}
}
@@ -632,16 +630,16 @@ void DownloadManager::_handle_connect()
if (!_connect_queryAccountStatusAndServiceURLs())
{
m_connectState.store(CONNECT_STATE::FAILED);
setStatusMessage(_("Failed to query account status").utf8_string(), DLMGR_STATUS_CODE::FAILED);
setStatusMessage(_tr("Failed to query account status"), DLMGR_STATUS_CODE::FAILED);
return;
}
// load ticket cache and sync
setStatusMessage(_("Updating ticket cache").utf8_string(), DLMGR_STATUS_CODE::CONNECTING);
setStatusMessage(_tr("Updating ticket cache"), DLMGR_STATUS_CODE::CONNECTING);
loadTicketCache();
if (!syncTicketCache())
{
m_connectState.store(CONNECT_STATE::FAILED);
setStatusMessage(_("Failed to request tickets").utf8_string(), DLMGR_STATUS_CODE::FAILED);
setStatusMessage(_tr("Failed to request tickets"), DLMGR_STATUS_CODE::FAILED);
return;
}
searchForIncompleteDownloads();
@@ -1006,7 +1004,7 @@ void DownloadManager::asyncPackageDownloadTMD(Package* package)
std::unique_lock<std::recursive_mutex> _l(m_mutex);
if (!tmdResult.isValid)
{
setPackageError(package, _("TMD download failed").utf8_string());
setPackageError(package, _tr("TMD download failed"));
package->state.isDownloadingTMD = false;
return;
}
@@ -1015,7 +1013,7 @@ void DownloadManager::asyncPackageDownloadTMD(Package* package)
NCrypto::TMDParser tmdParser;
if (!tmdParser.parse(tmdResult.tmdData.data(), tmdResult.tmdData.size()))
{
setPackageError(package, _("Invalid TMD").utf8_string());
setPackageError(package, _tr("Invalid TMD"));
package->state.isDownloadingTMD = false;
return;
}
@@ -1124,7 +1122,7 @@ void DownloadManager::asyncPackageDownloadContentFile(Package* package, uint16 i
size_t bytesWritten = callbackInfo->receiveBuffer.size();
if (callbackInfo->fileOutput->writeData(callbackInfo->receiveBuffer.data(), callbackInfo->receiveBuffer.size()) != (uint32)callbackInfo->receiveBuffer.size())
{
callbackInfo->downloadMgr->setPackageError(callbackInfo->package, _("Cannot write file. Disk full?").utf8_string());
callbackInfo->downloadMgr->setPackageError(callbackInfo->package, _tr("Cannot write file. Disk full?"));
return false;
}
callbackInfo->receiveBuffer.clear();
@@ -1145,12 +1143,12 @@ void DownloadManager::asyncPackageDownloadContentFile(Package* package, uint16 i
callbackInfoData.fileOutput = FileStream::createFile2(packageDownloadPath / fmt::format("{:08x}.app", contentId));
if (!callbackInfoData.fileOutput)
{
setPackageError(package, _("Cannot create file").utf8_string());
setPackageError(package, _tr("Cannot create file"));
return;
}
if (!NAPI::CCS_GetContentFile(GetDownloadMgrNetworkService(), titleId, contentId, CallbackInfo::writeCallback, &callbackInfoData))
{
setPackageError(package, _("Download failed").utf8_string());
setPackageError(package, _tr("Download failed"));
delete callbackInfoData.fileOutput;
return;
}
@@ -1405,7 +1403,7 @@ void DownloadManager::asyncPackageInstall(Package* package)
reportPackageStatus(package);
checkPackagesState();
// lastly request game list to be refreshed
MainWindow::RequestGameListRefresh();
WindowSystem::RefreshGameList();
return;
}

View File

@@ -98,6 +98,14 @@ using sint32 = int32_t;
using sint16 = int16_t;
using sint8 = int8_t;
#if _MSC_VER
#ifndef _SSIZE_T_DEFINED
#define _SSIZE_T_DEFINED
#include <basetsd.h>
typedef SSIZE_T ssize_t;
#endif
#endif
// types with explicit big endian order
#include "betype.h"
@@ -111,6 +119,39 @@ using uint8le = uint8_t;
#include "Cemu/Logging/CemuDebugLogging.h"
#include "Cemu/Logging/CemuLogging.h"
// localization
namespace
{
std::function<std::string(std::string_view)> g_translate;
}
inline void SetTranslationCallback(std::function<std::string(std::string_view)> translate)
{
g_translate = translate;
}
#define TR_NOOP(str) str
inline std::string _tr(std::string_view text)
{
if (g_translate)
return g_translate(text);
return std::string{text};
}
template<typename... TArgs>
inline std::string _tr(fmt::format_string<TArgs...> text, TArgs... args)
{
if (g_translate)
{
std::string_view textSV{text.get().data(), text.get().size()};
return fmt::format(fmt::runtime(g_translate(textSV)), std::forward<TArgs>(args)...);
}
return fmt::format(text, std::forward<TArgs>(args)...);
}
// manual endian-swapping
#if _MSC_VER

View File

@@ -7,12 +7,6 @@ add_library(CemuAudio
set_property(TARGET CemuAudio PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# move these to UI folder
target_sources(CemuAudio PRIVATE
audioDebuggerWindow.cpp
audioDebuggerWindow.h
)
if(WIN32)
target_sources(CemuAudio PRIVATE
DirectSoundAPI.cpp
@@ -38,9 +32,9 @@ target_include_directories(CemuAudio PUBLIC "../")
target_link_libraries(CemuAudio PRIVATE
CemuCafe
CemuGui
CemuCommon
CemuConfig
CemuGui
CemuUtil
)
@@ -48,8 +42,3 @@ if(ENABLE_CUBEB)
# PUBLIC because cubeb.h/cubeb.h is included in CubebAPI.h
target_link_libraries(CemuAudio PUBLIC cubeb::cubeb)
endif()
if (ENABLE_WXWIDGETS)
# PUBLIC because wx/wx.h is included in audioDebuggerWindow.h
target_link_libraries(CemuAudio PUBLIC wx::base wx::core)
endif()

View File

@@ -1,7 +1,7 @@
#include "DirectSoundAPI.h"
#include "util/helpers/helpers.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include <wrl/client.h>
#pragma comment(lib, "Dsound.lib")
@@ -17,7 +17,7 @@ DirectSoundAPI::DirectSoundAPI(GUID* guid, sint32 samplerate, sint32 channels, s
if (DirectSoundCreate8(guid, &m_direct_sound, nullptr) != DS_OK)
throw std::runtime_error("can't create directsound device");
if (FAILED(m_direct_sound->SetCooperativeLevel(gui_getWindowInfo().window_main.hwnd, DSSCL_PRIORITY)))
if (FAILED(m_direct_sound->SetCooperativeLevel(static_cast<HWND>(WindowSystem::GetWindowInfo().window_main.surface), DSSCL_PRIORITY)))
throw std::runtime_error("can't set directsound priority");
DSBUFFERDESC bd{};

View File

@@ -60,14 +60,6 @@ bool ActiveSettings::DisplayDRCEnabled()
return g_current_game_profile->StartWithGamepadView();
}
bool ActiveSettings::FullscreenEnabled()
{
if (LaunchSettings::FullscreenEnabled().has_value())
return LaunchSettings::FullscreenEnabled().value();
return GetConfig().fullscreen;
}
CPUMode ActiveSettings::GetCPUMode()
{
auto mode = g_current_game_profile->GetCPUMode().value_or(CPUMode::Auto);

View File

@@ -83,7 +83,6 @@ public:
// general
[[nodiscard]] static bool LoadSharedLibrariesEnabled();
[[nodiscard]] static bool DisplayDRCEnabled();
[[nodiscard]] static bool FullscreenEnabled();
// cpu
[[nodiscard]] static CPUMode GetCPUMode();

View File

@@ -18,14 +18,9 @@ target_include_directories(CemuConfig PUBLIC "../")
target_link_libraries(CemuConfig PRIVATE
CemuCafe
CemuCommon
CemuGui
CemuUtil
Boost::headers
Boost::program_options
pugixml::pugixml
)
if (ENABLE_WXWIDGETS)
# PUBLIC because wx/language.h is included in CemuConfig.h
# Could be made PRIVATE by using 0 instead of wxLANGUAGE_DEFAULT
target_link_libraries(CemuConfig PUBLIC wx::base wx::core)
endif()

View File

@@ -1,23 +1,20 @@
#include "config/CemuConfig.h"
#include "WindowSystem.h"
#include "util/helpers/helpers.h"
#include "config/ActiveSettings.h"
#include <wx/language.h>
#include "ActiveSettings.h"
XMLCemuConfig_t g_config(L"settings.xml");
void CemuConfig::SetMLCPath(fs::path path, bool save)
{
mlc_path.SetValue(_pathToUtf8(path));
if(save)
g_config.Save();
GetConfigHandle().Save();
Account::RefreshAccounts();
}
void CemuConfig::Load(XMLConfigParser& parser)
XMLConfigParser CemuConfig::Load(XMLConfigParser& parser)
{
auto new_parser = parser.get("content");
if (new_parser.valid())
@@ -33,94 +30,11 @@ void CemuConfig::Load(XMLConfigParser& parser)
permanent_storage = parser.get("permanent_storage", permanent_storage);
language = parser.get<sint32>("language", wxLANGUAGE_DEFAULT);
use_discord_presence = parser.get("use_discord_presence", true);
fullscreen_menubar = parser.get("fullscreen_menubar", false);
feral_gamemode = parser.get("feral_gamemode", false);
check_update = parser.get("check_update", check_update);
receive_untested_updates = parser.get("receive_untested_updates", receive_untested_updates);
save_screenshot = parser.get("save_screenshot", save_screenshot);
did_show_vulkan_warning = parser.get("vk_warning", did_show_vulkan_warning);
did_show_graphic_pack_download = parser.get("gp_download", did_show_graphic_pack_download);
did_show_macos_disclaimer = parser.get("macos_disclaimer", did_show_macos_disclaimer);
fullscreen = parser.get("fullscreen", fullscreen);
proxy_server = parser.get("proxy_server", "");
disable_screensaver = parser.get("disable_screensaver", disable_screensaver);
play_boot_sound = parser.get("play_boot_sound", play_boot_sound);
console_language = parser.get("console_language", console_language.GetInitValue());
window_position.x = parser.get("window_position").get("x", -1);
window_position.y = parser.get("window_position").get("y", -1);
window_size.x = parser.get("window_size").get("x", -1);
window_size.y = parser.get("window_size").get("y", -1);
window_maximized = parser.get("window_maximized", false);
pad_open = parser.get("open_pad", false);
pad_position.x = parser.get("pad_position").get("x", -1);
pad_position.y = parser.get("pad_position").get("y", -1);
pad_size.x = parser.get("pad_size").get("x", -1);
pad_size.y = parser.get("pad_size").get("y", -1);
pad_maximized = parser.get("pad_maximized", false);
auto gamelist = parser.get("GameList");
game_list_style = gamelist.get("style", 0);
game_list_column_order = gamelist.get("order", "");
show_icon_column = parser.get("show_icon_column", true);
// return default width if value in config file out of range
auto loadColumnSize = [&gamelist] (const char *name, uint32 defaultWidth)
{
sint64 val = gamelist.get(name, DefaultColumnSize::name);
if (val < 0 || val > (sint64) std::numeric_limits<uint32>::max)
return defaultWidth;
return static_cast<uint32>(val);
};
column_width.name = loadColumnSize("name_width", DefaultColumnSize::name);
column_width.version = loadColumnSize("version_width", DefaultColumnSize::version);
column_width.dlc = loadColumnSize("dlc_width", DefaultColumnSize::dlc);
column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time);
column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started);
column_width.region = loadColumnSize("region_width", DefaultColumnSize::region);
column_width.title_id = loadColumnSize("title_id", DefaultColumnSize::title_id);
recent_launch_files.clear();
auto launch_parser = parser.get("RecentLaunchFiles");
for (auto element = launch_parser.get("Entry"); element.valid(); element = launch_parser.get("Entry", element))
{
const std::string path = element.value("");
if (path.empty())
continue;
try
{
recent_launch_files.emplace_back(path);
}
catch (const std::exception&)
{
cemuLog_log(LogType::Force, "config load error: can't load recently launched game file: {}", path);
}
}
recent_nfc_files.clear();
auto nfc_parser = parser.get("RecentNFCFiles");
for (auto element = nfc_parser.get("Entry"); element.valid(); element = nfc_parser.get("Entry", element))
{
const std::string path = element.value("");
if (path.empty())
continue;
try
{
recent_nfc_files.emplace_back(path);
}
catch (const std::exception&)
{
cemuLog_log(LogType::Force, "config load error: can't load recently launched nfc file: {}", path);
}
}
game_paths.clear();
auto game_path_parser = parser.get("GamePaths");
for (auto element = game_path_parser.get("Entry"); element.valid(); element = game_path_parser.get("Entry", element))
@@ -354,23 +268,16 @@ void CemuConfig::Load(XMLConfigParser& parser)
dsu_client.host = dsuc.get_attribute("host", dsu_client.host);
dsu_client.port = dsuc.get_attribute("port", dsu_client.port);
// hotkeys
auto xml_hotkeys = parser.get("Hotkeys");
hotkeys.modifiers = xml_hotkeys.get("modifiers", sHotkeyCfg{});
hotkeys.exitFullscreen = xml_hotkeys.get("ExitFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}});
hotkeys.toggleFullscreen = xml_hotkeys.get("ToggleFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_F11}});
hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER
hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});
hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{});
// emulatedusbdevices
auto usbdevices = parser.get("EmulatedUsbDevices");
emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal);
emulated_usb_devices.emulate_infinity_base = usbdevices.get("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base);
emulated_usb_devices.emulate_dimensions_toypad = usbdevices.get("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad);
return parser;
}
void CemuConfig::Save(XMLConfigParser& parser)
XMLConfigParser CemuConfig::Save(XMLConfigParser& parser)
{
auto config = parser.set("content");
// general settings
@@ -378,65 +285,12 @@ void CemuConfig::Save(XMLConfigParser& parser)
config.set("advanced_ppc_logging", advanced_ppc_logging.GetValue());
config.set("mlc_path", mlc_path.GetValue().c_str());
config.set<bool>("permanent_storage", permanent_storage);
config.set<sint32>("language", language);
config.set<bool>("use_discord_presence", use_discord_presence);
config.set<bool>("fullscreen_menubar", fullscreen_menubar);
config.set<bool>("feral_gamemode", feral_gamemode);
config.set<bool>("check_update", check_update);
config.set<bool>("receive_untested_updates", receive_untested_updates);
config.set<bool>("save_screenshot", save_screenshot);
config.set<bool>("vk_warning", did_show_vulkan_warning);
config.set<bool>("gp_download", did_show_graphic_pack_download);
config.set<bool>("macos_disclaimer", did_show_macos_disclaimer);
config.set<bool>("fullscreen", fullscreen);
config.set("proxy_server", proxy_server.GetValue().c_str());
config.set<bool>("disable_screensaver", disable_screensaver);
config.set<bool>("play_boot_sound", play_boot_sound);
// config.set("cpu_mode", cpu_mode.GetValue());
//config.set("console_region", console_region.GetValue());
config.set("console_language", console_language.GetValue());
auto wpos = config.set("window_position");
wpos.set<sint32>("x", window_position.x);
wpos.set<sint32>("y", window_position.y);
auto wsize = config.set("window_size");
wsize.set<sint32>("x", window_size.x);
wsize.set<sint32>("y", window_size.y);
config.set<bool>("window_maximized", window_maximized);
config.set<bool>("open_pad", pad_open);
auto ppos = config.set("pad_position");
ppos.set<sint32>("x", pad_position.x);
ppos.set<sint32>("y", pad_position.y);
auto psize = config.set("pad_size");
psize.set<sint32>("x", pad_size.x);
psize.set<sint32>("y", pad_size.y);
config.set<bool>("pad_maximized", pad_maximized);
config.set<bool>("show_icon_column" , show_icon_column);
auto gamelist = config.set("GameList");
gamelist.set("style", game_list_style);
gamelist.set("order", game_list_column_order);
gamelist.set("name_width", column_width.name);
gamelist.set("version_width", column_width.version);
gamelist.set("dlc_width", column_width.dlc);
gamelist.set("game_time_width", column_width.game_time);
gamelist.set("game_started_width", column_width.game_started);
gamelist.set("region_width", column_width.region);
gamelist.set("title_id", column_width.title_id);
auto launch_files_parser = config.set("RecentLaunchFiles");
for (const auto& entry : recent_launch_files)
{
launch_files_parser.set("Entry", entry.c_str());
}
auto nfc_files_parser = config.set("RecentNFCFiles");
for (const auto& entry : recent_nfc_files)
{
nfc_files_parser.set("Entry", entry.c_str());
}
// game paths
auto game_path_parser = config.set("GamePaths");
@@ -566,20 +420,13 @@ void CemuConfig::Save(XMLConfigParser& parser)
dsuc.set_attribute("host", dsu_client.host);
dsuc.set_attribute("port", dsu_client.port);
// hotkeys
auto xml_hotkeys = config.set("Hotkeys");
xml_hotkeys.set("modifiers", hotkeys.modifiers);
xml_hotkeys.set("ExitFullscreen", hotkeys.exitFullscreen);
xml_hotkeys.set("ToggleFullscreen", hotkeys.toggleFullscreen);
xml_hotkeys.set("ToggleFullscreenAlt", hotkeys.toggleFullscreenAlt);
xml_hotkeys.set("TakeScreenshot", hotkeys.takeScreenshot);
xml_hotkeys.set("ToggleFastForward", hotkeys.toggleFastForward);
// emulated usb devices
auto usbdevices = config.set("EmulatedUsbDevices");
usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue());
usbdevices.set("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base.GetValue());
usbdevices.set("EmulateDimensionsToypad", emulated_usb_devices.emulate_dimensions_toypad.GetValue());
return config;
}
GameEntry* CemuConfig::GetGameEntryByTitleId(uint64 titleId)
@@ -646,22 +493,6 @@ void CemuConfig::SetGameListCustomName(uint64 titleId, std::string customName)
gameEntry->custom_name = std::move(customName);
}
void CemuConfig::AddRecentlyLaunchedFile(std::string_view file)
{
recent_launch_files.insert(recent_launch_files.begin(), std::string(file));
RemoveDuplicatesKeepOrder(recent_launch_files);
while(recent_launch_files.size() > kMaxRecentEntries)
recent_launch_files.pop_back();
}
void CemuConfig::AddRecentNfcFile(std::string_view file)
{
recent_nfc_files.insert(recent_nfc_files.begin(), std::string(file));
RemoveDuplicatesKeepOrder(recent_nfc_files);
while (recent_nfc_files.size() > kMaxRecentEntries)
recent_nfc_files.pop_back();
}
NetworkService CemuConfig::GetAccountNetworkService(uint32 persistentId)
{
auto it = account.service_select.find(persistentId);

View File

@@ -5,9 +5,6 @@
#include "util/math/vector2.h"
#include "Cafe/Account/Account.h"
#include <wx/language.h>
#include <wx/intl.h>
enum class NetworkService;
struct GameEntry
@@ -191,50 +188,6 @@ enum class CrashDump
ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);
#endif
typedef union
{
struct
{
uint16 key : 13; // enough bits for all keycodes
uint16 alt : 1;
uint16 ctrl : 1;
uint16 shift : 1;
};
uint16 raw;
} uKeyboardHotkey;
typedef sint16 ControllerHotkey_t;
struct sHotkeyCfg
{
static constexpr uint8 keyboardNone{WXK_NONE};
static constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0
uKeyboardHotkey keyboard{keyboardNone};
ControllerHotkey_t controller{controllerNone};
/* for defaults */
sHotkeyCfg(const uKeyboardHotkey& keyboard = {WXK_NONE}, const ControllerHotkey_t& controller = {-1}) :
keyboard(keyboard), controller(controller) {};
/* for reading from xml */
sHotkeyCfg(const char* xml_values)
{
std::istringstream iss(xml_values);
iss >> keyboard.raw >> controller;
}
};
template <>
struct fmt::formatter<sHotkeyCfg> : formatter<string_view>
{
template <typename FormatContext>
auto format(const sHotkeyCfg c, FormatContext &ctx) const {
std::string xml_values = fmt::format("{} {}", c.keyboard.raw, c.controller);
return formatter<string_view>::format(xml_values, ctx);
}
};
template <>
struct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {
template <typename FormatContext>
@@ -305,15 +258,15 @@ struct fmt::formatter<CafeConsoleRegion> : formatter<string_view> {
string_view name;
switch (v)
{
case CafeConsoleRegion::JPN: name = wxTRANSLATE("Japan"); break;
case CafeConsoleRegion::USA: name = wxTRANSLATE("USA"); break;
case CafeConsoleRegion::EUR: name = wxTRANSLATE("Europe"); break;
case CafeConsoleRegion::AUS_DEPR: name = wxTRANSLATE("Australia"); break;
case CafeConsoleRegion::CHN: name = wxTRANSLATE("China"); break;
case CafeConsoleRegion::KOR: name = wxTRANSLATE("Korea"); break;
case CafeConsoleRegion::TWN: name = wxTRANSLATE("Taiwan"); break;
case CafeConsoleRegion::Auto: name = wxTRANSLATE("Auto"); break;
default: name = wxTRANSLATE("many"); break;
case CafeConsoleRegion::JPN: name = TR_NOOP("Japan"); break;
case CafeConsoleRegion::USA: name = TR_NOOP("USA"); break;
case CafeConsoleRegion::EUR: name = TR_NOOP("Europe"); break;
case CafeConsoleRegion::AUS_DEPR: name = TR_NOOP("Australia"); break;
case CafeConsoleRegion::CHN: name = TR_NOOP("China"); break;
case CafeConsoleRegion::KOR: name = TR_NOOP("Korea"); break;
case CafeConsoleRegion::TWN: name = TR_NOOP("Taiwan"); break;
case CafeConsoleRegion::Auto: name = TR_NOOP("Auto"); break;
default: name = TR_NOOP("many"); break;
}
return formatter<string_view>::format(name, ctx);
@@ -379,17 +332,6 @@ struct fmt::formatter<CrashDump> : formatter<string_view> {
};
#endif
namespace DefaultColumnSize {
enum : uint32 {
name = 500u,
version = 60u,
dlc = 50u,
game_time = 140u,
game_started = 160u,
region = 80u,
title_id = 160u
};
};
struct CemuConfig
{
@@ -408,12 +350,7 @@ struct CemuConfig
ConfigValue<bool> permanent_storage{ true };
ConfigValue<sint32> language{ wxLANGUAGE_DEFAULT };
ConfigValue<bool> use_discord_presence{ true };
ConfigValue<std::string> mlc_path{};
ConfigValue<bool> fullscreen_menubar{ false };
ConfigValue<bool> fullscreen{ false };
ConfigValue<bool> feral_gamemode{false};
ConfigValue<std::string> proxy_server{};
// temporary workaround because feature crashes on macOS
@@ -444,43 +381,6 @@ struct CemuConfig
ConfigValueBounds<CPUMode> cpu_mode{ CPUMode::Auto };
ConfigValueBounds<CafeConsoleLanguage> console_language{ CafeConsoleLanguage::EN };
// max 15 entries
static constexpr size_t kMaxRecentEntries = 15;
std::vector<std::string> recent_launch_files;
std::vector<std::string> recent_nfc_files;
Vector2i window_position{-1,-1};
Vector2i window_size{ -1,-1 };
ConfigValue<bool> window_maximized;
ConfigValue<bool> pad_open;
Vector2i pad_position{ -1,-1 };
Vector2i pad_size{ -1,-1 };
ConfigValue<bool> pad_maximized;
ConfigValue<bool> check_update{true};
ConfigValue<bool> receive_untested_updates{false};
ConfigValue<bool> save_screenshot{true};
ConfigValue<bool> did_show_vulkan_warning{false};
ConfigValue<bool> did_show_graphic_pack_download{false}; // no longer used but we keep the config value around in case people downgrade Cemu. Despite the name this was used for the Getting Started dialog
ConfigValue<bool> did_show_macos_disclaimer{false};
ConfigValue<bool> show_icon_column{ true };
int game_list_style = 0;
std::string game_list_column_order;
struct
{
uint32 name = DefaultColumnSize::name;
uint32 version = DefaultColumnSize::version;
uint32 dlc = DefaultColumnSize::dlc;
uint32 game_time = DefaultColumnSize::game_time;
uint32 game_started = DefaultColumnSize::game_started;
uint32 region = DefaultColumnSize::region;
uint32 title_id = 0;
} column_width{};
// graphics
ConfigValue<GraphicAPI> graphic_api{ kVulkan };
std::array<uint8, 16> graphic_device_uuid;
@@ -543,26 +443,12 @@ struct CemuConfig
ConfigValue<uint16> port{ 26760 };
}dsu_client{};
// hotkeys
struct
{
sHotkeyCfg modifiers;
sHotkeyCfg toggleFullscreen;
sHotkeyCfg toggleFullscreenAlt;
sHotkeyCfg exitFullscreen;
sHotkeyCfg takeScreenshot;
sHotkeyCfg toggleFastForward;
} hotkeys{};
// debug
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
ConfigValue<uint16> gdb_port{ 1337 };
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);
void AddRecentlyLaunchedFile(std::string_view file);
void AddRecentNfcFile(std::string_view file);
XMLConfigParser Load(XMLConfigParser& parser);
XMLConfigParser Save(XMLConfigParser& parser);
bool IsGameListFavorite(uint64 titleId);
void SetGameListFavorite(uint64 titleId, bool isFavorite);
@@ -598,8 +484,15 @@ struct CemuConfig
GameEntry* CreateGameEntry(uint64 titleId);
};
typedef XMLDataConfig<CemuConfig, &CemuConfig::Load, &CemuConfig::Save> XMLCemuConfig_t;
extern XMLCemuConfig_t g_config;
inline CemuConfig& GetConfig() { return g_config.data(); }
typedef XMLDataConfig<CemuConfig> XMLCemuConfig_t;
inline XMLCemuConfig_t& GetConfigHandle()
{
static XMLCemuConfig_t config;
return config;
}
inline CemuConfig& GetConfig()
{
return GetConfigHandle().data();
}

View File

@@ -6,7 +6,6 @@
#include "Cafe/OS/libs/coreinit/coreinit.h"
#include "boost/program_options.hpp"
#include <wx/msgdlg.h>
#include "config/ActiveSettings.h"
#include "config/NetworkSettings.h"
@@ -226,11 +225,7 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
std::string errorMsg;
errorMsg.append("Error while trying to parse command line parameter:\n");
errorMsg.append(ex.what());
#if BOOST_OS_WINDOWS
wxMessageBox(errorMsg, "Parameter error", wxICON_ERROR);
#else
std::cout << errorMsg << std::endl;
#endif
return false;
}

View File

@@ -71,7 +71,7 @@ struct PretendoURLs {
inline static std::string OLVURL = "https://discovery.olv.pretendo.cc/v1/endpoint";
};
typedef XMLDataConfig<NetworkConfig, &NetworkConfig::Load, &NetworkConfig::Save> XMLNetworkConfig_t;
typedef XMLDataConfig<NetworkConfig> XMLNetworkConfig_t;
extern XMLNetworkConfig_t n_config;
inline NetworkConfig& GetNetworkConfig() { return n_config.data();};

View File

@@ -320,7 +320,15 @@ private:
bool m_is_root;
};
template <typename T, void(T::*L)(XMLConfigParser&) = nullptr, void(T::*S)(XMLConfigParser&) = nullptr>
using ChildXMLConfigParser = std::pair<std::function<void(XMLConfigParser&)>, std::function<void(XMLConfigParser&)>>;
template<typename T>
concept XMLConfigurable = requires(T t, XMLConfigParser& configParser) {
{ t.Save(configParser) } -> std::same_as<XMLConfigParser>;
{ t.Load(configParser) } -> std::same_as<XMLConfigParser>;
};
template <XMLConfigurable T>
class XMLConfig
{
public:
@@ -339,9 +347,6 @@ public:
bool Load()
{
if (L == nullptr)
return false;
if (m_filename.empty())
return false;
@@ -350,8 +355,6 @@ public:
bool Load(const std::wstring& filename)
{
if (L == nullptr)
return false;
FileStream* fs = FileStream::openFile(filename.c_str());
if (!fs)
{
@@ -370,19 +373,23 @@ public:
{
cemuLog_logDebug(LogType::Force, "XMLConfig::Load > LoadFile {}", error);
}
if (success)
if (!success)
{
auto parser = XMLConfigParser(&doc);
(m_instance.*L)(parser);
return false;
}
auto parser = XMLConfigParser(&doc);
auto parentParser = m_instance.Load(parser);
for (auto [save, load] : m_childConfigParsers)
load(parentParser);
return true;
}
bool Save()
{
if (S == nullptr)
return false;
if (m_filename.empty())
return false;
@@ -391,9 +398,6 @@ public:
bool Save(const std::wstring& filename)
{
if (S == nullptr)
return false;
std::wstring tmp_name = fmt::format(L"{}_{}.tmp", filename,rand() % 1000);
std::error_code err;
fs::create_directories(fs::path(filename).parent_path(), err);
@@ -420,7 +424,10 @@ public:
doc.InsertFirstChild(declaration);
auto parser = XMLConfigParser(&doc);
(m_instance.*S)(parser);
auto parentParser = m_instance.Save(parser);
for (auto [save, load] : m_childConfigParsers)
save(parentParser);
const tinyxml2::XMLError error = doc.SaveFile(file);
const bool success = error == tinyxml2::XML_SUCCESS;
@@ -445,24 +452,96 @@ public:
std::unique_lock<std::mutex> Lock() { return std::unique_lock(m_mutex); }
private:
void AddChildConfig(ChildXMLConfigParser childConfigParser)
{
m_childConfigParsers.push_back(childConfigParser);
}
private:
std::vector<ChildXMLConfigParser> m_childConfigParsers;
T& m_instance;
std::wstring m_filename;
std::mutex m_mutex;
};
template <typename T, void(T::*L)(XMLConfigParser&), void(T::*S)(XMLConfigParser&)>
class XMLDataConfig : public XMLConfig<T, L, S>
template<typename T>
concept XMLConfigProvider = requires(T t, ChildXMLConfigParser& configParser) {
{ t().Save() } -> std::same_as<bool>;
{ t().Load() } -> std::same_as<bool>;
{ t().Lock() } -> std::same_as<std::unique_lock<std::mutex>>;
{ t().AddChildConfig(configParser) } -> std::same_as<void>;
};
template<typename T, void (T::*L)(XMLConfigParser&), void (T::*S)(XMLConfigParser&)>
class XMLChildConfig
{
public:
XMLChildConfig(XMLConfigProvider auto getParentConfig)
{
m_parentConfig = {
.lock = [getParentConfig]() { return getParentConfig().Lock(); },
.save = [getParentConfig]() { return getParentConfig().Load(); },
.load = [getParentConfig]() { return getParentConfig().Save(); },
};
auto configParser = std::make_pair(
[this](XMLConfigParser& parser) {
(m_data.*S)(parser);
},
[this](XMLConfigParser& parser) {
(m_data.*L)(parser);
});
getParentConfig().AddChildConfig(configParser);
}
bool Save()
{
return m_parentConfig.save();
}
bool Load()
{
return m_parentConfig.load();
}
T& Data()
{
return m_data;
}
std::unique_lock<std::mutex> Lock()
{
return m_parentConfig.lock();
}
virtual ~XMLChildConfig() = default;
private:
T m_data;
struct
{
std::function<std::unique_lock<std::mutex>()> lock;
std::function<bool()> save;
std::function<bool()> load;
} m_parentConfig;
};
template<typename T>
struct XMLDataConfig {};
template <XMLConfigurable T>
class XMLDataConfig<T> : public XMLConfig<T>
{
public:
XMLDataConfig()
: XMLConfig<T, L, S>::XMLConfig(m_data), m_data() {}
: XMLConfig<T>::XMLConfig(m_data), m_data() {}
XMLDataConfig(std::wstring_view filename)
: XMLConfig<T, L, S>::XMLConfig(m_data, filename), m_data() {}
: XMLConfig<T>::XMLConfig(m_data, filename), m_data() {}
XMLDataConfig(std::wstring_view filename, T init_data)
: XMLConfig<T, L, S>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}
: XMLConfig<T>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}
XMLDataConfig(const XMLDataConfig& o) = delete;
@@ -471,3 +550,51 @@ public:
private:
T m_data;
};
template<typename T>
concept XMLStandaloneConfigurable = requires(T t, XMLConfigParser& configParser) {
{ t.Save(configParser) } -> std::same_as<void>;
{ t.Load(configParser) } -> std::same_as<void>;
};
template<XMLStandaloneConfigurable T>
struct XMLConfigWrapper
{
XMLConfigParser Save(XMLConfigParser& configParser)
{
data.Save(configParser);
return configParser;
}
XMLConfigParser Load(XMLConfigParser& configParser)
{
data.Load(configParser);
return configParser;
}
T data;
};
template<XMLStandaloneConfigurable T>
class XMLDataConfig<T> : public XMLConfig<XMLConfigWrapper<T>>
{
public:
XMLDataConfig()
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper), m_configWrapper() {}
XMLDataConfig(std::wstring_view filename)
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper() {}
XMLDataConfig(std::wstring_view filename, T init_data)
: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper{.data = std::move(init_data)} {}
XMLDataConfig(const XMLDataConfig& o) = delete;
T& data()
{
return m_configWrapper.data;
}
private:
XMLConfigWrapper<T> m_configWrapper;
};

View File

@@ -1,186 +1,7 @@
add_library(CemuGui
canvas/IRenderCanvas.h
canvas/OpenGLCanvas.cpp
canvas/OpenGLCanvas.h
canvas/VulkanCanvas.cpp
canvas/VulkanCanvas.h
CemuApp.cpp
CemuApp.h
CemuUpdateWindow.cpp
CemuUpdateWindow.h
ChecksumTool.cpp
ChecksumTool.h
components/TextList.cpp
components/TextList.h
components/wxDownloadManagerList.cpp
components/wxDownloadManagerList.h
components/wxGameList.cpp
components/wxGameList.h
components/wxInputDraw.cpp
components/wxInputDraw.h
components/wxLogCtrl.cpp
components/wxLogCtrl.h
components/wxTitleManagerList.cpp
components/wxTitleManagerList.h
debugger/BreakpointWindow.cpp
debugger/BreakpointWindow.h
debugger/DebuggerWindow2.cpp
debugger/DebuggerWindow2.h
debugger/DisasmCtrl.cpp
debugger/DisasmCtrl.h
debugger/DumpCtrl.cpp
debugger/DumpCtrl.h
debugger/DumpWindow.cpp
debugger/DumpWindow.h
debugger/ModuleWindow.cpp
debugger/ModuleWindow.h
debugger/RegisterCtrl.cpp
debugger/RegisterCtrl.h
debugger/RegisterWindow.cpp
debugger/RegisterWindow.h
debugger/SymbolCtrl.cpp
debugger/SymbolCtrl.h
debugger/SymbolWindow.cpp
debugger/SymbolWindow.h
dialogs/CreateAccount/wxCreateAccountDialog.cpp
dialogs/CreateAccount/wxCreateAccountDialog.h
dialogs/SaveImport/SaveImportWindow.cpp
dialogs/SaveImport/SaveImportWindow.h
dialogs/SaveImport/SaveTransfer.cpp
dialogs/SaveImport/SaveTransfer.h
DownloadGraphicPacksWindow.cpp
DownloadGraphicPacksWindow.h
GameProfileWindow.cpp
GameProfileWindow.h
GameUpdateWindow.cpp
GameUpdateWindow.h
GeneralSettings2.cpp
GeneralSettings2.h
GettingStartedDialog.cpp
GettingStartedDialog.h
GraphicPacksWindow2.cpp
GraphicPacksWindow2.h
guiWrapper.cpp
guiWrapper.h
helpers/wxControlObject.h
helpers/wxCustomData.h
helpers/wxCustomEvents.cpp
helpers/wxCustomEvents.h
helpers/wxHelpers.cpp
helpers/wxHelpers.h
helpers/wxLogEvent.h
helpers/wxWayland.cpp
helpers/wxWayland.h
input/HotkeySettings.cpp
input/HotkeySettings.h
input/InputAPIAddWindow.cpp
input/InputAPIAddWindow.h
input/InputSettings2.cpp
input/InputSettings2.h
input/PairingDialog.cpp
input/PairingDialog.h
input/panels/ClassicControllerInputPanel.cpp
input/panels/ClassicControllerInputPanel.h
input/panels/InputPanel.cpp
input/panels/InputPanel.h
input/panels/ProControllerInputPanel.cpp
input/panels/ProControllerInputPanel.h
input/panels/VPADInputPanel.cpp
input/panels/VPADInputPanel.h
input/panels/WiimoteInputPanel.cpp
input/panels/WiimoteInputPanel.h
input/settings/DefaultControllerSettings.cpp
input/settings/DefaultControllerSettings.h
input/settings/WiimoteControllerSettings.cpp
input/settings/WiimoteControllerSettings.h
LoggingWindow.cpp
LoggingWindow.h
MainWindow.cpp
MainWindow.h
MemorySearcherTool.cpp
MemorySearcherTool.h
PadViewFrame.cpp
PadViewFrame.h
TitleManager.cpp
TitleManager.h
EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp
EmulatedUSBDevices/EmulatedUSBDeviceFrame.h
windows/PPCThreadsViewer
windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp
windows/PPCThreadsViewer/DebugPPCThreadsWindow.h
windows/TextureRelationViewer
windows/TextureRelationViewer/TextureRelationWindow.cpp
windows/TextureRelationViewer/TextureRelationWindow.h
wxcomponents/checked2.xpm
wxcomponents/checked_dis.xpm
wxcomponents/checked_d.xpm
wxcomponents/checked_ld.xpm
wxcomponents/checkedlistctrl.cpp
wxcomponents/checkedlistctrl.h
wxcomponents/checked_mo.xpm
wxcomponents/checked.xpm
wxcomponents/checktree.cpp
wxcomponents/checktree.h
wxcomponents/unchecked2.xpm
wxcomponents/unchecked_dis.xpm
wxcomponents/unchecked_d.xpm
wxcomponents/unchecked_ld.xpm
wxcomponents/unchecked_mo.xpm
wxcomponents/unchecked.xpm
wxgui.h
wxHelper.h
)
add_library(CemuGui INTERFACE)
target_include_directories(CemuGui INTERFACE "interface")
set_property(TARGET CemuGui PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
target_include_directories(CemuGui PUBLIC "../")
# PUBLIC because rapidjson/document.h is included in ChecksumTool.h
target_include_directories(CemuGui PUBLIC ${RAPIDJSON_INCLUDE_DIRS})
target_link_libraries(CemuGui PRIVATE
CemuAudio
CemuCafe
CemuCommon
CemuComponents
CemuConfig
CemuInput
CemuResource
CemuUtil
Boost::headers
CURL::libcurl
libzip::zip
OpenSSL::Crypto
pugixml::pugixml
ZArchive::zarchive
)
if(ENABLE_WXWIDGETS AND UNIX AND NOT APPLE)
# PUBLIC because gdk/gdkkeysyms.h is included in guiWrapper.h
target_link_libraries(CemuGui PUBLIC GTK3::gtk)
if (ENABLE_WAYLAND)
target_link_libraries(CemuGui PRIVATE Wayland::Client CemuWaylandProtocols)
endif()
if(ENABLE_WXWIDGETS)
add_subdirectory(wxgui)
target_link_libraries(CemuGui INTERFACE CemuWxGui)
endif()
if(ENABLE_CUBEB)
target_link_libraries(CemuGui PRIVATE cubeb::cubeb)
endif()
if(UNIX AND NOT APPLE)
if(ENABLE_FERAL_GAMEMODE)
target_link_libraries(CemuGui PRIVATE gamemode)
endif()
endif()
if (ENABLE_WXWIDGETS)
# PUBLIC because wx/app.h is included in CemuApp.h
target_link_libraries(CemuGui PUBLIC wx::base wx::core wx::gl wx::propgrid wx::xrc)
endif()
if(WIN32)
target_link_libraries(CemuGui PRIVATE bthprops)
endif()
if(ALLOW_PORTABLE)
target_compile_definitions(CemuGui PRIVATE CEMU_ALLOW_PORTABLE)
endif ()

View File

@@ -1,44 +0,0 @@
#pragma once
#include <wx/frame.h>
#include <wx/listbox.h>
#include <wx/combobox.h>
#include "gui/components/wxLogCtrl.h"
class wxLogEvent;
class LoggingWindow : public wxFrame
{
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); }
template<typename ...TArgs>
static void Log(std::string_view filter, std::string_view format, TArgs&&... args)
{
Log(filter, fmt::format(format, std::forward<TArgs>(args)...));
}
template<typename ...TArgs>
static void Log(std::string_view filter, std::wstring_view format, TArgs&&... args)
{
Log(filter, fmt::format(format, std::forward<TArgs>(args)...));
}
private:
void OnLogMessage(wxLogEvent& event);
void OnFilterChange(wxCommandEvent& event);
void OnFilterMessageChange(wxCommandEvent& event);
wxComboBox* m_filter;
wxLogCtrl* m_log_list;
wxCheckBox* m_filter_message;
inline static std::shared_mutex s_mutex;
inline static LoggingWindow* s_instance = nullptr;
};

View File

@@ -1,8 +0,0 @@
#pragma once
#include <wx/window.h>
#include "gui/canvas/IRenderCanvas.h"
wxWindow* GLCanvas_Create(wxWindow* parent, const wxSize& size, bool is_main_window);
bool GLCanvas_MakeCurrent(bool padView);
void GLCanvas_SwapBuffers(bool swapTV, bool swapDRC);
bool GLCanvas_HasPadViewOpen();

View File

@@ -1,332 +0,0 @@
#if BOOST_OS_LINUX
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkwindow.h>
#include <gdk/gdkx.h>
#ifdef HAS_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#endif
#include "gui/wxgui.h"
#include "gui/guiWrapper.h"
#include "gui/CemuApp.h"
#include "gui/MainWindow.h"
#include "gui/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 "wxHelper.h"
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("cemu");
#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)
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("{} - FPS: {:.02f}", _("GamePad View").utf8_string(), 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;
}
#if BOOST_OS_LINUX
std::string gui_gtkRawKeyCodeToString(uint32 keyCode)
{
return gdk_keyval_name(keyCode);
}
#endif
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)
{
return gui_isKeyDown((std::underlying_type_t<PlatformKeyCodes>)key);
}
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);
}
}

View File

@@ -1,161 +0,0 @@
#pragma once
#if BOOST_OS_LINUX
#include "xcb/xproto.h"
#include <gdk/gdkkeysyms.h>
#endif
#if BOOST_OS_MACOS
#include <Carbon/Carbon.h>
#endif
struct WindowHandleInfo
{
#if BOOST_OS_WINDOWS
std::atomic<HWND> hwnd;
#elif BOOST_OS_LINUX
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
{
#if BOOST_OS_WINDOWS
LCONTROL = VK_LCONTROL,
RCONTROL = VK_RCONTROL,
TAB = VK_TAB,
ESCAPE = VK_ESCAPE,
#elif BOOST_OS_LINUX
LCONTROL = GDK_KEY_Control_L,
RCONTROL = GDK_KEY_Control_R,
TAB = GDK_KEY_Tab,
ESCAPE = GDK_KEY_Escape,
#elif BOOST_OS_MACOS
LCONTROL = kVK_Control,
RCONTROL = kVK_RightControl,
TAB = kVK_Tab,
ESCAPE = kVK_Escape,
#else
LCONTROL = 0,
RCONTROL = 0,
TAB = 0,
ESCAPE = 0,
#endif
};
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<double> 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<double> 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<std::mutex> lock(keycode_mutex);
m_keydown[keycode] = state;
}
bool get_keystate(uint32 keycode)
{
const std::lock_guard<std::mutex> 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<std::mutex> lock(keycode_mutex);
std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair<const uint32, bool>& el){ el.second = false; });
}
template <typename fn>
void iter_keystates(fn f)
{
const std::lock_guard<std::mutex> 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<uint32, bool> m_keydown;
};
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);
#if BOOST_OS_LINUX
std::string gui_gtkRawKeyCodeToString(uint32 keyCode);
#endif
/*
* 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);

View File

@@ -1,66 +0,0 @@
#include "gui/helpers/wxHelpers.h"
#include <wx/wupdlock.h>
#include <wx/stattext.h>
#include <wx/slider.h>
#include <wx/dirdlg.h>
#include "gui/helpers/wxControlObject.h"
void wxAutosizeColumn(wxListCtrlBase* ctrl, int col)
{
ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER);
int wh = ctrl->GetColumnWidth(col);
ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE);
int wc = ctrl->GetColumnWidth(col);
if (wh > wc)
ctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER);
}
void wxAutosizeColumns(wxListCtrlBase* ctrl, int col_start, int col_end)
{
wxWindowUpdateLocker lock(ctrl);
for (int i = col_start; i <= col_end; ++i)
wxAutosizeColumn(ctrl, i);
}
void update_slider_text(wxCommandEvent& event, const wxFormatString& format /*= "%d%%"*/)
{
const auto slider = dynamic_cast<wxSlider*>(event.GetEventObject());
wxASSERT(slider);
auto slider_text = dynamic_cast<wxControlObject*>(event.GetEventUserData())->GetControl<wxStaticText>();
wxASSERT(slider_text);
slider_text->SetLabel(wxString::Format(format, slider->GetValue()));
}
uint32 fix_raw_keycode(uint32 keycode, uint32 raw_flags)
{
#if BOOST_OS_WINDOWS
const auto flags = (HIWORD(raw_flags) & 0xFFF);
if(keycode == VK_SHIFT)
{
if(flags == 0x2A)
return 160;
else if (flags == 0x36)
return 161;
}
else if (keycode == VK_CONTROL)
{
if (flags == 0x1d)
return 162;
else if (flags == 0x11d)
return 163;
}
else if (keycode == VK_MENU)
{
if ((flags & 0xFF) == 0x38)
return 164;
else if ((flags & 0xFF) == 0x38)
return 165;
}
#endif
return keycode;
}

View File

@@ -0,0 +1,126 @@
#pragma once
#include "config/CemuConfig.h"
#include "input/api/ControllerState.h"
namespace WindowSystem
{
struct WindowHandleInfo
{
enum class Backend
{
X11,
Wayland,
Cocoa,
Windows,
} backend;
void* display = nullptr;
void* surface = nullptr;
};
enum struct PlatformKeyCodes : uint32
{
LCONTROL,
RCONTROL,
TAB,
ESCAPE,
};
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<double> 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<double> 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 is_fullscreen;
void set_keystate(uint32 keycode, bool state)
{
const std::lock_guard<std::mutex> lock(keycode_mutex);
m_keydown[keycode] = state;
}
bool get_keystate(uint32 keycode)
{
const std::lock_guard<std::mutex> 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<std::mutex> lock(keycode_mutex);
std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair<const uint32, bool>& el) { el.second = false; });
}
template<typename fn>
void iter_keystates(fn f)
{
const std::lock_guard<std::mutex> 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;
std::unordered_map<uint32, bool> m_keydown;
};
enum class ErrorCategory
{
KEYS_TXT_CREATION = 0,
GRAPHIC_PACKS = 1,
};
void ShowErrorDialog(std::string_view message, std::string_view title, std::optional<ErrorCategory> errorCategory = {});
inline void ShowErrorDialog(std::string_view message, std::optional<ErrorCategory> errorCategory = {})
{
ShowErrorDialog(message, "", errorCategory);
}
void Create();
WindowInfo& GetWindowInfo();
void UpdateWindowTitles(bool isIdle, bool isLoading, double fps);
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);
std::string GetKeyCodeName(uint32 key);
bool InputConfigWindowHasFocus();
void NotifyGameLoaded();
void NotifyGameExited();
void RefreshGameList();
bool IsFullScreen();
void CaptureInput(const ControllerState& currentState, const ControllerState& lastState);
}; // namespace WindowSystem

View File

@@ -1,5 +1,5 @@
#include "gui/wxgui.h"
#include "audioDebuggerWindow.h"
#include "wxgui.h"
#include "AudioDebuggerWindow.h"
#include "Cafe/OS/libs/snd_core/ax.h"
#include "Cafe/OS/libs/snd_core/ax_internal.h"

View File

@@ -0,0 +1,189 @@
add_library(CemuWxGui
canvas/IRenderCanvas.h
canvas/OpenGLCanvas.cpp
canvas/OpenGLCanvas.h
canvas/VulkanCanvas.cpp
canvas/VulkanCanvas.h
CemuApp.cpp
CemuApp.h
CemuUpdateWindow.cpp
CemuUpdateWindow.h
ChecksumTool.cpp
ChecksumTool.h
components/TextList.cpp
components/TextList.h
components/wxDownloadManagerList.cpp
components/wxDownloadManagerList.h
components/wxGameList.cpp
components/wxGameList.h
components/wxInputDraw.cpp
components/wxInputDraw.h
components/wxLogCtrl.cpp
components/wxLogCtrl.h
components/wxTitleManagerList.cpp
components/wxTitleManagerList.h
debugger/BreakpointWindow.cpp
debugger/BreakpointWindow.h
debugger/DebuggerWindow2.cpp
debugger/DebuggerWindow2.h
debugger/DisasmCtrl.cpp
debugger/DisasmCtrl.h
debugger/DumpCtrl.cpp
debugger/DumpCtrl.h
debugger/DumpWindow.cpp
debugger/DumpWindow.h
debugger/ModuleWindow.cpp
debugger/ModuleWindow.h
debugger/RegisterCtrl.cpp
debugger/RegisterCtrl.h
debugger/RegisterWindow.cpp
debugger/RegisterWindow.h
debugger/SymbolCtrl.cpp
debugger/SymbolCtrl.h
debugger/SymbolWindow.cpp
debugger/SymbolWindow.h
dialogs/CreateAccount/wxCreateAccountDialog.cpp
dialogs/CreateAccount/wxCreateAccountDialog.h
dialogs/SaveImport/SaveImportWindow.cpp
dialogs/SaveImport/SaveImportWindow.h
dialogs/SaveImport/SaveTransfer.cpp
dialogs/SaveImport/SaveTransfer.h
AudioDebuggerWindow.cpp
AudioDebuggerWindow.h
DownloadGraphicPacksWindow.cpp
DownloadGraphicPacksWindow.h
GameProfileWindow.cpp
GameProfileWindow.h
GameUpdateWindow.cpp
GameUpdateWindow.h
GeneralSettings2.cpp
GeneralSettings2.h
GettingStartedDialog.cpp
GettingStartedDialog.h
GraphicPacksWindow2.cpp
GraphicPacksWindow2.h
wxWindowSystem.cpp
helpers/wxControlObject.h
helpers/wxCustomData.h
helpers/wxCustomEvents.cpp
helpers/wxCustomEvents.h
helpers/wxHelpers.cpp
helpers/wxHelpers.h
helpers/wxLogEvent.h
helpers/wxWayland.cpp
helpers/wxWayland.h
input/HotkeySettings.cpp
input/HotkeySettings.h
input/InputAPIAddWindow.cpp
input/InputAPIAddWindow.h
input/InputSettings2.cpp
input/InputSettings2.h
input/PairingDialog.cpp
input/PairingDialog.h
input/panels/ClassicControllerInputPanel.cpp
input/panels/ClassicControllerInputPanel.h
input/panels/InputPanel.cpp
input/panels/InputPanel.h
input/panels/ProControllerInputPanel.cpp
input/panels/ProControllerInputPanel.h
input/panels/VPADInputPanel.cpp
input/panels/VPADInputPanel.h
input/panels/WiimoteInputPanel.cpp
input/panels/WiimoteInputPanel.h
input/settings/DefaultControllerSettings.cpp
input/settings/DefaultControllerSettings.h
input/settings/WiimoteControllerSettings.cpp
input/settings/WiimoteControllerSettings.h
LoggingWindow.cpp
LoggingWindow.h
MainWindow.cpp
MainWindow.h
MemorySearcherTool.cpp
MemorySearcherTool.h
PadViewFrame.cpp
PadViewFrame.h
TitleManager.cpp
TitleManager.h
wxCemuConfig.cpp
wxCemuConfig.h
EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp
EmulatedUSBDevices/EmulatedUSBDeviceFrame.h
windows/PPCThreadsViewer
windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp
windows/PPCThreadsViewer/DebugPPCThreadsWindow.h
windows/TextureRelationViewer
windows/TextureRelationViewer/TextureRelationWindow.cpp
windows/TextureRelationViewer/TextureRelationWindow.h
wxcomponents/checked2.xpm
wxcomponents/checked_dis.xpm
wxcomponents/checked_d.xpm
wxcomponents/checked_ld.xpm
wxcomponents/checkedlistctrl.cpp
wxcomponents/checkedlistctrl.h
wxcomponents/checked_mo.xpm
wxcomponents/checked.xpm
wxcomponents/checktree.cpp
wxcomponents/checktree.h
wxcomponents/unchecked2.xpm
wxcomponents/unchecked_dis.xpm
wxcomponents/unchecked_d.xpm
wxcomponents/unchecked_ld.xpm
wxcomponents/unchecked_mo.xpm
wxcomponents/unchecked.xpm
wxgui.h
wxHelper.h
)
set_property(TARGET CemuWxGui PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
target_include_directories(CemuWxGui PUBLIC "../")
# PUBLIC because rapidjson/document.h is included in ChecksumTool.h
target_include_directories(CemuWxGui PUBLIC ${RAPIDJSON_INCLUDE_DIRS})
target_link_libraries(CemuWxGui PRIVATE
CemuAudio
CemuCafe
CemuCommon
CemuComponents
CemuConfig
CemuInput
CemuResource
CemuUtil
Boost::headers
CURL::libcurl
libzip::zip
OpenSSL::Crypto
pugixml::pugixml
ZArchive::zarchive
)
if(ENABLE_WXWIDGETS AND UNIX AND NOT APPLE)
# PUBLIC because gdk/gdkkeysyms.h is included in guiWrapper.h
target_link_libraries(CemuWxGui PUBLIC GTK3::gtk)
if (ENABLE_WAYLAND)
target_link_libraries(CemuWxGui PRIVATE Wayland::Client CemuWaylandProtocols)
endif()
endif()
if(ENABLE_CUBEB)
target_link_libraries(CemuWxGui PRIVATE cubeb::cubeb)
endif()
if(UNIX AND NOT APPLE)
if(ENABLE_FERAL_GAMEMODE)
target_link_libraries(CemuWxGui PRIVATE gamemode)
endif()
endif()
if (ENABLE_WXWIDGETS)
# PUBLIC because wx/app.h is included in CemuApp.h
target_link_libraries(CemuWxGui PUBLIC wx::base wx::core wx::gl wx::propgrid wx::xrc)
endif()
if(WIN32)
target_link_libraries(CemuWxGui PRIVATE bthprops)
endif()
if(ALLOW_PORTABLE)
target_compile_definitions(CemuWxGui PRIVATE CEMU_ALLOW_PORTABLE)
endif ()

View File

@@ -1,20 +1,21 @@
#include "gui/CemuApp.h"
#include "gui/MainWindow.h"
#include "gui/wxgui.h"
#include "wxgui/CemuApp.h"
#include "wxCemuConfig.h"
#include "wxgui/MainWindow.h"
#include "wxgui/wxgui.h"
#include "config/CemuConfig.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
#include "gui/guiWrapper.h"
#include "config/ActiveSettings.h"
#include "config/LaunchSettings.h"
#include "gui/GettingStartedDialog.h"
#include "wxgui/GettingStartedDialog.h"
#include "input/InputManager.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/helpers/wxHelpers.h"
#include "Cemu/ncrypto/ncrypto.h"
#include "gui/input/HotkeySettings.h"
#include "wxgui/input/HotkeySettings.h"
#include <wx/language.h>
#if BOOST_OS_LINUX && HAS_WAYLAND
#include "gui/helpers/wxWayland.h"
#include "wxgui/helpers/wxWayland.h"
#endif
#if __WXGTK__
#include <glib.h>
@@ -30,8 +31,8 @@
wxIMPLEMENT_APP_NO_MAIN(CemuApp);
// defined in guiWrapper.cpp
extern WindowInfo g_window_info;
// defined in wxWindowSystem.cpp
extern WindowSystem::WindowInfo g_window_info;
extern std::shared_mutex g_mutex;
// forward declarations from main.cpp
@@ -238,7 +239,7 @@ void CemuApp::InitializeExistingMLCOrFail(fs::path mlc)
else // reset path
{
GetConfig().mlc_path = "";
g_config.Save();
GetConfigHandle().Save();
}
}
else
@@ -249,6 +250,11 @@ void CemuApp::InitializeExistingMLCOrFail(fs::path mlc)
}
}
std::string TranslationCallback(std::string_view msgId)
{
return wxGetTranslation(to_wxString(msgId)).utf8_string();
}
bool CemuApp::OnInit()
{
#if __WXGTK__
@@ -259,22 +265,27 @@ bool CemuApp::OnInit()
// make sure default cemu directories exist
CreateDefaultCemuFiles();
g_config.SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring());
GetConfigHandle().SetFilename(ActiveSettings::GetConfigPath("settings.xml").generic_wstring());
auto& config = GetWxGUIConfig();
std::error_code ec;
bool isFirstStart = !fs::exists(ActiveSettings::GetConfigPath("settings.xml"), ec);
NetworkConfig::LoadOnce();
if(!isFirstStart)
if (!isFirstStart)
{
g_config.Load();
LocalizeUI(static_cast<wxLanguage>(GetConfig().language == wxLANGUAGE_DEFAULT ? wxLocale::GetSystemLanguage() : GetConfig().language.GetValue()));
GetConfigHandle().Load();
sint32 language = config.language.GetValue();
LocalizeUI(static_cast<wxLanguage>(language == wxLANGUAGE_DEFAULT ? wxLocale::GetSystemLanguage() : language));
}
else
{
LocalizeUI(static_cast<wxLanguage>(wxLocale::GetSystemLanguage()));
}
SetTranslationCallback(TranslationCallback);
for (auto&& path : failedWriteAccess)
{
wxMessageBox(formatWxString(_("Cemu can't write to {}!"), wxString::FromUTF8(_pathToUtf8(path))),
@@ -287,7 +298,7 @@ bool CemuApp::OnInit()
GettingStartedDialog dia(nullptr);
dia.ShowModal();
// make sure config is created. Gfx pack UI and input UI may create it earlier already, but we still want to update it
g_config.Save();
GetConfigHandle().Save();
// create mlc, on failure the user can quit here. So do this after the Getting Started dialog
InitializeNewMLCOrFail(ActiveSettings::GetMlcPath());
}
@@ -326,7 +337,6 @@ bool CemuApp::OnInit()
Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this);
auto& config = GetConfig();
m_mainFrame = new MainWindow();
std::unique_lock lock(g_mutex);
@@ -344,7 +354,7 @@ bool CemuApp::OnInit()
// show warning on macOS about state of builds
#if BOOST_OS_MACOS
if (!GetConfig().did_show_macos_disclaimer)
if (!config.did_show_macos_disclaimer)
{
const auto message = _(
"Thank you for testing the in-development build of Cemu for macOS.\n \n"
@@ -353,8 +363,8 @@ bool CemuApp::OnInit()
wxMessageDialog dialog(nullptr, message, _("Preview version"), wxCENTRE | wxOK | wxICON_WARNING);
dialog.SetOKLabel(_("I understand"));
dialog.ShowModal();
GetConfig().did_show_macos_disclaimer = true;
g_config.Save();
config.did_show_macos_disclaimer = true;
GetConfigHandle().Save();
}
#endif

View File

@@ -1,10 +1,11 @@
#include "gui/CemuUpdateWindow.h"
#include "wxgui/CemuUpdateWindow.h"
#include "Common/version.h"
#include "util/helpers/helpers.h"
#include "util/helpers/SystemException.h"
#include "config/ActiveSettings.h"
#include "Common/FileStream.h"
#include "wxCemuConfig.h"
#include <wx/sizer.h>
#include <wx/gauge.h>
@@ -118,7 +119,7 @@ bool CemuUpdateWindow::QueryUpdateInfo(std::string& downloadUrlOut, std::string&
#elif
#error Name for current platform is missing
#endif
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
if(config.receive_untested_updates)
urlStr.append("&allowNewUpdates=1");

View File

@@ -1,10 +1,10 @@
#include "gui/ChecksumTool.h"
#include "wxgui/ChecksumTool.h"
#include "Cafe/TitleList/GameInfo.h"
#include "gui/helpers/wxCustomEvents.h"
#include "wxgui/helpers/wxCustomEvents.h"
#include "util/helpers/helpers.h"
#include "gui/helpers/wxHelpers.h"
#include "gui/wxHelper.h"
#include "wxgui/helpers/wxHelpers.h"
#include "wxgui/wxHelper.h"
#include "Cafe/Filesystem/WUD/wud.h"
#include <zip.h>

View File

@@ -1,6 +1,6 @@
#pragma once
#include <wx/dialog.h>
#include "gui/components/wxTitleManagerList.h"
#include "wxgui/components/wxTitleManagerList.h"
#include "Cafe/TitleList/TitleInfo.h"
#include <rapidjson/document.h>

View File

@@ -1,5 +1,5 @@
#include "gui/wxgui.h"
#include "gui/DownloadGraphicPacksWindow.h"
#include "wxgui/wxgui.h"
#include "wxgui/DownloadGraphicPacksWindow.h"
#include <filesystem>
#include <curl/curl.h>

View File

@@ -3,8 +3,8 @@
#include <algorithm>
#include "config/CemuConfig.h"
#include "gui/helpers/wxHelpers.h"
#include "gui/wxHelper.h"
#include "wxgui/helpers/wxHelpers.h"
#include "wxgui/wxHelper.h"
#include "util/helpers/helpers.h"
#include "Cafe/OS/libs/nsyshid/nsyshid.h"
@@ -73,7 +73,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddSkylanderPage(wxNotebook* notebook)
m_emulatePortal->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_skylander_portal =
m_emulatePortal->IsChecked();
g_config.Save();
GetConfigHandle().Save();
});
row->Add(m_emulatePortal, 1, wxEXPAND | wxALL, 2);
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
@@ -103,7 +103,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddInfinityPage(wxNotebook* notebook)
m_emulateBase->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_infinity_base =
m_emulateBase->IsChecked();
g_config.Save();
GetConfigHandle().Save();
});
row->Add(m_emulateBase, 1, wxEXPAND | wxALL, 2);
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
@@ -139,7 +139,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddDimensionsPage(wxNotebook* notebook)
m_emulateToypad->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_dimensions_toypad =
m_emulateToypad->IsChecked();
g_config.Save();
GetConfigHandle().Save();
});
row->Add(m_emulateToypad, 1, wxEXPAND | wxALL, 2);
box_sizer->Add(row, 1, wxEXPAND | wxALL, 2);

View File

@@ -1,4 +1,4 @@
#include "gui/GameProfileWindow.h"
#include "wxgui/GameProfileWindow.h"
#include <wx/statbox.h>
#include <wx/sizer.h>
@@ -8,7 +8,7 @@
#include <wx/wupdlock.h>
#include <wx/slider.h>
#include "gui/helpers/wxHelpers.h"
#include "wxgui/helpers/wxHelpers.h"
#include "input/InputManager.h"
#if BOOST_OS_LINUX || BOOST_OS_MACOS

View File

@@ -1,13 +1,13 @@
#include "gui/wxgui.h"
#include "gui/GameUpdateWindow.h"
#include "wxgui/wxgui.h"
#include "wxgui/GameUpdateWindow.h"
#include "util/helpers/helpers.h"
#include <filesystem>
#include <sstream>
#include "util/helpers/SystemException.h"
#include "gui/CemuApp.h"
#include "wxgui/CemuApp.h"
#include "Cafe/TitleList/GameInfo.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/helpers/wxHelpers.h"
#include "wxHelper.h"
wxString _GetTitleIdTypeStr(TitleId titleId)

View File

@@ -1,7 +1,8 @@
#include "gui/wxgui.h"
#include "gui/GeneralSettings2.h"
#include "gui/CemuApp.h"
#include "gui/helpers/wxControlObject.h"
#include "wxCemuConfig.h"
#include "wxgui/wxgui.h"
#include "wxgui/GeneralSettings2.h"
#include "wxgui/CemuApp.h"
#include "wxgui/helpers/wxControlObject.h"
#include "util/helpers/helpers.h"
@@ -31,7 +32,7 @@
#include <boost/tokenizer.hpp>
#include "util/helpers/SystemException.h"
#include "gui/dialogs/CreateAccount/wxCreateAccountDialog.h"
#include "wxgui/dialogs/CreateAccount/wxCreateAccountDialog.h"
#if BOOST_OS_WINDOWS
#include <VersionHelpers.h>
@@ -39,7 +40,7 @@
#include "config/LaunchSettings.h"
#include "config/ActiveSettings.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/helpers/wxHelpers.h"
#include "resource/embedded/resources.h"
@@ -959,14 +960,15 @@ void GeneralSettings2::StoreConfig()
{
auto* app = (CemuApp*)wxTheApp;
auto& config = GetConfig();
auto& wxGuiConfig = GetWxGUIConfig();
config.use_discord_presence = m_discord_presence->IsChecked();
config.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
config.check_update = m_auto_update->IsChecked();
config.save_screenshot = m_save_screenshot->IsChecked();
config.receive_untested_updates = m_receive_untested_releases->IsChecked();
wxGuiConfig.use_discord_presence = m_discord_presence->IsChecked();
wxGuiConfig.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
wxGuiConfig.check_update = m_auto_update->IsChecked();
wxGuiConfig.save_screenshot = m_save_screenshot->IsChecked();
wxGuiConfig.receive_untested_updates = m_receive_untested_releases->IsChecked();
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
config.feral_gamemode = m_feral_gamemode->IsChecked();
wxGuiConfig.feral_gamemode = m_feral_gamemode->IsChecked();
#endif
config.play_boot_sound = m_play_boot_sound->IsChecked();
config.disable_screensaver = m_disable_screensaver->IsChecked();
@@ -978,10 +980,10 @@ void GeneralSettings2::StoreConfig()
// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it
config.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.pad_position = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.pad_size = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.pad_position = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
wxGuiConfig.pad_size = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
config.game_paths.clear();
for (auto& path : m_game_paths->GetStrings())
@@ -989,7 +991,7 @@ void GeneralSettings2::StoreConfig()
auto selection = m_language->GetSelection();
if (selection == 0)
GetConfig().language = wxLANGUAGE_DEFAULT;
wxGuiConfig.language = wxLANGUAGE_DEFAULT;
else
{
const auto language = m_language->GetStringSelection();
@@ -997,7 +999,7 @@ void GeneralSettings2::StoreConfig()
{
if (lang->DescriptionNative == language)
{
GetConfig().language = lang->Language;
wxGuiConfig.language = lang->Language;
break;
}
}
@@ -1112,7 +1114,7 @@ void GeneralSettings2::StoreConfig()
config.crash_dump = (CrashDump)m_crash_dump->GetSelection();
config.gdb_port = m_gdb_port->GetValue();
g_config.Save();
GetConfigHandle().Save();
}
GeneralSettings2::~GeneralSettings2()
@@ -1133,9 +1135,9 @@ void GeneralSettings2::OnClose(wxCloseEvent& event)
void GeneralSettings2::ValidateConfig()
{
g_config.Load();
GetConfigHandle().Load();
auto& data = g_config.data();
auto& data = GetConfigHandle().data();
// todo
//data.fullscreen_scaling = min(max(data.fullscreen_scaling,))
}
@@ -1610,6 +1612,7 @@ void GeneralSettings2::HandleGraphicsApiSelection()
void GeneralSettings2::ApplyConfig()
{
ValidateConfig();
auto& wxGUIconfig = GetWxGUIConfig();
auto& config = GetConfig();
if (LaunchSettings::GetMLCPath().has_value())
@@ -1617,20 +1620,20 @@ void GeneralSettings2::ApplyConfig()
else
m_mlc_path->SetValue(wxHelper::FromUtf8(config.mlc_path.GetValue()));
m_save_window_position_size->SetValue(config.window_position != Vector2i{-1,-1});
m_save_padwindow_position_size->SetValue(config.pad_position != Vector2i{-1,-1});
m_save_window_position_size->SetValue(wxGUIconfig.window_position != Vector2i{-1,-1});
m_save_padwindow_position_size->SetValue(wxGUIconfig.pad_position != Vector2i{-1,-1});
m_discord_presence->SetValue(config.use_discord_presence);
m_fullscreen_menubar->SetValue(config.fullscreen_menubar);
m_discord_presence->SetValue(wxGUIconfig.use_discord_presence);
m_fullscreen_menubar->SetValue(wxGUIconfig.fullscreen_menubar);
m_auto_update->SetValue(config.check_update);
m_receive_untested_releases->SetValue(config.receive_untested_updates);
m_save_screenshot->SetValue(config.save_screenshot);
m_auto_update->SetValue(wxGUIconfig.check_update);
m_receive_untested_releases->SetValue(wxGUIconfig.receive_untested_updates);
m_save_screenshot->SetValue(wxGUIconfig.save_screenshot);
m_disable_screensaver->SetValue(config.disable_screensaver);
m_play_boot_sound->SetValue(config.play_boot_sound);
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
m_feral_gamemode->SetValue(config.feral_gamemode);
m_feral_gamemode->SetValue(wxGUIconfig.feral_gamemode);
#endif
// temporary workaround because feature crashes on macOS
#if BOOST_OS_MACOS
@@ -1646,7 +1649,7 @@ void GeneralSettings2::ApplyConfig()
const auto app = (CemuApp*)wxTheApp;
for (const auto& language : app->GetLanguages())
{
if (config.language == language->Language)
if (wxGUIconfig.language == language->Language)
{
m_language->SetStringSelection(language->DescriptionNative);
break;
@@ -2124,7 +2127,7 @@ void GeneralSettings2::OnMLCPathClear(wxCommandEvent& event)
return;
GetConfig().SetMLCPath("");
StoreConfig();
g_config.Save();
GetConfigHandle().Save();
wxMessageBox(_("Cemu needs to be restarted for the changes to take effect."), _("Information"), wxOK | wxCENTRE | wxICON_INFORMATION, this);
// close settings and then cemu
wxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW);

View File

@@ -1,4 +1,4 @@
#include "gui/GettingStartedDialog.h"
#include "wxgui/GettingStartedDialog.h"
#include <wx/sizer.h>
#include <wx/filepicker.h>
@@ -8,10 +8,11 @@
#include <wx/button.h>
#include "config/ActiveSettings.h"
#include "gui/CemuApp.h"
#include "gui/DownloadGraphicPacksWindow.h"
#include "gui/GraphicPacksWindow2.h"
#include "gui/input/InputSettings2.h"
#include "wxCemuConfig.h"
#include "wxgui/CemuApp.h"
#include "wxgui/DownloadGraphicPacksWindow.h"
#include "wxgui/GraphicPacksWindow2.h"
#include "wxgui/input/InputSettings2.h"
#include "config/CemuConfig.h"
#include "Cafe/TitleList/TitleList.h"
@@ -204,7 +205,7 @@ wxPanel* GettingStartedDialog::CreatePage2()
void GettingStartedDialog::ApplySettings()
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
m_page2.fullscreenCheckbox->SetValue(config.fullscreen.GetValue());
m_page2.updateCheckbox->SetValue(config.check_update.GetValue());
m_page2.separateCheckbox->SetValue(config.pad_open.GetValue());
@@ -225,11 +226,12 @@ void GettingStartedDialog::OnClose(wxCloseEvent& event)
{
event.Skip();
auto& config = GetConfig();
config.fullscreen = m_page2.fullscreenCheckbox->GetValue();
config.check_update = m_page2.updateCheckbox->GetValue();
config.pad_open = m_page2.separateCheckbox->GetValue();
auto& wxGUIConfig = GetWxGUIConfig();
wxGUIConfig.fullscreen = m_page2.fullscreenCheckbox->GetValue();
wxGUIConfig.check_update = m_page2.updateCheckbox->GetValue();
wxGUIConfig.pad_open = m_page2.separateCheckbox->GetValue();
auto& config = GetConfig();
const fs::path gamePath = wxHelper::MakeFSPath(m_page1.gamePathPicker->GetPath());
std::error_code ec;
if (!gamePath.empty() && fs::exists(gamePath, ec))

View File

@@ -1,6 +1,6 @@
#include "gui/wxgui.h"
#include "gui/GraphicPacksWindow2.h"
#include "gui/DownloadGraphicPacksWindow.h"
#include "wxgui/wxgui.h"
#include "wxgui/GraphicPacksWindow2.h"
#include "wxgui/DownloadGraphicPacksWindow.h"
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "config/CemuConfig.h"
#include "config/ActiveSettings.h"
@@ -325,7 +325,7 @@ GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_fil
void GraphicPacksWindow2::SaveStateToConfig()
{
auto& data = g_config.data();
auto& data = GetConfigHandle().data();
data.graphic_pack_entries.clear();
for (const auto& gp : GraphicPack2::GetGraphicPacks())
@@ -348,7 +348,7 @@ void GraphicPacksWindow2::SaveStateToConfig()
}
}
g_config.Save();
GetConfigHandle().Save();
}
GraphicPacksWindow2::~GraphicPacksWindow2()

View File

@@ -1,17 +1,14 @@
#include "gui/LoggingWindow.h"
#include "wxgui/LoggingWindow.h"
#include "gui/helpers/wxLogEvent.h"
#include "Cemu/Logging/CemuLogging.h"
#include "wxgui/helpers/wxLogEvent.h"
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/wupdlock.h>
#include "gui/helpers/wxHelpers.h"
wxDEFINE_EVENT(EVT_LOG, wxLogEvent);
LoggingWindow* s_instance;
LoggingWindow::LoggingWindow(wxFrame* parent)
: wxFrame(parent, wxID_ANY, _("Logging window"), wxDefaultPosition, wxSize(800, 600), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)
{
@@ -42,27 +39,20 @@ LoggingWindow::LoggingWindow(wxFrame* parent)
this->Bind(EVT_LOG, &LoggingWindow::OnLogMessage, this);
std::unique_lock lock(s_mutex);
cemu_assert_debug(s_instance == nullptr);
s_instance = this;
cemuLog_setCallbacks(this);
}
LoggingWindow::~LoggingWindow()
{
this->Unbind(EVT_LOG, &LoggingWindow::OnLogMessage, this);
std::unique_lock lock(s_mutex);
s_instance = nullptr;
cemuLog_clearCallbacks();
}
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);
OnLogMessage(event);
//const auto log_event = new wxLogEvent(filter, message);
//wxQueueEvent(s_instance, log_event);
@@ -70,12 +60,8 @@ void LoggingWindow::Log(std::string_view filter, std::string_view message)
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);
OnLogMessage(event);
//const auto log_event = new wxLogEvent(filter, message);
//wxQueueEvent(s_instance, log_event);

View File

@@ -0,0 +1,29 @@
#pragma once
#include "Cemu/Logging/CemuLogging.h"
#include <wx/frame.h>
#include <wx/listbox.h>
#include <wx/combobox.h>
#include "wxgui/components/wxLogCtrl.h"
class wxLogEvent;
class LoggingWindow : public wxFrame, public LoggingCallbacks
{
public:
LoggingWindow(wxFrame* parent);
~LoggingWindow();
void Log(std::string_view filter, std::string_view message) override;
void Log(std::string_view filter, std::wstring_view message) override;
private:
void OnLogMessage(wxLogEvent& event);
void OnFilterChange(wxCommandEvent& event);
void OnFilterMessageChange(wxCommandEvent& event);
wxComboBox* m_filter;
wxLogCtrl* m_log_list;
wxCheckBox* m_filter_message;
};

View File

@@ -1,46 +1,48 @@
#include "gui/wxgui.h"
#include "gui/MainWindow.h"
#include "gui/guiWrapper.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "interface/WindowSystem.h"
#include "wxCemuConfig.h"
#include "wxgui/wxgui.h"
#include "wxgui/MainWindow.h"
#include <wx/mstream.h>
#include <wx/clipbrd.h>
#include "gui/GameUpdateWindow.h"
#include "gui/PadViewFrame.h"
#include "gui/windows/TextureRelationViewer/TextureRelationWindow.h"
#include "gui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h"
#include "audio/audioDebuggerWindow.h"
#include "gui/canvas/OpenGLCanvas.h"
#include "gui/canvas/VulkanCanvas.h"
#include "wxgui/GameUpdateWindow.h"
#include "wxgui/PadViewFrame.h"
#include "wxgui/windows/TextureRelationViewer/TextureRelationWindow.h"
#include "wxgui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h"
#include "AudioDebuggerWindow.h"
#include "wxgui/canvas/OpenGLCanvas.h"
#include "wxgui/canvas/VulkanCanvas.h"
#include "Cafe/OS/libs/nfc/nfc.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
#include "gui/debugger/DebuggerWindow2.h"
#include "wxgui/debugger/DebuggerWindow2.h"
#include "util/helpers/helpers.h"
#include "config/CemuConfig.h"
#include "Cemu/DiscordPresence/DiscordPresence.h"
#include "util/ScreenSaver/ScreenSaver.h"
#include "gui/GeneralSettings2.h"
#include "gui/GraphicPacksWindow2.h"
#include "gui/CemuApp.h"
#include "gui/CemuUpdateWindow.h"
#include "gui/LoggingWindow.h"
#include "wxgui/GeneralSettings2.h"
#include "wxgui/GraphicPacksWindow2.h"
#include "wxgui/CemuApp.h"
#include "wxgui/CemuUpdateWindow.h"
#include "wxgui/LoggingWindow.h"
#include "config/ActiveSettings.h"
#include "config/LaunchSettings.h"
#include "Cafe/Filesystem/FST/FST.h"
#include "gui/TitleManager.h"
#include "gui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h"
#include "wxgui/TitleManager.h"
#include "wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h"
#include "Cafe/CafeSystem.h"
#include "util/helpers/SystemException.h"
#include "gui/DownloadGraphicPacksWindow.h"
#include "gui/GettingStartedDialog.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/DownloadGraphicPacksWindow.h"
#include "wxgui/GettingStartedDialog.h"
#include "wxgui/helpers/wxHelpers.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h"
#include "gui/input/InputSettings2.h"
#include "gui/input/HotkeySettings.h"
#include "wxgui/input/InputSettings2.h"
#include "wxgui/input/HotkeySettings.h"
#include "input/InputManager.h"
#if BOOST_OS_WINDOWS
@@ -54,7 +56,7 @@
#endif
#if BOOST_OS_LINUX && HAS_WAYLAND
#include "gui/helpers/wxWayland.h"
#include "wxgui/helpers/wxWayland.h"
#endif
//GameMode support
@@ -66,7 +68,7 @@
#include "Cafe/TitleList/TitleList.h"
#include "wxHelper.h"
extern WindowInfo g_window_info;
extern WindowSystem::WindowInfo g_window_info;
extern std::shared_mutex g_mutex;
enum
@@ -273,7 +275,7 @@ public:
std::string path = filenames[0].utf8_string();
if (nfc::TouchTagFromFile(_utf8ToPath(path), &nfcError))
{
GetConfig().AddRecentNfcFile(path);
GetWxGUIConfig().AddRecentNfcFile(path);
m_window->UpdateNFCMenu();
return true;
}
@@ -299,7 +301,7 @@ MainWindow::MainWindow()
wxApp::s_macAboutMenuItemId = MAINFRAME_MENU_ID_HELP_ABOUT;
wxApp::s_macPreferencesMenuItemId = MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS;
#endif
gui_initHandleContextFromWxWidgetsWindow(g_window_info.window_main, this);
g_window_info.window_main = initHandleContextFromWxWidgetsWindow(this);
g_mainFrame = this;
CafeSystem::SetImplementation(this);
@@ -362,9 +364,8 @@ MainWindow::MainWindow()
LoadSettings();
auto& config = GetConfig();
#ifdef ENABLE_DISCORD_RPC
if (config.use_discord_presence)
if (GetWxGUIConfig().use_discord_presence)
m_discord = std::make_unique<DiscordPresence>();
#endif
@@ -373,7 +374,7 @@ MainWindow::MainWindow()
if (LaunchSettings::GDBStubEnabled())
{
g_gdbstub = std::make_unique<GDBServer>(config.gdb_port);
g_gdbstub = std::make_unique<GDBServer>(GetConfig().gdb_port);
}
}
@@ -437,7 +438,7 @@ void MainWindow::OnClose(wxCloseEvent& event)
if(m_game_list)
m_game_list->OnClose(event);
if (!IsMaximized() && !gui_isFullScreen())
if (!IsMaximized() && !WindowSystem::IsFullScreen())
m_restored_size = GetSize();
SaveSettings();
@@ -571,9 +572,9 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
}
if(launchTitle.IsValid())
GetConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchTitle.GetPath()));
GetWxGUIConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchTitle.GetPath()));
else
GetConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchPath));
GetWxGUIConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchPath));
wxWindowUpdateLocker lock(this);
@@ -598,12 +599,12 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
// ScreenSaver::SetInhibit(false);
}
if (ActiveSettings::FullscreenEnabled())
if (FullscreenEnabled())
SetFullScreen(true);
//GameMode support
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
if(GetConfig().feral_gamemode)
if(GetWxGUIConfig().feral_gamemode)
{
// attempt to start gamemode
if(gamemode_request_start() < 0)
@@ -665,7 +666,7 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
}
else if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
const size_t index = menuId - MAINFRAME_MENU_ID_FILE_RECENT_0;
if (index < config.recent_launch_files.size())
{
@@ -759,14 +760,14 @@ void MainWindow::OnNFCMenu(wxCommandEvent& event)
}
else
{
GetConfig().AddRecentNfcFile(wxStrFilePath.utf8_string());
GetWxGUIConfig().AddRecentNfcFile(wxStrFilePath.utf8_string());
UpdateNFCMenu();
}
}
else if (event.GetId() >= MAINFRAME_MENU_ID_NFC_RECENT_0 && event.GetId() <= MAINFRAME_MENU_ID_NFC_RECENT_LAST)
{
const size_t index = event.GetId() - MAINFRAME_MENU_ID_NFC_RECENT_0;
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
if (index < config.recent_nfc_files.size())
{
const auto& path = config.recent_nfc_files[index];
@@ -799,7 +800,7 @@ void MainWindow::OnFileExit(wxCommandEvent& event)
void MainWindow::TogglePadView()
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
if (config.pad_open)
{
if (m_padView)
@@ -848,7 +849,7 @@ WXLRESULT MainWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
void MainWindow::OpenSettings()
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
const auto language = config.language;
GeneralSettings2 frame(this, m_game_launched);
@@ -900,8 +901,8 @@ void MainWindow::OnOptionsInput(wxCommandEvent& event)
}
case MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW:
{
GetConfig().pad_open = !GetConfig().pad_open;
g_config.Save();
GetWxGUIConfig().pad_open = !GetWxGUIConfig().pad_open;
g_wxConfig.Save();
TogglePadView();
break;
@@ -953,7 +954,7 @@ void MainWindow::OnAccountSelect(wxCommandEvent& event)
auto& config = GetConfig();
config.account.m_persistent_id = accounts[index].GetPersistentId();
// config.account.online_enabled.value = false; // reset online for safety
g_config.Save();
GetConfigHandle().Save();
}
void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
@@ -1004,7 +1005,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
m_game_list->DeleteCachedStrings();
m_game_list->ReloadGameEntries(false);
}
g_config.Save();
GetConfigHandle().Save();
}
//void MainWindow::OnCPUMode(wxCommandEvent& event)
@@ -1020,7 +1021,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
// else
// cemu_assert_debug(false);
//
// g_config.Save();
// GetConfigHandle().Save();
//}
void MainWindow::OnDebugSetting(wxCommandEvent& event)
@@ -1084,7 +1085,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
else
cemu_assert_debug(false);
g_config.Save();
GetConfigHandle().Save();
}
void MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)
@@ -1101,14 +1102,14 @@ void MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)
else
GetConfig().log_flag = GetConfig().log_flag.GetValue() & ~cemuLog_getFlag(loggingType);
cemuLog_setActiveLoggingFlags(GetConfig().log_flag.GetValue());
g_config.Save();
GetConfigHandle().Save();
}
}
void MainWindow::OnPPCInfoToggle(wxCommandEvent& event)
{
GetConfig().advanced_ppc_logging = !GetConfig().advanced_ppc_logging.GetValue();
g_config.Save();
GetConfigHandle().Save();
}
void MainWindow::OnDebugDumpGeneric(wxCommandEvent& event)
@@ -1289,8 +1290,8 @@ wxRect MainWindow::GetDesktopRect()
void MainWindow::LoadSettings()
{
g_config.Load();
const auto& config = GetConfig();
GetConfigHandle().Load();
const auto& config = GetWxGUIConfig();
if(config.check_update)
m_update_available = CemuUpdateWindow::IsUpdateAvailableAsync();
@@ -1328,8 +1329,8 @@ void MainWindow::LoadSettings()
void MainWindow::SaveSettings()
{
auto lock = g_config.Lock();
auto& config = GetConfig();
auto lock = GetConfigHandle().Lock();
auto& config = GetWxGUIConfig();
if (config.window_position != Vector2i{ -1,-1 })
{
@@ -1368,7 +1369,7 @@ void MainWindow::SaveSettings()
if(m_game_list)
m_game_list->SaveConfig();
g_config.Save();
g_wxConfig.Save();
}
void MainWindow::OnMouseMove(wxMouseEvent& event)
@@ -1388,7 +1389,7 @@ void MainWindow::OnMouseMove(wxMouseEvent& event)
if (!IsFullScreen())
return;
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
// if mouse goes to upper screen then show our menu in fullscreen mode
if (config.fullscreen_menubar)
SetMenuVisible(event.GetPosition().y < 50);
@@ -1640,7 +1641,7 @@ void MainWindow::DestroyCanvas()
void MainWindow::OnSizeEvent(wxSizeEvent& event)
{
if (!IsMaximized() && !gui_isFullScreen())
if (!IsMaximized() && !WindowSystem::IsFullScreen())
m_restored_size = GetSize();
const wxSize client_size = GetClientSize();
@@ -1671,7 +1672,7 @@ void MainWindow::OnDPIChangedEvent(wxDPIChangedEvent& event)
void MainWindow::OnMove(wxMoveEvent& event)
{
if (!IsMaximized() && !gui_isFullScreen())
if (!IsMaximized() && !WindowSystem::IsFullScreen())
m_restored_position = GetPosition();
if (m_debugger_window && m_debugger_window->IsShown())
@@ -1687,7 +1688,7 @@ void MainWindow::OnDebuggerClose(wxCloseEvent& event)
void MainWindow::OnPadClose(wxCloseEvent& event)
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
config.pad_open = false;
if (config.pad_position != Vector2i{ -1,-1 })
m_padView->GetPosition(&config.pad_position.x, &config.pad_position.y);
@@ -1695,7 +1696,7 @@ void MainWindow::OnPadClose(wxCloseEvent& event)
if (config.pad_size != Vector2i{ -1,-1 })
m_padView->GetSize(&config.pad_size.x, &config.pad_size.y);
g_config.Save();
g_wxConfig.Save();
// already deleted by wxwidget
m_padView = nullptr;
@@ -1726,8 +1727,8 @@ void MainWindow::SetFullScreen(bool state)
// only update config entry if we dont't have launch parameters
if (!LaunchSettings::FullscreenEnabled().has_value())
{
GetConfig().fullscreen = state;
g_config.Save();
GetWxGUIConfig().fullscreen = state;
g_wxConfig.Save();
}
if (state && !m_game_launched)
return;
@@ -1759,14 +1760,14 @@ void MainWindow::UpdateNFCMenu()
m_nfcMenuSeparator0 = nullptr;
}
// remove recent files list
for (sint32 i = 0; i < CemuConfig::kMaxRecentEntries; i++)
for (sint32 i = 0; i < wxCemuConfig::kMaxRecentEntries; i++)
{
if (m_nfcMenu->FindChildItem(MAINFRAME_MENU_ID_NFC_RECENT_0 + i) == nullptr)
continue;
m_nfcMenu->Remove(MAINFRAME_MENU_ID_NFC_RECENT_0 + i);
}
// add entries
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
sint32 recentFileIndex = 0;
for (size_t i = 0; i < config.recent_nfc_files.size(); i++)
{
@@ -2097,7 +2098,7 @@ void MainWindow::RecreateMenu()
m_menuBar = nullptr;
}
auto& config = GetConfig();
auto& guiConfig = GetWxGUIConfig();
m_menuBar = new wxMenuBar();
// file submenu
@@ -2111,9 +2112,9 @@ void MainWindow::RecreateMenu()
sint32 recentFileIndex = 0;
m_fileMenuSeparator0 = nullptr;
m_fileMenuSeparator1 = nullptr;
for (size_t i = 0; i < config.recent_launch_files.size(); i++)
for (size_t i = 0; i < guiConfig.recent_launch_files.size(); i++)
{
const std::string& pathStr = config.recent_launch_files[i];
const std::string& pathStr = guiConfig.recent_launch_files[i];
if (pathStr.empty())
continue;
if (recentFileIndex == 0)
@@ -2155,6 +2156,8 @@ void MainWindow::RecreateMenu()
++index;
}
auto& config = GetConfig();
auto& wxConfig = GetWxGUIConfig();
// options->console language submenu
wxMenu* optionsConsoleLanguageMenu = new wxMenu();
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH, _("&English"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::EN);
@@ -2181,11 +2184,11 @@ void MainWindow::RecreateMenu()
// options submenu
wxMenu* optionsMenu = new wxMenu();
m_fullscreenMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, _("&Fullscreen"), wxEmptyString);
m_fullscreenMenuItem->Check(ActiveSettings::FullscreenEnabled());
m_fullscreenMenuItem->Check(FullscreenEnabled());
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, _("&Graphic packs"));
m_padViewMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, _("&Separate GamePad view"), wxEmptyString);
m_padViewMenuItem->Check(GetConfig().pad_open);
m_padViewMenuItem->Check(wxConfig.pad_open);
optionsMenu->AppendSeparator();
#if BOOST_OS_MACOS
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS, _("&Settings..." "\tCtrl-,"));
@@ -2408,3 +2411,8 @@ void MainWindow::CafeRecreateCanvas()
wxQueueEvent(g_mainFrame, evt);
sem.decrementWithWait();
}
bool MainWindow::FullscreenEnabled() const
{
return LaunchSettings::FullscreenEnabled().value_or(GetWxGUIConfig().fullscreen);
}

View File

@@ -5,13 +5,13 @@
#include <wx/infobar.h>
#include "wxcomponents/checkedlistctrl.h"
#include "gui/PadViewFrame.h"
#include "gui/MemorySearcherTool.h"
#include "wxgui/PadViewFrame.h"
#include "wxgui/MemorySearcherTool.h"
#include "config/XMLConfig.h"
#include "gui/LoggingWindow.h"
#include "gui/components/wxGameList.h"
#include "wxgui/LoggingWindow.h"
#include "wxgui/components/wxGameList.h"
#include <future>
#include "Cafe/HW/Espresso/Debugger/GDBStub.h"
@@ -145,6 +145,7 @@ public:
static void RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy);
private:
bool FullscreenEnabled() const;
void RecreateMenu();
void UpdateChildWindowTitleRunningState();
static wxString GetInitialWindowTitle();

View File

@@ -1,6 +1,6 @@
#include "gui/wxgui.h"
#include "wxgui/wxgui.h"
#include "gui/MemorySearcherTool.h"
#include "wxgui/MemorySearcherTool.h"
#include <vector>
#include <sstream>
@@ -8,7 +8,7 @@
#include <wx/listctrl.h>
#include "config/ActiveSettings.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/helpers/wxHelpers.h"
#include "Common/FileStream.h"
#include "util/IniParser/IniParser.h"
#include "util/helpers/StringHelpers.h"

View File

@@ -6,7 +6,7 @@
#include "Cafe/HW/MMU/MMU.h"
#include "util/helpers/helpers.h"
#include "gui/helpers/wxCustomEvents.h"
#include "wxgui/helpers/wxCustomEvents.h"
enum SearchDataType
{

View File

@@ -1,16 +1,16 @@
#include "gui/wxgui.h"
#include "gui/guiWrapper.h"
#include "gui/PadViewFrame.h"
#include "interface/WindowSystem.h"
#include "wxgui/wxgui.h"
#include "wxgui/PadViewFrame.h"
#include <wx/display.h>
#include "config/ActiveSettings.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
#include "gui/canvas/OpenGLCanvas.h"
#include "gui/canvas/VulkanCanvas.h"
#include "wxgui/canvas/OpenGLCanvas.h"
#include "wxgui/canvas/VulkanCanvas.h"
#include "config/CemuConfig.h"
#include "gui/MainWindow.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/MainWindow.h"
#include "wxgui/helpers/wxHelpers.h"
#include "input/InputManager.h"
#if BOOST_OS_LINUX || BOOST_OS_MACOS
@@ -18,7 +18,7 @@
#endif
#include "wxHelper.h"
extern WindowInfo g_window_info;
extern WindowSystem::WindowInfo g_window_info;
#define PAD_MIN_WIDTH 320
#define PAD_MIN_HEIGHT 180
@@ -26,7 +26,7 @@ extern WindowInfo g_window_info;
PadViewFrame::PadViewFrame(wxFrame* parent)
: wxFrame(nullptr, wxID_ANY, _("GamePad View"), wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxCLOSE_BOX | wxWANTS_CHARS)
{
gui_initHandleContextFromWxWidgetsWindow(g_window_info.window_pad, this);
g_window_info.window_pad = initHandleContextFromWxWidgetsWindow(this);
SetIcon(wxICON(M_WND_ICON128));
wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);

View File

@@ -1,15 +1,15 @@
#include "gui/TitleManager.h"
#include "wxgui/TitleManager.h"
#include "gui/helpers/wxCustomEvents.h"
#include "gui/helpers/wxCustomData.h"
#include "wxgui/helpers/wxCustomEvents.h"
#include "wxgui/helpers/wxCustomData.h"
#include "Cafe/TitleList/GameInfo.h"
#include "util/helpers/helpers.h"
#include "gui/helpers/wxHelpers.h"
#include "gui/wxHelper.h"
#include "gui/components/wxTitleManagerList.h"
#include "gui/components/wxDownloadManagerList.h"
#include "gui/GameUpdateWindow.h"
#include "gui/dialogs/SaveImport/SaveTransfer.h"
#include "wxgui/helpers/wxHelpers.h"
#include "wxgui/wxHelper.h"
#include "wxgui/components/wxTitleManagerList.h"
#include "wxgui/components/wxDownloadManagerList.h"
#include "wxgui/GameUpdateWindow.h"
#include "wxgui/dialogs/SaveImport/SaveTransfer.h"
#include <wx/listbase.h>
#include <wx/sizer.h>
@@ -33,10 +33,10 @@
#include "Cafe/IOSU/legacy/iosu_crypto.h"
#include "config/ActiveSettings.h"
#include "gui/dialogs/SaveImport/SaveImportWindow.h"
#include "wxgui/dialogs/SaveImport/SaveImportWindow.h"
#include "Cafe/Account/Account.h"
#include "Cemu/Tools/DownloadManager/DownloadManager.h"
#include "gui/CemuApp.h"
#include "wxgui/CemuApp.h"
#include "Cafe/TitleList/TitleList.h"
#include "Cafe/TitleList/SaveList.h"
#include "resource/embedded/resources.h"

View File

@@ -1,4 +1,7 @@
#include "gui/canvas/OpenGLCanvas.h"
#include "wxgui/canvas/OpenGLCanvas.h"
#include "wxgui/canvas/IRenderCanvas.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "config/CemuConfig.h"
@@ -26,9 +29,59 @@ static const int g_gl_attribute_list[] =
0, // end of list
};
wxGLContext* sGLContext = nullptr;
class OpenGLCanvas* sGLTVView = nullptr;
class OpenGLCanvas* sGLPadView = nullptr;
class OpenGLCanvas;
class GLCanvasManager : public OpenGLCanvasCallbacks
{
public:
GLCanvasManager()
{
SetOpenGLCanvasCallbacks(this);
}
~GLCanvasManager()
{
ClearOpenGLCanvasCallbacks();
}
void SetTVView(OpenGLCanvas* canvas)
{
m_tvView = canvas;
}
void SetPadView(OpenGLCanvas* canvas)
{
m_padView = canvas;
}
void SetGLContext(wxGLContext* context)
{
m_glContext = context;
}
void DeleteGLContext()
{
if (m_tvView == nullptr && m_padView == nullptr && m_glContext)
{
delete m_glContext;
m_glContext = nullptr;
}
}
bool HasPadViewOpen() const
{
return m_padView != nullptr;
}
bool MakeCurrent(bool padView);
void SwapBuffers(bool swapTV, bool swapDRC);
private:
wxGLContext* m_glContext = nullptr;
OpenGLCanvas* m_tvView = nullptr;
OpenGLCanvas* m_padView = nullptr;
} s_glCanvasManager;
class OpenGLCanvas : public IRenderCanvas, public wxGLCanvas
{
@@ -38,13 +91,15 @@ public:
{
if (m_is_main_window)
{
sGLTVView = this;
sGLContext = new wxGLContext(this);
s_glCanvasManager.SetTVView(this);
s_glCanvasManager.SetGLContext(new wxGLContext(this));
g_renderer = std::make_unique<OpenGLRenderer>();
}
else
sGLPadView = this;
{
s_glCanvasManager.SetPadView(this);
}
wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);
}
@@ -54,12 +109,11 @@ public:
// todo - if this is the main window, make sure the renderer has been shut down
if (m_is_main_window)
sGLTVView = nullptr;
s_glCanvasManager.SetTVView(nullptr);
else
sGLPadView = nullptr;
s_glCanvasManager.SetPadView(nullptr);
if (sGLTVView == nullptr && sGLPadView == nullptr && sGLContext)
delete sGLContext;
s_glCanvasManager.DeleteGLContext();
}
void UpdateVSyncState()
@@ -95,34 +149,30 @@ wxWindow* GLCanvas_Create(wxWindow* parent, const wxSize& size, bool is_main_win
return new OpenGLCanvas(parent, size, is_main_window);
}
bool GLCanvas_HasPadViewOpen()
void GLCanvasManager::SwapBuffers(bool swapTV, bool swapDRC)
{
return sGLPadView != nullptr;
if (swapTV && m_tvView)
{
MakeCurrent(false);
m_tvView->SwapBuffers();
m_tvView->UpdateVSyncState();
}
if (swapDRC && m_padView)
{
MakeCurrent(true);
m_padView->SwapBuffers();
m_padView->UpdateVSyncState();
}
MakeCurrent(false);
}
bool GLCanvas_MakeCurrent(bool padView)
bool GLCanvasManager::MakeCurrent(bool padView)
{
OpenGLCanvas* canvas = padView ? sGLPadView : sGLTVView;
OpenGLCanvas* canvas = padView ? m_padView : m_tvView;
if (!canvas)
return false;
sGLContext->SetCurrent(*canvas);
m_glContext->SetCurrent(*canvas);
return true;
}
void GLCanvas_SwapBuffers(bool swapTV, bool swapDRC)
{
if (swapTV && sGLTVView)
{
GLCanvas_MakeCurrent(false);
sGLTVView->SwapBuffers();
sGLTVView->UpdateVSyncState();
}
if (swapDRC && sGLPadView)
{
GLCanvas_MakeCurrent(true);
sGLPadView->SwapBuffers();
sGLPadView->UpdateVSyncState();
}
GLCanvas_MakeCurrent(false);
}
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include <wx/window.h>
wxWindow* GLCanvas_Create(wxWindow* parent, const wxSize& size, bool is_main_window);

View File

@@ -1,9 +1,8 @@
#include "gui/canvas/VulkanCanvas.h"
#include "wxgui/canvas/VulkanCanvas.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
#include "gui/guiWrapper.h"
#if BOOST_OS_LINUX && HAS_WAYLAND
#include "gui/helpers/wxWayland.h"
#include "wxgui/helpers/wxWayland.h"
#endif
#include <wx/msgdlg.h>
@@ -15,10 +14,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 ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;
canvas = initHandleContextFromWxWidgetsWindow(this);
#if BOOST_OS_LINUX && HAS_WAYLAND
if (canvas.backend == WindowHandleInfo::Backend::WAYLAND)
if (canvas.backend == WindowSystem::WindowHandleInfo::Backend::Wayland)
{
m_subsurface = std::make_unique<wxWlSubsurface>(this);
canvas.surface = m_subsurface->getSurface();

View File

@@ -1,6 +1,6 @@
#pragma once
#include "gui/canvas/IRenderCanvas.h"
#include "wxgui/canvas/IRenderCanvas.h"
#include <wx/frame.h>

View File

@@ -1,4 +1,4 @@
#include "gui/wxgui.h"
#include "wxgui/wxgui.h"
#include "TextList.h"
#include <wx/setup.h>
#include <wx/tooltip.h>

View File

@@ -1,10 +1,10 @@
#include "gui/components/wxDownloadManagerList.h"
#include "wxgui/components/wxDownloadManagerList.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/helpers/wxHelpers.h"
#include "util/helpers/SystemException.h"
#include "Cafe/TitleList/GameInfo.h"
#include "gui/components/wxGameList.h"
#include "gui/helpers/wxCustomEvents.h"
#include "wxgui/components/wxGameList.h"
#include "wxgui/helpers/wxCustomEvents.h"
#include <wx/imaglist.h>
#include <wx/wupdlock.h>
@@ -18,10 +18,10 @@
#include <functional>
#include "config/ActiveSettings.h"
#include "gui/ChecksumTool.h"
#include "wxgui/ChecksumTool.h"
#include "Cemu/Tools/DownloadManager/DownloadManager.h"
#include "Cafe/TitleList/TitleId.h"
#include "gui/MainWindow.h"
#include "wxgui/MainWindow.h"
wxDEFINE_EVENT(wxEVT_REMOVE_ENTRY, wxCommandEvent);

View File

@@ -1,6 +1,6 @@
#pragma once
#include "gui/helpers/wxCustomData.h"
#include "wxgui/helpers/wxCustomData.h"
#include "config/CemuConfig.h"
#include <wx/listctrl.h>

View File

@@ -1,8 +1,9 @@
#include "gui/components/wxGameList.h"
#include "wxgui/components/wxGameList.h"
#include "gui/helpers/wxCustomData.h"
#include "wxgui/helpers/wxCustomData.h"
#include "wxCemuConfig.h"
#include "util/helpers/helpers.h"
#include "gui/GameProfileWindow.h"
#include "wxgui/GameProfileWindow.h"
#include <numeric>
@@ -28,9 +29,9 @@
#include "Cafe/TitleList/GameInfo.h"
#include "Cafe/TitleList/TitleList.h"
#include "gui/CemuApp.h"
#include "gui/helpers/wxHelpers.h"
#include "gui/MainWindow.h"
#include "wxgui/CemuApp.h"
#include "wxgui/helpers/wxHelpers.h"
#include "wxgui/MainWindow.h"
#include "../wxHelper.h"
@@ -137,7 +138,7 @@ bool writeICNS(const fs::path& pngPath, const fs::path& icnsPath) {
wxGameList::wxGameList(wxWindow* parent, wxWindowID id)
: wxListView(parent, id, wxDefaultPosition, wxDefaultSize, GetStyleFlags(Style::kList)), m_style(Style::kList)
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0);
if(config.show_icon_column)
@@ -221,7 +222,7 @@ wxGameList::~wxGameList()
void wxGameList::LoadConfig()
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
SetStyle((Style)config.game_list_style, false);
if (!config.game_list_column_order.empty())
@@ -327,7 +328,7 @@ int wxGameList::GetColumnDefaultWidth(int column)
void wxGameList::SaveConfig(bool flush)
{
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
config.game_list_style = (int)m_style;
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
@@ -335,7 +336,7 @@ void wxGameList::SaveConfig(bool flush)
#endif
if (flush)
g_config.Save();
GetConfigHandle().Save();
}
bool wxGameList::IsVisible(long item) const
@@ -426,8 +427,8 @@ void wxGameList::SetStyle(Style style, bool save)
if(save)
{
GetConfig().game_list_style = (int)m_style;
g_config.Save();
GetWxGUIConfig().game_list_style = (int)m_style;
GetConfigHandle().Save();
}
if (style == Style::kList)
@@ -726,7 +727,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event)
const auto custom_name = dialog.GetValue();
GetConfig().SetGameListCustomName(title_id, custom_name.utf8_string());
m_name_cache.clear();
g_config.Save();
GetConfigHandle().Save();
// update list entry
for (int i = 0; i < GetItemCount(); ++i)
{
@@ -906,7 +907,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
const auto menu = dynamic_cast<wxMenu*>(event.GetEventObject());
const int column = dynamic_cast<wxCustomData<int>*>(menu->GetClientObject())->GetData();
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
switch (event.GetId())
{
@@ -980,7 +981,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
}
}
g_config.Save();
GetConfigHandle().Save();
ApplyGameListColumnWidths();
});
@@ -990,7 +991,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event)
void wxGameList::ApplyGameListColumnWidths()
{
const auto& config = GetConfig();
const auto& config = GetWxGUIConfig();
wxWindowUpdateLocker lock(this);
if(config.show_icon_column)
SetColumnWidth(ColumnIcon, kListIconWidth);
@@ -1044,7 +1045,7 @@ void wxGameList::OnColumnResize(wxListEvent& event)
const int column = event.GetColumn();
const int width = GetColumnWidth(column);
auto& config = GetConfig();
auto& config = GetWxGUIConfig();
switch (column)
{
case ColumnName:
@@ -1069,7 +1070,7 @@ void wxGameList::OnColumnResize(wxListEvent& event)
break;
}
g_config.Save();
GetConfigHandle().Save();
AdjustLastColumnWidth();
}

View File

@@ -1,4 +1,4 @@
#include "gui/components/wxInputDraw.h"
#include "wxgui/components/wxInputDraw.h"
#include <wx/dcbuffer.h>

View File

@@ -1,4 +1,4 @@
#include "gui/components/wxLogCtrl.h"
#include "wxgui/components/wxLogCtrl.h"
#include <boost/algorithm/string.hpp>

View File

@@ -1,12 +1,12 @@
#include "gui/components/wxTitleManagerList.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/components/wxTitleManagerList.h"
#include "wxgui/helpers/wxHelpers.h"
#include "util/helpers/SystemException.h"
#include "Cafe/TitleList/GameInfo.h"
#include "Cafe/TitleList/TitleInfo.h"
#include "Cafe/TitleList/TitleList.h"
#include "gui/components/wxGameList.h"
#include "gui/helpers/wxCustomEvents.h"
#include "gui/helpers/wxHelpers.h"
#include "wxgui/components/wxGameList.h"
#include "wxgui/helpers/wxCustomEvents.h"
#include "wxgui/helpers/wxHelpers.h"
#include <wx/imaglist.h>
#include <wx/wupdlock.h>
@@ -22,8 +22,8 @@
#include <functional>
#include "config/ActiveSettings.h"
#include "gui/ChecksumTool.h"
#include "gui/MainWindow.h"
#include "wxgui/ChecksumTool.h"
#include "wxgui/MainWindow.h"
#include "Cafe/TitleList/TitleId.h"
#include "Cafe/TitleList/SaveList.h"
#include "Cafe/TitleList/TitleList.h"

Some files were not shown because too many files have changed in this diff Show More