Moved all Platform functions to the utility namespace.

This commit is contained in:
Leon Styhre 2022-01-10 18:43:17 +01:00
parent 5a085c585e
commit 2d149c5161
8 changed files with 263 additions and 256 deletions

View file

@ -1107,10 +1107,10 @@ void FileData::launchGame(Window* window)
// Possibly keep ES-DE running in the background while the game is launched. // Possibly keep ES-DE running in the background while the game is launched.
#if defined(_WIN64) #if defined(_WIN64)
returnValue = returnValue = Utils::Platform::launchGameWindows(Utils::String::stringToWideString(command),
launchGameWindows(Utils::String::stringToWideString(command), runInBackground, hideWindow); runInBackground, hideWindow);
#else #else
returnValue = launchGameUnix(command, runInBackground); returnValue = Utils::Platform::launchGameUnix(command, runInBackground);
#endif #endif
// Notify the user in case of a failed game launch using a popup window. // Notify the user in case of a failed game launch using a popup window.
if (returnValue != 0) { if (returnValue != 0) {

View file

@ -1135,7 +1135,7 @@ void GuiMenu::openQuitMenu()
[this] { [this] {
Scripting::fireEvent("quit"); Scripting::fireEvent("quit");
close(true); close(true);
quitES(); Utils::Platform::quitES();
}, },
"NO", nullptr)); "NO", nullptr));
} }
@ -1153,7 +1153,7 @@ void GuiMenu::openQuitMenu()
[this] { [this] {
Scripting::fireEvent("quit"); Scripting::fireEvent("quit");
close(true); close(true);
quitES(); Utils::Platform::quitES();
}, },
"NO", nullptr)); "NO", nullptr));
}); });
@ -1170,7 +1170,7 @@ void GuiMenu::openQuitMenu()
[] { [] {
Scripting::fireEvent("quit", "reboot"); Scripting::fireEvent("quit", "reboot");
Scripting::fireEvent("reboot"); Scripting::fireEvent("reboot");
if (quitES(QuitMode::REBOOT) != 0) { if (Utils::Platform::quitES(Utils::Platform::QuitMode::REBOOT) != 0) {
LOG(LogWarning) << "Reboot terminated with non-zero result!"; LOG(LogWarning) << "Reboot terminated with non-zero result!";
} }
}, },
@ -1189,7 +1189,7 @@ void GuiMenu::openQuitMenu()
[] { [] {
Scripting::fireEvent("quit", "poweroff"); Scripting::fireEvent("quit", "poweroff");
Scripting::fireEvent("poweroff"); Scripting::fireEvent("poweroff");
if (quitES(QuitMode::POWEROFF) != 0) { if (Utils::Platform::quitES(Utils::Platform::QuitMode::POWEROFF) != 0) {
LOG(LogWarning) << "Power off terminated with non-zero result!"; LOG(LogWarning) << "Power off terminated with non-zero result!";
} }
}, },

View file

@ -563,8 +563,8 @@ int main(int argc, char* argv[])
if (Settings::getInstance()->getBool("HideTaskbar")) { if (Settings::getInstance()->getBool("HideTaskbar")) {
taskbarStateChanged = true; taskbarStateChanged = true;
taskbarState = getTaskbarState(); taskbarState = Utils::Platform::getTaskbarState();
hideTaskbar(); Utils::Platform::hideTaskbar();
} }
#endif #endif
@ -692,10 +692,10 @@ int main(int argc, char* argv[])
#if defined(_WIN64) #if defined(_WIN64)
// If the taskbar state was changed (taskbar was hidden), then revert it. // If the taskbar state was changed (taskbar was hidden), then revert it.
if (taskbarStateChanged) if (taskbarStateChanged)
revertTaskbarState(taskbarState); Utils::Platform::revertTaskbarState(taskbarState);
#endif #endif
processQuitMode(); Utils::Platform::processQuitMode();
LOG(LogInfo) << "EmulationStation cleanly shutting down"; LOG(LogInfo) << "EmulationStation cleanly shutting down";

View file

