diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -111,6 +111,7 @@ endif() qt5_add_dbus_interface(kiocore_SRCS org.kde.KSlaveLauncher.xml klauncher_interface) +qt5_add_dbus_interface(kiocore_SRCS org.kde.KIOFuse.VFS.xml kiofuse_interface) set_source_files_properties(org.kde.KPasswdServer.xml PROPERTIES INCLUDE authinfo.h diff --git a/src/core/desktopexecparser.cpp b/src/core/desktopexecparser.cpp --- a/src/core/desktopexecparser.cpp +++ b/src/core/desktopexecparser.cpp @@ -20,6 +20,7 @@ */ #include "desktopexecparser.h" +#include "kiofuse_interface.h" #include #include @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include // CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 @@ -307,24 +310,52 @@ // Check if we need kioexec bool useKioexec = false; + org::kde::KIOFuse::VFS kiofuse_iface(QStringLiteral("org.kde.KIOFuse"), + QStringLiteral("/org/kde/KIOFuse"), + QDBusConnection::sessionBus()); + struct MountRequest { QDBusPendingReply reply; int urlIndex; }; + QVector requests; if (!mx1.hasUrls) { - for (const QUrl &url : qAsConst(d->urls)) { + for (int i = 0; i < d->urls.length(); ++i) { + const QUrl url = d->urls[i]; if (!url.isLocalFile() && !hasSchemeHandler(url)) { - useKioexec = true; - //qCDebug(KIO_CORE) << "non-local files, application does not support urls, using kioexec"; - break; + // Lets try a KIOFuse mount instead. + requests.push_back({ kiofuse_iface.mountUrl(url.toString()), i }); } } } else { // app claims to support %u/%U, check which protocols QStringList appSupportedProtocols = supportedProtocols(d->service); - for (const QUrl &url : qAsConst(d->urls)) { + for (int i = 0; i < d->urls.length(); ++i) { + const QUrl url = d->urls[i]; if (!isProtocolInSupportedList(url, appSupportedProtocols) && !hasSchemeHandler(url)) { - useKioexec = true; - //qCDebug(KIO_CORE) << "application does not support url, using kioexec:" << url; - break; + if (url.scheme() == QLatin1String("mtp") + || url.scheme() == QLatin1String("gdrive") + ) { + // KIOFuse doesn't work too well with mtp/gdrive. + // @see https://invent.kde.org/kde/kio-fuse/issues/1 (GDrive) + // @see https://invent.kde.org/kde/kio-fuse/issues/2 (MTP) + // This can be removed once those two issues are fixed. + useKioexec = true; + break; + } + // Lets try a KIOFuse mount instead. + requests.push_back({ kiofuse_iface.mountUrl(url.toString()), i }); } } } + + // Doesn't matter that we've blocked here to process the replies. + // Main thing that we want is to send the mount requests without blocking. + for (auto request : requests) { + request.reply.waitForFinished(); + if (request.reply.isError()) { + useKioexec = true; + // At this point we should just send the original urls to kioexec. + // There's no point sending urls to kioexec that go through kiofuse. + break; + } + } + if (useKioexec) { // We need to run the app through kioexec result << kioexecPath(); @@ -338,6 +369,12 @@ result << exec; result += QUrl::toStringList(d->urls); return result; + } else { + // At this point we know we're not using kioexec, so feel free to replace + // KIO URLs with their KIOFuse local path. + for (auto request : requests) { + d->urls[request.urlIndex] = QUrl::fromLocalFile(request.reply.value()); + } } if (appHasTempFileOption) { diff --git a/src/core/org.kde.KIOFuse.VFS.xml b/src/core/org.kde.KIOFuse.VFS.xml new file mode 100644 --- /dev/null +++ b/src/core/org.kde.KIOFuse.VFS.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -77,6 +77,7 @@ qt5_add_dbus_adaptor(kiowidgets_SRCS org.kde.kio.FileUndoManager.xml fileundomanager_p.h KIO::FileUndoManagerPrivate fileundomanager_adaptor KIOFileUndoManagerAdaptor) qt5_add_dbus_interface(kiowidgets_SRCS org.kde.kuiserver.xml kuiserver_interface) +qt5_add_dbus_interface(kiowidgets_SRCS org.kde.KIOFuse.VFS.xml kiofuse_interface) ki18n_wrap_ui(kiowidgets_SRCS checksumswidget.ui diff --git a/src/widgets/krun.cpp b/src/widgets/krun.cpp --- a/src/widgets/krun.cpp +++ b/src/widgets/krun.cpp @@ -59,6 +59,7 @@ #include "krecentdocument.h" #include "kdesktopfileactions.h" #include +#include "kiofuse_interface.h" #include #include @@ -572,19 +573,44 @@ const QStringList appSupportedProtocols = KIO::DesktopExecParser::supportedProtocols(_service); QList urls(_urls); if (!appSupportedProtocols.contains(QLatin1String("KIO"))) { - for (QUrl &url : urls) { - bool supported = KIO::DesktopExecParser::isProtocolInSupportedList(url, appSupportedProtocols); - //qDebug() << "Looking at url=" << url << " supported=" << supported; - if (!supported && KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) { + org::kde::KIOFuse::VFS kiofuse_iface(QStringLiteral("org.kde.KIOFuse"), + QStringLiteral("/org/kde/KIOFuse"), + QDBusConnection::sessionBus()); + struct MountRequest { QDBusPendingReply reply; int urlIndex; }; + QVector requests; + for (int i = 0; i < urls.length(); ++i) { + const QUrl url = urls[i]; + if (KIO::DesktopExecParser::isProtocolInSupportedList(url, appSupportedProtocols)) + continue; + if (KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) { // Maybe we can resolve to a local URL? KIO::StatJob *job = KIO::mostLocalUrl(url); if (job->exec()) { // ## nasty nested event loop! const QUrl localURL = job->mostLocalUrl(); if (localURL != url) { - url = localURL; + urls[i] = localURL; //qDebug() << "Changed to" << localURL; + // KIOFuse doesn't work too well with mtp/gdrive. + // @see https://invent.kde.org/kde/kio-fuse/issues/1 (GDrive) + // @see https://invent.kde.org/kde/kio-fuse/issues/2 (MTP) + // This can be removed once those two issues are fixed. + } else if (url.scheme() != QLatin1String("mtp") + && url.scheme() != QLatin1String("gdrive")) { + // Can't convert... + // Lets try a KIOFuse mount instead. + requests.push_back({ kiofuse_iface.mountUrl(url.toString()), i }); } } + } else { + requests.push_back({ kiofuse_iface.mountUrl(url.toString()), i }); + } + } + // Doesn't matter that we've blocked here to process the replies. + // Main thing that we want is to send the mount requests without blocking. + for (auto request : requests) { + request.reply.waitForFinished(); + if (!request.reply.isError()) { + urls[request.urlIndex] = QUrl::fromLocalFile(request.reply.value()); } } } diff --git a/src/widgets/org.kde.KIOFuse.VFS.xml b/src/widgets/org.kde.KIOFuse.VFS.xml new file mode 100644 --- /dev/null +++ b/src/widgets/org.kde.KIOFuse.VFS.xml @@ -0,0 +1,9 @@ + + + + + + + + +