Added initial support for iOS

This commit is contained in:
Leon Styhre 2025-01-14 19:17:12 +01:00
parent 2af7267933
commit f3e2c837f2
20 changed files with 205 additions and 54 deletions

View file

@ -156,6 +156,9 @@ const std::string FileData::getROMDirectory()
{ {
#if defined(__ANDROID__) #if defined(__ANDROID__)
return AndroidVariables::sROMDirectory; return AndroidVariables::sROMDirectory;
#elif defined(__IOS__)
std::string dir {Utils::FileSystem::getHomePath() + "/Documents/ROMs"};
return dir;
#endif #endif
const std::string& romDirSetting {Settings::getInstance()->getString("ROMDirectory")}; const std::string& romDirSetting {Settings::getInstance()->getString("ROMDirectory")};
@ -187,6 +190,10 @@ const std::string FileData::getROMDirectory()
const std::string FileData::getMediaDirectory() const std::string FileData::getMediaDirectory()
{ {
#if defined(__IOS__)
return Utils::FileSystem::getAppDataDirectory() + "/downloaded_media/";
#endif
const std::string& mediaDirSetting {Settings::getInstance()->getString("MediaDirectory")}; const std::string& mediaDirSetting {Settings::getInstance()->getString("MediaDirectory")};
std::string mediaDirPath; std::string mediaDirPath;

View file

@ -21,7 +21,7 @@
#include <windows.h> #include <windows.h>
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
#include "ConvertPDF.h" #include "ConvertPDF.h"
#endif #endif
@ -56,7 +56,7 @@ bool PDFViewer::startPDFViewer(FileData* game)
{ {
ViewController::getInstance()->pauseViewVideos(); ViewController::getInstance()->pauseViewVideos();
#if !defined(__ANDROID__) #if !defined(__ANDROID__) && !defined(__IOS__)
#if defined(_WIN64) #if defined(_WIN64)
const std::string convertBinary {"/es-pdf-converter/es-pdf-convert.exe"}; const std::string convertBinary {"/es-pdf-converter/es-pdf-convert.exe"};
#else #else
@ -305,7 +305,7 @@ bool PDFViewer::getDocumentInfo()
// Close process and thread handles. // Close process and thread handles.
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
#elif defined(__ANDROID__) #elif defined(__ANDROID__) || defined(__IOS__)
if (ConvertPDF::processFile(mManualPath, "-fileinfo", 0, 0, 0, commandOutput) == -1) if (ConvertPDF::processFile(mManualPath, "-fileinfo", 0, 0, 0, commandOutput) == -1)
return false; return false;
#else #else
@ -449,7 +449,7 @@ void PDFViewer::convertPage(int pageNum)
CloseHandle(childStdoutRead); CloseHandle(childStdoutRead);
WaitForSingleObject(pi.hThread, INFINITE); WaitForSingleObject(pi.hThread, INFINITE);
WaitForSingleObject(pi.hProcess, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE);
#elif (__ANDROID__) #elif (__ANDROID__) || defined(__IOS__)
ConvertPDF::processFile(mManualPath, "-convert", pageNum, ConvertPDF::processFile(mManualPath, "-convert", pageNum,
static_cast<int>(mPages[pageNum].width), static_cast<int>(mPages[pageNum].width),
static_cast<int>(mPages[pageNum].height), imageData); static_cast<int>(mPages[pageNum].height), imageData);
@ -478,7 +478,7 @@ void PDFViewer::convertPage(int pageNum)
#if defined(_WIN64) #if defined(_WIN64)
if (!processReturnValue || (static_cast<int>(imageDataSize) < if (!processReturnValue || (static_cast<int>(imageDataSize) <
mPages[pageNum].width * mPages[pageNum].height * 4)) { mPages[pageNum].width * mPages[pageNum].height * 4)) {
#elif defined(__ANDROID__) #elif defined(__ANDROID__) || defined(__IOS__)
if (static_cast<int>(imageDataSize) < mPages[pageNum].width * mPages[pageNum].height * 4) { if (static_cast<int>(imageDataSize) < mPages[pageNum].width * mPages[pageNum].height * 4) {
#else #else
if (returnValue != 0 || (static_cast<int>(imageDataSize) < if (returnValue != 0 || (static_cast<int>(imageDataSize) <

View file

@ -44,6 +44,10 @@
#include "utils/PlatformUtilAndroid.h" #include "utils/PlatformUtilAndroid.h"
#endif #endif
#if defined(__IOS__)
#include "InputOverlay.h"
#endif
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <algorithm> #include <algorithm>
@ -1332,7 +1336,7 @@ void GuiMenu::openInputDeviceOptions()
} }
}); });
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
// Touch overlay size. // Touch overlay size.
auto touchOverlaySize = std::make_shared<OptionListComponent<std::string>>( auto touchOverlaySize = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), _("TOUCH OVERLAY SIZE"), false); getHelpStyle(), _("TOUCH OVERLAY SIZE"), false);
@ -1585,6 +1589,7 @@ void GuiMenu::openOtherOptions()
std::bind([this] { mWindow->pushGui(new GuiAlternativeEmulators); })); std::bind([this] { mWindow->pushGui(new GuiAlternativeEmulators); }));
s->addRow(alternativeEmulatorsRow); s->addRow(alternativeEmulatorsRow);
#if !defined(__IOS__)
// Game media directory. // Game media directory.
ComponentListRow rowMediaDir; ComponentListRow rowMediaDir;
auto mediaDirectory = std::make_shared<TextComponent>( auto mediaDirectory = std::make_shared<TextComponent>(
@ -1626,6 +1631,7 @@ void GuiMenu::openOtherOptions()
} }
}); });
s->addRow(rowMediaDir); s->addRow(rowMediaDir);
#endif
// Maximum VRAM. // Maximum VRAM.
auto maxVram = std::make_shared<SliderComponent>(128.0f, 2048.0f, 16.0f, "MiB"); auto maxVram = std::make_shared<SliderComponent>(128.0f, 2048.0f, 16.0f, "MiB");
@ -1663,6 +1669,7 @@ void GuiMenu::openOtherOptions()
}); });
#endif #endif
#if !defined(__IOS__)
// Display/monitor. // Display/monitor.
auto displayIndex = std::make_shared<OptionListComponent<std::string>>( auto displayIndex = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), _("DISPLAY/MONITOR INDEX"), false); getHelpStyle(), _("DISPLAY/MONITOR INDEX"), false);
@ -1683,6 +1690,7 @@ void GuiMenu::openOtherOptions()
s->setNeedsSaving(); s->setNeedsSaving();
} }
}); });
#endif
// Screen contents rotation. // Screen contents rotation.
auto screenRotate = std::make_shared<OptionListComponent<std::string>>( auto screenRotate = std::make_shared<OptionListComponent<std::string>>(
@ -1918,6 +1926,7 @@ void GuiMenu::openOtherOptions()
} }
}); });
#if !defined(__IOS__)
// Custom event scripts, fired using Scripting::fireEvent(). // Custom event scripts, fired using Scripting::fireEvent().
auto customEventScripts = std::make_shared<SwitchComponent>(); auto customEventScripts = std::make_shared<SwitchComponent>();
customEventScripts->setState(Settings::getInstance()->getBool("CustomEventScripts")); customEventScripts->setState(Settings::getInstance()->getBool("CustomEventScripts"));
@ -1929,6 +1938,7 @@ void GuiMenu::openOtherOptions()
s->setNeedsSaving(); s->setNeedsSaving();
} }
}); });
#endif
// Only show games included in the gamelist.xml files. // Only show games included in the gamelist.xml files.
auto parseGamelistOnly = std::make_shared<SwitchComponent>(); auto parseGamelistOnly = std::make_shared<SwitchComponent>();

