From 83332316aa382e11e6af79b8432520ff4c9950b6 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 7 Dec 2025 07:13:43 +0100 Subject: [PATCH] [gamemode] Make available on other platforms (#353) Signed-off-by: lizzie Co-authored-by: crueter Co-authored-by: Caio Oliveira Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/353 Reviewed-by: CamilleLaVey Reviewed-by: Caio Oliveira Co-authored-by: lizzie Co-committed-by: lizzie --- CMakeLists.txt | 5 +- externals/CMakeLists.txt | 6 +- externals/cpmfile.json | 7 + externals/gamemode/gamemode_client.h | 376 ------------------ src/common/CMakeLists.txt | 6 - src/common/linux/gamemode.cpp | 40 -- src/common/linux/gamemode.h | 24 -- src/common/settings.cpp | 2 - src/common/settings.h | 7 - src/common/settings_common.h | 4 +- src/frontend_common/config.cpp | 26 -- src/frontend_common/config.h | 6 - src/qt_common/CMakeLists.txt | 4 + src/qt_common/config/shared_translation.cpp | 6 +- src/qt_common/config/uisettings.h | 13 + src/qt_common/gamemode.cpp | 52 +++ src/qt_common/gamemode.h | 14 + src/yuzu/CMakeLists.txt | 3 - src/yuzu/configuration/configure_general.cpp | 15 - src/yuzu/configuration/configure_general.ui | 27 -- .../configuration/configure_linux_tab.cpp | 75 ---- src/yuzu/configuration/configure_linux_tab.h | 44 -- src/yuzu/configuration/configure_linux_tab.ui | 53 --- src/yuzu/configuration/configure_per_game.cpp | 9 - src/yuzu/configuration/configure_per_game.h | 2 - src/yuzu/main.cpp | 4 +- src/yuzu/main_window.cpp | 52 +-- src/yuzu/main_window.h | 2 +- src/yuzu_cmd/yuzu.cpp | 14 - 29 files changed, 123 insertions(+), 775 deletions(-) delete mode 100644 externals/gamemode/gamemode_client.h delete mode 100644 src/common/linux/gamemode.cpp delete mode 100644 src/common/linux/gamemode.h create mode 100644 src/qt_common/gamemode.cpp create mode 100644 src/qt_common/gamemode.h delete mode 100644 src/yuzu/configuration/configure_linux_tab.cpp delete mode 100644 src/yuzu/configuration/configure_linux_tab.h delete mode 100644 src/yuzu/configuration/configure_linux_tab.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 1368ce3669..ea0bbe2423 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -487,10 +487,6 @@ else() # wow find_package(Boost 1.57.0 CONFIG REQUIRED OPTIONAL_COMPONENTS headers context system fiber filesystem) - if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID) - find_package(gamemode 1.7 MODULE) - endif() - if (ENABLE_OPENSSL) find_package(OpenSSL 1.1.1 REQUIRED) endif() @@ -566,6 +562,7 @@ find_package(VulkanUtilityLibraries) find_package(SimpleIni) find_package(SPIRV-Tools) find_package(sirit) +find_package(gamemode) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) find_package(xbyak) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 753cd181bb..18491962b2 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -267,9 +267,11 @@ if (ANDROID AND ARCHITECTURE_arm64) AddJsonPackage(libadrenotools) endif() -if (UNIX AND NOT APPLE AND NOT TARGET gamemode::headers) +AddJsonPackage(gamemode) + +if (gamemode_ADDED) add_library(gamemode INTERFACE) - target_include_directories(gamemode INTERFACE gamemode) + target_include_directories(gamemode INTERFACE ${gamemode_SOURCE_DIR}/lib) add_library(gamemode::headers ALIAS gamemode) endif() diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 0a059cdaef..47fb859268 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -218,5 +218,12 @@ "artifact": "MoltenVK-macOS.tar", "hash": "5695b36ca5775819a71791557fcb40a4a5ee4495be6b8442e0b666d0c436bec02aae68cc6210183f7a5c986bdbec0e117aecfad5396e496e9c2fd5c89133a347", "bundled": true + }, + "gamemode": { + "repo": "FeralInteractive/gamemode", + "sha": "ce6fe122f3", + "hash": "e87ec14ed3e826d578ebf095c41580069dda603792ba91efa84f45f4571a28f4d91889675055fd6f042d7dc25b0b9443daf70963ae463e38b11bcba95f4c65a9", + "version": "1.7", + "find_args": "MODULE" } } diff --git a/externals/gamemode/gamemode_client.h b/externals/gamemode/gamemode_client.h deleted file mode 100644 index b9f64fe460..0000000000 --- a/externals/gamemode/gamemode_client.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - -Copyright (c) 2017-2019, Feral Interactive -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Feral Interactive nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - - */ -#ifndef CLIENT_GAMEMODE_H -#define CLIENT_GAMEMODE_H -/* - * GameMode supports the following client functions - * Requests are refcounted in the daemon - * - * int gamemode_request_start() - Request gamemode starts - * 0 if the request was sent successfully - * -1 if the request failed - * - * int gamemode_request_end() - Request gamemode ends - * 0 if the request was sent successfully - * -1 if the request failed - * - * GAMEMODE_AUTO can be defined to make the above two functions apply during static init and - * destruction, as appropriate. In this configuration, errors will be printed to stderr - * - * int gamemode_query_status() - Query the current status of gamemode - * 0 if gamemode is inactive - * 1 if gamemode is active - * 2 if gamemode is active and this client is registered - * -1 if the query failed - * - * int gamemode_request_start_for(pid_t pid) - Request gamemode starts for another process - * 0 if the request was sent successfully - * -1 if the request failed - * -2 if the request was rejected - * - * int gamemode_request_end_for(pid_t pid) - Request gamemode ends for another process - * 0 if the request was sent successfully - * -1 if the request failed - * -2 if the request was rejected - * - * int gamemode_query_status_for(pid_t pid) - Query status of gamemode for another process - * 0 if gamemode is inactive - * 1 if gamemode is active - * 2 if gamemode is active and this client is registered - * -1 if the query failed - * - * const char* gamemode_error_string() - Get an error string - * returns a string describing any of the above errors - * - * Note: All the above requests can be blocking - dbus requests can and will block while the daemon - * handles the request. It is not recommended to make these calls in performance critical code - */ - -#include -#include - -#include -#include - -#include - -#include - -static char internal_gamemode_client_error_string[512] = { 0 }; - -/** - * Load libgamemode dynamically to dislodge us from most dependencies. - * This allows clients to link and/or use this regardless of runtime. - * See SDL2 for an example of the reasoning behind this in terms of - * dynamic versioning as well. - */ -static volatile int internal_libgamemode_loaded = 1; - -/* Typedefs for the functions to load */ -typedef int (*api_call_return_int)(void); -typedef const char *(*api_call_return_cstring)(void); -typedef int (*api_call_pid_return_int)(pid_t); - -/* Storage for functors */ -static api_call_return_int REAL_internal_gamemode_request_start = NULL; -static api_call_return_int REAL_internal_gamemode_request_end = NULL; -static api_call_return_int REAL_internal_gamemode_query_status = NULL; -static api_call_return_cstring REAL_internal_gamemode_error_string = NULL; -static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL; -static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL; -static api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL; - -/** - * Internal helper to perform the symbol binding safely. - * - * Returns 0 on success and -1 on failure - */ -__attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol( - void *handle, const char *name, void **out_func, size_t func_size, bool required) -{ - void *symbol_lookup = NULL; - char *dl_error = NULL; - - /* Safely look up the symbol */ - symbol_lookup = dlsym(handle, name); - dl_error = dlerror(); - if (required && (dl_error || !symbol_lookup)) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "dlsym failed - %s", - dl_error); - return -1; - } - - /* Have the symbol correctly, copy it to make it usable */ - memcpy(out_func, &symbol_lookup, func_size); - return 0; -} - -/** - * Loads libgamemode and needed functions - * - * Returns 0 on success and -1 on failure - */ -__attribute__((always_inline)) static inline int internal_load_libgamemode(void) -{ - /* We start at 1, 0 is a success and -1 is a fail */ - if (internal_libgamemode_loaded != 1) { - return internal_libgamemode_loaded; - } - - /* Anonymous struct type to define our bindings */ - struct binding { - const char *name; - void **functor; - size_t func_size; - bool required; - } bindings[] = { - { "real_gamemode_request_start", - (void **)&REAL_internal_gamemode_request_start, - sizeof(REAL_internal_gamemode_request_start), - true }, - { "real_gamemode_request_end", - (void **)&REAL_internal_gamemode_request_end, - sizeof(REAL_internal_gamemode_request_end), - true }, - { "real_gamemode_query_status", - (void **)&REAL_internal_gamemode_query_status, - sizeof(REAL_internal_gamemode_query_status), - false }, - { "real_gamemode_error_string", - (void **)&REAL_internal_gamemode_error_string, - sizeof(REAL_internal_gamemode_error_string), - true }, - { "real_gamemode_request_start_for", - (void **)&REAL_internal_gamemode_request_start_for, - sizeof(REAL_internal_gamemode_request_start_for), - false }, - { "real_gamemode_request_end_for", - (void **)&REAL_internal_gamemode_request_end_for, - sizeof(REAL_internal_gamemode_request_end_for), - false }, - { "real_gamemode_query_status_for", - (void **)&REAL_internal_gamemode_query_status_for, - sizeof(REAL_internal_gamemode_query_status_for), - false }, - }; - - void *libgamemode = NULL; - - /* Try and load libgamemode */ - libgamemode = dlopen("libgamemode.so.0", RTLD_NOW); - if (!libgamemode) { - /* Attempt to load unversioned library for compatibility with older - * versions (as of writing, there are no ABI changes between the two - - * this may need to change if ever ABI-breaking changes are made) */ - libgamemode = dlopen("libgamemode.so", RTLD_NOW); - if (!libgamemode) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "dlopen failed - %s", - dlerror()); - internal_libgamemode_loaded = -1; - return -1; - } - } - - /* Attempt to bind all symbols */ - for (size_t i = 0; i < sizeof(bindings) / sizeof(bindings[0]); i++) { - struct binding *binder = &bindings[i]; - - if (internal_bind_libgamemode_symbol(libgamemode, - binder->name, - binder->functor, - binder->func_size, - binder->required)) { - internal_libgamemode_loaded = -1; - return -1; - }; - } - - /* Success */ - internal_libgamemode_loaded = 0; - return 0; -} - -/** - * Redirect to the real libgamemode - */ -__attribute__((always_inline)) static inline const char *gamemode_error_string(void) -{ - /* If we fail to load the system gamemode, or we have an error string already, return our error - * string instead of diverting to the system version */ - if (internal_load_libgamemode() < 0 || internal_gamemode_client_error_string[0] != '\0') { - return internal_gamemode_client_error_string; - } - - /* Assert for static analyser that the function is not NULL */ - assert(REAL_internal_gamemode_error_string != NULL); - - return REAL_internal_gamemode_error_string(); -} - -/** - * Redirect to the real libgamemode - * Allow automatically requesting game mode - * Also prints errors as they happen. - */ -#ifdef GAMEMODE_AUTO -__attribute__((constructor)) -#else -__attribute__((always_inline)) static inline -#endif -int gamemode_request_start(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - /* Assert for static analyser that the function is not NULL */ - assert(REAL_internal_gamemode_request_start != NULL); - - if (REAL_internal_gamemode_request_start() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - return 0; -} - -/* Redirect to the real libgamemode */ -#ifdef GAMEMODE_AUTO -__attribute__((destructor)) -#else -__attribute__((always_inline)) static inline -#endif -int gamemode_request_end(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - /* Assert for static analyser that the function is not NULL */ - assert(REAL_internal_gamemode_request_end != NULL); - - if (REAL_internal_gamemode_request_end() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - return 0; -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_query_status(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_query_status == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_query_status missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_query_status(); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_request_start_for == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_request_start_for missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_request_start_for(pid); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t pid) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_request_end_for == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_request_end_for missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_request_end_for(pid); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_query_status_for == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_query_status_for missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_query_status_for(pid); -} - -#endif // CLIENT_GAMEMODE_H diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 999b380595..07e05a8fe4 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -181,12 +181,6 @@ if(ANDROID) android/applets/software_keyboard.h) endif() -if(LINUX AND NOT APPLE) - target_sources(common PRIVATE linux/gamemode.cpp linux/gamemode.h) - - target_link_libraries(common PRIVATE gamemode::headers) -endif() - if(ARCHITECTURE_x86_64) target_sources( common diff --git a/src/common/linux/gamemode.cpp b/src/common/linux/gamemode.cpp deleted file mode 100644 index 8d3e2934a6..0000000000 --- a/src/common/linux/gamemode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -#include "common/linux/gamemode.h" -#include "common/logging/log.h" -#include "common/settings.h" - -namespace Common::Linux { - -void StartGamemode() { - if (Settings::values.enable_gamemode) { - if (gamemode_request_start() < 0) { - LOG_WARNING(Frontend, "Failed to start gamemode: {}", gamemode_error_string()); - } else { - LOG_INFO(Frontend, "Started gamemode"); - } - } -} - -void StopGamemode() { - if (Settings::values.enable_gamemode) { - if (gamemode_request_end() < 0) { - LOG_WARNING(Frontend, "Failed to stop gamemode: {}", gamemode_error_string()); - } else { - LOG_INFO(Frontend, "Stopped gamemode"); - } - } -} - -void SetGamemodeState(bool state) { - if (state) { - StartGamemode(); - } else { - StopGamemode(); - } -} - -} // namespace Common::Linux diff --git a/src/common/linux/gamemode.h b/src/common/linux/gamemode.h deleted file mode 100644 index b80646ae27..0000000000 --- a/src/common/linux/gamemode.h +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -namespace Common::Linux { - -/** - * Start the (Feral Interactive) Linux gamemode if it is installed and it is activated - */ -void StartGamemode(); - -/** - * Stop the (Feral Interactive) Linux gamemode if it is installed and it is activated - */ -void StopGamemode(); - -/** - * Start or stop the (Feral Interactive) Linux gamemode if it is installed and it is activated - * @param state The new state the gamemode should have - */ -void SetGamemodeState(bool state); - -} // namespace Common::Linux diff --git a/src/common/settings.cpp b/src/common/settings.cpp index d3f7d9afea..706a899fcd 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -271,8 +271,6 @@ const char* TranslateCategory(Category category) { return "Services"; case Category::Paths: return "Paths"; - case Category::Linux: - return "Linux"; case Category::MaxEnum: break; } diff --git a/src/common/settings.h b/src/common/settings.h index e2fa2e75d9..6690411d2d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -616,13 +616,6 @@ struct Values { true, true}; - // Linux - SwitchableSetting enable_gamemode{linkage, true, "enable_gamemode", Category::Linux}; -#ifdef __unix__ - SwitchableSetting gui_force_x11{linkage, false, "gui_force_x11", Category::Linux}; - Setting gui_hide_backend_warning{linkage, false, "gui_hide_backend_warning", Category::Linux}; -#endif - // Controls InputSetting> players; diff --git a/src/common/settings_common.h b/src/common/settings_common.h index af16ec692b..0107895c8c 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -44,7 +47,6 @@ enum class Category : u32 { Multiplayer, Services, Paths, - Linux, LibraryApplet, MaxEnum, }; diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp index eec169aa14..94ec349651 100644 --- a/src/frontend_common/config.cpp +++ b/src/frontend_common/config.cpp @@ -308,16 +308,6 @@ void Config::ReadDebuggingValues() { EndGroup(); } -#ifdef __unix__ -void Config::ReadLinuxValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Linux)); - - ReadCategory(Settings::Category::Linux); - - EndGroup(); -} -#endif - void Config::ReadServiceValues() { BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); @@ -434,9 +424,6 @@ void Config::ReadValues() { ReadControlValues(); ReadCoreValues(); ReadCpuValues(); -#ifdef __unix__ - ReadLinuxValues(); -#endif ReadRendererValues(); ReadAudioValues(); ReadSystemValues(); @@ -537,9 +524,6 @@ void Config::SaveValues() { SaveControlValues(); SaveCoreValues(); SaveCpuValues(); -#ifdef __unix__ - SaveLinuxValues(); -#endif SaveRendererValues(); SaveAudioValues(); SaveSystemValues(); @@ -616,16 +600,6 @@ void Config::SaveDebuggingValues() { EndGroup(); } -#ifdef __unix__ -void Config::SaveLinuxValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Linux)); - - WriteCategory(Settings::Category::Linux); - - EndGroup(); -} -#endif - void Config::SaveNetworkValues() { BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h index ff816443ad..8aaf71cc60 100644 --- a/src/frontend_common/config.h +++ b/src/frontend_common/config.h @@ -84,9 +84,6 @@ protected: void ReadCoreValues(); void ReadDataStorageValues(); void ReadDebuggingValues(); -#ifdef __unix__ - void ReadLinuxValues(); -#endif void ReadServiceValues(); void ReadDisabledAddOnValues(); void ReadMiscellaneousValues(); @@ -119,9 +116,6 @@ protected: void SaveCoreValues(); void SaveDataStorageValues(); void SaveDebuggingValues(); -#ifdef __unix__ - void SaveLinuxValues(); -#endif void SaveNetworkValues(); void SaveDisabledAddOnValues(); void SaveMiscellaneousValues(); diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 2100760d9c..5a6bbda13c 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -5,6 +5,9 @@ add_library(qt_common STATIC qt_common.h qt_common.cpp + gamemode.cpp + gamemode.h + config/uisettings.cpp config/uisettings.h config/qt_config.cpp @@ -82,6 +85,7 @@ find_package(frozen) target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PUBLIC frozen::frozen-headers) +target_link_libraries(qt_common PRIVATE gamemode::headers) if (NOT APPLE AND ENABLE_OPENGL) target_compile_definitions(qt_common PUBLIC HAS_OPENGL) diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index c601d25d80..48190eda79 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -433,10 +433,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) tr("Whether or not to check for updates upon startup.")); // Linux - INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString()); + INSERT(UISettings, enable_gamemode, tr("Enable Gamemode"), QString()); #ifdef __unix__ - INSERT(Settings, gui_force_x11, tr("Force X11 as Graphics Backend"), QString()); - INSERT(Settings, gui_hide_backend_warning, QString(), QString()); + INSERT(UISettings, gui_force_x11, tr("Force X11 as Graphics Backend"), QString()); + INSERT(UISettings, gui_hide_backend_warning, QString(), QString()); #endif // Ui Debugging diff --git a/src/qt_common/config/uisettings.h b/src/qt_common/config/uisettings.h index 65d03cc990..c5a7d0b483 100644 --- a/src/qt_common/config/uisettings.h +++ b/src/qt_common/config/uisettings.h @@ -142,6 +142,19 @@ struct Values { Setting check_for_updates{linkage, true, "check_for_updates", Category::UiGeneral}; + // Linux/MinGW may support (requires libdl support) + SwitchableSetting enable_gamemode{linkage, +#ifndef _MSC_VER + true, +#else + false, +#endif + "enable_gamemode", Category::UiGeneral}; +#ifdef __unix__ + SwitchableSetting gui_force_x11{linkage, false, "gui_force_x11", Category::UiGeneral}; + Setting gui_hide_backend_warning{linkage, false, "gui_hide_backend_warning", Category::UiGeneral}; +#endif + // Discord RPC Setting enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui}; diff --git a/src/qt_common/gamemode.cpp b/src/qt_common/gamemode.cpp new file mode 100644 index 0000000000..6a3d870aae --- /dev/null +++ b/src/qt_common/gamemode.cpp @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// While technically available on al *NIX platforms, Linux is only available +// as the primary target of libgamemode.so - so warnings are suppressed +#ifdef __unix__ +#include +#endif +#include "qt_common/gamemode.h" +#include "common/logging/log.h" +#include "qt_common/config/uisettings.h" + +namespace Common::FeralGamemode { + +/// @brief Start the gamemode client +void Start() noexcept { + if (UISettings::values.enable_gamemode) { +#ifdef __unix__ + if (gamemode_request_start() < 0) { +#ifdef __linux__ + LOG_WARNING(Frontend, "{}", gamemode_error_string()); +#else + LOG_INFO(Frontend, "{}", gamemode_error_string()); +#endif + } else { + LOG_INFO(Frontend, "Done"); + } +#endif + } +} + +/// @brief Stop the gmemode client +void Stop() noexcept { + if (UISettings::values.enable_gamemode) { +#ifdef __unix__ + if (gamemode_request_end() < 0) { +#ifdef __linux__ + LOG_WARNING(Frontend, "{}", gamemode_error_string()); +#else + LOG_INFO(Frontend, "{}", gamemode_error_string()); +#endif + } else { + LOG_INFO(Frontend, "Done"); + } +#endif + } +} + +} // namespace Common::Linux diff --git a/src/qt_common/gamemode.h b/src/qt_common/gamemode.h new file mode 100644 index 0000000000..10cac730e2 --- /dev/null +++ b/src/qt_common/gamemode.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Common::FeralGamemode { + +void Start() noexcept; +void Stop() noexcept; + +} // namespace Common::FeralGamemode diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 8abeb90086..f3f0939705 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -104,9 +104,6 @@ add_executable(yuzu configuration/configure_input_profile_dialog.cpp configuration/configure_input_profile_dialog.h configuration/configure_input_profile_dialog.ui - configuration/configure_linux_tab.cpp - configuration/configure_linux_tab.h - configuration/configure_linux_tab.ui configuration/configure_mouse_panning.cpp configuration/configure_mouse_panning.h configuration/configure_mouse_panning.ui diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 29168ed79e..b2fe566a17 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -40,8 +40,6 @@ void ConfigureGeneral::SetConfiguration() {} void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { QLayout& general_layout = *ui->general_widget->layout(); - QLayout& linux_layout = *ui->linux_widget->layout(); - std::map general_hold{}; std::map linux_hold{}; @@ -54,13 +52,6 @@ void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { }; push(UISettings::values.linkage.by_category[Settings::Category::UiGeneral]); - push(Settings::values.linkage.by_category[Settings::Category::Linux]); - - // Only show Linux group on Unix -#ifndef __unix__ - ui->LinuxGroupBox->setVisible(false); -#endif - for (const auto setting : settings) { auto* widget = builder.BuildWidget(setting, apply_funcs); @@ -76,9 +67,6 @@ void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { case Settings::Category::UiGeneral: general_hold.emplace(setting->Id(), widget); break; - case Settings::Category::Linux: - linux_hold.emplace(setting->Id(), widget); - break; default: widget->deleteLater(); } @@ -87,9 +75,6 @@ void ConfigureGeneral::Setup(const ConfigurationShared::Builder& builder) { for (const auto& [id, widget] : general_hold) { general_layout.addWidget(widget); } - for (const auto& [id, widget] : linux_hold) { - linux_layout.addWidget(widget); - } } // Called to set the callback when resetting settings to defaults diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index ef20891a32..a10e7d3a50 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -46,33 +46,6 @@ - - - - Linux - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - diff --git a/src/yuzu/configuration/configure_linux_tab.cpp b/src/yuzu/configuration/configure_linux_tab.cpp deleted file mode 100644 index ab3d188162..0000000000 --- a/src/yuzu/configuration/configure_linux_tab.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/settings.h" -#include "core/core.h" -#include "ui_configure_linux_tab.h" -#include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/configure_linux_tab.h" -#include "yuzu/configuration/shared_widget.h" - -ConfigureLinuxTab::ConfigureLinuxTab(const Core::System& system_, - std::shared_ptr> group_, - const ConfigurationShared::Builder& builder, QWidget* parent) - : Tab(group_, parent), ui(std::make_unique()), system{system_} { - ui->setupUi(this); - - Setup(builder); - - SetConfiguration(); -} - -ConfigureLinuxTab::~ConfigureLinuxTab() = default; - -void ConfigureLinuxTab::SetConfiguration() {} -void ConfigureLinuxTab::Setup(const ConfigurationShared::Builder& builder) { - QLayout& linux_layout = *ui->linux_widget->layout(); - - std::map linux_hold{}; - - std::vector settings; - const auto push = [&](Settings::Category category) { - for (const auto setting : Settings::values.linkage.by_category[category]) { - settings.push_back(setting); - } - }; - - push(Settings::Category::Linux); - - for (auto* setting : settings) { - auto* widget = builder.BuildWidget(setting, apply_funcs); - - if (widget == nullptr) { - continue; - } - if (!widget->Valid()) { - widget->deleteLater(); - continue; - } - - linux_hold.insert({setting->Id(), widget}); - } - - for (const auto& [id, widget] : linux_hold) { - linux_layout.addWidget(widget); - } -} - -void ConfigureLinuxTab::ApplyConfiguration() { - const bool is_powered_on = system.IsPoweredOn(); - for (const auto& apply_func : apply_funcs) { - apply_func(is_powered_on); - } -} - -void ConfigureLinuxTab::changeEvent(QEvent* event) { - if (event->type() == QEvent::LanguageChange) { - RetranslateUI(); - } - - QWidget::changeEvent(event); -} - -void ConfigureLinuxTab::RetranslateUI() { - ui->retranslateUi(this); -} diff --git a/src/yuzu/configuration/configure_linux_tab.h b/src/yuzu/configuration/configure_linux_tab.h deleted file mode 100644 index 2f402079c9..0000000000 --- a/src/yuzu/configuration/configure_linux_tab.h +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -namespace Core { -class System; -} - -namespace Ui { -class ConfigureLinuxTab; -} - -namespace ConfigurationShared { -class Builder; -} - -class ConfigureLinuxTab : public ConfigurationShared::Tab { - Q_OBJECT - -public: - explicit ConfigureLinuxTab(const Core::System& system_, - std::shared_ptr> group, - const ConfigurationShared::Builder& builder, - QWidget* parent = nullptr); - ~ConfigureLinuxTab() override; - - void ApplyConfiguration() override; - void SetConfiguration() override; - -private: - void changeEvent(QEvent* event) override; - void RetranslateUI(); - - void Setup(const ConfigurationShared::Builder& builder); - - std::unique_ptr ui; - - const Core::System& system; - - std::vector> apply_funcs{}; -}; diff --git a/src/yuzu/configuration/configure_linux_tab.ui b/src/yuzu/configuration/configure_linux_tab.ui deleted file mode 100644 index f8e07f5811..0000000000 --- a/src/yuzu/configuration/configure_linux_tab.ui +++ /dev/null @@ -1,53 +0,0 @@ - - - ConfigureLinuxTab - - - Linux - - - - - - Linux - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 08a7a2da1f..691fc766ae 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -37,7 +37,6 @@ #include "yuzu/configuration/configure_graphics_advanced.h" #include "yuzu/configuration/configure_graphics_extensions.h" #include "yuzu/configuration/configure_input_per_game.h" -#include "yuzu/configuration/configure_linux_tab.h" #include "yuzu/configuration/configure_per_game.h" #include "yuzu/configuration/configure_per_game_addons.h" #include "yuzu/configuration/configure_system.h" @@ -68,7 +67,6 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, [](Settings::AspectRatio, Settings::ResolutionSetup) {}, tab_group, *builder, this); input_tab = std::make_unique(system_, game_config.get(), this); - linux_tab = std::make_unique(system_, tab_group, *builder, this); system_tab = std::make_unique(system_, tab_group, *builder, this); network_tab = std::make_unique(system_, this); @@ -84,13 +82,6 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles")); ui->tabWidget->addTab(network_tab.get(), tr("Network")); - // Only show Linux tab on Unix - linux_tab->setVisible(false); -#ifdef __unix__ - linux_tab->setVisible(true); - ui->tabWidget->addTab(linux_tab.get(), tr("Linux")); -#endif - setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("Properties")); diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index 81a652262e..e4d18f29b9 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -36,7 +36,6 @@ class ConfigureGraphics; class ConfigureGraphicsAdvanced; class ConfigureGraphicsExtensions; class ConfigureInputPerGame; -class ConfigureLinuxTab; class ConfigureSystem; class ConfigureNetwork; @@ -92,7 +91,6 @@ private: std::unique_ptr graphics_extensions_tab; std::unique_ptr graphics_tab; std::unique_ptr input_tab; - std::unique_ptr linux_tab; std::unique_ptr system_tab; std::unique_ptr network_tab; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 621c74a618..4de159627f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -122,7 +122,9 @@ int main(int argc, char* argv[]) { // the user folder in the Qt Frontend, we need to cd into that working directory const auto bin_path = Common::FS::GetBundleDirectory() / ".."; chdir(Common::FS::PathToUTF8String(bin_path).c_str()); -#elif defined(__unix__) && !defined(__ANDROID__) +#endif + +#ifdef __unix__ // Set the DISPLAY variable in order to open web browsers // TODO (lat9nq): Find a better solution for AppImages to start external applications if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) { diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index d0ece67028..32f15156f7 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -164,9 +164,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #endif -#ifdef __linux__ -#include "common/linux/gamemode.h" -#endif +#include "qt_common/gamemode.h" #ifdef _WIN32 #include "core/core_timing.h" @@ -423,9 +421,7 @@ MainWindow::MainWindow(bool has_broken_vulkan) SetupSigInterrupts(); #endif -#ifdef __linux__ - SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); -#endif + SetGamemodeEnabled(UISettings::values.enable_gamemode.GetValue()); UISettings::RestoreWindowState(config); @@ -2198,10 +2194,7 @@ void MainWindow::OnEmulationStopped() { emulation_running = false; discord_rpc->Update(); - -#ifdef __linux__ - Common::Linux::StopGamemode(); -#endif + Common::FeralGamemode::Stop(); // The emulation is stopped, so closing the window or not does not matter anymore disconnect(render_window, &GRenderWindow::Closed, this, &MainWindow::OnStopGame); @@ -3072,10 +3065,7 @@ void MainWindow::OnStartGame() { play_time_manager->Start(); discord_rpc->Update(); - -#ifdef __linux__ - Common::Linux::StartGamemode(); -#endif + Common::FeralGamemode::Start(); } void MainWindow::OnRestartGame() { @@ -3096,10 +3086,7 @@ void MainWindow::OnPauseGame() { play_time_manager->Stop(); UpdateMenuState(); AllowOSSleep(); - -#ifdef __linux__ - Common::Linux::StopGamemode(); -#endif + Common::FeralGamemode::Stop(); } void MainWindow::OnPauseContinueGame() { @@ -3384,11 +3371,9 @@ void MainWindow::OnConfigure() { const auto old_theme = UISettings::values.theme; const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue(); const auto old_language_index = Settings::values.language_index.GetValue(); -#ifdef __linux__ - const bool old_gamemode = Settings::values.enable_gamemode.GetValue(); -#endif + const bool old_gamemode = UISettings::values.enable_gamemode.GetValue(); #ifdef __unix__ - const bool old_force_x11 = Settings::values.gui_force_x11.GetValue(); + const bool old_force_x11 = UISettings::values.gui_force_x11.GetValue(); #endif Settings::SetConfiguringGlobal(true); @@ -3449,14 +3434,12 @@ void MainWindow::OnConfigure() { if (UISettings::values.enable_discord_presence.GetValue() != old_discord_presence) { SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); } -#ifdef __linux__ - if (Settings::values.enable_gamemode.GetValue() != old_gamemode) { - SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); + if (UISettings::values.enable_gamemode.GetValue() != old_gamemode) { + SetGamemodeEnabled(UISettings::values.enable_gamemode.GetValue()); } -#endif #ifdef __unix__ - if (Settings::values.gui_force_x11.GetValue() != old_force_x11) { - GraphicsBackend::SetForceX11(Settings::values.gui_force_x11.GetValue()); + if (UISettings::values.gui_force_x11.GetValue() != old_force_x11) { + GraphicsBackend::SetForceX11(UISettings::values.gui_force_x11.GetValue()); } #endif @@ -4403,7 +4386,7 @@ void MainWindow::OnCheckGraphicsBackend() { if (!isWayland) return; - const bool currently_hidden = Settings::values.gui_hide_backend_warning.GetValue(); + const bool currently_hidden = UISettings::values.gui_hide_backend_warning.GetValue(); if (currently_hidden) return; @@ -4426,11 +4409,11 @@ void MainWindow::OnCheckGraphicsBackend() { const bool hide = cb->isChecked(); if (hide != currently_hidden) { - Settings::values.gui_hide_backend_warning.SetValue(hide); + UISettings::values.gui_hide_backend_warning.SetValue(hide); } if (msgbox.clickedButton() == okButton) { - Settings::values.gui_force_x11.SetValue(true); + UISettings::values.gui_force_x11.SetValue(true); GraphicsBackend::SetForceX11(true); QMessageBox::information(this, tr("Restart Required"), @@ -4760,13 +4743,14 @@ void MainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { discord_rpc->Update(); } -#ifdef __linux__ void MainWindow::SetGamemodeEnabled(bool state) { if (emulation_running) { - Common::Linux::SetGamemodeState(state); + if (state) + Common::FeralGamemode::Start(); + else + Common::FeralGamemode::Stop(); } } -#endif void MainWindow::changeEvent(QEvent* event) { #ifdef __unix__ diff --git a/src/yuzu/main_window.h b/src/yuzu/main_window.h index 2ba92d476c..bbd76e847f 100644 --- a/src/yuzu/main_window.h +++ b/src/yuzu/main_window.h @@ -314,8 +314,8 @@ private: void SetupSigInterrupts(); static void HandleSigInterrupt(int); void OnSigInterruptNotifierActivated(); - void SetGamemodeEnabled(bool state); #endif + void SetGamemodeEnabled(bool state); Service::AM::FrontendAppletParameters ApplicationAppletParameters(); Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id, diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 6ec6f973bb..975e72e00c 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -60,10 +60,6 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } #endif -#ifdef __linux__ -#include "common/linux/gamemode.h" -#endif - static void PrintHelp(const char* argv0) { std::cout << "Usage: " << argv0 << " [options] \n" @@ -427,11 +423,6 @@ int main(int argc, char** argv) { // Just exit right away. exit(0); }); - -#ifdef __linux__ - Common::Linux::StartGamemode(); -#endif - void(system.Run()); if (system.DebuggerEnabled()) { system.InitializeDebugger(); @@ -442,11 +433,6 @@ int main(int argc, char** argv) { system.DetachDebugger(); void(system.Pause()); system.ShutdownMainProcess(); - -#ifdef __linux__ - Common::Linux::StopGamemode(); -#endif - detached_tasks.WaitForAllTasks(); return 0; }