Index: src/CMakeLists.txt =================================================================== --- src/CMakeLists.txt +++ src/CMakeLists.txt @@ -304,6 +304,22 @@ kf5_add_kdeinit_executable(dolphin ${dolphin_SRCS}) +if (APPLE) + # own plist template + set_target_properties (dolphin PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/MacOSXBundleInfo.plist.in) + # the MacOSX bundle display name property (CFBundleDisplayName) is not currently supported by cmake, + # so has to be set for all targets in this cmake file + set(MACOSX_BUNDLE_DISPLAY_NAME Okular5) + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.Dolphin") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Dolphin5") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_DISPLAY_NAME "Dolphin5") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_INFO_STRING "Dolphin, KDE's file manager focusing on usability") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_LONG_VERSION_STRING "Dolphin ${KDE_APPLICATIONS_VERSION}") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION "${KDE_APPLICATIONS_VERSION}") + set_target_properties(dolphin PROPERTIES MACOSX_BUNDLE_COPYRIGHT "2002-2020 The Dolphin Authors") +endif (APPLE) + target_link_libraries(kdeinit_dolphin PUBLIC dolphinprivate Index: src/MacOSXBundleInfo.plist.in =================================================================== --- /dev/null +++ src/MacOSXBundleInfo.plist.in @@ -0,0 +1,73 @@ + + + + + NSPrincipalClass + NSApplication + NSHighResolutionCapable + True + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + CFBundleDocumentTypes + + + CFBundleTypeName + Folder + CFBundleTypeOSTypes + + fold + + CFBundleTypeRole + Editor + + + CFBundleTypeName + Volume + CFBundleTypeOSTypes + + disk + + CFBundleTypeRole + Editor + + + CFBundleTypeExtensions + + * + + CFBundleTypeName + NSStringPboardType + CFBundleTypeRole + Viewer + + + + Index: src/dolphinmainwindow.cpp =================================================================== --- src/dolphinmainwindow.cpp +++ src/dolphinmainwindow.cpp @@ -931,7 +931,11 @@ QUrl urlA = items.at(0).url(); QUrl urlB = items.at(1).url(); +#ifdef Q_OS_MACOS + QString command(QStringLiteral("open -a kompare --args -c \"")); +#else QString command(QStringLiteral("kompare -c \"")); +#endif command.append(urlA.toDisplayString(QUrl::PreferLocalFile)); command.append("\" \""); command.append(urlB.toDisplayString(QUrl::PreferLocalFile)); Index: src/dolphinpart.cpp =================================================================== --- src/dolphinpart.cpp +++ src/dolphinpart.cpp @@ -547,7 +547,11 @@ if (!(actions.isEmpty())) { actions.first()->trigger(); } else { +#ifdef Q_OS_MACOS + KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QStringLiteral("open -a kfind --args"), {url().toString()}, this); +#else KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QStringLiteral("kfind"), {url().toString()}, this); +#endif job->setDesktopName(QStringLiteral("org.kde.kfind")); job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, widget())); job->start(); Index: src/dolphintabwidget.cpp =================================================================== --- src/dolphintabwidget.cpp +++ src/dolphintabwidget.cpp @@ -334,7 +334,7 @@ } args << QStringLiteral("--new-window"); - KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob("dolphin", args, this); + KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(KShell::quoteArgs(QCoreApplication::applicationFilePath()), args, this); job->setDesktopName(QStringLiteral("org.kde.dolphin")); job->start(); Index: src/global.cpp =================================================================== --- src/global.cpp +++ src/global.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,7 @@ void Dolphin::openNewWindow(const QList &urls, QWidget *window, const OpenNewWindowFlags &flags) { - QString command = QStringLiteral("dolphin --new-window"); + QString command = QStringLiteral("%1 --new-window").arg(KShell::quoteArg(QCoreApplication::applicationFilePath())); if (flags.testFlag(OpenNewWindowFlag::Select)) { command.append(QLatin1String(" --select")); Index: src/main.cpp =================================================================== --- src/main.cpp +++ src/main.cpp @@ -45,6 +45,59 @@ #endif #include +#ifdef Q_OS_MACOS +class OpenFileEventHandler : public QObject +{ + Q_OBJECT +public: + OpenFileEventHandler(QApplication *parent) + : QObject(parent) + { + parent->installEventFilter(this); + } + + bool eventFilter(QObject *obj, QEvent *event) override + { + if (event->type() == QEvent::FileOpen) { + QFileOpenEvent *openEvent = static_cast(event); + qCDebug(DolphinDebug) << "File open event:" << openEvent->url(); + m_urls.append(Dolphin::validateUris(QStringList(openEvent->file()))); + if (m_mainWindow && !m_urls.isEmpty()) { + if (GeneralSettings::openExternallyCalledFolderInNewTab()) { + const auto serviceName = QStringLiteral("org.kde.dolphin-%1").arg(QCoreApplication::applicationPid()); + if (!Dolphin::attachToExistingInstance(m_urls, false, false, serviceName)) { + qCWarning(DolphinDebug) << "Failed to open" << m_urls; + } + } else { + Dolphin::openNewWindow(m_urls, m_mainWindow); + } + m_urls.clear(); + } + return true; + } + return QObject::eventFilter(obj, event); + } + + QList popUrls() + { + const auto ret = m_urls; + m_urls.clear(); + return ret; + } + + + void setMainWindow(DolphinMainWindow *w) + { + m_mainWindow = w; + } + +private: + DolphinMainWindow* m_mainWindow = nullptr; + QList m_urls; +}; + +#endif + extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv) { #ifndef Q_OS_WIN @@ -70,6 +123,10 @@ app.setWindowIcon(QIcon::fromTheme(QStringLiteral("system-file-manager"), app.windowIcon())); KCrash::initialize(); +#ifdef Q_OS_MACOS + // start processing Mac OS FileOpenEvents + const auto openEventHandler = new OpenFileEventHandler(&app); +#endif Kdelibs4ConfigMigrator migrate(QStringLiteral("dolphin")); migrate.setConfigFiles(QStringList() << QStringLiteral("dolphinrc")); @@ -140,24 +197,45 @@ const bool openFiles = parser.isSet(QStringLiteral("select")); const QStringList args = parser.positionalArguments(); QList urls = Dolphin::validateUris(args); - // We later mutate urls, so we need to store if it was empty originally - const bool startedWithURLs = !urls.isEmpty(); - if (parser.isSet(QStringLiteral("daemon"))) { KDBusService dolphinDBusService; DBusInterface interface; interface.setAsDaemon(); +#ifdef Q_OS_MACOS + // we probably shouldn't be accepting requests via Apple's LaunchServices + app.removeEventFilter(openEventHandler); +#endif return app.exec(); } +#ifdef Q_OS_MACOS + // Get the file open events that have been queued; a priori those are only + // for the documents or folders with which the user launched us. This has to + // be done in "jit" fashion so we don't drop any events. Any such events \ + // coming in from now until we call setMainWindow will get lost. + // Since D11382 we also need to get the startup urls before setting startedWithURLs. + QCoreApplication::sendPostedEvents(&app, QEvent::FileOpen); + QCoreApplication::processEvents(); + urls.append(openEventHandler->popUrls()); +#endif + // We later mutate urls, so we need to store if it was empty originally + const bool startedWithURLs = !urls.isEmpty(); + if (!parser.isSet(QStringLiteral("new-window"))) { if (Dolphin::attachToExistingInstance(urls, openFiles, splitView)) { // Successfully attached to existing instance of Dolphin return 0; } } + // Open the main window now, so we can activate normal file open event + // handling (on Mac) as soon as possible. + DolphinMainWindow* mainWindow = new DolphinMainWindow(); +#ifdef Q_OS_MACOS + openEventHandler->setMainWindow(mainWindow); +#endif + if (!startedWithURLs) { // We need at least one URL to open Dolphin urls.append(Dolphin::homeUrl()); @@ -168,8 +246,6 @@ urls.append(urls.last()); } - DolphinMainWindow* mainWindow = new DolphinMainWindow(); - if (openFiles) { mainWindow->openFiles(urls, splitView); } else { @@ -205,3 +281,5 @@ return app.exec(); // krazy:exclude=crash; } + +#include "main.moc" Index: src/settings/services/servicemenuinstaller/CMakeLists.txt =================================================================== --- src/settings/services/servicemenuinstaller/CMakeLists.txt +++ src/settings/services/servicemenuinstaller/CMakeLists.txt @@ -1,7 +1,9 @@ +include(ECMMarkNonGuiExecutable) remove_definitions(-DTRANSLATION_DOMAIN=\"dolphin\") add_definitions(-DTRANSLATION_DOMAIN=\"dolphin_servicemenuinstaller\") add_executable(servicemenuinstaller servicemenuinstaller.cpp) +ecm_mark_nongui_executable(servicemenuinstaller) target_link_libraries(servicemenuinstaller PRIVATE Qt5::Core Qt5::Gui