View file

@ -166,7 +166,7 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
git_libgit2_init(); git_libgit2_init();
#if defined(__ANDROID__) && defined(USE_BUNDLED_CERTIFICATES) #if (defined(__ANDROID__) || defined(__IOS__)) && defined(USE_BUNDLED_CERTIFICATES)
git_libgit2_opts( git_libgit2_opts(
GIT_OPT_SET_SSL_CERT_LOCATIONS, GIT_OPT_SET_SSL_CERT_LOCATIONS,
ResourceManager::getInstance().getResourcePath(":/certificates/curl-ca-bundle.crt").c_str(), ResourceManager::getInstance().getResourcePath(":/certificates/curl-ca-bundle.crt").c_str(),
@ -178,7 +178,7 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
std::promise<bool>().swap(mPromise); std::promise<bool>().swap(mPromise);
mFuture = mPromise.get_future(); mFuture = mPromise.get_future();
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
mThemeDirectory = Utils::FileSystem::getInternalAppDataDirectory() + "/themes"; mThemeDirectory = Utils::FileSystem::getInternalAppDataDirectory() + "/themes";
#else #else
const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"}; const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"};

View file

@ -35,9 +35,13 @@
#include "views/ViewController.h" #include "views/ViewController.h"
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_main.h>
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
// TODO: Not needed after moving to SDL3.
#if !defined(__IOS__)
#include <SDL2/SDL_main.h>
#endif
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include "utils/PlatformUtilAndroid.h" #include "utils/PlatformUtilAndroid.h"
#endif #endif
@ -570,7 +574,7 @@ int main(int argc, char* argv[])
SDL_SetHint(SDL_HINT_APP_NAME, "ES-DE"); SDL_SetHint(SDL_HINT_APP_NAME, "ES-DE");
#if defined(__APPLE__) #if defined(__APPLE__) && !defined(__IOS__)
// This is a workaround to disable the incredibly annoying save state functionality in // This is a workaround to disable the incredibly annoying save state functionality in
// macOS which forces a restore of the previous window state. The problem is that this // macOS which forces a restore of the previous window state. The problem is that this
// removes the splash screen on startup and it may have other adverse effects as well. // removes the splash screen on startup and it may have other adverse effects as well.
@ -598,7 +602,7 @@ int main(int argc, char* argv[])
outputToConsole(); outputToConsole();
#endif #endif
#if !defined(__ANDROID__) #if !defined(__ANDROID__) && !defined(__IOS__)
{ {
std::vector<std::string> arguments; std::vector<std::string> arguments;
for (int i {0}; i < argc; ++i) for (int i {0}; i < argc; ++i)
@ -871,7 +875,7 @@ int main(int argc, char* argv[])
} }
{ {
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
const std::string themeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"}; const std::string themeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"};
if (!Utils::FileSystem::exists(themeDir)) { if (!Utils::FileSystem::exists(themeDir)) {
LOG(LogInfo) << "Creating themes directory \"" << themeDir << "\"..."; LOG(LogInfo) << "Creating themes directory \"" << themeDir << "\"...";
@ -881,6 +885,7 @@ int main(int argc, char* argv[])
LOG(LogWarning) << "Couldn't create directory, permission problems?"; LOG(LogWarning) << "Couldn't create directory, permission problems?";
} }
} }
#if defined(__ANDROID__)
if (!Utils::FileSystem::exists(themeDir + "/.nomedia")) { if (!Utils::FileSystem::exists(themeDir + "/.nomedia")) {
LOG(LogInfo) << "Creating \"no media\" file \"" << themeDir + "/.nomedia" << "\"..."; LOG(LogInfo) << "Creating \"no media\" file \"" << themeDir + "/.nomedia" << "\"...";
Utils::FileSystem::createEmptyFile(themeDir + "/.nomedia"); Utils::FileSystem::createEmptyFile(themeDir + "/.nomedia");
@ -888,6 +893,7 @@ int main(int argc, char* argv[])
LOG(LogWarning) << "Couldn't create file, permission problems?"; LOG(LogWarning) << "Couldn't create file, permission problems?";
} }
} }
#endif
#else #else
// Create the themes folder in the application data directory (or elsewhere if the // Create the themes folder in the application data directory (or elsewhere if the
// UserThemeDirectory setting has been defined). // UserThemeDirectory setting has been defined).
@ -932,6 +938,7 @@ int main(int argc, char* argv[])
#endif #endif
} }
#if !defined(__IOS__)
{ {
// Create the scripts folder in the application data directory. This is only required // Create the scripts folder in the application data directory. This is only required
// for custom event scripts so it's also created as a convenience. // for custom event scripts so it's also created as a convenience.
@ -949,6 +956,7 @@ int main(int argc, char* argv[])
} }
} }
} }
#endif
{ {
// Create the screensavers and screensavers/custom_slideshow directories. // Create the screensavers and screensavers/custom_slideshow directories.
@ -1064,9 +1072,11 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
InputOverlay::getInstance().init(); InputOverlay::getInstance().init();
#endif
#if defined(__ANDROID__)
LOG(LogDebug) << "Android API level: " << SDL_GetAndroidSDKVersion(); LOG(LogDebug) << "Android API level: " << SDL_GetAndroidSDKVersion();
Utils::Platform::Android::printDeviceInfo(); Utils::Platform::Android::printDeviceInfo();
int storageState {SDL_AndroidGetExternalStorageState()}; int storageState {SDL_AndroidGetExternalStorageState()};
@ -1313,5 +1323,9 @@ int main(int argc, char* argv[])
FreeConsole(); FreeConsole();
#endif #endif
#if defined(__IOS__)
exit(0);
#endif
return 0; return 0;
} }

