File indexing completed on 2024-04-28 11:42:11

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "openfilemanagerwindowjob.h"
0009 #include "openfilemanagerwindowjob_p.h"
0010 
0011 #include <QDBusConnection>
0012 #include <QDBusMessage>
0013 #include <QDBusPendingCallWatcher>
0014 #include <QDBusPendingReply>
0015 #include <QGuiApplication>
0016 
0017 #include <KJobWidgets>
0018 #include <KWindowSystem>
0019 
0020 #include <KIO/JobUiDelegate>
0021 #include <KIO/JobUiDelegateFactory>
0022 #include <KIO/OpenUrlJob>
0023 
0024 namespace KIO
0025 {
0026 class OpenFileManagerWindowJobPrivate
0027 {
0028 public:
0029     OpenFileManagerWindowJobPrivate(OpenFileManagerWindowJob *qq)
0030         : q(qq)
0031         , strategy(nullptr)
0032     {
0033     }
0034 
0035     ~OpenFileManagerWindowJobPrivate()
0036     {
0037         delete strategy;
0038     }
0039 
0040     AbstractOpenFileManagerWindowStrategy *createDBusStrategy()
0041     {
0042         delete strategy;
0043         strategy = new OpenFileManagerWindowDBusStrategy(q);
0044         return strategy;
0045     }
0046 
0047     AbstractOpenFileManagerWindowStrategy *createKRunStrategy()
0048     {
0049         delete strategy;
0050         strategy = new OpenFileManagerWindowKRunStrategy(q);
0051         return strategy;
0052     }
0053 
0054     OpenFileManagerWindowJob *const q;
0055     QList<QUrl> highlightUrls;
0056     QByteArray startupId;
0057 
0058     AbstractOpenFileManagerWindowStrategy *strategy;
0059 };
0060 
0061 OpenFileManagerWindowJob::OpenFileManagerWindowJob(QObject *parent)
0062     : KJob(parent)
0063     , d(new OpenFileManagerWindowJobPrivate(this))
0064 {
0065 #ifdef Q_OS_LINUX
0066     d->createDBusStrategy();
0067 #else
0068     d->createKRunStrategy();
0069 #endif
0070 }
0071 
0072 OpenFileManagerWindowJob::~OpenFileManagerWindowJob() = default;
0073 
0074 QList<QUrl> OpenFileManagerWindowJob::highlightUrls() const
0075 {
0076     return d->highlightUrls;
0077 }
0078 
0079 void OpenFileManagerWindowJob::setHighlightUrls(const QList<QUrl> &highlightUrls)
0080 {
0081     d->highlightUrls = highlightUrls;
0082 }
0083 
0084 QByteArray OpenFileManagerWindowJob::startupId() const
0085 {
0086     return d->startupId;
0087 }
0088 
0089 void OpenFileManagerWindowJob::setStartupId(const QByteArray &startupId)
0090 {
0091     d->startupId = startupId;
0092 }
0093 
0094 void OpenFileManagerWindowJob::start()
0095 {
0096     if (d->highlightUrls.isEmpty()) {
0097         setError(NoValidUrlsError);
0098         emitResult();
0099         return;
0100     }
0101 
0102     d->strategy->start(d->highlightUrls, d->startupId);
0103 }
0104 
0105 OpenFileManagerWindowJob *highlightInFileManager(const QList<QUrl> &urls, const QByteArray &asn)
0106 {
0107     auto *job = new OpenFileManagerWindowJob();
0108     job->setHighlightUrls(urls);
0109 
0110     if (asn.isNull()) {
0111         auto window = qGuiApp->focusWindow();
0112         if (!window && !qGuiApp->allWindows().isEmpty()) {
0113             window = qGuiApp->allWindows().constFirst();
0114         }
0115         const int launchedSerial = KWindowSystem::lastInputSerial(window);
0116         QObject::connect(KWindowSystem::self(), &KWindowSystem::xdgActivationTokenArrived, job, [launchedSerial, job](int serial, const QString &token) {
0117             QObject::disconnect(KWindowSystem::self(), &KWindowSystem::xdgActivationTokenArrived, job, nullptr);
0118             if (serial == launchedSerial) {
0119                 job->setStartupId(token.toLatin1());
0120                 job->start();
0121             }
0122         });
0123         KWindowSystem::requestXdgActivationToken(window, launchedSerial, {});
0124     } else {
0125         job->setStartupId(asn);
0126         job->start();
0127     }
0128 
0129     return job;
0130 }
0131 
0132 void OpenFileManagerWindowDBusStrategy::start(const QList<QUrl> &urls, const QByteArray &asn)
0133 {
0134     // see the spec at: https://www.freedesktop.org/wiki/Specifications/file-manager-interface/
0135 
0136     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.FileManager1"),
0137                                                       QStringLiteral("/org/freedesktop/FileManager1"),
0138                                                       QStringLiteral("org.freedesktop.FileManager1"),
0139                                                       QStringLiteral("ShowItems"));
0140 
0141     msg << QUrl::toStringList(urls) << QString::fromUtf8(asn);
0142 
0143     QDBusPendingReply<void> reply = QDBusConnection::sessionBus().asyncCall(msg);
0144     QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, m_job);
0145     QObject::connect(watcher, &QDBusPendingCallWatcher::finished, m_job, [=](QDBusPendingCallWatcher *watcher) {
0146         QDBusPendingReply<void> reply = *watcher;
0147         watcher->deleteLater();
0148 
0149         if (reply.isError()) {
0150             // Try the KRun strategy as fallback, also calls emitResult inside
0151             AbstractOpenFileManagerWindowStrategy *kRunStrategy = m_job->d->createKRunStrategy();
0152             kRunStrategy->start(urls, asn);
0153             return;
0154         }
0155 
0156         emitResultProxy();
0157     });
0158 }
0159 
0160 void OpenFileManagerWindowKRunStrategy::start(const QList<QUrl> &urls, const QByteArray &asn)
0161 {
0162     KIO::OpenUrlJob *urlJob = new KIO::OpenUrlJob(urls.at(0).adjusted(QUrl::RemoveFilename), QStringLiteral("inode/directory"));
0163     urlJob->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, KJobWidgets::window(m_job)));
0164     urlJob->setStartupId(asn);
0165     QObject::connect(urlJob, &KJob::result, m_job, [this](KJob *urlJob) {
0166         if (urlJob->error()) {
0167             emitResultProxy(OpenFileManagerWindowJob::LaunchFailedError);
0168         } else {
0169             emitResultProxy();
0170         }
0171     });
0172     urlJob->start();
0173 }
0174 
0175 } // namespace KIO
0176 
0177 #include "moc_openfilemanagerwindowjob.cpp"