@ -239,7 +239,7 @@ void InputManager::doOnFinish()
LOG(LogInfo) << " " << tocall; LOG(LogInfo) << " " << tocall;
std::cout << "==============================================\n" std::cout << "==============================================\n"
"input config finish command:\n"; "input config finish command:\n";
int exitCode = runSystemCommand(tocall); int exitCode = Utils::Platform::runSystemCommand(tocall);
std::cout << "==============================================\n"; std::cout << "==============================================\n";
if (exitCode != 0) { if (exitCode != 0) {

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition // EmulationStation Desktop Edition
// Platform.cpp // Platform.cpp
// //
// Platform-specific functions. // Platform utility functions.
// //
#include "Platform.h" #include "Platform.h"
@ -25,133 +25,139 @@
#endif #endif
#include <fcntl.h> #include <fcntl.h>
int runRebootCommand() namespace Utils
{ {
namespace Platform
{
int runRebootCommand()
{
#if defined(_WIN64) #if defined(_WIN64)
return system("shutdown -r -t 0"); return system("shutdown -r -t 0");
#elif defined(__APPLE__) #elif defined(__APPLE__)
// This will probably never be used as macOS requires root privileges to reboot. // This will probably never be used as macOS requires root privileges to reboot.
return system("shutdown -r now"); return system("shutdown -r now");
#else #else
return system("shutdown --reboot now"); return system("shutdown --reboot now");
#endif #endif
} }
int runPoweroffCommand() int runPoweroffCommand()
{ {
#if defined(_WIN64) #if defined(_WIN64)
return system("shutdown -s -t 0"); return system("shutdown -s -t 0");
#elif defined(__APPLE__) #elif defined(__APPLE__)
// This will probably never be used as macOS requires root privileges to power off. // This will probably never be used as macOS requires root privileges to power off.
return system("shutdown now"); return system("shutdown now");
#else #else
return system("shutdown --poweroff now"); return system("shutdown --poweroff now");
#endif #endif
} }
int runSystemCommand(const std::string& cmd_utf8) int runSystemCommand(const std::string& cmd_utf8)
{ {
#if defined(_WIN64) #if defined(_WIN64)
// On Windows we use _wsystem to support non-ASCII paths // On Windows we use _wsystem to support non-ASCII paths
// which requires converting from UTF-8 to a wstring. // which requires converting from UTF-8 to a wstring.
std::wstring wchar_str = Utils::String::stringToWideString(cmd_utf8); std::wstring wchar_str = Utils::String::stringToWideString(cmd_utf8);
return _wsystem(wchar_str.c_str()); return _wsystem(wchar_str.c_str());
#else #else
return system(cmd_utf8.c_str()); return system(cmd_utf8.c_str());
#endif #endif
} }
int runSystemCommand(const std::wstring& cmd_utf16) int runSystemCommand(const std::wstring& cmd_utf16)
{ {
#if defined(_WIN64) #if defined(_WIN64)
return _wsystem(cmd_utf16.c_str()); return _wsystem(cmd_utf16.c_str());
#else #else
return 0; return 0;
#endif #endif
} }
int launchGameUnix(const std::string& cmd_utf8, bool runInBackground) int launchGameUnix(const std::string& cmd_utf8, bool runInBackground)
{ {
#if defined(__unix__) || defined(__APPLE__) #if defined(__unix__) || defined(__APPLE__)
std::string command = std::string(cmd_utf8) + " 2>&1 &"; std::string command = std::string(cmd_utf8) + " 2>&1 &";
// Launching games while keeping ES-DE running in the background is very crude as for // Launching games while keeping ES-DE running in the background is very crude as for
// instance no output from the command is captured and no real error handling is // instance no output from the command is captured and no real error handling is
// implemented. It should therefore only be used when absolutely necessary. // implemented. It should therefore only be used when absolutely necessary.
if (runInBackground) { if (runInBackground) {
LOG(LogDebug) << "Platform::launchGameUnix(): Launching game while keeping ES-DE running " LOG(LogDebug)
"in the background, no command output will be written to the log file"; << "Platform::launchGameUnix(): Launching game while keeping ES-DE running "
return system(command.c_str()); "in the background, no command output will be written to the log file";
} return system(command.c_str());
}
FILE* commandPipe; FILE* commandPipe;
std::array<char, 128> buffer; std::array<char, 128> buffer;
std::string commandOutput; std::string commandOutput;
int returnValue; int returnValue;
if (!(commandPipe = reinterpret_cast<FILE*>(popen(command.c_str(), "r")))) { if (!(commandPipe = reinterpret_cast<FILE*>(popen(command.c_str(), "r")))) {
LOG(LogError) << "Couldn't open pipe to command."; LOG(LogError) << "Couldn't open pipe to command.";
return -1; return -1;
} }
while (fgets(buffer.data(), buffer.size(), commandPipe) != nullptr) { while (fgets(buffer.data(), buffer.size(), commandPipe) != nullptr) {
commandOutput += buffer.data(); commandOutput += buffer.data();
} }
returnValue = pclose(commandPipe); returnValue = pclose(commandPipe);
#if defined(_RPI_) #if defined(_RPI_)
// Hack to avoid that the application window occasionally loses focus when returning from // Hack to avoid that the application window occasionally loses focus when returning
// a game, which only seems to happen on Raspberry Pi OS 10. // from a game, which only seems to happen on Raspberry Pi OS 10.
SDL_Delay(50); SDL_Delay(50);
SDL_SetWindowInputFocus(Renderer::getSDLWindow()); SDL_SetWindowInputFocus(Renderer::getSDLWindow());
#endif #endif
// We need to shift the return value as it contains some flags (which we don't need). // We need to shift the return value as it contains some flags (which we don't need).
returnValue >>= 8; returnValue >>= 8;
// Remove any trailing newline from the command output. // Remove any trailing newline from the command output.
if (commandOutput.size()) { if (commandOutput.size()) {
if (commandOutput.back() == '\n') if (commandOutput.back() == '\n')
commandOutput.pop_back(); commandOutput.pop_back();
} }
if (returnValue) { if (returnValue) {
LOG(LogError) << "launchGameUnix - return value " << std::to_string(returnValue) + ":"; LOG(LogError) << "launchGameUnix - return value "
if (commandOutput.size()) << std::to_string(returnValue) + ":";
LOG(LogError) << commandOutput; if (commandOutput.size())
else LOG(LogError) << commandOutput;
LOG(LogError) << "No error output provided by game or emulator"; else
} LOG(LogError) << "No error output provided by game or emulator";
else if (commandOutput.size()) { }
LOG(LogDebug) << "Platform::launchGameUnix():"; else if (commandOutput.size()) {
LOG(LogDebug) << "Output from launched game:\n" << commandOutput; LOG(LogDebug) << "Platform::launchGameUnix():";
} LOG(LogDebug) << "Output from launched game:\n" << commandOutput;
}
return returnValue; return returnValue;
#else // __unix__ #else // __unix__
return 0; return 0;
#endif #endif
} }
int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground, bool hideWindow) int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground, bool hideWindow)
{ {
#if defined(_WIN64) #if defined(_WIN64)
STARTUPINFOW si{}; STARTUPINFOW si{};
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
si.cb = sizeof(si); si.cb = sizeof(si);
if (hideWindow) { if (hideWindow) {
// Optionally hide the window. This is intended primarily for hiding console windows when // Optionally hide the window. This is intended primarily for hiding console windows
// launching scripts (used for example by Steam games and source ports). // when launching scripts (used for example by Steam games and source ports).
si.dwFlags = STARTF_USESHOWWINDOW; si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; si.wShowWindow = SW_HIDE;
} }
bool processReturnValue = true; bool processReturnValue = true;
DWORD errorCode = 0; DWORD errorCode = 0;
// clang-format off // clang-format off
processReturnValue = CreateProcessW( processReturnValue = CreateProcessW(
nullptr, // No application name (use command line). nullptr, // No application name (use command line).
const_cast<wchar_t*>(cmd_utf16.c_str()), // Command line. const_cast<wchar_t*>(cmd_utf16.c_str()), // Command line.
@ -163,148 +169,136 @@ int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground, bool
nullptr, // Use parent's starting directory. nullptr, // Use parent's starting directory.
&si, // Pointer to the STARTUPINFOW structure. &si, // Pointer to the STARTUPINFOW structure.
&pi); // Pointer to the PROCESS_INFORMATION structure. &pi); // Pointer to the PROCESS_INFORMATION structure.
// clang-format on // clang-format on
if (!runInBackground) { if (!runInBackground) {
int width{}; int width{};
int height{}; int height{};
// Hack to make the emulator window render correctly when launching games while running in // Hack to make the emulator window render correctly when launching games while
// full screen mode. If not done, the emulator window will simply be black although the // running in full screen mode. If not done, the emulator window will simply be
// game actually works and outputs sounds, accepts input etc. There is sometimes a white // black although the game actually works and outputs sounds, accepts input etc.
// flash the first time an emulator is started during the program session and a white // There is sometimes a white flash the first time an emulator is started during the
// single-pixel line will be visible at the bottom of the screen while the game is loading. // program session and a white single-pixel line will be visible at the bottom of
// But it's at least a tolerable workaround. // the screen while the game is loading. But it's at least a tolerable workaround.
SDL_GetWindowSize(Renderer::getSDLWindow(), &width, &height); SDL_GetWindowSize(Renderer::getSDLWindow(), &width, &height);
SDL_SetWindowSize(Renderer::getSDLWindow(), width, height - 1); SDL_SetWindowSize(Renderer::getSDLWindow(), width, height - 1);
SDL_Delay(100); SDL_Delay(100);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Renderer::swapBuffers(); Renderer::swapBuffers();
WaitForSingleObject(pi.hThread, INFINITE); WaitForSingleObject(pi.hThread, INFINITE);
WaitForSingleObject(pi.hProcess, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE);
SDL_SetWindowSize(Renderer::getSDLWindow(), width, height); SDL_SetWindowSize(Renderer::getSDLWindow(), width, height);
} }
// If the return value is false, then something failed. // If the return value is false, then something failed.
if (!processReturnValue) { if (!processReturnValue) {
LPWSTR pBuffer = nullptr; LPWSTR pBuffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&pBuffer), 0, nullptr); reinterpret_cast<LPWSTR>(&pBuffer), 0, nullptr);
errorCode = GetLastError(); errorCode = GetLastError();
std::string errorMessage = Utils::String::wideStringToString(pBuffer); std::string errorMessage = Utils::String::wideStringToString(pBuffer);
// Remove trailing newline from the error message. // Remove trailing newline from the error message.
if (errorMessage.size()) { if (errorMessage.size()) {
if (errorMessage.back() == '\n') if (errorMessage.back() == '\n')
errorMessage.pop_back(); errorMessage.pop_back();
if (errorMessage.size()) { if (errorMessage.size()) {
if (errorMessage.back() == '\r') if (errorMessage.back() == '\r')
errorMessage.pop_back(); errorMessage.pop_back();
}
}
LOG(LogError) << "launchGameWindows - system error code " << errorCode << ": "
<< errorMessage;
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return errorCode;
#else // _WIN64
return 0;
#endif
}
unsigned int getTaskbarState()
{
#if defined(_WIN64)
APPBARDATA barData;
barData.cbSize = sizeof(APPBARDATA);
return static_cast<UINT>(SHAppBarMessage(ABM_GETSTATE, &barData));
#else
return 0;
#endif
}
void hideTaskbar()
{
#if defined(_WIN64)
APPBARDATA barData;
barData.cbSize = sizeof(APPBARDATA);
barData.lParam = ABS_AUTOHIDE;
SHAppBarMessage(ABM_SETSTATE, &barData);
#endif
}
void revertTaskbarState(unsigned int& state)
{
#if defined(_WIN64)
APPBARDATA barData;
barData.cbSize = sizeof(APPBARDATA);
barData.lParam = state;
SHAppBarMessage(ABM_SETSTATE, &barData);
#endif
}
int quitES(QuitMode mode)
{
quitMode = mode;
SDL_Event quit;
quit.type = SDL_QUIT;
SDL_PushEvent(&quit);
return 0;
}
void emergencyShutdown()
{
LOG(LogError) << "Critical - Performing emergency shutdown...";
Window::getInstance()->deinit();
Log::flush();
exit(EXIT_FAILURE);
}
void processQuitMode()
{
switch (quitMode) {
case QuitMode::REBOOT: {
LOG(LogInfo) << "Rebooting system";
runRebootCommand();
break;
}
case QuitMode::POWEROFF: {
LOG(LogInfo) << "Powering off system";
runPoweroffCommand();
break;
}
default: {
break;
}
} }
} }
LOG(LogError) << "launchGameWindows - system error code " << errorCode << ": " } // namespace Platform
<< errorMessage;
}
// Close process and thread handles. } // namespace Utils
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return errorCode;
#else // _WIN64
return 0;
#endif
}
unsigned int getTaskbarState()
{
#if defined(_WIN64)
APPBARDATA barData;
barData.cbSize = sizeof(APPBARDATA);
return static_cast<UINT>(SHAppBarMessage(ABM_GETSTATE, &barData));
#else
return 0;
#endif
}
void hideTaskbar()
{
#if defined(_WIN64)
APPBARDATA barData;
barData.cbSize = sizeof(APPBARDATA);
barData.lParam = ABS_AUTOHIDE;
SHAppBarMessage(ABM_SETSTATE, &barData);
#endif
}
void revertTaskbarState(unsigned int& state)
{
#if defined(_WIN64)
APPBARDATA barData;
barData.cbSize = sizeof(APPBARDATA);
barData.lParam = state;
SHAppBarMessage(ABM_SETSTATE, &barData);
#endif
}
QuitMode quitMode = QuitMode::QUIT;
int quitES(QuitMode mode)
{
quitMode = mode;
SDL_Event quit;
quit.type = SDL_QUIT;
SDL_PushEvent(&quit);
return 0;
}
void emergencyShutdown()
{
LOG(LogError) << "Critical - Performing emergency shutdown...";
Window::getInstance()->deinit();
Log::flush();
exit(EXIT_FAILURE);
}
void touch(const std::string& filename)
{
#if defined(_WIN64)
FILE* fp;
fopen_s(&fp, filename.c_str(), "ab+");
if (fp != nullptr)
fclose(fp);
#else
int fd = open(filename.c_str(), O_CREAT | O_WRONLY, 0644);
if (fd >= 0)
close(fd);
#endif
}
void processQuitMode()
{
switch (quitMode) {
case QuitMode::REBOOT: {
LOG(LogInfo) << "Rebooting system";
runRebootCommand();
break;
}
case QuitMode::POWEROFF: {
LOG(LogInfo) << "Powering off system";
runPoweroffCommand();
break;
}
default: {
break;
}
}
}

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition // EmulationStation Desktop Edition
// Platform.h // Platform.h
// //
// Platform-specific functions. // Platform utility functions.
// //
#ifndef ES_CORE_PLATFORM_H #ifndef ES_CORE_PLATFORM_H
@ -17,29 +17,42 @@
#include <windows.h> #include <windows.h>
#endif #endif
enum QuitMode { namespace Utils
QUIT = 0, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0). {
REBOOT = 1, namespace Platform
POWEROFF = 2 {
}; enum QuitMode {
QUIT = 0, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
REBOOT = 1,
POWEROFF = 2
};
// Uses UTF-8 for Unix and does a UTF-16/wstring conversion for Windows. int runRebootCommand();
int runSystemCommand(const std::string& cmd_utf8); int runPoweroffCommand();
// Windows specific UTF-16/wstring function. (FOR FUTURE USE)
int runSystemCommand(const std::wstring& cmd_utf16);
int launchGameUnix(const std::string& cmd_utf8, bool runInBackground); // Uses UTF-8 for Unix and does a UTF-16/wstring conversion for Windows.
int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground, bool hideWindow); int runSystemCommand(const std::string& cmd_utf8);
// Windows specific UTF-16/wstring function. (FOR FUTURE USE)
int runSystemCommand(const std::wstring& cmd_utf16);
unsigned int getTaskbarState(); int launchGameUnix(const std::string& cmd_utf8, bool runInBackground);
void hideTaskbar(); int launchGameWindows(const std::wstring& cmd_utf16, bool runInBackground, bool hideWindow);
void revertTaskbarState(unsigned int& state);
// Clean, normal shutdown. unsigned int getTaskbarState();
int quitES(QuitMode mode = QuitMode::QUIT); void hideTaskbar();
void revertTaskbarState(unsigned int& state);
// Immediately shut down the application as cleanly as possible. // Clean, normal shutdown.
void emergencyShutdown(); int quitES(QuitMode mode = QuitMode::QUIT);
void processQuitMode();
// Immediately shut down the application as cleanly as possible.
void emergencyShutdown();
void processQuitMode();
inline static QuitMode quitMode = QuitMode::QUIT;
} // namespace Platform
} // namespace Utils
#endif // ES_CORE_PLATFORM_H #endif // ES_CORE_PLATFORM_H

View file

@ -77,7 +77,7 @@ namespace Scripting
.append(arg4) .append(arg4)
.append(arg4Quotation); .append(arg4Quotation);
LOG(LogDebug) << "Executing: " << script; LOG(LogDebug) << "Executing: " << script;
runSystemCommand(script); Utils::Platform::runSystemCommand(script);
} }
} }
} }

View file

@ -79,7 +79,7 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi
LOG(LogError) << testExePath; LOG(LogError) << testExePath;
LOG(LogError) << "Has EmulationStation been properly installed?"; LOG(LogError) << "Has EmulationStation been properly installed?";
Scripting::fireEvent("quit"); Scripting::fireEvent("quit");
emergencyShutdown(); Utils::Platform::emergencyShutdown();
} }
else { else {
return ""; return "";