View file

@ -67,6 +67,8 @@ public:
const std::string platformIdentifier {" P"}; const std::string platformIdentifier {" P"};
#elif defined(__linux__) #elif defined(__linux__)
const std::string platformIdentifier {" L"}; const std::string platformIdentifier {" L"};
#elif defined(__IOS__)
const std::string platformIdentifier {" I"};
#elif defined(__APPLE__) #elif defined(__APPLE__)
const std::string platformIdentifier {" M"}; const std::string platformIdentifier {" M"};
#elif defined(_WIN64) #elif defined(_WIN64)

View file

@ -266,7 +266,7 @@ void ViewController::invalidSystemsFileDialog()
void ViewController::noGamesDialog() void ViewController::noGamesDialog()
{ {
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
mNoGamesErrorMessage = _("NO GAME FILES WERE FOUND, PLEASE PLACE YOUR GAMES IN " mNoGamesErrorMessage = _("NO GAME FILES WERE FOUND, PLEASE PLACE YOUR GAMES IN "
"THE CONFIGURED ROM DIRECTORY. OPTIONALLY THE ROM " "THE CONFIGURED ROM DIRECTORY. OPTIONALLY THE ROM "
"DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL " "DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL "
@ -289,7 +289,7 @@ void ViewController::noGamesDialog()
mRomDirectory = FileData::getROMDirectory(); mRomDirectory = FileData::getROMDirectory();
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
mNoGamesMessageBox = new GuiMsgBox( mNoGamesMessageBox = new GuiMsgBox(
HelpStyle(), mNoGamesErrorMessage + mRomDirectory, HelpStyle(), mNoGamesErrorMessage + mRomDirectory,
#else #else
@ -404,7 +404,7 @@ void ViewController::noGamesDialog()
quit.type = SDL_QUIT; quit.type = SDL_QUIT;
SDL_PushEvent(&quit); SDL_PushEvent(&quit);
}, },
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
"", nullptr, nullptr, true, false, "", nullptr, nullptr, true, false,
(mRenderer->getIsVerticalOrientation() ? (mRenderer->getIsVerticalOrientation() ?
0.90f : 0.90f :

View file

@ -30,6 +30,10 @@
#include "utils/PlatformUtilAndroid.h" #include "utils/PlatformUtilAndroid.h"
#endif #endif
#if defined(__IOS__)
#define TOUCH_GUID_STRING "-3"
#endif
namespace namespace
{ {
int SDL_USER_CECBUTTONDOWN {-1}; int SDL_USER_CECBUTTONDOWN {-1};
@ -38,7 +42,7 @@ namespace
InputManager::InputManager() noexcept InputManager::InputManager() noexcept
: mWindow {Window::getInstance()} : mWindow {Window::getInstance()}
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
, mInputOverlay {InputOverlay::getInstance()} , mInputOverlay {InputOverlay::getInstance()}
#endif #endif
, mKeyboardInputConfig {nullptr} , mKeyboardInputConfig {nullptr}
@ -92,7 +96,7 @@ void InputManager::init()
LOG(LogInfo) << "Added keyboard with default configuration"; LOG(LogInfo) << "Added keyboard with default configuration";
} }
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
mTouchInputConfig = std::make_unique<InputConfig>(DEVICE_TOUCH, "Touch", TOUCH_GUID_STRING); mTouchInputConfig = std::make_unique<InputConfig>(DEVICE_TOUCH, "Touch", TOUCH_GUID_STRING);
loadTouchConfig(); loadTouchConfig();
#endif #endif
@ -301,7 +305,7 @@ int InputManager::getNumConfiguredDevices()
if (mKeyboardInputConfig->isConfigured()) if (mKeyboardInputConfig->isConfigured())
++num; ++num;
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
if (mTouchInputConfig->isConfigured()) if (mTouchInputConfig->isConfigured())
++num; ++num;
#endif #endif
@ -335,7 +339,7 @@ std::string InputManager::getDeviceGUIDString(int deviceId)
{ {
if (deviceId == DEVICE_KEYBOARD) if (deviceId == DEVICE_KEYBOARD)
return KEYBOARD_GUID_STRING; return KEYBOARD_GUID_STRING;
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
else if (deviceId == DEVICE_TOUCH) else if (deviceId == DEVICE_TOUCH)
return TOUCH_GUID_STRING; return TOUCH_GUID_STRING;
#endif #endif
@ -358,7 +362,7 @@ InputConfig* InputManager::getInputConfigByDevice(int device)
{ {
if (device == DEVICE_KEYBOARD) if (device == DEVICE_KEYBOARD)
return mKeyboardInputConfig.get(); return mKeyboardInputConfig.get();
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
else if (device == DEVICE_TOUCH) else if (device == DEVICE_TOUCH)
return mTouchInputConfig.get(); return mTouchInputConfig.get();
#endif #endif
@ -542,7 +546,7 @@ bool InputManager::parseEvent(const SDL_Event& event)
Input(DEVICE_KEYBOARD, TYPE_KEY, event.key.keysym.sym, 0, false)); Input(DEVICE_KEYBOARD, TYPE_KEY, event.key.keysym.sym, 0, false));
return true; return true;
} }
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
case SDL_FINGERDOWN: { case SDL_FINGERDOWN: {
if (!Settings::getInstance()->getBool("InputTouchOverlay")) if (!Settings::getInstance()->getBool("InputTouchOverlay"))
return false; return false;
@ -736,7 +740,7 @@ void InputManager::loadDefaultControllerConfig(SDL_JoystickID deviceIndex)
void InputManager::loadTouchConfig() void InputManager::loadTouchConfig()
{ {
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
InputConfig* cfg {mTouchInputConfig.get()}; InputConfig* cfg {mTouchInputConfig.get()};
if (cfg->isConfigured()) if (cfg->isConfigured())

View file

@ -13,7 +13,7 @@
#include "CECInput.h" #include "CECInput.h"
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
#include "InputOverlay.h" #include "InputOverlay.h"
#endif #endif
@ -68,7 +68,7 @@ private:
Window* mWindow; Window* mWindow;
CECInput mCECInput; CECInput mCECInput;
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
InputOverlay& mInputOverlay; InputOverlay& mInputOverlay;
#endif #endif

View file

@ -30,6 +30,9 @@ namespace Scripting
const std::string& arg3, const std::string& arg3,
const std::string& arg4) const std::string& arg4)
{ {
#if defined(__IOS__)
return;
#endif
if (!Settings::getInstance()->getBool("CustomEventScripts")) if (!Settings::getInstance()->getBool("CustomEventScripts"))
return; return;

View file

@ -245,7 +245,7 @@ void Settings::setDefaults()
// Input device settings. // Input device settings.
mStringMap["InputControllerType"] = {"xbox", "xbox"}; mStringMap["InputControllerType"] = {"xbox", "xbox"};
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
mStringMap["InputTouchOverlaySize"] = {"medium", "medium"}; mStringMap["InputTouchOverlaySize"] = {"medium", "medium"};
mStringMap["InputTouchOverlayOpacity"] = {"normal", "normal"}; mStringMap["InputTouchOverlayOpacity"] = {"normal", "normal"};
mIntMap["InputTouchOverlayFadeTime"] = {6, 6}; mIntMap["InputTouchOverlayFadeTime"] = {6, 6};
@ -263,7 +263,9 @@ void Settings::setDefaults()
mBoolMap["FavStarCustom"] = {false, false}; mBoolMap["FavStarCustom"] = {false, false};
// Other settings. // Other settings.
#if !defined(__IOS__)
mStringMap["MediaDirectory"] = {"", ""}; mStringMap["MediaDirectory"] = {"", ""};
#endif
#if defined(STEAM_DECK) || defined(RETRODECK) #if defined(STEAM_DECK) || defined(RETRODECK)
mIntMap["MaxVRAM"] = {512, 512}; mIntMap["MaxVRAM"] = {512, 512};
#elif defined(RASPBERRY_PI) #elif defined(RASPBERRY_PI)
@ -274,7 +276,9 @@ void Settings::setDefaults()
#if !defined(USE_OPENGLES) #if !defined(USE_OPENGLES)
mIntMap["AntiAliasing"] = {0, 0}; mIntMap["AntiAliasing"] = {0, 0};
#endif #endif
#if !defined(__IOS__)
mIntMap["DisplayIndex"] = {1, 1}; mIntMap["DisplayIndex"] = {1, 1};
#endif
mIntMap["ScreenRotate"] = {0, 0}; mIntMap["ScreenRotate"] = {0, 0};
#if defined(__APPLE__) #if defined(__APPLE__)
mStringMap["KeyboardQuitShortcut"] = {"CmdQ", "CmdQ"}; mStringMap["KeyboardQuitShortcut"] = {"CmdQ", "CmdQ"};
@ -304,7 +308,9 @@ void Settings::setDefaults()
mBoolMap["AlternativeEmulatorPerGame"] = {true, true}; mBoolMap["AlternativeEmulatorPerGame"] = {true, true};
mBoolMap["ShowHiddenFiles"] = {true, true}; mBoolMap["ShowHiddenFiles"] = {true, true};
mBoolMap["ShowHiddenGames"] = {true, true}; mBoolMap["ShowHiddenGames"] = {true, true};
#if !defined(__IOS__)
mBoolMap["CustomEventScripts"] = {false, false}; mBoolMap["CustomEventScripts"] = {false, false};
#endif
mBoolMap["ParseGamelistOnly"] = {false, false}; mBoolMap["ParseGamelistOnly"] = {false, false};
mBoolMap["MAMENameStripExtraInfo"] = {true, true}; mBoolMap["MAMENameStripExtraInfo"] = {true, true};
#if defined(__unix__) && !defined(__ANDROID__) #if defined(__unix__) && !defined(__ANDROID__)
@ -351,11 +357,11 @@ void Settings::setDefaults()
mBoolMap["LegacyGamelistFileLocation"] = {false, false}; mBoolMap["LegacyGamelistFileLocation"] = {false, false};
mBoolMap["CreatePlaceholderSystemDirectories"] = {false, false}; mBoolMap["CreatePlaceholderSystemDirectories"] = {false, false};
mStringMap["OpenGLVersion"] = {"", ""}; mStringMap["OpenGLVersion"] = {"", ""};
#if !defined(__ANDROID__) #if !defined(__ANDROID__) && !defined(__IOS__)
mStringMap["ROMDirectory"] = {"", ""}; mStringMap["ROMDirectory"] = {"", ""};
#endif #endif
mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"}; mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"};
#if !defined(__ANDROID__) #if !defined(__ANDROID__) && !defined(__IOS__)
mStringMap["UserThemeDirectory"] = {"", ""}; mStringMap["UserThemeDirectory"] = {"", ""};
#endif #endif
mIntMap["LottieMaxFileCache"] = {150, 150}; mIntMap["LottieMaxFileCache"] = {150, 150};

View file

@ -21,6 +21,10 @@
#include <algorithm> #include <algorithm>
#include <pugixml.hpp> #include <pugixml.hpp>
#if defined(__IOS__)
#include "utils/PlatformUtilIOS.h"
#endif
// clang-format off // clang-format off
std::vector<std::string> ThemeData::sSupportedViews { std::vector<std::string> ThemeData::sSupportedViews {
{"all"}, {"all"},
@ -770,6 +774,8 @@ void ThemeData::populateThemes()
#if defined(__ANDROID__) #if defined(__ANDROID__)
const std::string userThemeDirectory {Utils::FileSystem::getInternalAppDataDirectory() + const std::string userThemeDirectory {Utils::FileSystem::getInternalAppDataDirectory() +
"/themes"}; "/themes"};
#elif defined(__IOS__)
const std::string userThemeDirectory;
#else #else
const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"}; const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"};
const std::string userThemeDirSetting {Utils::FileSystem::expandHomePath( const std::string userThemeDirSetting {Utils::FileSystem::expandHomePath(
@ -801,6 +807,10 @@ void ThemeData::populateThemes()
const std::vector<std::string> themePaths {Utils::FileSystem::getProgramDataPath() + "/themes", const std::vector<std::string> themePaths {Utils::FileSystem::getProgramDataPath() + "/themes",
Utils::FileSystem::getAppDataDirectory() + "/themes", Utils::FileSystem::getAppDataDirectory() + "/themes",
userThemeDirectory}; userThemeDirectory};
#elif defined(__IOS__)
const std::vector<std::string> themePaths {Utils::Platform::iOS::getPackagePath() + "themes",
Utils::FileSystem::getAppDataDirectory() +
"/themes"};
#elif defined(__APPLE__) #elif defined(__APPLE__)
const std::vector<std::string> themePaths { const std::vector<std::string> themePaths {
Utils::FileSystem::getExePath() + "/themes", Utils::FileSystem::getExePath() + "/themes",

View file

@ -19,7 +19,7 @@
#include "resources/Font.h" #include "resources/Font.h"
#include "utils/LocalizationUtil.h" #include "utils/LocalizationUtil.h"
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
#include "InputOverlay.h" #include "InputOverlay.h"
#endif #endif
@ -436,7 +436,7 @@ void Window::update(int deltaTime)
if (mScreensaver && mRenderScreensaver) if (mScreensaver && mRenderScreensaver)
mScreensaver->update(deltaTime); mScreensaver->update(deltaTime);
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
if (Settings::getInstance()->getBool("InputTouchOverlay")) if (Settings::getInstance()->getBool("InputTouchOverlay"))
InputOverlay::getInstance().update(deltaTime); InputOverlay::getInstance().update(deltaTime);
#endif #endif
@ -657,7 +657,7 @@ void Window::render()
if (mRenderScreensaver) if (mRenderScreensaver)
mScreensaver->renderScreensaver(); mScreensaver->renderScreensaver();
#if defined(__ANDROID__) #if defined(__ANDROID__) || defined(__IOS__)
if (Settings::getInstance()->getBool("InputTouchOverlay")) if (Settings::getInstance()->getBool("InputTouchOverlay"))
InputOverlay::getInstance().render(mRenderer->getIdentity()); InputOverlay::getInstance().render(mRenderer->getIdentity());
#endif #endif

View file

@ -69,6 +69,9 @@ bool Renderer::createWindow()
mInitialCursorState = (SDL_ShowCursor(0) != 0); mInitialCursorState = (SDL_ShowCursor(0) != 0);
#if defined(__IOS__)
int displayIndex {0};
#else
int displayIndex {Settings::getInstance()->getInt("DisplayIndex")}; int displayIndex {Settings::getInstance()->getInt("DisplayIndex")};
// Check that an invalid value has not been manually entered in the es_settings.xml file. // Check that an invalid value has not been manually entered in the es_settings.xml file.
if (displayIndex != 1 && displayIndex != 2 && displayIndex != 3 && displayIndex != 4) { if (displayIndex != 1 && displayIndex != 2 && displayIndex != 3 && displayIndex != 4) {
@ -88,6 +91,7 @@ bool Renderer::createWindow()
else { else {
LOG(LogInfo) << "Using display: " << std::to_string(displayIndex + 1); LOG(LogInfo) << "Using display: " << std::to_string(displayIndex + 1);
} }
#endif
SDL_DisplayMode displayMode; SDL_DisplayMode displayMode;
SDL_GetDesktopDisplayMode(displayIndex, &displayMode); SDL_GetDesktopDisplayMode(displayIndex, &displayMode);
@ -217,6 +221,8 @@ bool Renderer::createWindow()
else else
// If the resolution has been manually set from the command line, then keep the border. // If the resolution has been manually set from the command line, then keep the border.
windowFlags = SDL_WINDOW_OPENGL; windowFlags = SDL_WINDOW_OPENGL;
#elif defined(__IOS__)
windowFlags = SDL_WINDOW_FULLSCREEN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
#elif defined(__APPLE__) #elif defined(__APPLE__)
// Not sure if this could be a useful setting. // Not sure if this could be a useful setting.
// SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0"); // SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0");
@ -249,19 +255,22 @@ bool Renderer::createWindow()
mDisplayIndex = displayIndex; mDisplayIndex = displayIndex;
#if defined(__APPLE__) #if defined(__APPLE__)
// The code below is required as the high DPI scaling on macOS is very bizarre and is // The code below is required as the high DPI scaling on macOS and iOS is measured in "points"
// measured in "points" rather than pixels (even though the naming convention sure looks // rather than pixels. For example there could be a 1920x1080 entry in the macOS display
// like pixels). For example there could be a 1920x1080 entry in the OS display settings // settings that actually corresponds to something like 3840x2160 pixels while at the same
// that actually corresponds to something like 3840x2160 pixels while at the same time // time there is a separate 1080p entry which corresponds to a "real" 1920x1080 resolution.
// there is a separate 1080p entry which corresponds to a "real" 1920x1080 resolution.
// Therefore the --resolution flag results in different things depending on whether a high // Therefore the --resolution flag results in different things depending on whether a high
// DPI screen is used. E.g. 1280x720 on a 4K display would actually end up as 2560x1440 // DPI screen is used. E.g. 1280x720 on a 4K display would actually end up as 2560x1440 pixels.
// which is incredibly strange. No point in struggling with this strangeness though, // The scale factor on macOS and iOS can be 1, 2 or 3 and we use this factor to calculate the
// instead we simply indicate the physical pixel dimensions in parenthesis in the log // actual physical pixel dimensions. We indicate these numbers inside parenthesis in the log
// file and make sure to double the window and screen sizes in case of a high DPI // file and we multiply the internal pixel resolution accordingly so that the full display
// display so that the full application window is used for rendering. // or window size is always used for rendering.
int width {0}; int width {0};
#if defined(__IOS__)
SDL_GetWindowSizeInPixels(mSDLWindow, &width, nullptr);
#else
SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr); SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr);
#endif
int scaleFactor {static_cast<int>(width / mWindowWidth)}; int scaleFactor {static_cast<int>(width / mWindowWidth)};
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"

View file

@ -14,9 +14,17 @@
#include <chrono> #include <chrono>
#endif #endif
#if defined(__IOS__)
#include <SDL2/SDL_syswm.h>
#endif
RendererOpenGL::RendererOpenGL() noexcept RendererOpenGL::RendererOpenGL() noexcept
: mShaderFBO1 {0} : mShaderFBO1 {0}
, mShaderFBO2 {0} , mShaderFBO2 {0}
, mFramebuffer {0}
#if defined(__IOS__)
, mColorbuffer {0}
#endif
, mVertexBuffer1 {0} , mVertexBuffer1 {0}
, mVertexBuffer2 {0} , mVertexBuffer2 {0}
, mSDLContext {nullptr} , mSDLContext {nullptr}
@ -112,7 +120,7 @@ GLenum RendererOpenGL::convertTextureType(const TextureType type)
#else #else
case TextureType::BGRA: { return GL_BGRA; } break; case TextureType::BGRA: { return GL_BGRA; } break;
#endif #endif
#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) #if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(__IOS__)
case TextureType::RED: { return GL_LUMINANCE; } break; case TextureType::RED: { return GL_LUMINANCE; } break;
#else #else
case TextureType::RED: { return GL_RED; } break; case TextureType::RED: { return GL_RED; } break;
@ -251,6 +259,28 @@ bool RendererOpenGL::createContext()
#endif #endif
#endif #endif
#if defined(__IOS__)
SDL_SysWMinfo info {};
SDL_VERSION(&info.version);
UIWindow* uiWindow {nullptr};
if (SDL_GetWindowWMInfo(getSDLWindow(), &info) && info.subsystem == SDL_SYSWM_UIKIT)
uiWindow = (UIWindow*)info.info.uikit.window;
if (uiWindow) {
mFramebuffer = info.info.uikit.framebuffer;
mColorbuffer = info.info.uikit.colorbuffer;
}
GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer));
GL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mColorbuffer));
GLenum status {glCheckFramebufferStatus(GL_FRAMEBUFFER)};
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOG(LogError) << "Couldn't setup framebuffer: " << status;
}
#endif
GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0)); GL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
GL_CHECK_ERROR(glEnable(GL_BLEND)); GL_CHECK_ERROR(glEnable(GL_BLEND));
@ -306,7 +336,7 @@ bool RendererOpenGL::createContext()
GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mPostProcTexture2, 0)); mPostProcTexture2, 0));
GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer));
return true; return true;
} }
@ -379,7 +409,7 @@ void RendererOpenGL::setSwapInterval()
void RendererOpenGL::swapBuffers() void RendererOpenGL::swapBuffers()
{ {
#if defined(__APPLE__) #if defined(__APPLE__) && !defined(__IOS__)
// On macOS when running in the background, the OpenGL driver apparently does not swap // On macOS when running in the background, the OpenGL driver apparently does not swap
// the frames which leads to a very fast swap time. This makes ES-DE use a lot of CPU // the frames which leads to a very fast swap time. This makes ES-DE use a lot of CPU
// resources which slows down the games significantly on slower machines. By introducing // resources which slows down the games significantly on slower machines. By introducing
@ -444,8 +474,17 @@ unsigned int RendererOpenGL::createTexture(const unsigned int texUnit,
GL_UNSIGNED_BYTE, data)); GL_UNSIGNED_BYTE, data));
} }
else { else {
#if defined(__IOS__)
if (type == TextureType::RED)
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0,
textureType, GL_UNSIGNED_BYTE, data));
else
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType,
GL_UNSIGNED_BYTE, data));
#else
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType,
GL_UNSIGNED_BYTE, data)); GL_UNSIGNED_BYTE, data));
#endif
} }
#else #else
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType, GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType,
@ -756,7 +795,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
for (int p {0}; p < shaderPasses; ++p) { for (int p {0}; p < shaderPasses; ++p) {
if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) { if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) {
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer));
if (offsetOrPadding) if (offsetOrPadding)
setViewport(mViewport); setViewport(mViewport);
drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA, drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
@ -818,10 +857,10 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
GL_CHECK_ERROR( GL_CHECK_ERROR(
glReadPixels(0, 0, height, width, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA)); glReadPixels(0, 0, height, width, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA));
#endif #endif
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer));
} }
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer));
if (offsetOrPadding) if (offsetOrPadding)
setViewport(mViewport); setViewport(mViewport);

