diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 5a9439481..4879536ba 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -466,7 +466,7 @@ void FileData::launchGame(Window* window) #endif Scripting::fireEvent("game-start", rom, basename); - int exitCode = 0; + int returnValue = 0; if (command.find("%EMUPATH%") != std::string::npos) { // Extract the emulator executable from the launch command string. This could either be @@ -530,24 +530,28 @@ void FileData::launchGame(Window* window) #ifdef _WIN64 LOG(LogInfo) << Utils::String::wideStringToString(commandWide); - exitCode = launchEmulatorWindows(commandWide); + returnValue = launchEmulatorWindows(commandWide); #else LOG(LogInfo) << command; - exitCode = launchEmulatorUnix(command); + returnValue = launchEmulatorUnix(command); #endif // Notify the user in case of a failed game launch using a popup window. - if (exitCode != 0) { - LOG(LogWarning) << "...launch terminated with nonzero exit code " << exitCode << "!"; + if (returnValue != 0) { + LOG(LogWarning) << "...launch terminated with nonzero return value " << returnValue << "!"; GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR LAUNCHING GAME '" + - Utils::String::toUpper(metadata.get("name")) + "' (EXIT CODE " + - Utils::String::toUpper(std::to_string(exitCode) + ")"), 4000); + Utils::String::toUpper(metadata.get("name")) + "' (ERROR CODE " + + Utils::String::toUpper(std::to_string(returnValue) + ")"), 6000); window->setInfoPopup(s); } + // This code is only needed for Windows, where we need to keep ES running while + // the game/emulator is in use. It's basically used to pause any playing game video. + #ifdef _WIN64 else { window->setLaunchedGame(); } + #endif Scripting::fireEvent("game-end"); diff --git a/es-app/src/animations/LaunchAnimation.h b/es-app/src/animations/LaunchAnimation.h index dc593a062..dbf5e6631 100644 --- a/es-app/src/animations/LaunchAnimation.h +++ b/es-app/src/animations/LaunchAnimation.h @@ -56,6 +56,8 @@ public: void apply(float t) override { + // TEMPORARY, disabled as it causes flicker when launching games. + return; cameraOut = Transform4x4f::Identity(); float zoom = Math::lerp(1.0, 4.25f, t*t); diff --git a/es-app/src/animations/MoveCameraAnimation.h b/es-app/src/animations/MoveCameraAnimation.h index 939e3d9e9..9da0c6bba 100644 --- a/es-app/src/animations/MoveCameraAnimation.h +++ b/es-app/src/animations/MoveCameraAnimation.h @@ -1,7 +1,7 @@ // // MoveCameraAnimation.h // -// Animation to play when moving the camera. +// Animation to play when moving the camera, used by the slide transition style. // #pragma once diff --git a/es-app/src/views/ViewController.cpp b/es-app/src/views/ViewController.cpp index 71570e166..fa7115a59 100644 --- a/es-app/src/views/ViewController.cpp +++ b/es-app/src/views/ViewController.cpp @@ -408,12 +408,16 @@ bool ViewController::input(InputConfig* config, Input input) if (mLockInput) return true; + // This code is only needed for Windows, where we need to keep ES running while + // the game/emulator is in use. It's basically used to pause any playing game video. + #ifdef _WIN64 // If we have previously launched a game and there is now input registered, it means // the user is back in ES, so unset the flag to indicate that a game has been launched // and update all the GUI components to reflect this. if (mWindow->getGameLaunchedState()) { mWindow->unsetLaunchedGame(); } + #endif // Open menu. if (!(UIModeController::getInstance()->isUIModeKid() && @@ -539,9 +543,13 @@ void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme) } } + // This code is only needed for Windows, where we need to keep ES running while + // the game/emulator is in use. It's basically used to pause any playing game video. + #ifdef _WIN64 // If a game has been launched, then update all the GUI components to reflect this. if (mWindow->getGameLaunchedState()) mWindow->setLaunchedGame(); + #endif // Redisplay the current view. if (mCurrentView) diff --git a/es-core/src/Platform.cpp b/es-core/src/Platform.cpp index c95bf8e4a..e7215d4d5 100644 --- a/es-core/src/Platform.cpp +++ b/es-core/src/Platform.cpp @@ -68,10 +68,49 @@ int runSystemCommand(const std::wstring& cmd_utf16) int launchEmulatorUnix(const std::string& cmd_utf8) { - // TODO, replace with proper child process execution. #ifdef __unix__ - return system(cmd_utf8.c_str()); - #else + std::string command = std::string(cmd_utf8) + " 2>&1"; + + FILE* commandPipe; + std::array buffer; + std::string commandOutput; + int returnValue; + + if (!(commandPipe = (FILE*)popen(command.c_str(), "r"))) { + LOG(LogError) << "Error - couldn't open pipe to command."; + return -1; + } + + while (fgets(buffer.data(), buffer.size(), commandPipe) != nullptr) { + commandOutput += buffer.data(); + } + + returnValue = pclose(commandPipe); + // We need to shift the return value as it contains some flags (which we don't need). + returnValue >>= 8; + + // Remove any trailing newline from the command output. + if (commandOutput.size()) { + if (commandOutput.back() == '\n') + commandOutput.pop_back(); + } + + if (returnValue) { + LOG(LogError) << "Error - launchEmulatorUnix - return value " << + std::to_string(returnValue) + ":"; + if (commandOutput.size()) + LOG(LogError) << commandOutput; + else + LOG(LogError) << "No error output provided by emulator."; + } + else if (commandOutput.size()) { + LOG(LogDebug) << "Platform::launchEmulatorUnix():"; + LOG(LogDebug) << "Output from launched game:\n" << commandOutput; + } + + return returnValue; + + #else // __unix__ return 0; #endif } @@ -98,6 +137,15 @@ int launchEmulatorWindows(const std::wstring& cmd_utf16) &si, // Pointer to the STARTUPINFOW structure. &pi); // Pointer to the PROCESS_INFORMATION structure. + // Unfortunately suspending ES and resuming when the emulator process has exited + // doesn't work reliably on Windows, so we need to keep ES running. Maybe there is + // some workaround for this. Possibly it's just SDL that is glitchy or it's actually + // something OS-specific. Keeping the code here just in case it could be reactivated. + // For sure it would simplify things, like not having to pause playing videos. +// // Wait for the child process to exit. +// WaitForSingleObject(pi.hThread, INFINITE); +// WaitForSingleObject(pi.hProcess, INFINITE); + // If the return value is false, then something failed. if (!processReturnValue) { LPWSTR pBuffer = nullptr; @@ -110,10 +158,14 @@ int launchEmulatorWindows(const std::wstring& cmd_utf16) std::string errorMessage = Utils::String::wideStringToString(pBuffer); // Remove trailing newline from the error message. - if (errorMessage.back() == '\n'); - errorMessage.pop_back(); - if (errorMessage.back() == '\r'); - errorMessage.pop_back(); + if (errorMessage.size()) { + if (errorMessage.back() == '\n') + errorMessage.pop_back(); + if (errorMessage.size()) { + if (errorMessage.back() == '\r') + errorMessage.pop_back(); + } + } LOG(LogError) << "Error - launchEmulatorWindows - system error code " << errorCode << ": " << errorMessage; @@ -124,6 +176,7 @@ int launchEmulatorWindows(const std::wstring& cmd_utf16) CloseHandle(pi.hThread); return errorCode; + #else // _WIN64 return 0; #endif diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 43ac9d9cc..ebdbd8819 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -27,6 +27,7 @@ Window::Window() mTimeSinceLastInput(0), mScreenSaver(nullptr), mRenderScreenSaver(false), + mGameLaunchedState(false), mInfoPopup(nullptr) { mHelp = new HelpComponent(this);