diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ TextWidgets Notifications Crash + WindowSystem ) find_package(KF5 ${KF5_MIN_VERSION} OPTIONAL_COMPONENTS Activities diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -148,6 +148,7 @@ KF5::ConfigCore KF5::NewStuff KF5::Parts + KF5::WindowSystem ) if(HAVE_BALOO) diff --git a/src/dbusinterface.cpp b/src/dbusinterface.cpp --- a/src/dbusinterface.cpp +++ b/src/dbusinterface.cpp @@ -19,10 +19,13 @@ #include "dbusinterface.h" #include "global.h" +#include "dolphin_generalsettings.h" #include +#include #include +#include #include DBusInterface::DBusInterface() : @@ -41,17 +44,42 @@ if (urls.isEmpty()) { return; } - Dolphin::openNewWindow(urls); + const auto serviceName = QStringLiteral("org.kde.dolphin-%1").arg( + QCoreApplication::applicationPid() + ); + QScopedPointer service; + service.reset(new QDBusInterface(serviceName, + QStringLiteral("/dolphin/Dolphin_1"), + QStringLiteral("org.kde.dolphin.MainWindow"))); + if (!service->isValid()) { + return; + } + service->call(QStringLiteral("openDirectories"), + QUrl::toStringList(urls), + GeneralSettings::splitView()); + service->call(QStringLiteral("activateWindow")); } void DBusInterface::ShowItems(const QStringList& uriList, const QString& startUpId) { - Q_UNUSED(startUpId); const QList urls = Dolphin::validateUris(uriList); if (urls.isEmpty()) { return; } - Dolphin::openNewWindow(urls, nullptr, Dolphin::OpenNewWindowFlag::Select); + const auto serviceName = QStringLiteral("org.kde.dolphin-%1").arg( + QCoreApplication::applicationPid() + ); + QScopedPointer service; + service.reset(new QDBusInterface(serviceName, + QStringLiteral("/dolphin/Dolphin_1"), + QStringLiteral("org.kde.dolphin.MainWindow"))); + if (!service->isValid()) { + return; + } + service->call(QStringLiteral("openFiles"), + QUrl::toStringList(urls), + GeneralSettings::splitView()); + service->call(QStringLiteral("activateWindow")); } void DBusInterface::ShowItemProperties(const QStringList& uriList, const QString& startUpId) diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -71,29 +71,34 @@ */ DolphinViewContainer* activeViewContainer() const; + /** + * Returns the 'Create New...' sub menu which also can be shared + * with other menus (e. g. a context menu). + */ + KNewFileMenu* newFileMenu() const; + + void setTabsToHomeIfMountPathOpen(const QString& mountPath); + +public slots: /** * Opens each directory in \p dirs in a separate tab. If \a splitView is set, * 2 directories are collected within one tab. * \pre \a dirs must contain at least one url. */ - void openDirectories(const QList &dirs, bool splitView); + void openDirectories(const QStringList &dirs, bool splitView); /** * Opens the directories which contain the files \p files and selects all files. * If \a splitView is set, 2 directories are collected within one tab. * \pre \a files must contain at least one url. */ - void openFiles(const QList& files, bool splitView); - + void openFiles(const QStringList &files, bool splitView); + /** - * Returns the 'Create New...' sub menu which also can be shared - * with other menus (e. g. a context menu). + * Tries to raise/activate the Dolphin window. */ - KNewFileMenu* newFileMenu() const; - - void setTabsToHomeIfMountPathOpen(const QString& mountPath); - -public slots: + void activateWindow(); + /** * Pastes the clipboard data into the currently selected folder * of the active view. If not exactly one folder is selected, @@ -117,7 +122,7 @@ /** Stores all settings and quits Dolphin. */ void quit(); - + signals: /** * Is sent if the selection of the currently active view has diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -183,14 +184,19 @@ { } -void DolphinMainWindow::openDirectories(const QList& dirs, bool splitView) +void DolphinMainWindow::openDirectories(const QStringList& dirs, bool splitView) { - m_tabWidget->openDirectories(dirs, splitView); + m_tabWidget->openDirectories(QUrl::fromStringList(dirs), splitView); } -void DolphinMainWindow::openFiles(const QList& files, bool splitView) +void DolphinMainWindow::openFiles(const QStringList& files, bool splitView) { - m_tabWidget->openFiles(files, splitView); + m_tabWidget->openFiles(QUrl::fromStringList(files), splitView); +} + +void DolphinMainWindow::activateWindow() +{ + KWindowSystem::activateWindow(window()->effectiveWinId()); } void DolphinMainWindow::showCommand(CommandType command) diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp --- a/src/dolphintabwidget.cpp +++ b/src/dolphintabwidget.cpp @@ -179,9 +179,9 @@ const QUrl& primaryUrl = *(it++); if (splitView && (it != dirs.constEnd())) { const QUrl& secondaryUrl = *(it++); - openNewTab(primaryUrl, secondaryUrl); + openNewActivatedTab(primaryUrl, secondaryUrl); } else { - openNewTab(primaryUrl); + openNewActivatedTab(primaryUrl); } } } @@ -281,6 +281,7 @@ args << tabPage->secondaryViewContainer()->url().url(); args << QStringLiteral("--split"); } + args << QStringLiteral("--new-window"); const QString command = QStringLiteral("dolphin %1").arg(KShell::joinArgs(args)); KRun::runCommand(command, this); diff --git a/src/global.h b/src/global.h --- a/src/global.h +++ b/src/global.h @@ -41,6 +41,12 @@ * Opens a new Dolphin window */ void openNewWindow(const QList &urls = {}, QWidget *window = nullptr, const OpenNewWindowFlags &flags = OpenNewWindowFlag::None); + + /** + * Attaches URLs to an existing Dolphin instance if possible. + * Returns true if URLs were successfully attached + */ + bool attachToExistingInstance(const QStringList urls, bool openFiles, bool splitView); /** * TODO: Move this somewhere global to all KDE apps, not just Dolphin diff --git a/src/global.cpp b/src/global.cpp --- a/src/global.cpp +++ b/src/global.cpp @@ -26,6 +26,8 @@ #include #include +#include +#include QList Dolphin::validateUris(const QStringList& uriList) { @@ -49,15 +51,46 @@ void Dolphin::openNewWindow(const QList &urls, QWidget *window, const OpenNewWindowFlags &flags) { - QString command = QStringLiteral("dolphin"); + QString command = QStringLiteral("dolphin --new-window"); if (flags.testFlag(OpenNewWindowFlag::Select)) { command.append(QLatin1String(" --select")); } if (!urls.isEmpty()) { command.append(QLatin1String(" %U")); } + KRun::run( + command, + urls, + window, + QApplication::applicationDisplayName(), + QApplication::windowIcon().name() + ); +} + +bool Dolphin::attachToExistingInstance(const QStringList urls, bool openFiles, bool splitView) +{ + const QStringList services = QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); - KRun::run(command, urls, window, qApp->applicationDisplayName(), qApp->windowIcon().name()); + // Don't match the service without trailing "-" (unique instance) + const QString pattern = QStringLiteral("org.kde.dolphin-"); + const QString myPid = QString::number(QCoreApplication::applicationPid()); + QScopedPointer bestService; + + // Select the first instance that isn't us + for (const QString& service: services) { + if (service.startsWith(pattern) && !service.endsWith(myPid)) { + // Check if instance can handle our URLs + bestService.reset(new QDBusInterface(service, + QStringLiteral("/dolphin/Dolphin_1"), QStringLiteral("org.kde.dolphin.MainWindow"))); + if (!bestService->isValid()) { + break; + } + bestService->call(openFiles ? QStringLiteral("openFiles") : QStringLiteral("openDirectories"), urls, splitView); + bestService->call(QStringLiteral("activateWindow")); + return true; + } + } + return false; } diff --git a/src/main.cpp b/src/main.cpp --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,10 @@ #include #include +#include +#include +#include +#include #ifndef Q_OS_WIN #include @@ -122,33 +126,42 @@ parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("select"), i18nc("@info:shell", "The files and folders passed as arguments " "will be selected."))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("split"), i18nc("@info:shell", "Dolphin will get started with a split view."))); + parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("new-window"), i18nc("@info:shell", "Dolphin will explicitly open in a new window."))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("daemon"), i18nc("@info:shell", "Start Dolphin Daemon (only required for DBus Interface)"))); parser.addPositionalArgument(QStringLiteral("+[Url]"), i18nc("@info:shell", "Document to open")); parser.process(app); aboutData.processCommandLine(&parser); + const bool splitView = parser.isSet(QStringLiteral("split")) || GeneralSettings::splitView(); + const bool openFiles = parser.isSet(QStringLiteral("select")); + const QStringList args = parser.positionalArguments(); + QStringList urls = QUrl::toStringList(Dolphin::validateUris(args)); + if (parser.isSet(QStringLiteral("daemon"))) { return app.exec(); } - - const QStringList args = parser.positionalArguments(); - QList urls = Dolphin::validateUris(args); - + if (urls.isEmpty()) { // We need at least one URL to open Dolphin - urls.append(Dolphin::homeUrl()); + urls.append(Dolphin::homeUrl().toString()); } - const bool splitView = parser.isSet(QStringLiteral("split")) || GeneralSettings::splitView(); if (splitView && urls.size() < 2) { // Split view does only make sense if we have at least 2 URLs urls.append(urls.last()); } + if (!parser.isSet(QStringLiteral("new-window"))) { + if (Dolphin::attachToExistingInstance(urls, openFiles, splitView)) { + // Successfully attached to existing instance of Dolphin + return 0; + } + } + DolphinMainWindow* mainWindow = new DolphinMainWindow(); - if (parser.isSet(QStringLiteral("select"))) { + if (openFiles) { mainWindow->openFiles(urls, splitView); } else { mainWindow->openDirectories(urls, splitView); diff --git a/src/tests/dolphinmainwindowtest.cpp b/src/tests/dolphinmainwindowtest.cpp --- a/src/tests/dolphinmainwindowtest.cpp +++ b/src/tests/dolphinmainwindowtest.cpp @@ -63,7 +63,7 @@ // See https://bugs.kde.org/show_bug.cgi?id=379135 void DolphinMainWindowTest::testClosingTabsWithSearchBoxVisible() { - m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()) }, false); + m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()).toString() }, false); m_mainWindow->show(); // Without this call the searchbox doesn't get FocusIn events. QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); @@ -93,7 +93,7 @@ void DolphinMainWindowTest::testActiveViewAfterClosingSplitView() { - m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()) }, false); + m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()).toString() }, false); m_mainWindow->show(); QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); QVERIFY(m_mainWindow->isVisible()); @@ -138,7 +138,7 @@ // Test case for bug #385111 void DolphinMainWindowTest::testUpdateWindowTitleAfterClosingSplitView() { - m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()) }, false); + m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()).toString() }, false); m_mainWindow->show(); QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); QVERIFY(m_mainWindow->isVisible()); @@ -179,7 +179,7 @@ // Test case for bug #402641 void DolphinMainWindowTest::testUpdateWindowTitleAfterChangingSplitView() { - m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()) }, false); + m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()).toString() }, false); m_mainWindow->show(); QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); QVERIFY(m_mainWindow->isVisible()); @@ -209,7 +209,7 @@ // Test case for bug #397910 void DolphinMainWindowTest::testOpenInNewTabTitle() { - m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()) }, false); + m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()).toString() }, false); m_mainWindow->show(); QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); QVERIFY(m_mainWindow->isVisible()); @@ -238,7 +238,7 @@ void DolphinMainWindowTest::testNewFileMenuEnabled() { QFETCH(QUrl, activeViewUrl); - m_mainWindow->openDirectories({ activeViewUrl }, false); + m_mainWindow->openDirectories({ activeViewUrl.toString() }, false); m_mainWindow->show(); QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); QVERIFY(m_mainWindow->isVisible());