mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-22 00:59:18 +01:00
Add GameMode support for Linux build (#796)
This commit is contained in:
parent
b74ae21953
commit
1bcdb35e42
@ -76,12 +76,14 @@ endif()
|
|||||||
|
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
||||||
|
option(ENABLE_FERAL_GAMEMODE "Enables Feral Interactive GameMode Support" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(ENABLE_OPENGL "Enables the OpenGL backend" ON)
|
option(ENABLE_OPENGL "Enables the OpenGL backend" ON)
|
||||||
option(ENABLE_VULKAN "Enables the Vulkan backend" ON)
|
option(ENABLE_VULKAN "Enables the Vulkan backend" ON)
|
||||||
option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON)
|
option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON)
|
||||||
|
|
||||||
|
|
||||||
# input backends
|
# input backends
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
option(ENABLE_XINPUT "Enables the usage of XInput" ON)
|
option(ENABLE_XINPUT "Enables the usage of XInput" ON)
|
||||||
@ -127,6 +129,7 @@ if (UNIX AND NOT APPLE)
|
|||||||
add_compile_definitions(HAS_WAYLAND)
|
add_compile_definitions(HAS_WAYLAND)
|
||||||
endif()
|
endif()
|
||||||
find_package(GTK3 REQUIRED)
|
find_package(GTK3 REQUIRED)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_VULKAN)
|
if (ENABLE_VULKAN)
|
||||||
@ -143,6 +146,14 @@ if (ENABLE_DISCORD_RPC)
|
|||||||
target_include_directories(discord-rpc INTERFACE ./dependencies/discord-rpc/include)
|
target_include_directories(discord-rpc INTERFACE ./dependencies/discord-rpc/include)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
if(ENABLE_FERAL_GAMEMODE)
|
||||||
|
add_compile_definitions(ENABLE_FERAL_GAMEMODE)
|
||||||
|
add_subdirectory(dependencies/gamemode EXCLUDE_FROM_ALL)
|
||||||
|
target_include_directories(gamemode INTERFACE ./dependencies/gamemode/lib)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if (ENABLE_WXWIDGETS)
|
if (ENABLE_WXWIDGETS)
|
||||||
find_package(wxWidgets 3.2 REQUIRED COMPONENTS base core gl propgrid xrc)
|
find_package(wxWidgets 3.2 REQUIRED COMPONENTS base core gl propgrid xrc)
|
||||||
endif()
|
endif()
|
||||||
|
4
dependencies/gamemode/CMakeLists.txt
vendored
Normal file
4
dependencies/gamemode/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
project( gamemode LANGUAGES C )
|
||||||
|
add_library (gamemode
|
||||||
|
"lib/gamemode_client.h"
|
||||||
|
"lib/client_loader.c")
|
35
dependencies/gamemode/lib/client_loader.c
vendored
Normal file
35
dependencies/gamemode/lib/client_loader.c
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Simply include the header with GAMEMODE_AUTO set
|
||||||
|
// This will ensure it calls the functions when it's loaded
|
||||||
|
#define GAMEMODE_AUTO
|
||||||
|
#include "gamemode_client.h"
|
376
dependencies/gamemode/lib/gamemode_client.h
vendored
Normal file
376
dependencies/gamemode/lib/gamemode_client.h
vendored
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
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
|
@ -53,6 +53,7 @@ void CemuConfig::Load(XMLConfigParser& parser)
|
|||||||
language = parser.get<sint32>("language", wxLANGUAGE_DEFAULT);
|
language = parser.get<sint32>("language", wxLANGUAGE_DEFAULT);
|
||||||
use_discord_presence = parser.get("use_discord_presence", true);
|
use_discord_presence = parser.get("use_discord_presence", true);
|
||||||
fullscreen_menubar = parser.get("fullscreen_menubar", false);
|
fullscreen_menubar = parser.get("fullscreen_menubar", false);
|
||||||
|
feral_gamemode = parser.get("feral_gamemode", false);
|
||||||
check_update = parser.get("check_update", check_update);
|
check_update = parser.get("check_update", check_update);
|
||||||
save_screenshot = parser.get("save_screenshot", save_screenshot);
|
save_screenshot = parser.get("save_screenshot", save_screenshot);
|
||||||
did_show_vulkan_warning = parser.get("vk_warning", did_show_vulkan_warning);
|
did_show_vulkan_warning = parser.get("vk_warning", did_show_vulkan_warning);
|
||||||
@ -357,6 +358,7 @@ void CemuConfig::Save(XMLConfigParser& parser)
|
|||||||
config.set<sint32>("language", language);
|
config.set<sint32>("language", language);
|
||||||
config.set<bool>("use_discord_presence", use_discord_presence);
|
config.set<bool>("use_discord_presence", use_discord_presence);
|
||||||
config.set<bool>("fullscreen_menubar", fullscreen_menubar);
|
config.set<bool>("fullscreen_menubar", fullscreen_menubar);
|
||||||
|
config.set<bool>("feral_gamemode", feral_gamemode);
|
||||||
config.set<bool>("check_update", check_update);
|
config.set<bool>("check_update", check_update);
|
||||||
config.set<bool>("save_screenshot", save_screenshot);
|
config.set<bool>("save_screenshot", save_screenshot);
|
||||||
config.set<bool>("vk_warning", did_show_vulkan_warning);
|
config.set<bool>("vk_warning", did_show_vulkan_warning);
|
||||||
|
@ -366,6 +366,7 @@ struct CemuConfig
|
|||||||
ConfigValue<std::string> mlc_path {};
|
ConfigValue<std::string> mlc_path {};
|
||||||
ConfigValue<bool> fullscreen_menubar{ false };
|
ConfigValue<bool> fullscreen_menubar{ false };
|
||||||
ConfigValue<bool> fullscreen{ false };
|
ConfigValue<bool> fullscreen{ false };
|
||||||
|
ConfigValue<bool> feral_gamemode{false};
|
||||||
ConfigValue<std::string> proxy_server{};
|
ConfigValue<std::string> proxy_server{};
|
||||||
|
|
||||||
// temporary workaround because feature crashes on macOS
|
// temporary workaround because feature crashes on macOS
|
||||||
|
@ -161,6 +161,11 @@ if(ENABLE_CUBEB)
|
|||||||
target_link_libraries(CemuGui PRIVATE cubeb::cubeb)
|
target_link_libraries(CemuGui PRIVATE cubeb::cubeb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
if(ENABLE_FERAL_GAMEMODE)
|
||||||
|
target_link_libraries(CemuGui PRIVATE gamemode)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
if (ENABLE_WXWIDGETS)
|
if (ENABLE_WXWIDGETS)
|
||||||
# PUBLIC because wx/app.h is included in CemuApp.h
|
# PUBLIC because wx/app.h is included in CemuApp.h
|
||||||
target_link_libraries(CemuGui PUBLIC wx::base wx::core wx::gl wx::propgrid wx::xrc)
|
target_link_libraries(CemuGui PUBLIC wx::base wx::core wx::gl wx::propgrid wx::xrc)
|
||||||
|
@ -179,6 +179,13 @@ wxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)
|
|||||||
m_disable_screensaver->SetToolTip(_("Prevents the system from activating the screen saver or going to sleep while running a game."));
|
m_disable_screensaver->SetToolTip(_("Prevents the system from activating the screen saver or going to sleep while running a game."));
|
||||||
second_row->Add(m_disable_screensaver, 0, botflag, 5);
|
second_row->Add(m_disable_screensaver, 0, botflag, 5);
|
||||||
|
|
||||||
|
// Enable/disable feral interactive gamemode
|
||||||
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
|
m_feral_gamemode = new wxCheckBox(box, wxID_ANY, _("Enable Feral GameMode"));
|
||||||
|
m_feral_gamemode->SetToolTip(_("Use FeralInteractive GameMode if installed."));
|
||||||
|
second_row->Add(m_feral_gamemode, 0, botflag, 5);
|
||||||
|
#endif
|
||||||
|
|
||||||
// temporary workaround because feature crashes on macOS
|
// temporary workaround because feature crashes on macOS
|
||||||
#if BOOST_OS_MACOS
|
#if BOOST_OS_MACOS
|
||||||
m_disable_screensaver->Enable(false);
|
m_disable_screensaver->Enable(false);
|
||||||
@ -868,7 +875,7 @@ void GeneralSettings2::StoreConfig()
|
|||||||
config.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
|
config.fullscreen_menubar = m_fullscreen_menubar->IsChecked();
|
||||||
config.check_update = m_auto_update->IsChecked();
|
config.check_update = m_auto_update->IsChecked();
|
||||||
config.save_screenshot = m_save_screenshot->IsChecked();
|
config.save_screenshot = m_save_screenshot->IsChecked();
|
||||||
|
config.feral_gamemode = m_feral_gamemode->IsChecked();
|
||||||
const bool use_ps = m_permanent_storage->IsChecked();
|
const bool use_ps = m_permanent_storage->IsChecked();
|
||||||
if(use_ps)
|
if(use_ps)
|
||||||
{
|
{
|
||||||
@ -1508,6 +1515,8 @@ void GeneralSettings2::ApplyConfig()
|
|||||||
|
|
||||||
m_permanent_storage->SetValue(config.permanent_storage);
|
m_permanent_storage->SetValue(config.permanent_storage);
|
||||||
m_disable_screensaver->SetValue(config.disable_screensaver);
|
m_disable_screensaver->SetValue(config.disable_screensaver);
|
||||||
|
|
||||||
|
m_feral_gamemode->SetValue(config.feral_gamemode);
|
||||||
// temporary workaround because feature crashes on macOS
|
// temporary workaround because feature crashes on macOS
|
||||||
#if BOOST_OS_MACOS
|
#if BOOST_OS_MACOS
|
||||||
m_disable_screensaver->SetValue(false);
|
m_disable_screensaver->SetValue(false);
|
||||||
|
@ -43,6 +43,7 @@ private:
|
|||||||
wxCheckBox* m_auto_update, *m_save_screenshot;
|
wxCheckBox* m_auto_update, *m_save_screenshot;
|
||||||
wxCheckBox* m_permanent_storage;
|
wxCheckBox* m_permanent_storage;
|
||||||
wxCheckBox* m_disable_screensaver;
|
wxCheckBox* m_disable_screensaver;
|
||||||
|
wxCheckBox* m_feral_gamemode;
|
||||||
wxListBox* m_game_paths;
|
wxListBox* m_game_paths;
|
||||||
wxTextCtrl* m_mlc_path;
|
wxTextCtrl* m_mlc_path;
|
||||||
|
|
||||||
|
@ -61,6 +61,11 @@
|
|||||||
#include "gui/helpers/wxWayland.h"
|
#include "gui/helpers/wxWayland.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//GameMode support
|
||||||
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
|
#include "gamemode_client.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Cafe/TitleList/TitleInfo.h"
|
#include "Cafe/TitleList/TitleInfo.h"
|
||||||
#include "Cafe/TitleList/TitleList.h"
|
#include "Cafe/TitleList/TitleList.h"
|
||||||
#include "wxHelper.h"
|
#include "wxHelper.h"
|
||||||
@ -581,6 +586,23 @@ bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY
|
|||||||
if (ActiveSettings::FullscreenEnabled())
|
if (ActiveSettings::FullscreenEnabled())
|
||||||
SetFullScreen(true);
|
SetFullScreen(true);
|
||||||
|
|
||||||
|
//GameMode support
|
||||||
|
#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)
|
||||||
|
if(GetConfig().feral_gamemode)
|
||||||
|
{
|
||||||
|
// attempt to start gamemode
|
||||||
|
if(gamemode_request_start() < 0)
|
||||||
|
{
|
||||||
|
// GameMode failed to start
|
||||||
|
cemuLog_log(LogType::Force, "Could not start GameMode");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "GameMode has been started.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CreateCanvas();
|
CreateCanvas();
|
||||||
CafeSystem::LaunchForegroundTitle();
|
CafeSystem::LaunchForegroundTitle();
|
||||||
RecreateMenu();
|
RecreateMenu();
|
||||||
|
Loading…
Reference in New Issue
Block a user