View file

@ -13,7 +13,11 @@
#include "renderers/ShaderOpenGL.h" #include "renderers/ShaderOpenGL.h"
#if defined(USE_OPENGLES) #if defined(USE_OPENGLES)
#if defined(__IOS__)
#include <OpenGLES/ES3/gl.h>
#else
#include <GLES3/gl3.h> #include <GLES3/gl3.h>
#endif
#include <SDL2/SDL_opengles.h> #include <SDL2/SDL_opengles.h>
#else #else
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
@ -78,6 +82,10 @@ private:
std::vector<std::shared_ptr<ShaderOpenGL>> mShaderProgramVector; std::vector<std::shared_ptr<ShaderOpenGL>> mShaderProgramVector;
GLuint mShaderFBO1; GLuint mShaderFBO1;
GLuint mShaderFBO2; GLuint mShaderFBO2;
GLuint mFramebuffer;
#if defined(__IOS__)
GLuint mColorbuffer;
#endif
GLuint mVertexBuffer1; GLuint mVertexBuffer1;
GLuint mVertexBuffer2; GLuint mVertexBuffer2;

View file

@ -14,13 +14,21 @@
#include "renderers/Renderer.h" #include "renderers/Renderer.h"
#include "utils/MathUtil.h" #include "utils/MathUtil.h"
#if defined(__IOS__)
#define GLES_SILENCE_DEPRECATION
#endif
#if defined(_WIN64) #if defined(_WIN64)
#include <GL/glew.h> #include <GL/glew.h>
#endif #endif
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#if defined(USE_OPENGLES) #if defined(USE_OPENGLES)
#if defined(__IOS__)
#include <OpenGLES/ES3/gl.h>
#else
#include <GLES3/gl3.h> #include <GLES3/gl3.h>
#endif
#include <SDL2/SDL_opengles.h> #include <SDL2/SDL_opengles.h>
#else #else
#include <SDL2/SDL_opengl.h> #include <SDL2/SDL_opengl.h>

