diff --git a/CMakeLists.txt b/CMakeLists.txt index 9364e52a6..f2f6b183f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,17 @@ option(ENABLE_LTO "Enable link time optimization" ${DEFAULT_ENABLE_LTO}) option(CITRA_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) option(CITRA_WARNINGS_AS_ERRORS "Enable warnings as errors" ON) +# Pass the following values to C++ land +if (ENABLE_QT) + add_definitions(-DENABLE_QT) +endif() +if (ENABLE_QT_TRANSLATION) + add_definitions(-DENABLE_QT_TRANSLATION) +endif() +if (ENABLE_SDL2_FRONTEND) + add_definitions(-DENABLE_SDL2_FRONTEND) +endif() + include(CitraHandleSystemLibs) if (CITRA_USE_PRECOMPILED_HEADERS) @@ -429,24 +440,18 @@ endif() add_subdirectory(src) add_subdirectory(dist/installer) - -# Set citra-qt project or citra project as default StartUp Project in Visual Studio depending on whether QT is enabled or not -if(ENABLE_QT) - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT citra-qt) -else() - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT citra) -endif() +set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT citra) # Create target for outputting distributable bundles. # Not supported for mobile platforms as distributables are built differently. if (NOT ANDROID AND NOT IOS) include(BundleTarget) - if (ENABLE_SDL2_FRONTEND) - bundle_target(citra) - endif() if (ENABLE_QT) - bundle_target(citra-qt) + qt_bundle_target(citra_meta) + elseif (ENABLE_SDL2_FRONTEND) + bundle_target(citra_meta) endif() + if (ENABLE_DEDICATED_ROOM) bundle_target(citra-room) endif() diff --git a/CMakeModules/BundleTarget.cmake b/CMakeModules/BundleTarget.cmake index bac86093d..d3c395237 100644 --- a/CMakeModules/BundleTarget.cmake +++ b/CMakeModules/BundleTarget.cmake @@ -308,21 +308,16 @@ else() # Adds a target to the bundle target, packing in required libraries. # If in_place is true, the bundling will be done in-place as part of the specified target. - function(bundle_target_internal target_name in_place) + function(bundle_target_internal target_name in_place bundle_qt) # Create base bundle target if it does not exist. if (NOT in_place AND NOT TARGET bundle) create_base_bundle_target() endif() set(bundle_executable_path "$") - if (target_name MATCHES ".*qt") - set(bundle_qt ON) - if (APPLE) - # For Qt targets on Apple, expect an app bundle. - set(bundle_executable_path "$") - endif() - else() - set(bundle_qt OFF) + if (bundle_qt AND APPLE) + # For Qt targets on Apple, expect an app bundle. + set(bundle_executable_path "$") endif() # Build a list of library search paths from prefix paths. @@ -364,11 +359,21 @@ else() # Adds a target to the bundle target, packing in required libraries. function(bundle_target target_name) - bundle_target_internal("${target_name}" OFF) + bundle_target_internal("${target_name}" OFF OFF) + endfunction() + + # Same as bundle_target, but also bundles Qt libraries + function(qt_bundle_target target_name) + bundle_target_internal("${target_name}" OFF ON) endfunction() # Bundles the target in-place, packing in required libraries. function(bundle_target_in_place target_name) - bundle_target_internal("${target_name}" ON) + bundle_target_internal("${target_name}" ON OFF) + endfunction() + + # Same as bundle_target_in_place, but also bundles Qt libraries + function(qt_bundle_target_in_place target_name) + bundle_target_internal("${target_name}" ON ON) endfunction() endif() diff --git a/dist/qt_themes/colorful/style.qrc b/dist/qt_themes/colorful/theme_colorful.qrc similarity index 100% rename from dist/qt_themes/colorful/style.qrc rename to dist/qt_themes/colorful/theme_colorful.qrc diff --git a/dist/qt_themes/colorful_dark/style.qrc b/dist/qt_themes/colorful_dark/theme_colorful_dark.qrc similarity index 100% rename from dist/qt_themes/colorful_dark/style.qrc rename to dist/qt_themes/colorful_dark/theme_colorful_dark.qrc diff --git a/dist/qt_themes/colorful_midnight_blue/style.qrc b/dist/qt_themes/colorful_midnight_blue/theme_colorful_midnight_blue.qrc similarity index 100% rename from dist/qt_themes/colorful_midnight_blue/style.qrc rename to dist/qt_themes/colorful_midnight_blue/theme_colorful_midnight_blue.qrc diff --git a/dist/qt_themes/default/default.qrc b/dist/qt_themes/default/theme_default.qrc similarity index 100% rename from dist/qt_themes/default/default.qrc rename to dist/qt_themes/default/theme_default.qrc diff --git a/dist/qt_themes/qdarkstyle/style.qrc b/dist/qt_themes/qdarkstyle/theme_qdarkstyle.qrc similarity index 100% rename from dist/qt_themes/qdarkstyle/style.qrc rename to dist/qt_themes/qdarkstyle/theme_qdarkstyle.qrc diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/theme_qdarkstyle_midnight_blue.qrc similarity index 100% rename from dist/qt_themes/qdarkstyle_midnight_blue/style.qrc rename to dist/qt_themes/qdarkstyle_midnight_blue/theme_qdarkstyle_midnight_blue.qrc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 007b63dcd..477cb1ce6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -180,14 +180,18 @@ if (ENABLE_TESTS) add_subdirectory(tests) endif() -if (ENABLE_SDL2 AND ENABLE_SDL2_FRONTEND) - add_subdirectory(citra) +if (ENABLE_SDL2_FRONTEND) + add_subdirectory(citra_sdl) endif() if (ENABLE_QT) add_subdirectory(citra_qt) endif() +if (ENABLE_QT OR ENABLE_SDL2_FRONTEND) + add_subdirectory(citra_meta) +endif() + if (ENABLE_DEDICATED_ROOM) add_subdirectory(citra_room) endif() diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt deleted file mode 100644 index 42de087c7..000000000 --- a/src/citra/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) - -add_executable(citra - citra.cpp - citra.rc - config.cpp - config.h - default_ini.h - emu_window/emu_window_sdl2.cpp - emu_window/emu_window_sdl2.h - precompiled_headers.h - resource.h -) - -if (ENABLE_SOFTWARE_RENDERER) - target_sources(citra PRIVATE - emu_window/emu_window_sdl2_sw.cpp - emu_window/emu_window_sdl2_sw.h - ) -endif() -if (ENABLE_OPENGL) - target_sources(citra PRIVATE - emu_window/emu_window_sdl2_gl.cpp - emu_window/emu_window_sdl2_gl.h - ) -endif() -if (ENABLE_VULKAN) - target_sources(citra PRIVATE - emu_window/emu_window_sdl2_vk.cpp - emu_window/emu_window_sdl2_vk.h - ) -endif() - -create_target_directory_groups(citra) - -target_link_libraries(citra PRIVATE citra_common citra_core input_common network) -target_link_libraries(citra PRIVATE inih) -if (MSVC) - target_link_libraries(citra PRIVATE getopt) -endif() -target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2::SDL2 Threads::Threads) - -if (ENABLE_OPENGL) - target_link_libraries(citra PRIVATE glad) -endif() - -if(UNIX AND NOT APPLE) - install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") -endif() - -if (CITRA_USE_PRECOMPILED_HEADERS) - target_precompile_headers(citra PRIVATE precompiled_headers.h) -endif() - -# Bundle in-place on MSVC so dependencies can be resolved by builds. -if (MSVC) - include(BundleTarget) - bundle_target_in_place(citra) -endif() diff --git a/src/citra/citra.rc b/src/citra/citra.rc deleted file mode 100644 index 2c6bcd589..000000000 --- a/src/citra/citra.rc +++ /dev/null @@ -1,17 +0,0 @@ -#include "winresrc.h" -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -CITRA_ICON ICON "../../dist/citra.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -0 RT_MANIFEST "../../dist/citra.manifest" diff --git a/src/citra_meta/CMakeLists.txt b/src/citra_meta/CMakeLists.txt new file mode 100644 index 000000000..ee990b5b7 --- /dev/null +++ b/src/citra_meta/CMakeLists.txt @@ -0,0 +1,79 @@ +add_executable(citra_meta + citra.rc + main.cpp +) + +set_target_properties(citra_meta PROPERTIES OUTPUT_NAME "citra") + +if (APPLE) + set(DIST_DIR "../../dist/apple") + set(APPLE_RESOURCES + "${DIST_DIR}/citra.icns" + "${DIST_DIR}/LaunchScreen.storyboard" + "${DIST_DIR}/launch_logo.png" + ) + target_sources(citra_meta PRIVATE ${APPLE_RESOURCES}) + + # Define app bundle metadata. + include(GenerateBuildInfo) + set_target_properties(citra_meta PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST "${DIST_DIR}/Info.plist.in" + MACOSX_BUNDLE_BUNDLE_NAME "Citra" + MACOSX_BUNDLE_GUI_IDENTIFIER "com.citra-emu.citra" + MACOSX_BUNDLE_BUNDLE_VERSION "${BUILD_VERSION}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${BUILD_FULLNAME}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${BUILD_FULLNAME}" + MACOSX_BUNDLE_ICON_FILE "citra.icns" + RESOURCE "${APPLE_RESOURCES}" + ) + + if (IOS) + set_target_properties(citra_meta PROPERTIES + # Have Xcode copy and sign MoltenVK into app bundle. + XCODE_EMBED_FRAMEWORKS "${MOLTENVK_LIBRARY}" + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY YES + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" + # Support iPhone and iPad. + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + ) + endif() +endif() + +target_link_libraries(citra_meta PRIVATE fmt) + +if (ENABLE_SDL2_FRONTEND) + target_link_libraries(citra_meta PRIVATE citra_sdl) +endif() + +if (ENABLE_QT) + target_link_libraries(citra_meta PRIVATE citra_qt) + target_link_libraries(citra_meta PRIVATE Boost::boost Qt6::Widgets) +endif() + +if (ENABLE_QT AND UNIX AND NOT APPLE) + target_link_libraries(citra_meta PRIVATE Qt6::DBus gamemode) +endif() + +if (ENABLE_QT AND USE_DISCORD_PRESENCE) + target_link_libraries(citra_meta PRIVATE discord-rpc) +endif() + +if(WIN32) + # compile as a win32 gui application instead of a console application + if(MSVC) + set_target_properties(citra_meta PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") + elseif(MINGW) + set_target_properties(citra_meta PROPERTIES LINK_FLAGS_RELEASE "-mwindows") + endif() +endif() + +# Bundle in-place on MSVC so dependencies can be resolved by builds. +if (ENABLE_QT AND MSVC) + include(BundleTarget) + qt_bundle_target_in_place(citra_meta) +endif() + +if(UNIX AND NOT APPLE) + install(TARGETS citra_meta RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") +endif() diff --git a/src/citra_qt/citra-qt.rc b/src/citra_meta/citra.rc similarity index 100% rename from src/citra_qt/citra-qt.rc rename to src/citra_meta/citra.rc diff --git a/src/citra_meta/common_strings.h b/src/citra_meta/common_strings.h new file mode 100644 index 000000000..9fa12200a --- /dev/null +++ b/src/citra_meta/common_strings.h @@ -0,0 +1,29 @@ +// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace Common { + +constexpr char help_string[] = + "Usage: {} [options] \n" + "-d, --dump-video [path] Dump video recording of emulator playback to the given file path\n" + "-f, --fullscreen Start in fullscreen mode\n" + "-g, --gdbport [port] Enable gdb stub on the given port\n" + "-h, --help Display this help and exit\n" + "-i, --install [path] Install a CIA file at the given path\n" + "-p, --movie-play [path] Play a TAS movie located at the given path\n" + "-r, --movie-record [path] Record a TAS movie to the given file path\n" + "-a, --movie-record-author [author] Set the author for the recorded TAS movie (to be used " + "alongside --movie-record)\n" + "-n, --no-gui Use the lightweight SDL frontend instead of the usual Qt " + "frontend\n" + "-m, --multiplayer [nick:password@address:port] Nickname, password, address and port for " + "multiplayer\n" + "-v, --version Output version information and exit\n" + "-w, --windowed Start in windowed mode"; + +} diff --git a/src/citra_meta/main.cpp b/src/citra_meta/main.cpp new file mode 100644 index 000000000..b43ca0566 --- /dev/null +++ b/src/citra_meta/main.cpp @@ -0,0 +1,45 @@ +// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#ifdef ENABLE_QT +#include "citra_qt/citra_qt.h" +#endif +#ifdef ENABLE_SDL2_FRONTEND +#include "citra_sdl/citra_sdl.h" +#endif + +#ifdef _WIN32 +extern "C" { +// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics +__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; +} +#endif + +int main(int argc, char* argv[]) { +#if ENABLE_QT + bool no_gui = false; + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--no-gui") == 0 || strcmp(argv[i], "-n") == 0) { + no_gui = true; + } + } + + if (!no_gui) { + LaunchQtFrontend(argc, argv); + return 0; + } +#endif + +#if ENABLE_SDL2_FRONTEND + LaunchSdlFrontend(argc, argv); +#else + std::cout << "Cannot use SDL frontend as it was excluded at compile time. Exiting." + << std::endl; + return -1; +#endif + + return 0; +} \ No newline at end of file diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 8213a9e0f..ca07b213e 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -7,7 +7,7 @@ if (POLICY CMP0071) cmake_policy(SET CMP0071 NEW) endif() -add_executable(citra-qt +add_library(citra_qt STATIC EXCLUDE_FROM_ALL aboutdialog.cpp aboutdialog.h aboutdialog.ui @@ -27,10 +27,8 @@ add_executable(citra-qt camera/qt_camera_base.h camera/qt_multimedia_camera.cpp camera/qt_multimedia_camera.h - citra-qt.rc - compatdb.cpp - compatdb.h - compatdb.ui + citra_qt.cpp + citra_qt.h configuration/config.cpp configuration/config.h configuration/configure.ui @@ -142,8 +140,6 @@ add_executable(citra-qt loading_screen.cpp loading_screen.h loading_screen.ui - main.cpp - main.h main.ui movie/movie_play_dialog.cpp movie/movie_play_dialog.h @@ -201,12 +197,12 @@ file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*) file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*) if (ENABLE_QT_UPDATER) - target_sources(citra-qt PRIVATE + target_sources(citra_qt PRIVATE updater/updater.cpp updater/updater.h updater/updater_p.h ) - target_compile_definitions(citra-qt PUBLIC ENABLE_QT_UPDATER) + target_compile_definitions(citra_qt PUBLIC ENABLE_QT_UPDATER) endif() if (ENABLE_QT_TRANSLATION) @@ -215,13 +211,13 @@ if (ENABLE_QT_TRANSLATION) # Update source TS file if enabled if (GENERATE_QT_TRANSLATION) - get_target_property(QT_SRCS citra-qt SOURCES) - get_target_property(QT_INCLUDES citra-qt INCLUDE_DIRECTORIES) - qt_add_lupdate(citra-qt TS_FILES ${CITRA_QT_LANGUAGES}/en.ts + get_target_property(QT_SRCS citra_qt SOURCES) + get_target_property(QT_INCLUDES citra_qt INCLUDE_DIRECTORIES) + qt_add_lupdate(citra_qt TS_FILES ${CITRA_QT_LANGUAGES}/en.ts SOURCES ${QT_SRCS} ${UIS} INCLUDE_DIRECTORIES ${QT_INCLUDES} NO_GLOBAL_TARGET) - add_custom_target(translation ALL DEPENDS citra-qt_lupdate) + add_custom_target(translation ALL DEPENDS citra_qt_lupdate) endif() # Find all TS files except en.ts @@ -229,7 +225,7 @@ if (ENABLE_QT_TRANSLATION) list(REMOVE_ITEM LANGUAGES_TS ${CITRA_QT_LANGUAGES}/en.ts) # Compile TS files to QM files - qt_add_lrelease(citra-qt TS_FILES ${LANGUAGES_TS} NO_GLOBAL_TARGET QM_FILES_OUTPUT_VARIABLE LANGUAGES_QM) + qt_add_lrelease(citra_qt TS_FILES ${LANGUAGES_TS} NO_GLOBAL_TARGET QM_FILES_OUTPUT_VARIABLE LANGUAGES_QM) # Build a QRC file from the QM file list set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) @@ -246,7 +242,7 @@ else() set(LANGUAGES) endif() -target_sources(citra-qt +target_sources(citra_qt PRIVATE ${COMPAT_LIST} ${ICONS} @@ -254,77 +250,38 @@ target_sources(citra-qt ${THEMES} ) -if (APPLE) - set(DIST_DIR "../../dist/apple") - set(APPLE_RESOURCES - "${DIST_DIR}/citra.icns" - "${DIST_DIR}/LaunchScreen.storyboard" - "${DIST_DIR}/launch_logo.png" - ) - target_sources(citra-qt PRIVATE ${APPLE_RESOURCES}) - - # Define app bundle metadata. - include(GenerateBuildInfo) - set_target_properties(citra-qt PROPERTIES - MACOSX_BUNDLE TRUE - MACOSX_BUNDLE_INFO_PLIST "${DIST_DIR}/Info.plist.in" - MACOSX_BUNDLE_BUNDLE_NAME "Citra" - MACOSX_BUNDLE_GUI_IDENTIFIER "com.citra-emu.citra" - MACOSX_BUNDLE_BUNDLE_VERSION "${BUILD_VERSION}" - MACOSX_BUNDLE_SHORT_VERSION_STRING "${BUILD_FULLNAME}" - MACOSX_BUNDLE_LONG_VERSION_STRING "${BUILD_FULLNAME}" - MACOSX_BUNDLE_ICON_FILE "citra.icns" - RESOURCE "${APPLE_RESOURCES}" - ) - - if (IOS) - set_target_properties(citra-qt PROPERTIES - # Have Xcode copy and sign MoltenVK into app bundle. - XCODE_EMBED_FRAMEWORKS "${MOLTENVK_LIBRARY}" - XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY YES - XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" - # Support iPhone and iPad. - XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" - ) - endif() -elseif(WIN32) - # compile as a win32 gui application instead of a console application - target_link_libraries(citra-qt PRIVATE Qt6::EntryPointImplementation) - if(MSVC) - set_target_properties(citra-qt PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") - elseif(MINGW) - set_target_properties(citra-qt PROPERTIES LINK_FLAGS_RELEASE "-mwindows") - endif() +if (WIN32) + target_link_libraries(citra_qt PRIVATE Qt6::EntryPointImplementation) endif() if(ENABLE_SDL2) - target_link_libraries(citra-qt PRIVATE SDL2::SDL2) - target_compile_definitions(citra-qt PRIVATE HAVE_SDL2) + target_link_libraries(citra_qt PRIVATE SDL2::SDL2) + target_compile_definitions(citra_qt PRIVATE HAVE_SDL2) endif() -create_target_directory_groups(citra-qt) +create_target_directory_groups(citra_qt) -target_link_libraries(citra-qt PRIVATE audio_core citra_common citra_core input_common network video_core) -target_link_libraries(citra-qt PRIVATE Boost::boost nihstro-headers Qt6::Widgets Qt6::Multimedia Qt6::Concurrent) -target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) +target_link_libraries(citra_qt PRIVATE audio_core citra_common citra_core input_common network video_core) +target_link_libraries(citra_qt PRIVATE Boost::boost nihstro-headers Qt6::Widgets Qt6::Multimedia Qt6::Concurrent) +target_link_libraries(citra_qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if (ENABLE_OPENGL) - target_link_libraries(citra-qt PRIVATE glad) + target_link_libraries(citra_qt PRIVATE glad) endif() if (ENABLE_VULKAN) - target_link_libraries(citra-qt PRIVATE vulkan-headers) + target_link_libraries(citra_qt PRIVATE vulkan-headers) endif() if (NOT WIN32) - target_include_directories(citra-qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) + target_include_directories(citra_qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() if (UNIX AND NOT APPLE) - target_link_libraries(citra-qt PRIVATE Qt6::DBus gamemode) + target_link_libraries(citra_qt PRIVATE Qt6::DBus gamemode) endif() -target_compile_definitions(citra-qt PRIVATE +target_compile_definitions(citra_qt PRIVATE # Use QStringBuilder for string concatenation to reduce # the overall number of temporary strings created. -DQT_USE_QSTRINGBUILDER @@ -344,28 +301,18 @@ target_compile_definitions(citra-qt PRIVATE ) if (USE_DISCORD_PRESENCE) - target_sources(citra-qt PUBLIC + target_sources(citra_qt PUBLIC discord_impl.cpp discord_impl.h ) - target_link_libraries(citra-qt PRIVATE discord-rpc) - target_compile_definitions(citra-qt PRIVATE -DUSE_DISCORD_PRESENCE) + target_link_libraries(citra_qt PRIVATE discord-rpc) + target_compile_definitions(citra_qt PRIVATE -DUSE_DISCORD_PRESENCE) endif() if (ENABLE_WEB_SERVICE) - target_link_libraries(citra-qt PRIVATE web_service) -endif() - -if(UNIX AND NOT APPLE) - install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") + target_link_libraries(citra_qt PRIVATE web_service) endif() if (CITRA_USE_PRECOMPILED_HEADERS) - target_precompile_headers(citra-qt PRIVATE precompiled_headers.h) -endif() - -# Bundle in-place on MSVC so dependencies can be resolved by builds. -if (MSVC) - include(BundleTarget) - bundle_target_in_place(citra-qt) + target_precompile_headers(citra_qt PRIVATE precompiled_headers.h) endif() diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 8f63f6713..fcab2be0b 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -9,7 +9,7 @@ #include #include #include "citra_qt/bootmanager.h" -#include "citra_qt/main.h" +#include "citra_qt/citra_qt.h" #include "common/color.h" #include "common/microprofile.h" #include "common/scm_rev.h" diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp index 47b9f0f26..f96829b4b 100644 --- a/src/citra_qt/camera/qt_multimedia_camera.cpp +++ b/src/citra_qt/camera/qt_multimedia_camera.cpp @@ -7,7 +7,7 @@ #include #include #include "citra_qt/camera/qt_multimedia_camera.h" -#include "citra_qt/main.h" +#include "citra_qt/citra_qt.h" #if defined(__APPLE__) #include "common/apple_authorization.h" diff --git a/src/citra_qt/main.cpp b/src/citra_qt/citra_qt.cpp similarity index 98% rename from src/citra_qt/main.cpp rename to src/citra_qt/citra_qt.cpp index d939c584d..2cb409c88 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/citra_qt.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #else -#include #include #endif #ifdef __unix__ @@ -33,13 +33,13 @@ #include #include "common/linux/gamemode.h" #endif +#include "citra_meta/common_strings.h" #include "citra_qt/aboutdialog.h" #include "citra_qt/applets/mii_selector.h" #include "citra_qt/applets/swkbd.h" #include "citra_qt/bootmanager.h" #include "citra_qt/camera/qt_multimedia_camera.h" #include "citra_qt/camera/still_image_camera.h" -#include "citra_qt/compatdb.h" #include "citra_qt/compatibility_list.h" #include "citra_qt/configuration/config.h" #include "citra_qt/configuration/configure_dialog.h" @@ -61,7 +61,7 @@ #include "citra_qt/game_list.h" #include "citra_qt/hotkeys.h" #include "citra_qt/loading_screen.h" -#include "citra_qt/main.h" +#include "citra_qt/citra_qt.h" #include "citra_qt/movie/movie_play_dialog.h" #include "citra_qt/movie/movie_record_dialog.h" #include "citra_qt/multiplayer/state.h" @@ -118,13 +118,6 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #endif -#ifdef _WIN32 -extern "C" { -// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics -__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -} -#endif - #ifdef HAVE_SDL2 #include #endif @@ -171,7 +164,7 @@ void GMainWindow::ShowCommandOutput(std::string title, std::string message) { GMainWindow::GMainWindow(Core::System& system_) : ui{std::make_unique()}, system{system_}, movie{system.Movie()}, - config{std::make_unique()}, emu_thread{nullptr} { + config{std::make_unique()}, emu_thread{nullptr} { Common::Log::Initialize(); Common::Log::Start(); @@ -188,7 +181,7 @@ GMainWindow::GMainWindow(Core::System& system_) } // Dump video - if (args[i] == QStringLiteral("-d")) { + if (args[i] == QStringLiteral("--dump-video") || args[i] == QStringLiteral("-d")) { if (i >= args.size() - 1 || args[i + 1].startsWith(QChar::fromLatin1('-'))) { continue; } @@ -202,13 +195,13 @@ GMainWindow::GMainWindow(Core::System& system_) } // Launch game in fullscreen mode - if (args[i] == QStringLiteral("-f")) { + if (args[i] == QStringLiteral("--fullscreen") || args[i] == QStringLiteral("-f")) { fullscreen_override = true; continue; } // Enable GDB stub - if (args[i] == QStringLiteral("-g")) { + if (args[i] == QStringLiteral("--gdbport") || args[i] == QStringLiteral("-g")) { if (i >= args.size() - 1 || args[i + 1].startsWith(QChar::fromLatin1('-'))) { continue; } @@ -217,24 +210,12 @@ GMainWindow::GMainWindow(Core::System& system_) continue; } - if (args[i] == QStringLiteral("-h")) { - const std::string help_string = - std::string("Usage: ") + args[0].toStdString() + - " [options] \n" - "-d [path] Dump video recording of emulator playback to the given file path\n" - "-g [port] Enable gdb stub on the given port\n" - "-f Start in fullscreen mode\n" - "-h Display this help and exit\n" - "-i [path] Install a CIA file at the given path\n" - "-p [path] Play a TAS movie located at the given path\n" - "-r [path] Record a TAS movie to the given file path\n" - "-v Output version information and exit"; - - ShowCommandOutput("Help", help_string); + if (args[i] == QStringLiteral("--help") || args[i] == QStringLiteral("-h")) { + ShowCommandOutput("Help", fmt::format(Common::help_string, args[0].toStdString())); exit(0); } - if (args[i] == QStringLiteral("-i")) { + if (args[i] == QStringLiteral("--install") || args[i] == QStringLiteral("-i")) { if (i >= args.size() - 1 || args[i + 1].startsWith(QChar::fromLatin1('-'))) { continue; } @@ -267,7 +248,7 @@ GMainWindow::GMainWindow(Core::System& system_) exit(0); } - if (args[i] == QStringLiteral("-p")) { + if (args[i] == QStringLiteral("--movie-play") || args[i] == QStringLiteral("-p")) { if (i >= args.size() - 1 || args[i + 1].startsWith(QChar::fromLatin1('-'))) { continue; } @@ -276,7 +257,7 @@ GMainWindow::GMainWindow(Core::System& system_) continue; } - if (args[i] == QStringLiteral("-r")) { + if (args[i] == QStringLiteral("--movie-record") || args[i] == QStringLiteral("-r")) { if (i >= args.size() - 1 || args[i + 1].startsWith(QChar::fromLatin1('-'))) { continue; } @@ -285,7 +266,25 @@ GMainWindow::GMainWindow(Core::System& system_) continue; } - if (args[i] == QStringLiteral("-v")) { + if (args[i] == QStringLiteral("--movie-record-author") || args[i] == QStringLiteral("-a")) { + if (i >= args.size() - 1 || args[i + 1].startsWith(QChar::fromLatin1('-'))) { + continue; + } + movie_record_author = args[++i]; + continue; + } + + if (args[i] == QStringLiteral("--multiplayer") || args[i] == QStringLiteral("-m")) { + std::cout << "Warning: The --multiplayer option is not yet implemented for the Qt " + "frontend; Ignoring." + << std::endl; + if (i < args.size() - 1 && !args[i + 1].startsWith(QChar::fromLatin1('-'))) { + i++; + } + continue; + } + + if (args[i] == QStringLiteral("--version") || args[i] == QStringLiteral("-v")) { const std::string version_string = std::string("Lime3DS ") + Common::g_scm_branch + " " + Common::g_scm_desc; ShowCommandOutput("Version", version_string); @@ -293,7 +292,7 @@ GMainWindow::GMainWindow(Core::System& system_) } // Launch game in windowed mode - if (args[i] == QStringLiteral("-w")) { + if (args[i] == QStringLiteral("--windowed") || args[i] == QStringLiteral("-w")) { fullscreen_override = false; continue; } @@ -1410,7 +1409,7 @@ void GMainWindow::BootGame(const QString& filename) { const std::string config_file_name = title_id == 0 ? name : fmt::format("{:016X}", title_id); LOG_INFO(Frontend, "Loading per game config file for title {}", config_file_name); - Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); + QtConfig per_game_config(config_file_name, QtConfig::ConfigType::PerGameConfig); } // Artic Base Server cannot accept a client multiple times, so multiple loaders are not @@ -2403,14 +2402,7 @@ void GMainWindow::OnLoadComplete() { } void GMainWindow::OnMenuReportCompatibility() { - if (!NetSettings::values.citra_token.empty() && !NetSettings::values.citra_username.empty()) { - CompatDB compatdb{this}; - compatdb.exec(); - } else { - QMessageBox::critical(this, tr("Missing Citra Account"), - tr("You must link your Citra account to submit test cases." - "
Go to Emulation > Configure... > Web to do so.")); - } + // NoOp } void GMainWindow::ToggleFullscreen() { @@ -3685,7 +3677,7 @@ static Qt::HighDpiScaleFactorRoundingPolicy GetHighDpiRoundingPolicy() { #endif } -int main(int argc, char* argv[]) { +void LaunchQtFrontend(int argc, char* argv[]) { Common::DetachedTasks detached_tasks; MicroProfileOnThreadCreate("Frontend"); SCOPE_EXIT({ MicroProfileShutdown(); }); @@ -3711,6 +3703,19 @@ int main(int argc, char* argv[]) { QApplication app(argc, argv); + // Required when using .qrc resources from within a static library. + // See https://doc.qt.io/qt-5/resources.html#using-resources-in-a-library + Q_INIT_RESOURCE(compatibility_list); + Q_INIT_RESOURCE(theme_colorful); + Q_INIT_RESOURCE(theme_colorful_dark); + Q_INIT_RESOURCE(theme_colorful_midnight_blue); + Q_INIT_RESOURCE(theme_default); + Q_INIT_RESOURCE(theme_qdarkstyle); + Q_INIT_RESOURCE(theme_qdarkstyle_midnight_blue); +#ifdef ENABLE_QT_TRANSLATION + Q_INIT_RESOURCE(languages); +#endif + // Qt changes the locale and causes issues in float conversion using std::to_string() when // generating shaders setlocale(LC_ALL, "C"); @@ -3740,5 +3745,5 @@ int main(int argc, char* argv[]) { int result = app.exec(); detached_tasks.WaitForAllTasks(); - return result; + exit(result); } diff --git a/src/citra_qt/main.h b/src/citra_qt/citra_qt.h similarity index 99% rename from src/citra_qt/main.h rename to src/citra_qt/citra_qt.h index 040ca6407..1d95c5603 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/citra_qt.h @@ -25,7 +25,7 @@ #include class AboutDialog; -class Config; +class QtConfig; class ClickableLabel; class EmuThread; class GameList; @@ -86,6 +86,8 @@ namespace Service::FS { enum class MediaType : u32; } +void LaunchQtFrontend(int argc, char* argv[]); + class GMainWindow : public QMainWindow { Q_OBJECT @@ -346,7 +348,7 @@ private: bool message_label_used_for_movie = false; MultiplayerState* multiplayer_state = nullptr; - std::unique_ptr config; + std::unique_ptr config; // Whether emulation is currently running in Citra. bool emulation_running = false; diff --git a/src/citra_qt/compatdb.cpp b/src/citra_qt/compatdb.cpp deleted file mode 100644 index 62066b6ff..000000000 --- a/src/citra_qt/compatdb.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include "citra_qt/compatdb.h" -#include "core/core.h" -#include "ui_compatdb.h" - -CompatDB::CompatDB(QWidget* parent) - : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), - ui{std::make_unique()} { - ui->setupUi(this); - connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Okay, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_Bad, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); - connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); - connect(&testcase_watcher, &QFutureWatcher::finished, this, - &CompatDB::OnTestcaseSubmitted); -} - -CompatDB::~CompatDB() = default; - -enum class CompatDBPage { - Intro = 0, - Selection = 1, - Final = 2, -}; - -void CompatDB::Submit() { - QButtonGroup* compatibility = new QButtonGroup(this); - compatibility->addButton(ui->radioButton_Perfect, 0); - compatibility->addButton(ui->radioButton_Great, 1); - compatibility->addButton(ui->radioButton_Okay, 2); - compatibility->addButton(ui->radioButton_Bad, 3); - compatibility->addButton(ui->radioButton_IntroMenu, 4); - compatibility->addButton(ui->radioButton_WontBoot, 5); - switch ((static_cast(currentId()))) { - case CompatDBPage::Selection: - if (compatibility->checkedId() == -1) { - button(NextButton)->setEnabled(false); - } - break; - case CompatDBPage::Final: - back(); - LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); - - button(NextButton)->setEnabled(false); - button(NextButton)->setText(tr("Submitting")); - button(CancelButton)->setVisible(false); - - break; - default: - LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); - } -} - -void CompatDB::OnTestcaseSubmitted() { - if (!testcase_watcher.result()) { - QMessageBox::critical(this, tr("Communication error"), - tr("An error occurred while sending the Testcase")); - button(NextButton)->setEnabled(true); - button(NextButton)->setText(tr("Next")); - button(CancelButton)->setVisible(true); - } else { - next(); - // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a - // workaround - button(CancelButton)->setVisible(false); - } -} - -void CompatDB::EnableNext() { - button(NextButton)->setEnabled(true); -} diff --git a/src/citra_qt/compatdb.h b/src/citra_qt/compatdb.h deleted file mode 100644 index 5381f67f7..000000000 --- a/src/citra_qt/compatdb.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -namespace Ui { -class CompatDB; -} - -class CompatDB : public QWizard { - Q_OBJECT - -public: - explicit CompatDB(QWidget* parent = nullptr); - ~CompatDB(); - -private: - QFutureWatcher testcase_watcher; - - std::unique_ptr ui; - - void Submit(); - void OnTestcaseSubmitted(); - void EnableNext(); -}; diff --git a/src/citra_qt/compatdb.ui b/src/citra_qt/compatdb.ui deleted file mode 100644 index 33519814c..000000000 --- a/src/citra_qt/compatdb.ui +++ /dev/null @@ -1,215 +0,0 @@ - - - CompatDB - - - - 0 - 0 - 600 - 482 - - - - - 500 - 410 - - - - Report Compatibility - - - QWizard::DisabledBackButtonOnLastPage|QWizard::HelpButtonOnRight|QWizard::NoBackButtonOnStartPage - - - - Report Game Compatibility - - - 0 - - - - - - <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Citra Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of Citra you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected Citra account</li></ul></body></html> - - - true - - - true - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - Report Game Compatibility - - - 1 - - - - - - Perfect - - - - - - - <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> - - - true - - - - - - - Great - - - - - - - <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> - - - true - - - - - - - Okay - - - - - - - <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> - - - true - - - - - - - Bad - - - - - - - <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> - - - true - - - - - - - Intro/Menu - - - - - - - <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> - - - true - - - - - - - Won't Boot - - - true - - - false - - - - - - - <html><head/><body><p>The game crashes when attempting to startup.</p></body></html> - - - - - - - - 10 - - - - <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of Citra?</p></body></html> - - - true - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - Thank you for your submission! - - - 2 - - - - - - diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index b5ca2f2c1..85e23e50e 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -15,24 +15,24 @@ #include "network/network.h" #include "network/network_settings.h" -Config::Config(const std::string& config_name, ConfigType config_type) : type{config_type} { +QtConfig::QtConfig(const std::string& config_name, ConfigType config_type) : type{config_type} { global = config_type == ConfigType::GlobalConfig; Initialize(config_name); } -Config::~Config() { +QtConfig::~QtConfig() { if (global) { Save(); } } -const std::array Config::default_buttons = { +const std::array QtConfig::default_buttons = { Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N, Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V, }; -const std::array, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ +const std::array, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{ { Qt::Key_Up, Qt::Key_Down, @@ -54,7 +54,7 @@ const std::array, Settings::NativeAnalog::NumAnalogs> Config: // This must be in alphabetical order according to action name as it must have the same order as // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off -const std::array Config::default_hotkeys {{ +const std::array QtConfig::default_hotkeys {{ {QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), Qt::WindowShortcut}}, {QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral(""), Qt::WindowShortcut}}, @@ -93,7 +93,7 @@ const std::array Config::default_hotkeys {{ }}; // clang-format on -void Config::Initialize(const std::string& config_name) { +void QtConfig::Initialize(const std::string& config_name) { const std::string fs_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir); const std::string config_file = fmt::format("{}.ini", config_name); @@ -120,7 +120,7 @@ void Config::Initialize(const std::string& config_name) { // Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant, nor // can it implicitly convert a QVariant back to a {std::,Q}string template <> -void Config::ReadBasicSetting(Settings::Setting& setting) { +void QtConfig::ReadBasicSetting(Settings::Setting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const auto default_value = QString::fromStdString(setting.GetDefault()); if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { @@ -131,7 +131,7 @@ void Config::ReadBasicSetting(Settings::Setting& setting) { } template -void Config::ReadBasicSetting(Settings::Setting& setting) { +void QtConfig::ReadBasicSetting(Settings::Setting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const Type default_value = setting.GetDefault(); if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { @@ -150,7 +150,7 @@ void Config::ReadBasicSetting(Settings::Setting& setting) { } template -void Config::ReadGlobalSetting(Settings::SwitchableSetting& setting) { +void QtConfig::ReadGlobalSetting(Settings::SwitchableSetting& setting) { QString name = QString::fromStdString(setting.GetLabel()); const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); setting.SetGlobal(use_global); @@ -168,7 +168,7 @@ void Config::ReadGlobalSetting(Settings::SwitchableSetting& settin } template <> -void Config::ReadGlobalSetting(Settings::SwitchableSetting& setting) { +void QtConfig::ReadGlobalSetting(Settings::SwitchableSetting& setting) { QString name = QString::fromStdString(setting.GetLabel()); const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool(); setting.SetGlobal(use_global); @@ -181,7 +181,7 @@ void Config::ReadGlobalSetting(Settings::SwitchableSetting& setting // Explicit std::string definition: Qt can't implicitly convert a std::string to a QVariant template <> -void Config::WriteBasicSetting(const Settings::Setting& setting) { +void QtConfig::WriteBasicSetting(const Settings::Setting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const std::string& value = setting.GetValue(); qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault()); @@ -190,7 +190,7 @@ void Config::WriteBasicSetting(const Settings::Setting& setting) { // Explicit u16 definition: Qt would store it as QMetaType otherwise, which is not human-readable template <> -void Config::WriteBasicSetting(const Settings::Setting& setting) { +void QtConfig::WriteBasicSetting(const Settings::Setting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const u16& value = setting.GetValue(); qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault()); @@ -198,7 +198,7 @@ void Config::WriteBasicSetting(const Settings::Setting& setting) { } template -void Config::WriteBasicSetting(const Settings::Setting& setting) { +void QtConfig::WriteBasicSetting(const Settings::Setting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const Type value = setting.GetValue(); qt_config->setValue(name + QStringLiteral("/default"), value == setting.GetDefault()); @@ -210,7 +210,7 @@ void Config::WriteBasicSetting(const Settings::Setting& setting) { } template -void Config::WriteGlobalSetting(const Settings::SwitchableSetting& setting) { +void QtConfig::WriteGlobalSetting(const Settings::SwitchableSetting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const Type& value = setting.GetValue(global); if (!global) { @@ -227,7 +227,7 @@ void Config::WriteGlobalSetting(const Settings::SwitchableSetting& } template <> -void Config::WriteGlobalSetting(const Settings::SwitchableSetting& setting) { +void QtConfig::WriteGlobalSetting(const Settings::SwitchableSetting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const std::string& value = setting.GetValue(global); if (!global) { @@ -241,7 +241,7 @@ void Config::WriteGlobalSetting(const Settings::SwitchableSetting& // Explicit u16 definition: Qt would store it as QMetaType otherwise, which is not human-readable template <> -void Config::WriteGlobalSetting(const Settings::SwitchableSetting& setting) { +void QtConfig::WriteGlobalSetting(const Settings::SwitchableSetting& setting) { const QString name = QString::fromStdString(setting.GetLabel()); const u16& value = setting.GetValue(global); if (!global) { @@ -253,7 +253,7 @@ void Config::WriteGlobalSetting(const Settings::SwitchableSetting& se } } -void Config::ReadValues() { +void QtConfig::ReadValues() { if (global) { ReadControlValues(); ReadCameraValues(); @@ -273,7 +273,7 @@ void Config::ReadValues() { ReadUtilityValues(); } -void Config::ReadAudioValues() { +void QtConfig::ReadAudioValues() { qt_config->beginGroup(QStringLiteral("Audio")); ReadGlobalSetting(Settings::values.audio_emulation); @@ -291,7 +291,7 @@ void Config::ReadAudioValues() { qt_config->endGroup(); } -void Config::ReadCameraValues() { +void QtConfig::ReadCameraValues() { using namespace Service::CAM; qt_config->beginGroup(QStringLiteral("Camera")); @@ -325,7 +325,7 @@ void Config::ReadCameraValues() { qt_config->endGroup(); } -void Config::ReadControlValues() { +void QtConfig::ReadControlValues() { qt_config->beginGroup(QStringLiteral("Controls")); ReadBasicSetting(Settings::values.use_artic_base_controller); @@ -442,7 +442,7 @@ void Config::ReadControlValues() { qt_config->endGroup(); } -void Config::ReadUtilityValues() { +void QtConfig::ReadUtilityValues() { qt_config->beginGroup(QStringLiteral("Utility")); ReadGlobalSetting(Settings::values.dump_textures); @@ -453,7 +453,7 @@ void Config::ReadUtilityValues() { qt_config->endGroup(); } -void Config::ReadCoreValues() { +void QtConfig::ReadCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); ReadGlobalSetting(Settings::values.cpu_clock_percentage); @@ -466,7 +466,7 @@ void Config::ReadCoreValues() { qt_config->endGroup(); } -void Config::ReadDataStorageValues() { +void QtConfig::ReadDataStorageValues() { qt_config->beginGroup(QStringLiteral("Data Storage")); ReadBasicSetting(Settings::values.use_virtual_sd); @@ -485,7 +485,7 @@ void Config::ReadDataStorageValues() { qt_config->endGroup(); } -void Config::ReadDebuggingValues() { +void QtConfig::ReadDebuggingValues() { qt_config->beginGroup(QStringLiteral("Debugging")); // Intentionally not using the QT default setting as this is intended to be changed in the ini @@ -506,7 +506,7 @@ void Config::ReadDebuggingValues() { qt_config->endGroup(); } -void Config::ReadLayoutValues() { +void QtConfig::ReadLayoutValues() { qt_config->beginGroup(QStringLiteral("Layout")); ReadGlobalSetting(Settings::values.render_3d); @@ -551,7 +551,7 @@ void Config::ReadLayoutValues() { qt_config->endGroup(); } -void Config::ReadMiscellaneousValues() { +void QtConfig::ReadMiscellaneousValues() { qt_config->beginGroup(QStringLiteral("Miscellaneous")); ReadBasicSetting(Settings::values.log_filter); @@ -561,7 +561,7 @@ void Config::ReadMiscellaneousValues() { qt_config->endGroup(); } -void Config::ReadMultiplayerValues() { +void QtConfig::ReadMultiplayerValues() { qt_config->beginGroup(QStringLiteral("Multiplayer")); UISettings::values.nickname = ReadSetting(QStringLiteral("nickname"), QString{}).toString(); @@ -612,7 +612,7 @@ void Config::ReadMultiplayerValues() { qt_config->endGroup(); } -void Config::ReadPathValues() { +void QtConfig::ReadPathValues() { qt_config->beginGroup(QStringLiteral("Paths")); ReadGlobalSetting(UISettings::values.screenshot_path); @@ -664,7 +664,7 @@ void Config::ReadPathValues() { qt_config->endGroup(); } -void Config::ReadRendererValues() { +void QtConfig::ReadRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); ReadGlobalSetting(Settings::values.graphics_api); @@ -695,7 +695,7 @@ void Config::ReadRendererValues() { qt_config->endGroup(); } -void Config::ReadShortcutValues() { +void QtConfig::ReadShortcutValues() { qt_config->beginGroup(QStringLiteral("Shortcuts")); for (const auto& [name, group, shortcut] : default_hotkeys) { @@ -716,7 +716,7 @@ void Config::ReadShortcutValues() { qt_config->endGroup(); } -void Config::ReadSystemValues() { +void QtConfig::ReadSystemValues() { qt_config->beginGroup(QStringLiteral("System")); ReadGlobalSetting(Settings::values.is_new_3ds); @@ -743,7 +743,7 @@ const QString DEFAULT_VIDEO_ENCODER_OPTIONS = QStringLiteral("quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1"); const QString DEFAULT_AUDIO_ENCODER_OPTIONS = QStringLiteral(""); -void Config::ReadVideoDumpingValues() { +void QtConfig::ReadVideoDumpingValues() { qt_config->beginGroup(QStringLiteral("VideoDumping")); Settings::values.output_format = @@ -780,7 +780,7 @@ void Config::ReadVideoDumpingValues() { qt_config->endGroup(); } -void Config::ReadUIValues() { +void QtConfig::ReadUIValues() { qt_config->beginGroup(QStringLiteral("UI")); ReadPathValues(); @@ -816,7 +816,7 @@ void Config::ReadUIValues() { qt_config->endGroup(); } -void Config::ReadUIGameListValues() { +void QtConfig::ReadUIGameListValues() { qt_config->beginGroup(QStringLiteral("GameList")); ReadBasicSetting(UISettings::values.game_list_icon_size); @@ -842,7 +842,7 @@ void Config::ReadUIGameListValues() { qt_config->endGroup(); } -void Config::ReadUILayoutValues() { +void QtConfig::ReadUILayoutValues() { qt_config->beginGroup(QStringLiteral("UILayout")); UISettings::values.geometry = ReadSetting(QStringLiteral("geometry")).toByteArray(); @@ -858,7 +858,7 @@ void Config::ReadUILayoutValues() { qt_config->endGroup(); } -void Config::ReadUpdaterValues() { +void QtConfig::ReadUpdaterValues() { qt_config->beginGroup(QStringLiteral("Updater")); ReadBasicSetting(UISettings::values.check_for_update_on_start); @@ -867,7 +867,7 @@ void Config::ReadUpdaterValues() { qt_config->endGroup(); } -void Config::ReadWebServiceValues() { +void QtConfig::ReadWebServiceValues() { qt_config->beginGroup(QStringLiteral("WebService")); NetSettings::values.web_api_url = @@ -882,7 +882,7 @@ void Config::ReadWebServiceValues() { qt_config->endGroup(); } -void Config::SaveValues() { +void QtConfig::SaveValues() { if (global) { SaveControlValues(); SaveCameraValues(); @@ -903,7 +903,7 @@ void Config::SaveValues() { qt_config->sync(); } -void Config::SaveAudioValues() { +void QtConfig::SaveAudioValues() { qt_config->beginGroup(QStringLiteral("Audio")); WriteGlobalSetting(Settings::values.audio_emulation); @@ -921,7 +921,7 @@ void Config::SaveAudioValues() { qt_config->endGroup(); } -void Config::SaveCameraValues() { +void QtConfig::SaveCameraValues() { using namespace Service::CAM; qt_config->beginGroup(QStringLiteral("Camera")); @@ -951,7 +951,7 @@ void Config::SaveCameraValues() { qt_config->endGroup(); } -void Config::SaveControlValues() { +void QtConfig::SaveControlValues() { qt_config->beginGroup(QStringLiteral("Controls")); WriteBasicSetting(Settings::values.use_artic_base_controller); @@ -1012,7 +1012,7 @@ void Config::SaveControlValues() { qt_config->endGroup(); } -void Config::SaveUtilityValues() { +void QtConfig::SaveUtilityValues() { qt_config->beginGroup(QStringLiteral("Utility")); WriteGlobalSetting(Settings::values.dump_textures); @@ -1023,7 +1023,7 @@ void Config::SaveUtilityValues() { qt_config->endGroup(); } -void Config::SaveCoreValues() { +void QtConfig::SaveCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); WriteGlobalSetting(Settings::values.cpu_clock_percentage); @@ -1036,7 +1036,7 @@ void Config::SaveCoreValues() { qt_config->endGroup(); } -void Config::SaveDataStorageValues() { +void QtConfig::SaveDataStorageValues() { qt_config->beginGroup(QStringLiteral("Data Storage")); WriteBasicSetting(Settings::values.use_virtual_sd); @@ -1051,7 +1051,7 @@ void Config::SaveDataStorageValues() { qt_config->endGroup(); } -void Config::SaveDebuggingValues() { +void QtConfig::SaveDebuggingValues() { qt_config->beginGroup(QStringLiteral("Debugging")); // Intentionally not using the QT default setting as this is intended to be changed in the ini @@ -1070,7 +1070,7 @@ void Config::SaveDebuggingValues() { qt_config->endGroup(); } -void Config::SaveLayoutValues() { +void QtConfig::SaveLayoutValues() { qt_config->beginGroup(QStringLiteral("Layout")); WriteGlobalSetting(Settings::values.render_3d); @@ -1114,7 +1114,7 @@ void Config::SaveLayoutValues() { qt_config->endGroup(); } -void Config::SaveMiscellaneousValues() { +void QtConfig::SaveMiscellaneousValues() { qt_config->beginGroup(QStringLiteral("Miscellaneous")); WriteBasicSetting(Settings::values.log_filter); @@ -1124,7 +1124,7 @@ void Config::SaveMiscellaneousValues() { qt_config->endGroup(); } -void Config::SaveMultiplayerValues() { +void QtConfig::SaveMultiplayerValues() { qt_config->beginGroup(QStringLiteral("Multiplayer")); WriteSetting(QStringLiteral("nickname"), UISettings::values.nickname, QString{}); @@ -1167,7 +1167,7 @@ void Config::SaveMultiplayerValues() { qt_config->endGroup(); } -void Config::SavePathValues() { +void QtConfig::SavePathValues() { qt_config->beginGroup(QStringLiteral("Paths")); WriteGlobalSetting(UISettings::values.screenshot_path); @@ -1195,7 +1195,7 @@ void Config::SavePathValues() { qt_config->endGroup(); } -void Config::SaveRendererValues() { +void QtConfig::SaveRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); WriteGlobalSetting(Settings::values.graphics_api); @@ -1227,7 +1227,7 @@ void Config::SaveRendererValues() { qt_config->endGroup(); } -void Config::SaveShortcutValues() { +void QtConfig::SaveShortcutValues() { qt_config->beginGroup(QStringLiteral("Shortcuts")); // Lengths of UISettings::values.shortcuts & default_hotkeys are same. @@ -1247,7 +1247,7 @@ void Config::SaveShortcutValues() { qt_config->endGroup(); } -void Config::SaveSystemValues() { +void QtConfig::SaveSystemValues() { qt_config->beginGroup(QStringLiteral("System")); WriteGlobalSetting(Settings::values.is_new_3ds); @@ -1268,7 +1268,7 @@ void Config::SaveSystemValues() { qt_config->endGroup(); } -void Config::SaveVideoDumpingValues() { +void QtConfig::SaveVideoDumpingValues() { qt_config->beginGroup(QStringLiteral("VideoDumping")); WriteSetting(QStringLiteral("output_format"), @@ -1295,7 +1295,7 @@ void Config::SaveVideoDumpingValues() { qt_config->endGroup(); } -void Config::SaveUIValues() { +void QtConfig::SaveUIValues() { qt_config->beginGroup(QStringLiteral("UI")); SavePathValues(); @@ -1330,7 +1330,7 @@ void Config::SaveUIValues() { qt_config->endGroup(); } -void Config::SaveUIGameListValues() { +void QtConfig::SaveUIGameListValues() { qt_config->beginGroup(QStringLiteral("GameList")); WriteBasicSetting(UISettings::values.game_list_icon_size); @@ -1356,7 +1356,7 @@ void Config::SaveUIGameListValues() { qt_config->endGroup(); } -void Config::SaveUILayoutValues() { +void QtConfig::SaveUILayoutValues() { qt_config->beginGroup(QStringLiteral("UILayout")); WriteSetting(QStringLiteral("geometry"), UISettings::values.geometry); @@ -1370,7 +1370,7 @@ void Config::SaveUILayoutValues() { qt_config->endGroup(); } -void Config::SaveUpdaterValues() { +void QtConfig::SaveUpdaterValues() { qt_config->beginGroup(QStringLiteral("Updater")); WriteBasicSetting(UISettings::values.check_for_update_on_start); @@ -1379,7 +1379,7 @@ void Config::SaveUpdaterValues() { qt_config->endGroup(); } -void Config::SaveWebServiceValues() { +void QtConfig::SaveWebServiceValues() { qt_config->beginGroup(QStringLiteral("WebService")); WriteSetting(QStringLiteral("web_api_url"), @@ -1393,11 +1393,11 @@ void Config::SaveWebServiceValues() { qt_config->endGroup(); } -QVariant Config::ReadSetting(const QString& name) const { +QVariant QtConfig::ReadSetting(const QString& name) const { return qt_config->value(name); } -QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) const { +QVariant QtConfig::ReadSetting(const QString& name, const QVariant& default_value) const { QVariant result; if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { result = default_value; @@ -1407,22 +1407,22 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) return result; } -void Config::WriteSetting(const QString& name, const QVariant& value) { +void QtConfig::WriteSetting(const QString& name, const QVariant& value) { qt_config->setValue(name, value); } -void Config::WriteSetting(const QString& name, const QVariant& value, - const QVariant& default_value) { +void QtConfig::WriteSetting(const QString& name, const QVariant& value, + const QVariant& default_value) { qt_config->setValue(name + QStringLiteral("/default"), value == default_value); qt_config->setValue(name, value); } -void Config::Reload() { +void QtConfig::Reload() { ReadValues(); // To apply default value changes SaveValues(); } -void Config::Save() { +void QtConfig::Save() { SaveValues(); } diff --git a/src/citra_qt/configuration/config.h b/src/citra_qt/configuration/config.h index 521c6baf9..d1412b1fa 100644 --- a/src/citra_qt/configuration/config.h +++ b/src/citra_qt/configuration/config.h @@ -13,13 +13,13 @@ class QSettings; -class Config { +class QtConfig { public: enum class ConfigType : u32 { GlobalConfig, PerGameConfig }; - explicit Config(const std::string& config_name = "qt-config", - ConfigType config_type = ConfigType::GlobalConfig); - ~Config(); + explicit QtConfig(const std::string& config_name = "qt-config", + ConfigType config_type = ConfigType::GlobalConfig); + ~QtConfig(); void Reload(); void Save(); diff --git a/src/citra_qt/configuration/configure_hotkeys.cpp b/src/citra_qt/configuration/configure_hotkeys.cpp index b07370528..6ac0dcd8a 100644 --- a/src/citra_qt/configuration/configure_hotkeys.cpp +++ b/src/citra_qt/configuration/configure_hotkeys.cpp @@ -162,7 +162,7 @@ void ConfigureHotkeys::RestoreDefaults() { for (int r2 = 0; r2 < parent->rowCount(); ++r2) { model->item(r, 0) ->child(r2, hotkey_column) - ->setText(Config::default_hotkeys[r2].shortcut.keyseq); + ->setText(QtConfig::default_hotkeys[r2].shortcut.keyseq); } } } @@ -198,7 +198,7 @@ void ConfigureHotkeys::PopupContextMenu(const QPoint& menu_location) { void ConfigureHotkeys::RestoreHotkey(QModelIndex index) { const QKeySequence& default_key_sequence = QKeySequence::fromString( - Config::default_hotkeys[index.row()].shortcut.keyseq, QKeySequence::NativeText); + QtConfig::default_hotkeys[index.row()].shortcut.keyseq, QKeySequence::NativeText); const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence); if (key_sequence_used && default_key_sequence != QKeySequence(model->data(index).toString())) { diff --git a/src/citra_qt/configuration/configure_input.cpp b/src/citra_qt/configuration/configure_input.cpp index 158885ca5..b51d2a483 100644 --- a/src/citra_qt/configuration/configure_input.cpp +++ b/src/citra_qt/configuration/configure_input.cpp @@ -228,8 +228,9 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent) Settings::SaveProfile(ui->profile->currentIndex()); }); context_menu.addAction(tr("Restore Default"), this, [&] { - buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; + buttons_param[button_id] = + Common::ParamPackage{InputCommon::GenerateKeyboardParam( + QtConfig::default_buttons[button_id])}; button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); ApplyConfiguration(); Settings::SaveProfile(ui->profile->currentIndex()); @@ -268,7 +269,7 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent) }); context_menu.addAction(tr("Restore Default"), this, [&] { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id][sub_button_id])}; + QtConfig::default_analogs[analog_id][sub_button_id])}; SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( @@ -347,8 +348,8 @@ ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent) for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id] - [static_cast(AnalogSubButtons::modifier)])}; + QtConfig::default_analogs[analog_id][static_cast( + AnalogSubButtons::modifier)])}; SetAnalogButton(params, analogs_param[analog_id], "modifier"); ui->buttonCircleMod->setText( AnalogToText(analogs_param[analog_id], "modifier")); @@ -464,13 +465,13 @@ void ConfigureInput::LoadConfiguration() { void ConfigureInput::RestoreDefaults() { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; + InputCommon::GenerateKeyboardParam(QtConfig::default_buttons[button_id])}; } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id][sub_button_id])}; + QtConfig::default_analogs[analog_id][sub_button_id])}; SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); } analogs_param[analog_id].Set("modifier_scale", 0.5f); diff --git a/src/citra_qt/configuration/configure_per_game.cpp b/src/citra_qt/configuration/configure_per_game.cpp index fe236bce3..f48e7bea9 100644 --- a/src/citra_qt/configuration/configure_per_game.cpp +++ b/src/citra_qt/configuration/configure_per_game.cpp @@ -31,7 +31,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString filename{file_name.toStdString()}, title_id{title_id_}, system{system_} { const auto config_file_name = title_id == 0 ? std::string(FileUtil::GetFilename(filename)) : fmt::format("{:016X}", title_id); - game_config = std::make_unique(config_file_name, Config::ConfigType::PerGameConfig); + game_config = std::make_unique(config_file_name, QtConfig::ConfigType::PerGameConfig); const bool is_powered_on = system.IsPoweredOn(); audio_tab = std::make_unique(is_powered_on, this); diff --git a/src/citra_qt/configuration/configure_per_game.h b/src/citra_qt/configuration/configure_per_game.h index 110687b27..68d55756a 100644 --- a/src/citra_qt/configuration/configure_per_game.h +++ b/src/citra_qt/configuration/configure_per_game.h @@ -65,7 +65,7 @@ private: QGraphicsScene* scene; - std::unique_ptr game_config; + std::unique_ptr game_config; Core::System& system; diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index fe408d110..c61bfd41d 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -29,7 +29,7 @@ #include "citra_qt/game_list.h" #include "citra_qt/game_list_p.h" #include "citra_qt/game_list_worker.h" -#include "citra_qt/main.h" +#include "citra_qt/citra_qt.h" #include "citra_qt/uisettings.h" #include "common/logging/log.h" #include "common/settings.h" diff --git a/src/citra_qt/multiplayer/direct_connect.cpp b/src/citra_qt/multiplayer/direct_connect.cpp index bdc866a75..c77aac36f 100644 --- a/src/citra_qt/multiplayer/direct_connect.cpp +++ b/src/citra_qt/multiplayer/direct_connect.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "citra_qt/main.h" +#include "citra_qt/citra_qt.h" #include "citra_qt/multiplayer/direct_connect.h" #include "citra_qt/multiplayer/message.h" #include "citra_qt/multiplayer/validation.h" diff --git a/src/citra_qt/multiplayer/lobby.cpp b/src/citra_qt/multiplayer/lobby.cpp index 00671b842..58be92cb8 100644 --- a/src/citra_qt/multiplayer/lobby.cpp +++ b/src/citra_qt/multiplayer/lobby.cpp @@ -6,7 +6,7 @@ #include #include #include "citra_qt/game_list_p.h" -#include "citra_qt/main.h" +#include "citra_qt/citra_qt.h" #include "citra_qt/multiplayer/lobby.h" #include "citra_qt/multiplayer/lobby_p.h" #include "citra_qt/multiplayer/message.h" diff --git a/src/citra_sdl/CMakeLists.txt b/src/citra_sdl/CMakeLists.txt new file mode 100644 index 000000000..cf3deda2d --- /dev/null +++ b/src/citra_sdl/CMakeLists.txt @@ -0,0 +1,48 @@ +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) + +add_library(citra_sdl STATIC EXCLUDE_FROM_ALL + config.cpp + config.h + default_ini.h + emu_window/emu_window_sdl2.cpp + emu_window/emu_window_sdl2.h + citra_sdl.cpp + precompiled_headers.h + resource.h +) + +if (ENABLE_SOFTWARE_RENDERER) + target_sources(citra_sdl PRIVATE + emu_window/emu_window_sdl2_sw.cpp + emu_window/emu_window_sdl2_sw.h + ) +endif() +if (ENABLE_OPENGL) + target_sources(citra_sdl PRIVATE + emu_window/emu_window_sdl2_gl.cpp + emu_window/emu_window_sdl2_gl.h + ) +endif() +if (ENABLE_VULKAN) + target_sources(citra_sdl PRIVATE + emu_window/emu_window_sdl2_vk.cpp + emu_window/emu_window_sdl2_vk.h + ) +endif() + +create_target_directory_groups(citra_sdl) + +target_link_libraries(citra_sdl PRIVATE citra_common citra_core input_common network) +target_link_libraries(citra_sdl PRIVATE inih) +if (MSVC) + target_link_libraries(citra_sdl PRIVATE getopt) +endif() +target_link_libraries(citra_sdl PRIVATE ${PLATFORM_LIBRARIES} SDL2::SDL2 Threads::Threads) + +if (ENABLE_OPENGL) + target_link_libraries(citra_sdl PRIVATE glad) +endif() + +if (CITRA_USE_PRECOMPILED_HEADERS) + target_precompile_headers(citra_sdl PRIVATE precompiled_headers.h) +endif() diff --git a/src/citra/citra.cpp b/src/citra_sdl/citra_sdl.cpp similarity index 88% rename from src/citra/citra.cpp rename to src/citra_sdl/citra_sdl.cpp index 9c79baeda..bedeebfa0 100644 --- a/src/citra/citra.cpp +++ b/src/citra_sdl/citra_sdl.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright Citra Emulator Project / Lime3DS Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -11,17 +11,18 @@ // This needs to be included before getopt.h because the latter #defines symbols used by it #include "common/microprofile.h" -#include "citra/config.h" -#include "citra/emu_window/emu_window_sdl2.h" +#include "citra_sdl/config.h" +#include "citra_sdl/emu_window/emu_window_sdl2.h" #ifdef ENABLE_OPENGL -#include "citra/emu_window/emu_window_sdl2_gl.h" +#include "citra_sdl/emu_window/emu_window_sdl2_gl.h" #endif #ifdef ENABLE_SOFTWARE_RENDERER -#include "citra/emu_window/emu_window_sdl2_sw.h" +#include "citra_sdl/emu_window/emu_window_sdl2_sw.h" #endif #ifdef ENABLE_VULKAN -#include "citra/emu_window/emu_window_sdl2_vk.h" +#include "citra_sdl/emu_window/emu_window_sdl2_vk.h" #endif +#include "SDL_messagebox.h" #include "common/common_paths.h" #include "common/detached_tasks.h" #include "common/file_util.h" @@ -40,6 +41,7 @@ #include "core/hle/service/cfg/cfg.h" #include "core/movie.h" #include "input_common/main.h" +#include "citra_meta/common_strings.h" #include "network/network.h" #include "video_core/gpu.h" #include "video_core/renderer_base.h" @@ -59,31 +61,18 @@ #include #include - -extern "C" { -// tells Nvidia drivers to use the dedicated GPU by default on laptops with switchable graphics -__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -} #endif -static void PrintHelp(const char* argv0) { - std::cout << "Usage: " << argv0 - << " [options] \n" - "-g, --gdbport=NUMBER Enable gdb stub on port NUMBER\n" - "-i, --install=FILE Installs a specified CIA file\n" - "-m, --multiplayer=nick:password@address:port" - " Nickname, password, address and port for multiplayer\n" - "-r, --movie-record=[file] Record a movie (game inputs) to the given file\n" - "-a, --movie-record-author=AUTHOR Sets the author of the movie to be recorded\n" - "-p, --movie-play=[file] Playback the movie (game inputs) from the given file\n" - "-d, --dump-video=[file] Dumps audio and video to the given video file\n" - "-f, --fullscreen Start in fullscreen mode\n" - "-h, --help Display this help and exit\n" - "-v, --version Output version information and exit\n"; +static void ShowCommandOutput(std::string title, std::string message) { +#ifdef _WIN32 + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, title.c_str(), message.c_str(), NULL); +#else + std::cout << message << std::endl; +#endif } -static void PrintVersion() { - std::cout << "Citra " << Common::g_scm_branch << " " << Common::g_scm_desc << std::endl; +static void PrintHelp(const char* argv0) { + ShowCommandOutput("Help", fmt::format(Common::help_string, argv0)); } static void OnStateChanged(const Network::RoomMember::State& state) { @@ -182,12 +171,12 @@ static void OnStatusMessageReceived(const Network::StatusMessageEntry& msg) { } /// Application entry point -int main(int argc, char** argv) { +void LaunchSdlFrontend(int argc, char** argv) { Common::Log::Initialize(); Common::Log::SetColorConsoleBackendEnabled(true); Common::Log::Start(); Common::DetachedTasks detached_tasks; - Config config; + SdlConfig config; int option_index = 0; bool use_gdbstub = Settings::values.use_gdbstub.GetValue(); u32 gdb_port = static_cast(Settings::values.gdbstub_port.GetValue()); @@ -203,7 +192,7 @@ int main(int argc, char** argv) { if (argv_w == nullptr) { LOG_CRITICAL(Frontend, "Failed to get command line arguments"); - return -1; + exit(-1); } #endif std::string filepath; @@ -216,23 +205,31 @@ int main(int argc, char** argv) { u16 port = Network::DefaultRoomPort; static struct option long_options[] = { - {"gdbport", required_argument, 0, 'g'}, - {"install", required_argument, 0, 'i'}, - {"multiplayer", required_argument, 0, 'm'}, - {"movie-record", required_argument, 0, 'r'}, - {"movie-record-author", required_argument, 0, 'a'}, - {"movie-play", required_argument, 0, 'p'}, {"dump-video", required_argument, 0, 'd'}, {"fullscreen", no_argument, 0, 'f'}, + {"gdbport", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, + {"install", required_argument, 0, 'i'}, + {"movie-play", required_argument, 0, 'p'}, + {"movie-record", required_argument, 0, 'r'}, + {"movie-record-author", required_argument, 0, 'a'}, + {"multiplayer", required_argument, 0, 'm'}, {"version", no_argument, 0, 'v'}, + {"windowed", no_argument, 0, 'w'}, {0, 0, 0, 0}, }; while (optind < argc) { - int arg = getopt_long(argc, argv, "g:i:m:r:p:fhv", long_options, &option_index); + int arg = getopt_long(argc, argv, "d:fg:hi:p:r:a:m:nvw", long_options, &option_index); if (arg != -1) { switch (static_cast(arg)) { + case 'd': + dump_video = optarg; + break; + case 'f': + fullscreen = true; + LOG_INFO(Frontend, "Starting in fullscreen mode..."); + break; case 'g': errno = 0; gdb_port = strtoul(optarg, &endarg, 0); @@ -244,6 +241,9 @@ int main(int argc, char** argv) { exit(1); } break; + case 'h': + PrintHelp(argv[0]); + exit(0); case 'i': { const auto cia_progress = [](std::size_t written, std::size_t total) { LOG_INFO(Frontend, "{:02d}%", (written * 100 / total)); @@ -255,6 +255,15 @@ int main(int argc, char** argv) { exit(1); break; } + case 'p': + movie_play = optarg; + break; + case 'r': + movie_record = optarg; + break; + case 'a': + movie_record_author = optarg; + break; case 'm': { use_multiplayer = true; const std::string str_arg(optarg); @@ -264,7 +273,7 @@ int main(int argc, char** argv) { if (!std::regex_match(str_arg, re)) { std::cout << "Wrong format for option --multiplayer\n"; PrintHelp(argv[0]); - return 0; + exit(0); } std::smatch match; @@ -279,36 +288,19 @@ int main(int argc, char** argv) { if (!std::regex_match(nickname, nickname_re)) { std::cout << "Nickname is not valid. Must be 4 to 20 alphanumeric characters.\n"; - return 0; + exit(0); } if (address.empty()) { std::cout << "Address to room must not be empty.\n"; - return 0; + exit(0); } break; } - case 'r': - movie_record = optarg; - break; - case 'a': - movie_record_author = optarg; - break; - case 'p': - movie_play = optarg; - break; - case 'd': - dump_video = optarg; - break; - case 'f': - fullscreen = true; - LOG_INFO(Frontend, "Starting in fullscreen mode..."); - break; - case 'h': - PrintHelp(argv[0]); - return 0; case 'v': - PrintVersion(); - return 0; + const std::string version_string = + std::string("Citra ") + Common::g_scm_branch + " " + Common::g_scm_desc; + ShowCommandOutput("Version", version_string); + exit(0); } } else { #ifdef _WIN32 @@ -329,12 +321,12 @@ int main(int argc, char** argv) { if (filepath.empty()) { LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); - return -1; + exit(-1); } if (!movie_record.empty() && !movie_play.empty()) { LOG_CRITICAL(Frontend, "Cannot both play and record a movie"); - return -1; + exit(-1); } auto& system = Core::System::GetInstance(); @@ -385,7 +377,7 @@ int main(int argc, char** argv) { #elif ENABLE_SOFTWARE_RENDERER return std::make_unique(system, fullscreen, is_secondary); #else -// TODO: Add a null renderer backend for this, perhaps. + // TODO: Add a null renderer backend for this, perhaps. #error "At least one renderer must be enabled." #endif } @@ -399,8 +391,8 @@ int main(int argc, char** argv) { const auto scope = emu_window->Acquire(); - LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, - Common::g_scm_desc); + LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, + Common::g_scm_branch, Common::g_scm_desc); Settings::LogSettings(); const Core::System::ResultStatus load_result{ @@ -409,26 +401,26 @@ int main(int argc, char** argv) { switch (load_result) { case Core::System::ResultStatus::ErrorGetLoader: LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); - return -1; + exit(-1); case Core::System::ResultStatus::ErrorLoader: LOG_CRITICAL(Frontend, "Failed to load ROM!"); - return -1; + exit(-1); case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before " "being used with Citra. \n\n For more information on dumping and " "decrypting games, please refer to: " "https://web.archive.org/web/20240304210021/https://citra-emu.org/" "wiki/dumping-game-cartridges/"); - return -1; + exit(-1); case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported."); - return -1; + exit(-1); case Core::System::ResultStatus::ErrorNotInitialized: LOG_CRITICAL(Frontend, "CPUCore not initialized"); - return -1; + exit(-1); case Core::System::ResultStatus::ErrorSystemMode: LOG_CRITICAL(Frontend, "Failed to determine system mode!"); - return -1; + exit(-1); case Core::System::ResultStatus::Success: break; // Expected case default: @@ -448,7 +440,7 @@ int main(int argc, char** argv) { Network::NoPreferredMac, password); } else { LOG_ERROR(Network, "Could not access RoomMember"); - return 0; + exit(0); } } @@ -532,5 +524,5 @@ int main(int argc, char** argv) { #endif detached_tasks.WaitForAllTasks(); - return 0; + exit(0); } diff --git a/src/citra_sdl/citra_sdl.h b/src/citra_sdl/citra_sdl.h new file mode 100644 index 000000000..ba4b90ce0 --- /dev/null +++ b/src/citra_sdl/citra_sdl.h @@ -0,0 +1,7 @@ +// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +void LaunchSdlFrontend(int argc, char** argv); diff --git a/src/citra/config.cpp b/src/citra_sdl/config.cpp similarity index 96% rename from src/citra/config.cpp rename to src/citra_sdl/config.cpp index 138e3eea3..0312c4a24 100644 --- a/src/citra/config.cpp +++ b/src/citra_sdl/config.cpp @@ -8,8 +8,8 @@ #include #include #include -#include "citra/config.h" -#include "citra/default_ini.h" +#include "citra_sdl/config.h" +#include "citra_sdl/default_ini.h" #include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -19,7 +19,7 @@ #include "input_common/udp/client.h" #include "network/network_settings.h" -Config::Config() { +SdlConfig::SdlConfig() { // TODO: Don't hardcode the path; let the frontend decide where to put the config files. sdl2_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "sdl2-config.ini"; sdl2_config = std::make_unique(sdl2_config_loc); @@ -27,9 +27,9 @@ Config::Config() { Reload(); } -Config::~Config() = default; +SdlConfig::~SdlConfig() = default; -bool Config::LoadINI(const std::string& default_contents, bool retry) { +bool SdlConfig::LoadINI(const std::string& default_contents, bool retry) { const std::string& location = this->sdl2_config_loc; if (sdl2_config->ParseError() < 0) { if (retry) { @@ -71,7 +71,7 @@ static const std::array, Settings::NativeAnalog::NumAnalogs> }}; template <> -void Config::ReadSetting(const std::string& group, Settings::Setting& setting) { +void SdlConfig::ReadSetting(const std::string& group, Settings::Setting& setting) { std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); if (setting_value.empty()) { setting_value = setting.GetDefault(); @@ -80,12 +80,12 @@ void Config::ReadSetting(const std::string& group, Settings::Setting -void Config::ReadSetting(const std::string& group, Settings::Setting& setting) { +void SdlConfig::ReadSetting(const std::string& group, Settings::Setting& setting) { setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); } template -void Config::ReadSetting(const std::string& group, Settings::Setting& setting) { +void SdlConfig::ReadSetting(const std::string& group, Settings::Setting& setting) { if constexpr (std::is_floating_point_v) { setting = static_cast( sdl2_config->GetReal(group, setting.GetLabel(), setting.GetDefault())); @@ -95,7 +95,7 @@ void Config::ReadSetting(const std::string& group, Settings::SettingGetInteger("Video Dumping", "audio_bitrate", 64000); } -void Config::Reload() { +void SdlConfig::Reload() { LoadINI(DefaultINI::sdl2_config_file); ReadValues(); } diff --git a/src/citra/config.h b/src/citra_sdl/config.h similarity index 93% rename from src/citra/config.h rename to src/citra_sdl/config.h index 22a71891b..d7c3e6c80 100644 --- a/src/citra/config.h +++ b/src/citra_sdl/config.h @@ -10,7 +10,7 @@ class INIReader; -class Config { +class SdlConfig { std::unique_ptr sdl2_config; std::string sdl2_config_loc; @@ -18,8 +18,8 @@ class Config { void ReadValues(); public: - Config(); - ~Config(); + SdlConfig(); + ~SdlConfig(); void Reload(); diff --git a/src/citra/default_ini.h b/src/citra_sdl/default_ini.h similarity index 100% rename from src/citra/default_ini.h rename to src/citra_sdl/default_ini.h diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra_sdl/emu_window/emu_window_sdl2.cpp similarity index 99% rename from src/citra/emu_window/emu_window_sdl2.cpp rename to src/citra_sdl/emu_window/emu_window_sdl2.cpp index 698dcc3dd..b70c33557 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra_sdl/emu_window/emu_window_sdl2.cpp @@ -7,7 +7,7 @@ #include #define SDL_MAIN_HANDLED #include -#include "citra/emu_window/emu_window_sdl2.h" +#include "citra_sdl/emu_window/emu_window_sdl2.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "core/core.h" diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra_sdl/emu_window/emu_window_sdl2.h similarity index 100% rename from src/citra/emu_window/emu_window_sdl2.h rename to src/citra_sdl/emu_window/emu_window_sdl2.h diff --git a/src/citra/emu_window/emu_window_sdl2_gl.cpp b/src/citra_sdl/emu_window/emu_window_sdl2_gl.cpp similarity index 99% rename from src/citra/emu_window/emu_window_sdl2_gl.cpp rename to src/citra_sdl/emu_window/emu_window_sdl2_gl.cpp index 09a7f5995..6242aa369 100644 --- a/src/citra/emu_window/emu_window_sdl2_gl.cpp +++ b/src/citra_sdl/emu_window/emu_window_sdl2_gl.cpp @@ -8,7 +8,7 @@ #define SDL_MAIN_HANDLED #include #include -#include "citra/emu_window/emu_window_sdl2_gl.h" +#include "citra_sdl/emu_window/emu_window_sdl2_gl.h" #include "common/scm_rev.h" #include "common/settings.h" #include "core/core.h" diff --git a/src/citra/emu_window/emu_window_sdl2_gl.h b/src/citra_sdl/emu_window/emu_window_sdl2_gl.h similarity index 95% rename from src/citra/emu_window/emu_window_sdl2_gl.h rename to src/citra_sdl/emu_window/emu_window_sdl2_gl.h index 4a4d70601..6e9045cba 100644 --- a/src/citra/emu_window/emu_window_sdl2_gl.h +++ b/src/citra_sdl/emu_window/emu_window_sdl2_gl.h @@ -5,7 +5,7 @@ #pragma once #include -#include "citra/emu_window/emu_window_sdl2.h" +#include "citra_sdl/emu_window/emu_window_sdl2.h" struct SDL_Window; diff --git a/src/citra/emu_window/emu_window_sdl2_sw.cpp b/src/citra_sdl/emu_window/emu_window_sdl2_sw.cpp similarity index 98% rename from src/citra/emu_window/emu_window_sdl2_sw.cpp rename to src/citra_sdl/emu_window/emu_window_sdl2_sw.cpp index 3f2cf6db9..9ba30d0d5 100644 --- a/src/citra/emu_window/emu_window_sdl2_sw.cpp +++ b/src/citra_sdl/emu_window/emu_window_sdl2_sw.cpp @@ -8,7 +8,7 @@ #define SDL_MAIN_HANDLED #include #include -#include "citra/emu_window/emu_window_sdl2_sw.h" +#include "citra_sdl/emu_window/emu_window_sdl2_sw.h" #include "common/scm_rev.h" #include "common/settings.h" #include "core/core.h" diff --git a/src/citra/emu_window/emu_window_sdl2_sw.h b/src/citra_sdl/emu_window/emu_window_sdl2_sw.h similarity index 94% rename from src/citra/emu_window/emu_window_sdl2_sw.h rename to src/citra_sdl/emu_window/emu_window_sdl2_sw.h index 22fcd3bd2..12f446e33 100644 --- a/src/citra/emu_window/emu_window_sdl2_sw.h +++ b/src/citra_sdl/emu_window/emu_window_sdl2_sw.h @@ -5,7 +5,7 @@ #pragma once #include -#include "citra/emu_window/emu_window_sdl2.h" +#include "citra_sdl/emu_window/emu_window_sdl2.h" struct SDL_Renderer; struct SDL_Surface; diff --git a/src/citra/emu_window/emu_window_sdl2_vk.cpp b/src/citra_sdl/emu_window/emu_window_sdl2_vk.cpp similarity index 98% rename from src/citra/emu_window/emu_window_sdl2_vk.cpp rename to src/citra_sdl/emu_window/emu_window_sdl2_vk.cpp index b7e46e1a3..9c47ce186 100644 --- a/src/citra/emu_window/emu_window_sdl2_vk.cpp +++ b/src/citra_sdl/emu_window/emu_window_sdl2_vk.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "citra/emu_window/emu_window_sdl2_vk.h" +#include "citra_sdl/emu_window/emu_window_sdl2_vk.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "core/frontend/emu_window.h" diff --git a/src/citra/emu_window/emu_window_sdl2_vk.h b/src/citra_sdl/emu_window/emu_window_sdl2_vk.h similarity index 91% rename from src/citra/emu_window/emu_window_sdl2_vk.h rename to src/citra_sdl/emu_window/emu_window_sdl2_vk.h index be1cd1352..ce0f1d8ce 100644 --- a/src/citra/emu_window/emu_window_sdl2_vk.h +++ b/src/citra_sdl/emu_window/emu_window_sdl2_vk.h @@ -5,7 +5,7 @@ #pragma once #include -#include "citra/emu_window/emu_window_sdl2.h" +#include "citra_sdl/emu_window/emu_window_sdl2.h" namespace Frontend { class GraphicsContext; diff --git a/src/citra/precompiled_headers.h b/src/citra_sdl/precompiled_headers.h similarity index 100% rename from src/citra/precompiled_headers.h rename to src/citra_sdl/precompiled_headers.h diff --git a/src/citra/resource.h b/src/citra_sdl/resource.h similarity index 100% rename from src/citra/resource.h rename to src/citra_sdl/resource.h diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 346b36eb9..c73759ce2 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -38,7 +38,7 @@ enum class Class : u8 { Core_ARM11, ///< ARM11 CPU core Core_Timing, ///< CoreTiming functions Core_Cheats, ///< Cheat functions - Config, ///< Emulator configuration (including commandline) + Config, ///< Emulator configuration Debug, ///< Debugging tools Debug_Emulated, ///< Debug messages from the emulated programs Debug_GPU, ///< GPU debugging tools