From b0624f2bc93e1bde39b8bf94efe596964a99a0f8 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Tue, 18 Aug 2020 17:48:21 +0200 Subject: [PATCH] Updates to make the application work correctly (more or less) on macOS. --- NEWS.md | 5 ++++- es-app/src/guis/GuiMenu.cpp | 4 ++++ es-app/src/main.cpp | 6 +++--- es-core/src/InputManager.cpp | 4 ++++ es-core/src/Settings.cpp | 2 +- es-core/src/ThemeData.h | 2 +- es-core/src/guis/GuiInputConfig.cpp | 6 +++--- es-core/src/renderers/Renderer.cpp | 9 ++++++++- es-core/src/renderers/Renderer_GL21.cpp | 11 +++++++++++ es-core/src/utils/FileSystemUtil.cpp | 6 ++++-- 10 files changed, 43 insertions(+), 12 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4fac0b4fa..85eb0cd42 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,7 +4,9 @@ ### Release overview -First release, a major update to the application compared to the RetroPie version on which it is based. This includes new gamelist sorting logic, new game media handling and a completely updated Windows port (which now works about as well as the Unix version). The menu system has also been completely overhauled and the scraper has been expanded to support multiple media types (including videos) as well as providing detailed scraping configuration options. +First release, a major update to the application compared to the RetroPie version on which it is based. This includes new gamelist sorting logic, new game media handling and a completely updated Windows port (which works about as well as the Unix version). The menu system has also been completely overhauled and the scraper has been expanded to support multiple media types (including videos) as well as providing detailed scraping configuration options. + +Work has started on a macOS port too. It already runs more or less correctly, but is not completely ready for general use as of this version. Full navigation sound support has been implemented, and the metadata editor has seen a lot of updates including color coding of all changes done by the user and by the scraper. Favorite games can now also be sorted on top of the gamelists and game collections. @@ -27,6 +29,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * New default theme rbsimple-DE bundled with the software, this theme is largely based on recalbox-multi by the Recalbox community * Added extensive es_systems.cfg templates for Unix and Windows * Updated the application to compile and work on Microsoft Windows, including full UTF-16 (Unicode) support +* Updated the application to compile and work (more or less) on Apple macOS * Seamless (almost) launch of games without showing the desktop when starting and when returning from RetroArch and other emulators * Per-game launch command override, so that different cores or emulators can be used on a per-game basis (saved to gamelist.xml) * Core location can be defined relative to the emulator binary using the %EMUPATH% variable in es_systems.cfg (mostly useful for Windows) diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 8d7f1afb7..e627c66ec 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -78,12 +78,16 @@ void GuiMenu::openSoundSettings() { auto s = new GuiSettings(mWindow, "SOUND SETTINGS"); + // TEMPORARY - Hide the volume slider on macOS until the volume control logic + // has been implemented for this operating system. + #if !defined(__APPLE__) // System volume. auto volume = std::make_shared(mWindow, 0.f, 100.f, 1.f, "%"); volume->setValue((float)VolumeControl::getInstance()->getVolume()); s->addWithLabel("SYSTEM VOLUME", volume); s->addSaveFunc([volume] { VolumeControl::getInstance()-> setVolume((int)Math::round(volume->getValue())); }); + #endif if (UIModeController::getInstance()->isUIModeFull()) { // The ALSA Audio Card and Audio Device selection code is disabled at the moment. diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index f7c10dccf..a7f69dca2 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -594,12 +594,12 @@ int main(int argc, char* argv[]) } } - // Check if the media directory exists, and if not, log a warning. + // Check if the media directory exists, otherwise log an information entry. if (!Utils::FileSystem::isDirectory(FileData::getMediaDirectory()) || Utils::FileSystem::isSymlink(FileData::getMediaDirectory())) { - LOG(LogWarning) << "Game media directory does not exist " + LOG(LogInfo) << "Game media directory does not exist " "(or is not a directory or a symlink):"; - LOG(LogWarning) << FileData::getMediaDirectory(); + LOG(LogInfo) << FileData::getMediaDirectory(); } // Generate joystick events since we're done loading. diff --git a/es-core/src/InputManager.cpp b/es-core/src/InputManager.cpp index 609f21556..41eb23d30 100644 --- a/es-core/src/InputManager.cpp +++ b/es-core/src/InputManager.cpp @@ -388,7 +388,11 @@ void InputManager::loadDefaultKBConfig() cfg->mapInput("a", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RETURN, 1, true)); cfg->mapInput("b", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_BACKSPACE, 1, true)); cfg->mapInput("x", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_DELETE, 1, true)); + #if defined(__APPLE__) + cfg->mapInput("y", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_PRINTSCREEN, 1, true)); + #else cfg->mapInput("y", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_INSERT, 1, true)); + #endif cfg->mapInput("start", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_ESCAPE, 1, true)); cfg->mapInput("select", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F1, 1, true)); diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 0af5466b9..e5d74fcba 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -172,7 +172,7 @@ void Settings::setDefaults() #else mIntMap["MaxVRAM"] = 128; #endif - #if defined (__unix__) || defined (__APPLE__) + #if defined (__unix__) mStringMap["FullscreenMode"] = "normal"; #endif mStringMap["PowerSaverMode"] = "disabled"; diff --git a/es-core/src/ThemeData.h b/es-core/src/ThemeData.h index 2fde3d553..ef9b46cdd 100644 --- a/es-core/src/ThemeData.h +++ b/es-core/src/ThemeData.h @@ -66,7 +66,7 @@ public: inline void setFiles(const std::deque& deque) { - *this << "from theme \"" << deque.front() << "\"\n"; + *this << "From theme \"" << deque.front() << "\"\n"; for (auto it = deque.cbegin() + 1; it != deque.cend(); it++) *this << " (from included file \"" << (*it) << "\")\n"; *this << " "; diff --git a/es-core/src/guis/GuiInputConfig.cpp b/es-core/src/guis/GuiInputConfig.cpp index 7d6d94f1e..9bf5ee7e5 100755 --- a/es-core/src/guis/GuiInputConfig.cpp +++ b/es-core/src/guis/GuiInputConfig.cpp @@ -376,9 +376,9 @@ void GuiInputConfig::clearAssignment(int inputId) bool GuiInputConfig::filterTrigger(Input input, InputConfig* config, int inputId) { - #if defined(__linux__) - // On Linux, some gamepads return both an analog axis and a digital button for the trigger; - // we want the analog axis only, so this function removes the button press event. + #if defined(__linux__) || defined(__APPLE__) + // On Linux and macOS, some gamepads return both an analog axis and a digital button for + // the trigger; we want the analog axis only, so this function removes the button press event. // This is relevant mostly for Sony Dual Shock controllers. if (InputManager::getInstance()->getAxisCountByDevice(config->getDeviceId()) == 6) { if (config->getDeviceName().find("PLAYSTATION") != std::string::npos || diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index ea6f024c6..91259f4fd 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -113,15 +113,22 @@ namespace Renderer #else if (Settings::getInstance()->getBool("Windowed")) windowFlags = getWindowFlags(); + #if defined(__APPLE__) + else + // This seems to be the best fullscreen mode on macOS as the taskbar switcher + // works etc. while still filling the entire screen with the application window. + windowFlags = SDL_WINDOW_FULLSCREEN_DESKTOP | getWindowFlags(); + #else else if (Settings::getInstance()->getString("FullscreenMode") == "borderless") windowFlags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALWAYS_ON_TOP | getWindowFlags(); else windowFlags = SDL_WINDOW_FULLSCREEN | getWindowFlags(); #endif + #endif if ((sdlWindow = SDL_CreateWindow("EmulationStation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowWidth, windowHeight, windowFlags)) == nullptr) { - LOG(LogError) << "Error creating SDL window!\n\t" << SDL_GetError(); + LOG(LogError) << "Couldn't create SDL window. " << SDL_GetError(); return false; } diff --git a/es-core/src/renderers/Renderer_GL21.cpp b/es-core/src/renderers/Renderer_GL21.cpp index c7c509d26..012ef35d0 100644 --- a/es-core/src/renderers/Renderer_GL21.cpp +++ b/es-core/src/renderers/Renderer_GL21.cpp @@ -84,7 +84,13 @@ namespace Renderer void setupWindow() { + #if defined(__APPLE__) + // This is required on macOS, as the operating system will otherwise insist on using + // a newer OpenGL version which completely breaks the application. + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + #else SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + #endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); @@ -99,6 +105,11 @@ namespace Renderer void createContext() { sdlContext = SDL_GL_CreateContext(getSDLWindow()); + + if (!sdlContext) { + LOG(LogError) << "Error creating OpenGL context. " << SDL_GetError(); + } + SDL_GL_MakeCurrent(getSDLWindow(), sdlContext); std::string vendor = glGetString(GL_VENDOR) ? diff --git a/es-core/src/utils/FileSystemUtil.cpp b/es-core/src/utils/FileSystemUtil.cpp index 0d2417f00..9f100854a 100644 --- a/es-core/src/utils/FileSystemUtil.cpp +++ b/es-core/src/utils/FileSystemUtil.cpp @@ -751,7 +751,8 @@ namespace Utils #if defined(__APPLE__) struct stat info; - return (stat(path.c_str(), &info) == 0); + if (stat(path.c_str(), &info) != 0) + return false; #elif defined(_WIN64) struct stat64 info; if (_wstat64(Utils::String::stringToWideString(path).c_str(), &info) != 0) @@ -772,7 +773,8 @@ namespace Utils #if defined(__APPLE__) struct stat info; - return (stat(path.c_str(), &info) == 0); + if (stat(path.c_str(), &info) != 0) + return false; #elif defined(_WIN64) struct stat64 info; if (_wstat64(Utils::String::stringToWideString(path).c_str(), &info) != 0)