View file

@ -16,6 +16,10 @@
#include <fstream> #include <fstream>
#if defined(__IOS__)
#include "utils/PlatformUtilIOS.h"
#endif
ResourceManager& ResourceManager::getInstance() ResourceManager& ResourceManager::getInstance()
{ {
static ResourceManager instance; static ResourceManager instance;
@ -32,14 +36,21 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi
if (Utils::FileSystem::exists(testHome)) if (Utils::FileSystem::exists(testHome))
return testHome; return testHome;
#if defined(__APPLE__) #if defined(__IOS__)
const std::string iOSPackagePath {Utils::Platform::iOS::getPackagePath() + &path[2]};
if (Utils::FileSystem::exists(iOSPackagePath))
return iOSPackagePath;
#endif
#if defined(__APPLE__) && !defined(__IOS__)
// For macOS, check in the ../Resources directory relative to the executable directory. // For macOS, check in the ../Resources directory relative to the executable directory.
std::string applePackagePath {Utils::FileSystem::getExePath() + "/../Resources/resources/" + std::string applePackagePath {Utils::FileSystem::getExePath() + "/../Resources/resources/" +
&path[2]}; &path[2]};
if (Utils::FileSystem::exists(applePackagePath)) { if (Utils::FileSystem::exists(applePackagePath))
return applePackagePath; return applePackagePath;
}
#elif (defined(__unix__) && !defined(APPIMAGE_BUILD)) || defined(__ANDROID__) || defined(__HAIKU__) #elif (defined(__unix__) && !defined(APPIMAGE_BUILD)) || defined(__ANDROID__) || defined(__HAIKU__)
// Check in the program data directory. // Check in the program data directory.
std::string testDataPath {Utils::FileSystem::getProgramDataPath() + "/resources/" + std::string testDataPath {Utils::FileSystem::getProgramDataPath() + "/resources/" +
@ -71,10 +82,12 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi
LOG(LogError) << "Program resource missing: " << path; LOG(LogError) << "Program resource missing: " << path;
LOG(LogError) << "Tried to find the resource in the following locations:"; LOG(LogError) << "Tried to find the resource in the following locations:";
LOG(LogError) << testHome; LOG(LogError) << testHome;
#if defined(__APPLE__) #if defined(__IOS__)
LOG(LogError) << iOSPackagePath;
#elif defined(__APPLE__)
LOG(LogError) << applePackagePath; LOG(LogError) << applePackagePath;
#elif defined(__unix__) && !defined(APPIMAGE_BUILD) #elif defined(__unix__) && !defined(APPIMAGE_BUILD)
LOG(LogError) << testDataPath; LOG(LogError) << testDataPath;
#endif #endif
#if !defined(__ANDROID__) #if !defined(__ANDROID__)
LOG(LogError) << testExePath; LOG(LogError) << testExePath;

View file

@ -260,7 +260,10 @@ namespace Utils
{ {
#if defined(__ANDROID__) #if defined(__ANDROID__)
return getHomePath(); return getHomePath();
#else #elif defined(__IOS__)
return getHomePath() + "/Documents/ES-DE";
#endif
if (FileSystemVariables::sAppDataDirectory.empty()) { if (FileSystemVariables::sAppDataDirectory.empty()) {
#if !defined(_WIN64) #if !defined(_WIN64)
if (getenv("ESDE_APPDATA_DIR") != nullptr) { if (getenv("ESDE_APPDATA_DIR") != nullptr) {
@ -282,7 +285,6 @@ namespace Utils
} }
return FileSystemVariables::sAppDataDirectory; return FileSystemVariables::sAppDataDirectory;
#endif
} }
std::string getInternalAppDataDirectory() std::string getInternalAppDataDirectory()

View file

@ -41,6 +41,9 @@ namespace Utils
{ {
int runRebootCommand() int runRebootCommand()
{ {
#if defined(__IOS__)
return 0;
#else
#if defined(_WIN64) #if defined(_WIN64)
return system("shutdown -r -t 0"); return system("shutdown -r -t 0");
#elif defined(__APPLE__) || defined(__FreeBSD__) #elif defined(__APPLE__) || defined(__FreeBSD__)
@ -48,11 +51,15 @@ namespace Utils
return system("shutdown -r now"); return system("shutdown -r now");
#else #else
return system("shutdown --reboot now"); return system("shutdown --reboot now");
#endif
#endif #endif
} }
int runPoweroffCommand() int runPoweroffCommand()
{ {
#if defined(__IOS__)
return 0;
#else
#if defined(_WIN64) #if defined(_WIN64)
return system("shutdown -s -t 0"); return system("shutdown -s -t 0");
#elif defined(__APPLE__) #elif defined(__APPLE__)
@ -62,11 +69,15 @@ namespace Utils
return system("shutdown -p now"); return system("shutdown -p now");
#else #else
return system("shutdown --poweroff now"); return system("shutdown --poweroff now");
#endif
#endif #endif
} }
int runSystemCommand(const std::string& cmd_utf8) int runSystemCommand(const std::string& cmd_utf8)
{ {
#if defined(__IOS__)
return 0;
#else
#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.
@ -74,6 +85,7 @@ namespace Utils
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 #endif
} }
@ -102,7 +114,11 @@ namespace Utils
LOG(LogDebug) LOG(LogDebug)
<< "Platform::launchGameUnix(): Launching game while keeping ES-DE running " << "Platform::launchGameUnix(): Launching game while keeping ES-DE running "
"in the background, no command output will be written to the log file"; "in the background, no command output will be written to the log file";
#if defined(__IOS__)
return 0;
#else
return system(command.c_str()); return system(command.c_str());
#endif
} }
FILE* commandPipe; FILE* commandPipe;