File indexing completed on 2024-09-01 10:25:48
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"