diff --git a/.travis/build-mac.bash b/.travis/build-mac.bash index 6662921455..ced36667d0 100644 --- a/.travis/build-mac.bash +++ b/.travis/build-mac.bash @@ -15,7 +15,9 @@ unzip -: sdk-*.zip mkdir vulkan-sdk ln -s ${PWD}/Vulkan-Headers*/include vulkan-sdk/include mkdir vulkan-sdk/lib -ln target/release/libportability.dylib vulkan-sdk/lib/libVulkan.dylib +cp target/release/libportability.dylib vulkan-sdk/lib/libVulkan.dylib +# Let macdeployqt locate and install Vulkan library +install_name_tool -id ${PWD}/vulkan-sdk/lib/libVulkan.dylib vulkan-sdk/lib/libVulkan.dylib export VULKAN_SDK=${PWD}/vulkan-sdk git submodule update --quiet --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng 3rdparty/cereal 3rdparty/hidapi 3rdparty/xxHash 3rdparty/yaml-cpp Vulkan/glslang diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 32c002a544..dd16ede5b9 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -1376,10 +1376,16 @@ const std::string& fs::get_config_dir() dir.resize(dir.rfind('/') + 1); #else + +#ifdef __APPLE__ + if (const char* home = ::getenv("HOME")) + dir = home + "/Library/Application Support"s; +#else if (const char* home = ::getenv("XDG_CONFIG_HOME")) dir = home; else if (const char* home = ::getenv("HOME")) dir = home + "/.config"s; +#endif else // Just in case dir = "./config"; diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 53178044ef..d087717809 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -41,6 +41,15 @@ file(GLOB RPCS3_SRC "*.cpp") if(WIN32) add_executable(rpcs3 WIN32 ${RPCS3_SRC}) +elseif(APPLE) + set(MACOSX_BUNDLE_BUNDLE_NAME rpcs3) + set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.rpcs3.rpcs3") + set(MACOSX_BUNDLE_INFO_STRING "Open-source Sony PlayStation 3 emulator") + set(MACOSX_BUNDLE_ICON_FILE "rpcs3.icns") + set(MACOSX_BUNDLE_LONG_VERSION_STRING "0.0.5") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "0.0.5") + set(MACOSX_BUNDLE_BUNDLE_VERSION "0.0.5") + add_executable(rpcs3 MACOSX_BUNDLE ${RPCS3_SRC} "${RPCS3_SRC_DIR}/rpcs3.icns") else() add_executable(rpcs3 ${RPCS3_SRC}) endif() @@ -84,8 +93,17 @@ set_target_properties(rpcs3 PROPERTIES cotire(rpcs3) -if (UNIX) - # Copy icons to executable directory +# Copy icons to executable directory +if(APPLE) + add_custom_command(TARGET rpcs3 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${RPCS3_SRC_DIR}/rpcs3.icns $/../Resources/rpcs3.icns + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/bin/Icons $/../Resources/Icons + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $/../Resources/GuiConfigs + COMMAND "${Qt5_DIR}/../../../bin/macdeployqt" "${PROJECT_BINARY_DIR}/bin/rpcs3.app") +elseif(UNIX) add_custom_command(TARGET rpcs3 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $/Icons) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 50e6b47c87..a58e1c3021 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -15,6 +15,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + // STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally #include #include @@ -505,24 +509,37 @@ namespace rsx if (info->data == nullptr) { // Resource was not found in config dir, try and grab from relative path (linux) - info = std::make_unique(("Icons/ui/" + res).c_str()); + auto src = "Icons/ui/" + res; + info = std::make_unique(src.c_str()); #ifndef _WIN32 - // Check for Icons in ../share/rpcs3 for AppImages and /usr/bin/ + // Check for Icons in ../share/rpcs3 for AppImages, + // in rpcs3.app/Contents/Resources for App Bundles, and /usr/bin. if (info->data == nullptr) { char result[ PATH_MAX ]; -#ifdef __linux__ - ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX ); +#if defined(__APPLE__) + uint32_t bufsize = PATH_MAX; + bool success = _NSGetExecutablePath( result, &bufsize ) == 0; +#elif defined(__linux__) + bool success = readlink( "/proc/self/exe", result, PATH_MAX ) >= 0; #else - ssize_t count = readlink( "/proc/curproc/file", result, PATH_MAX ); + bool success = readlink( "/proc/curproc/file", result, PATH_MAX ) >= 0; #endif - std::string executablePath = dirname(result); - info = std::make_unique((executablePath + "/../share/rpcs3/Icons/ui/" + res).c_str()); - - // Check if the icons are in the same directory as the executable (local builds) - if (info->data == nullptr) + if (success) { - info = std::make_unique((executablePath + "/Icons/ui/" + res).c_str()); + std::string executablePath = dirname(result); +#ifdef __APPLE__ + src = executablePath + "/../Resources/Icons/ui/" + res; +#else + src = executablePath + "/../share/rpcs3/Icons/ui/" + res; +#endif + info = std::make_unique(src.c_str()); + // Check if the icons are in the same directory as the executable (local builds) + if (info->data == nullptr) + { + src = executablePath + "/Icons/ui/" + res; + info = std::make_unique(src.c_str()); + } } } #endif @@ -530,7 +547,6 @@ namespace rsx { // Install the image to config dir auto dst_dir = fs::get_config_dir() + "Icons/ui/"; - auto src = "Icons/ui/" + res; auto dst = dst_dir + res; if (!fs::is_dir(dst_dir)) diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index 567a5ceaa7..1ad213a146 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -18,6 +18,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include "rpcs3_version.h" inline std::string sstr(const QString& _in) { return _in.toStdString(); } @@ -50,23 +54,38 @@ static semaphore<> s_qt_mutex{}; static QApplication app0{argc, argv}; } - QMessageBox msg; - msg.setWindowTitle(tr("RPCS3: Fatal Error")); - msg.setIcon(QMessageBox::Critical); - msg.setTextFormat(Qt::RichText); - msg.setText(QString(R"( -

- %1
- %2
- https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support
- %3
-

- )") - .arg(Qt::convertFromPlainText(QString::fromStdString(text))) - .arg(tr("HOW TO REPORT ERRORS:")) - .arg(tr("Please, don't send incorrect reports. Thanks for understanding."))); - msg.layout()->setSizeConstraint(QLayout::SetFixedSize); - msg.exec(); + auto show_report = [](const std::string& text) + { + QMessageBox msg; + msg.setWindowTitle(tr("RPCS3: Fatal Error")); + msg.setIcon(QMessageBox::Critical); + msg.setTextFormat(Qt::RichText); + msg.setText(QString(R"( +

+ %1
+ %2
+ https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support
+ %3
+

+ )") + .arg(Qt::convertFromPlainText(QString::fromStdString(text))) + .arg(tr("HOW TO REPORT ERRORS:")) + .arg(tr("Please, don't send incorrect reports. Thanks for understanding."))); + msg.layout()->setSizeConstraint(QLayout::SetFixedSize); + msg.exec(); + }; + +#ifdef __APPLE__ + // Cocoa access is not allowed outside of the main thread + if (!pthread_main_np()) + { + dispatch_sync(dispatch_get_main_queue(), ^ { show_report(text); }); + } + else +#endif + { + show_report(text); + } std::abort(); } diff --git a/rpcs3/rpcs3.icns b/rpcs3/rpcs3.icns new file mode 100644 index 0000000000..bf076ef391 Binary files /dev/null and b/rpcs3/rpcs3.icns differ diff --git a/rpcs3/rpcs3_app.cpp b/rpcs3/rpcs3_app.cpp index 00a43c6961..a1c34b4d2e 100644 --- a/rpcs3/rpcs3_app.cpp +++ b/rpcs3/rpcs3_app.cpp @@ -422,9 +422,13 @@ void rpcs3_app::OnChangeStyleSheetRequest(const QString& path) QFile file(path); -#if !defined(_WIN32) && !defined(__APPLE__) - // If we can't open the file, try the /share folder + // If we can't open the file, try the /share or /Resources folder +#if !defined(_WIN32) +#ifdef __APPLE__ + QString share_dir = QCoreApplication::applicationDirPath() + "/../Resources/"; +#else QString share_dir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/"; +#endif QFile share_file(share_dir + "GuiConfigs/" + QFileInfo(file.fileName()).fileName()); #endif @@ -451,7 +455,7 @@ void rpcs3_app::OnChangeStyleSheetRequest(const QString& path) setStyleSheet(file.readAll()); file.close(); } -#if !defined(_WIN32) && !defined(__APPLE__) +#if !defined(_WIN32) else if (share_file.open(QIODevice::ReadOnly | QIODevice::Text)) { QDir::setCurrent(share_dir); diff --git a/rpcs3/rpcs3_version.cpp b/rpcs3/rpcs3_version.cpp index ca8319d28e..a1d9ebb13d 100644 --- a/rpcs3/rpcs3_version.cpp +++ b/rpcs3/rpcs3_version.cpp @@ -9,5 +9,6 @@ namespace rpcs3 return RPCS3_GIT_BRANCH; } + //TODO: Make this accessible from cmake and keep in sync with MACOSX_BUNDLE_BUNDLE_VERSION. const extern utils::version version{ 0, 0, 5, utils::version_type::alpha, 1, RPCS3_GIT_VERSION }; } diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index b46bc99000..315dc4f708 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -338,10 +338,14 @@ QStringList gui_settings::GetStylesheetEntries() { QStringList nameFilter = QStringList("*.qss"); QStringList res = gui::utils::get_dir_entries(m_settingsDir, nameFilter); -#if !defined(_WIN32) && !defined(__APPLE__) - // Makes stylesheets load if using AppImage or installed to /usr/bin - QDir linuxStylesheetDir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/GuiConfigs/"; - res.append(gui::utils::get_dir_entries(linuxStylesheetDir, nameFilter)); +#if !defined(_WIN32) + // Makes stylesheets load if using AppImage (App Bundle) or installed to /usr/bin +#ifdef __APPLE__ + QDir platformStylesheetDir = QCoreApplication::applicationDirPath() + "/../Resources/GuiConfigs/"; +#else + QDir platformStylesheetDir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/GuiConfigs/"; +#endif + res.append(gui::utils::get_dir_entries(platformStylesheetDir, nameFilter)); res.removeDuplicates(); #endif res.sort(Qt::CaseInsensitive);