| 
									
										
										
										
											2023-07-10 10:18:33 +08:00
										 |  |  | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 14:25:22 +08:00
										 |  |  | #include "dbus/applicationservice.h"
 | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  | #include "APPobjectmanager1adaptor.h"
 | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  | #include "applicationchecker.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | #include "applicationmanager1service.h"
 | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  | #include "applicationmanagerstorage.h"
 | 
					
						
							| 
									
										
										
										
											2023-09-08 10:58:41 +08:00
										 |  |  | #include "propertiesForwarder.h"
 | 
					
						
							| 
									
										
										
										
											2023-08-07 14:25:22 +08:00
										 |  |  | #include "dbus/instanceadaptor.h"
 | 
					
						
							| 
									
										
										
										
											2023-08-30 18:36:52 +08:00
										 |  |  | #include "launchoptions.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | #include <QUuid>
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | #include <QStringList>
 | 
					
						
							|  |  |  | #include <QList>
 | 
					
						
							|  |  |  | #include <QUrl>
 | 
					
						
							|  |  |  | #include <QRegularExpression>
 | 
					
						
							|  |  |  | #include <QProcess>
 | 
					
						
							| 
									
										
										
										
											2023-09-01 15:48:29 +08:00
										 |  |  | #include <QStandardPaths>
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | #include <new>
 | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  | #include <utility>
 | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  | #include <wordexp.h>
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  | ApplicationService::ApplicationService(DesktopFile source, | 
					
						
							|  |  |  |                                        ApplicationManager1Service *parent, | 
					
						
							|  |  |  |                                        std::weak_ptr<ApplicationManager1Storage> storage) | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     : QObject(parent) | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  |     , m_storage(std::move(storage)) | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     , m_desktopSource(std::move(source)) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-14 17:16:10 +08:00
										 |  |  |     auto storagePtr = m_storage.lock(); | 
					
						
							|  |  |  |     if (!storagePtr) { | 
					
						
							|  |  |  |         m_lastLaunch = -1; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto appId = id(); | 
					
						
							|  |  |  |     auto value = storagePtr->readApplicationValue(appId, ApplicationPropertiesGroup, LastLaunchedTime); | 
					
						
							|  |  |  |     if (value.isNull()) { | 
					
						
							|  |  |  |         if (!storagePtr->createApplicationValue( | 
					
						
							|  |  |  |                 appId, ApplicationPropertiesGroup, LastLaunchedTime, QVariant::fromValue<qint64>(0))) { | 
					
						
							|  |  |  |             m_lastLaunch = -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_lastLaunch = value.toInt(); | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-10 10:18:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | ApplicationService::~ApplicationService() | 
					
						
							| 
									
										
										
										
											2023-07-10 10:18:33 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-14 17:16:10 +08:00
										 |  |  |     detachAllInstance(); | 
					
						
							| 
									
										
										
										
											2023-07-10 10:18:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  | QSharedPointer<ApplicationService> ApplicationService::createApplicationService( | 
					
						
							|  |  |  |     DesktopFile source, ApplicationManager1Service *parent, std::weak_ptr<ApplicationManager1Storage> storage) noexcept | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  |     QSharedPointer<ApplicationService> app{new (std::nothrow) ApplicationService{std::move(source), parent, std::move(storage)}}; | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  |     if (!app) { | 
					
						
							|  |  |  |         qCritical() << "new application service failed."; | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     QString objectPath; | 
					
						
							|  |  |  |     QTextStream sourceStream; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  |     auto appId = app->desktopFileSource().desktopId(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!appId.isEmpty()) { | 
					
						
							|  |  |  |         objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(appId); | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 17:20:47 +08:00
										 |  |  |     DesktopFileGuard guard{app->desktopFileSource()}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!guard.try_open()) { | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  |     sourceStream.setDevice(app->desktopFileSource().sourceFile()); | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     std::unique_ptr<DesktopEntry> entry{std::make_unique<DesktopEntry>()}; | 
					
						
							|  |  |  |     auto error = entry->parse(sourceStream); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (error != DesktopErrorCode::NoError) { | 
					
						
							| 
									
										
										
										
											2023-08-25 10:47:17 +08:00
										 |  |  |         qWarning() << "parse failed:" << error << app->desktopFileSource().sourcePath(); | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  |     if (!shouldBeShown(entry)) { | 
					
						
							|  |  |  |         qDebug() << "application shouldn't be shown:" << app->desktopFileSource().sourcePath(); | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     app->m_entry.reset(entry.release()); | 
					
						
							|  |  |  |     app->m_applicationPath = QDBusObjectPath{std::move(objectPath)}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO: icon lookup
 | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  |     if (auto *ptr = new (std::nothrow) APPObjectManagerAdaptor{app.data()}; ptr == nullptr) { | 
					
						
							|  |  |  |         qCritical() << "new Object Manager of Application failed."; | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-08 10:58:41 +08:00
										 |  |  |     if (auto *ptr = new (std::nothrow) PropertiesForwarder{app->m_applicationPath.path(), app.data()}; ptr == nullptr) { | 
					
						
							|  |  |  |         qCritical() << "new PropertiesForwarder of Application failed."; | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     return app; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  | bool ApplicationService::shouldBeShown(const std::unique_ptr<DesktopEntry> &entry) noexcept | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-06 14:19:50 +08:00
										 |  |  |     if (ApplicationFilter::hiddenCheck(entry)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 14:19:50 +08:00
										 |  |  |     if (ApplicationFilter::tryExecCheck(entry)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 14:19:50 +08:00
										 |  |  |     if (ApplicationFilter::showInCheck(entry)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 14:19:50 +08:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2023-09-05 11:49:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options) | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |     QString execStr; | 
					
						
							|  |  |  |     bool ok; | 
					
						
							|  |  |  |     const auto &supportedActions = actions(); | 
					
						
							| 
									
										
										
										
											2023-09-07 15:55:25 +08:00
										 |  |  |     auto optionsMap = options; | 
					
						
							|  |  |  |     QString oldEnv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto factor = getDeepinWineScaleFactor(m_desktopSource.desktopId()).toDouble(); | 
					
						
							|  |  |  |     if (factor != 1.0) { | 
					
						
							|  |  |  |         if (auto it = optionsMap.find("env"); it != optionsMap.cend()) { | 
					
						
							|  |  |  |             oldEnv = it->value<QString>(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         oldEnv.append(QString{"DEEPIN_WINE_SCALE=%1;"}.arg(factor)); | 
					
						
							|  |  |  |         optionsMap.insert("env", oldEnv); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     while (!action.isEmpty() and !supportedActions.isEmpty()) {  // break trick
 | 
					
						
							|  |  |  |         if (auto index = supportedActions.indexOf(action); index == -1) { | 
					
						
							|  |  |  |             qWarning() << "can't find " << action << " in supported actions List. application will use default action to launch."; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 16:25:21 +08:00
										 |  |  |         const auto &actionHeader = QString{"%1%2"}.arg(DesktopFileActionKey, action); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         const auto &actionExec = m_entry->value(actionHeader, "Exec"); | 
					
						
							|  |  |  |         if (!actionExec) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         execStr = actionExec->toString(ok); | 
					
						
							|  |  |  |         if (!ok) { | 
					
						
							|  |  |  |             qWarning() << "exec value to string failed, try default action."; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (execStr.isEmpty()) { | 
					
						
							|  |  |  |         auto Actions = m_entry->value(DesktopFileEntryKey, "Exec"); | 
					
						
							|  |  |  |         if (!Actions) { | 
					
						
							| 
									
										
										
										
											2023-09-01 17:30:14 +08:00
										 |  |  |             QString msg{"application can't be executed."}; | 
					
						
							|  |  |  |             qWarning() << msg; | 
					
						
							|  |  |  |             sendErrorReply(QDBusError::Failed, msg); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             return {}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         execStr = Actions->toString(ok); | 
					
						
							|  |  |  |         if (!ok) { | 
					
						
							| 
									
										
										
										
											2023-09-01 17:30:14 +08:00
										 |  |  |             QString msg{"maybe entry actions's format is invalid, abort launch."}; | 
					
						
							|  |  |  |             qWarning() << msg; | 
					
						
							|  |  |  |             sendErrorReply(QDBusError::Failed, msg); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             return {}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 15:55:25 +08:00
										 |  |  |     auto cmds = generateCommand(optionsMap); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 18:36:52 +08:00
										 |  |  |     auto [bin, execCmds, res] = unescapeExec(execStr, fields); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     if (bin.isEmpty()) { | 
					
						
							|  |  |  |         qCritical() << "error command is detected, abort."; | 
					
						
							|  |  |  |         sendErrorReply(QDBusError::Failed); | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 18:36:52 +08:00
										 |  |  |     cmds.append(std::move(execCmds)); | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     auto &jobManager = static_cast<ApplicationManager1Service *>(parent())->jobManager(); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |     return jobManager.addJob( | 
					
						
							|  |  |  |         m_applicationPath.path(), | 
					
						
							| 
									
										
										
										
											2023-09-13 11:47:04 +08:00
										 |  |  |         [this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &variantValue) mutable -> QVariant { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             auto resourceFile = variantValue.toString(); | 
					
						
							| 
									
										
										
										
											2023-08-16 17:44:56 +08:00
										 |  |  |             auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128); | 
					
						
							|  |  |  |             auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID; | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  |             commands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath())); | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 10:15:48 +08:00
										 |  |  |             auto location = commands.indexOf(R"(%f)"); | 
					
						
							|  |  |  |             if (location != -1) {  // due to std::move, there only remove once
 | 
					
						
							|  |  |  |                 commands.remove(location); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             if (resourceFile.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2023-08-08 15:10:32 +08:00
										 |  |  |                 commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg( | 
					
						
							| 
									
										
										
										
											2023-08-11 10:12:46 +08:00
										 |  |  |                     escapeApplicationId(this->id()), instanceRandomUUID));  // launcher should use this instanceId
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |                 QProcess process; | 
					
						
							| 
									
										
										
										
											2023-09-07 10:15:48 +08:00
										 |  |  |                 qDebug() << "run with commands:" << commands; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |                 process.start(m_launcher, commands); | 
					
						
							|  |  |  |                 process.waitForFinished(); | 
					
						
							|  |  |  |                 if (auto code = process.exitCode(); code != 0) { | 
					
						
							| 
									
										
										
										
											2023-09-05 14:33:21 +08:00
										 |  |  |                     qWarning() << "Launch Application Failed"; | 
					
						
							|  |  |  |                     return QDBusError::Failed; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-08-16 17:44:56 +08:00
										 |  |  |                 return objectPath; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             auto url = QUrl::fromUserInput(resourceFile); | 
					
						
							|  |  |  |             if (!url.isValid()) {  // if url is invalid, passing to launcher directly
 | 
					
						
							|  |  |  |                 auto scheme = url.scheme(); | 
					
						
							|  |  |  |                 if (!scheme.isEmpty()) { | 
					
						
							|  |  |  |                     // TODO: resourceFile = processRemoteFile(resourceFile);
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |             // NOTE: resourceFile must be available in the following contexts
 | 
					
						
							|  |  |  |             commands.insert(location, resourceFile); | 
					
						
							|  |  |  |             commands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID)); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             QProcess process; | 
					
						
							| 
									
										
										
										
											2023-09-07 10:15:48 +08:00
										 |  |  |             qDebug() << "run with commands:" << commands; | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |             process.start(getApplicationLauncherBinary(), commands); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             process.waitForFinished(); | 
					
						
							|  |  |  |             auto exitCode = process.exitCode(); | 
					
						
							|  |  |  |             if (exitCode != 0) { | 
					
						
							| 
									
										
										
										
											2023-09-05 14:33:21 +08:00
										 |  |  |                 qWarning() << "Launch Application Failed"; | 
					
						
							|  |  |  |                 return QDBusError::Failed; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-08-16 17:44:56 +08:00
										 |  |  |             return objectPath; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         }, | 
					
						
							|  |  |  |         std::move(res)); | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-01 15:48:29 +08:00
										 |  |  | bool ApplicationService::SendToDesktop() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (isOnDesktop()) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); | 
					
						
							|  |  |  |     if (dir.isEmpty()) { | 
					
						
							|  |  |  |         qDebug() << "no desktop directory found."; | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto desktopFile = QDir{dir}.filePath(m_desktopSource.desktopId() + ".desktop"); | 
					
						
							|  |  |  |     auto success = m_desktopSource.sourceFileRef().link(desktopFile); | 
					
						
							|  |  |  |     if (!success) { | 
					
						
							|  |  |  |         qDebug() << "create link failed:" << m_desktopSource.sourceFileRef().errorString() << "path:" << desktopFile; | 
					
						
							| 
									
										
										
										
											2023-09-01 17:30:14 +08:00
										 |  |  |         sendErrorReply(QDBusError::ErrorType::Failed, m_desktopSource.sourceFileRef().errorString()); | 
					
						
							| 
									
										
										
										
											2023-09-01 15:48:29 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return success; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ApplicationService::RemoveFromDesktop() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!isOnDesktop()) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); | 
					
						
							|  |  |  |     if (dir.isEmpty()) { | 
					
						
							|  |  |  |         qDebug() << "no desktop directory found."; | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QFile desktopFile{QDir{dir}.filePath(m_desktopSource.desktopId() + ".desktop")}; | 
					
						
							|  |  |  |     auto success = desktopFile.remove(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!success) { | 
					
						
							|  |  |  |         qDebug() << "remove desktop file failed:" << desktopFile.errorString(); | 
					
						
							| 
									
										
										
										
											2023-09-01 17:30:14 +08:00
										 |  |  |         sendErrorReply(QDBusError::ErrorType::Failed, desktopFile.errorString()); | 
					
						
							| 
									
										
										
										
											2023-09-01 15:48:29 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return success; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ApplicationService::isOnDesktop() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (dir.isEmpty()) { | 
					
						
							|  |  |  |         qDebug() << "no desktop directory found."; | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QFileInfo info{QDir{dir}.filePath(m_desktopSource.desktopId() + ".desktop")}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!info.exists()) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!info.isSymbolicLink()) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return info.symLinkTarget() == m_desktopSource.sourcePath(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 12:01:08 +08:00
										 |  |  | bool ApplicationService::noDisplay() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto val = findEntryValue(DesktopFileEntryKey, "NoDisplay", EntryValueType::Boolean); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (val.isNull()) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return val.toBool(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | QStringList ApplicationService::actions() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-30 15:21:20 +08:00
										 |  |  |     auto val = findEntryValue(DesktopFileEntryKey, "Actions", EntryValueType::String); | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 15:21:20 +08:00
										 |  |  |     if (val.isNull()) { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 15:21:20 +08:00
										 |  |  |     auto actionList = val.toString().split(";", Qt::SkipEmptyParts); | 
					
						
							|  |  |  |     return actionList; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QStringList ApplicationService::categories() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto val = findEntryValue(DesktopFileEntryKey, "Categories", EntryValueType::String); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (val.isNull()) { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-30 15:21:20 +08:00
										 |  |  |     return val.toString().split(';', Qt::SkipEmptyParts); | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-25 10:47:17 +08:00
										 |  |  | PropMap ApplicationService::actionName() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PropMap ret; | 
					
						
							|  |  |  |     auto actionList = actions(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto &action : actionList) { | 
					
						
							|  |  |  |         action.prepend(DesktopFileActionKey); | 
					
						
							|  |  |  |         auto value = m_entry->value(action, "Name"); | 
					
						
							|  |  |  |         if (!value.has_value()) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ret.insert(action, {std::move(value).value()}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PropMap ApplicationService::displayName() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PropMap ret; | 
					
						
							|  |  |  |     auto value = std::move(m_entry->value(DesktopFileEntryKey, "Name")).value(); | 
					
						
							|  |  |  |     ret.insert(QString{"Name"}, {std::move(value)}); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 13:28:25 +08:00
										 |  |  | PropMap ApplicationService::icons() const noexcept | 
					
						
							| 
									
										
										
										
											2023-08-25 10:47:17 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     PropMap ret; | 
					
						
							|  |  |  |     auto actionList = actions(); | 
					
						
							|  |  |  |     for (const auto &action : actionList) { | 
					
						
							|  |  |  |         auto value = m_entry->value(QString{action}.prepend(DesktopFileActionKey), "Icon"); | 
					
						
							|  |  |  |         if (!value.has_value()) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ret.insert(action, {std::move(value).value()}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto mainIcon = m_entry->value(DesktopFileEntryKey, "Icon"); | 
					
						
							|  |  |  |     if (mainIcon.has_value()) { | 
					
						
							|  |  |  |         ret.insert(defaultKeyStr, {std::move(mainIcon).value()}); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-18 10:01:52 +08:00
										 |  |  | ObjectMap ApplicationService::GetManagedObjects() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-18 17:22:38 +08:00
										 |  |  |     return dumpDBusObject(m_Instances); | 
					
						
							| 
									
										
										
										
											2023-08-18 10:01:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | QString ApplicationService::id() const noexcept | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-21 16:02:26 +08:00
										 |  |  |     return m_desktopSource.desktopId(); | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 16:40:29 +08:00
										 |  |  | bool ApplicationService::x_Flatpak() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto val = findEntryValue(DesktopFileEntryKey, "X-flatpak", EntryValueType::String); | 
					
						
							| 
									
										
										
										
											2023-09-01 15:49:30 +08:00
										 |  |  |     return !val.isNull(); | 
					
						
							| 
									
										
										
										
											2023-08-31 16:40:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ApplicationService::x_linglong() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto val = findEntryValue(DesktopFileEntryKey, "X-linglong", EntryValueType::String); | 
					
						
							| 
									
										
										
										
											2023-09-01 15:49:30 +08:00
										 |  |  |     return !val.isNull(); | 
					
						
							| 
									
										
										
										
											2023-08-31 16:40:29 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | qulonglong ApplicationService::installedTime() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_desktopSource.createTime(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 17:20:47 +08:00
										 |  |  | qulonglong ApplicationService::lastLaunchedTime() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_lastLaunch; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 13:22:01 +08:00
										 |  |  | bool ApplicationService::autostartCheck(const QString &linkPath) noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QFileInfo info{linkPath}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-08 10:58:41 +08:00
										 |  |  |     if (info.exists()) { | 
					
						
							|  |  |  |         if (info.isSymbolicLink()) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-06 13:22:01 +08:00
										 |  |  |         qWarning() << "same name desktop file exists:" << linkPath << "but this may not created by AM."; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-08 10:58:41 +08:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2023-09-06 13:22:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | bool ApplicationService::isAutoStart() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-06 13:22:01 +08:00
										 |  |  |     auto path = getAutoStartDirs().first(); | 
					
						
							|  |  |  |     auto linkName = QDir{path}.filePath(m_desktopSource.desktopId() + ".desktop"); | 
					
						
							|  |  |  |     return autostartCheck(linkName); | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | void ApplicationService::setAutoStart(bool autostart) noexcept | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-04 18:18:20 +08:00
										 |  |  |     auto path = getAutoStartDirs().first(); | 
					
						
							|  |  |  |     auto linkName = QDir{path}.filePath(m_desktopSource.desktopId() + ".desktop"); | 
					
						
							|  |  |  |     auto &file = m_desktopSource.sourceFileRef(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (autostart) { | 
					
						
							| 
									
										
										
										
											2023-09-06 13:22:01 +08:00
										 |  |  |         if (!autostartCheck(linkName) and !file.link(linkName)) { | 
					
						
							| 
									
										
										
										
											2023-09-04 18:18:20 +08:00
										 |  |  |             qWarning() << "link to autostart failed:" << file.errorString(); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-09-06 13:22:01 +08:00
										 |  |  |         if (autostartCheck(linkName)) { | 
					
						
							|  |  |  |             QFile linkFile{linkName}; | 
					
						
							|  |  |  |             if (!linkFile.remove()) { | 
					
						
							|  |  |  |                 qWarning() << "remove link failed:" << linkFile.errorString(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-09-04 18:18:20 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-08 10:58:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     emit autostartChanged(); | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | QList<QDBusObjectPath> ApplicationService::instances() const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_Instances.keys(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 16:52:53 +08:00
										 |  |  | bool ApplicationService::addOneInstance(const QString &instanceId, | 
					
						
							|  |  |  |                                         const QString &application, | 
					
						
							|  |  |  |                                         const QString &systemdUnitPath, | 
					
						
							|  |  |  |                                         const QString &launcher) | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-13 16:52:53 +08:00
										 |  |  |     auto *service = new InstanceService{instanceId, application, systemdUnitPath, launcher}; | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  |     auto *adaptor = new InstanceAdaptor(service); | 
					
						
							| 
									
										
										
										
											2023-08-16 17:44:56 +08:00
										 |  |  |     QString objectPath{m_applicationPath.path() + "/" + instanceId}; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-28 11:11:50 +08:00
										 |  |  |     if (registerObjectToDBus(service, objectPath, InstanceInterface)) { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         m_Instances.insert(QDBusObjectPath{objectPath}, QSharedPointer<InstanceService>{service}); | 
					
						
							|  |  |  |         service->moveToThread(this->thread()); | 
					
						
							|  |  |  |         adaptor->moveToThread(this->thread()); | 
					
						
							| 
									
										
										
										
											2023-08-25 10:47:17 +08:00
										 |  |  |         emit InterfacesAdded(QDBusObjectPath{objectPath}, getChildInterfacesAndPropertiesFromObject(service)); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     adaptor->deleteLater(); | 
					
						
							|  |  |  |     service->deleteLater(); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | void ApplicationService::removeOneInstance(const QDBusObjectPath &instance) noexcept | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-08-18 10:01:52 +08:00
										 |  |  |     if (auto it = m_Instances.find(instance); it != m_Instances.cend()) { | 
					
						
							| 
									
										
										
										
											2023-08-25 10:47:17 +08:00
										 |  |  |         emit InterfacesRemoved(instance, getChildInterfacesFromObject(it->data())); | 
					
						
							| 
									
										
										
										
											2023-08-18 10:01:52 +08:00
										 |  |  |         unregisterObjectFromDBus(instance.path()); | 
					
						
							|  |  |  |         m_Instances.remove(instance); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 14:49:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | void ApplicationService::removeAllInstance() noexcept | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |     for (const auto &instance : m_Instances.keys()) { | 
					
						
							|  |  |  |         removeOneInstance(instance); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 17:16:10 +08:00
										 |  |  | void ApplicationService::detachAllInstance() noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (auto &instance : m_Instances.values()) { | 
					
						
							|  |  |  |         orphanedInstances->append(instance); | 
					
						
							| 
									
										
										
										
											2023-09-14 17:57:44 +08:00
										 |  |  |         instance->setProperty("Orphaned", true); | 
					
						
							| 
									
										
										
										
											2023-09-14 17:16:10 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_Instances.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | QDBusObjectPath ApplicationService::findInstance(const QString &instanceId) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-06 16:49:47 +08:00
										 |  |  |     for (auto it = m_Instances.constKeyValueBegin(); it != m_Instances.constKeyValueEnd(); ++it) { | 
					
						
							|  |  |  |         const auto &[path, ptr] = *it; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         if (ptr->instanceId() == instanceId) { | 
					
						
							|  |  |  |             return path; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 18:25:59 +08:00
										 |  |  | void ApplicationService::resetEntry(DesktopEntry *newEntry) noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_entry.reset(newEntry); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  | LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     LaunchTask task; | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     auto deleter = [](wordexp_t *word) { wordfree(word); }; | 
					
						
							|  |  |  |     std::unique_ptr<wordexp_t, decltype(deleter)> words{new (std::nothrow) wordexp_t{0, nullptr, 0}, deleter}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (auto ret = wordexp(str.toLocal8Bit().constData(), words.get(), WRDE_SHOWERR); ret != 0) { | 
					
						
							|  |  |  |         if (ret != 0) { | 
					
						
							|  |  |  |             QString errMessage; | 
					
						
							|  |  |  |             switch (ret) { | 
					
						
							|  |  |  |             case WRDE_BADCHAR: | 
					
						
							|  |  |  |                 errMessage = "BADCHAR"; | 
					
						
							|  |  |  |                 qWarning() << "wordexp error: " << errMessage; | 
					
						
							|  |  |  |                 return {}; | 
					
						
							|  |  |  |             case WRDE_BADVAL: | 
					
						
							|  |  |  |                 errMessage = "BADVAL"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WRDE_CMDSUB: | 
					
						
							|  |  |  |                 errMessage = "CMDSUB"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WRDE_NOSPACE: | 
					
						
							|  |  |  |                 errMessage = "NOSPACE"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WRDE_SYNTAX: | 
					
						
							|  |  |  |                 errMessage = "SYNTAX"; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 errMessage = "unknown"; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             qWarning() << "wordexp error: " << errMessage; | 
					
						
							|  |  |  |             return {}; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QStringList execList; | 
					
						
							|  |  |  |     for (int i = 0; i < words->we_wordc; ++i) { | 
					
						
							|  |  |  |         execList.emplace_back(words->we_wordv[i]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |     task.LaunchBin = execList.first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QRegularExpression re{"%[fFuUickdDnNvm]"}; | 
					
						
							|  |  |  |     auto matcher = re.match(str); | 
					
						
							|  |  |  |     if (!matcher.hasMatch()) { | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-08-25 18:21:11 +08:00
										 |  |  |         task.Resources.emplace_back(QString{""});  // mapReduce should run once at least
 | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         return task; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto list = matcher.capturedTexts(); | 
					
						
							|  |  |  |     if (list.count() > 1) { | 
					
						
							|  |  |  |         qWarning() << "invalid exec format, all filed code will be ignored."; | 
					
						
							|  |  |  |         for (const auto &code : list) { | 
					
						
							|  |  |  |             execList.removeOne(code); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							|  |  |  |         return task; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto filesCode = list.first().back().toLatin1(); | 
					
						
							|  |  |  |     auto codeStr = QString(R"(%%1)").arg(filesCode); | 
					
						
							|  |  |  |     auto location = execList.indexOf(codeStr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (filesCode) { | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'f': {  // Defer to async job
 | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |         for (const auto &field : fields) { | 
					
						
							|  |  |  |             task.Resources.emplace_back(field); | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'u': { | 
					
						
							|  |  |  |         execList.removeAt(location); | 
					
						
							|  |  |  |         if (fields.empty()) { | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             task.command.append(execList); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |         if (fields.count() > 1) { | 
					
						
							|  |  |  |             qDebug() << R"(fields count is greater than one, %u will only take first element.)"; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |         execList.insert(location, fields.first()); | 
					
						
							|  |  |  |         task.command.append(execList); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'F': | 
					
						
							|  |  |  |         [[fallthrough]]; | 
					
						
							|  |  |  |     case 'U': { | 
					
						
							|  |  |  |         execList.removeAt(location); | 
					
						
							|  |  |  |         auto it = execList.begin() + location; | 
					
						
							|  |  |  |         for (const auto &field : fields) { | 
					
						
							|  |  |  |             it = execList.insert(it, field); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'i': { | 
					
						
							|  |  |  |         execList.removeAt(location); | 
					
						
							|  |  |  |         auto val = m_entry->value(DesktopFileEntryKey, "Icon"); | 
					
						
							|  |  |  |         if (!val) { | 
					
						
							|  |  |  |             qDebug() << R"(Application Icons can't be found. %i will be ignored.)"; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |             return task; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |         bool ok; | 
					
						
							|  |  |  |         auto iconStr = val->toIconString(ok); | 
					
						
							|  |  |  |         if (!ok) { | 
					
						
							|  |  |  |             qDebug() << R"(Icons Convert to string failed. %i will be ignored.)"; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |             return task; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |         auto it = execList.insert(location, iconStr); | 
					
						
							|  |  |  |         execList.insert(it, "--icon"); | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'c': { | 
					
						
							|  |  |  |         execList.removeAt(location); | 
					
						
							|  |  |  |         auto val = m_entry->value(DesktopFileEntryKey, "Name"); | 
					
						
							|  |  |  |         if (!val) { | 
					
						
							|  |  |  |             qDebug() << R"(Application Name can't be found. %c will be ignored.)"; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |             return task; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |         bool ok; | 
					
						
							|  |  |  |         auto NameStr = val->toLocaleString(getUserLocale(), ok); | 
					
						
							|  |  |  |         if (!ok) { | 
					
						
							|  |  |  |             qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)"; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |             task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |             return task; | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |         execList.insert(location, NameStr); | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'k': {  // ignore all desktop file location for now.
 | 
					
						
							|  |  |  |         execList.removeAt(location); | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     case 'd': | 
					
						
							|  |  |  |     case 'D': | 
					
						
							|  |  |  |     case 'n': | 
					
						
							|  |  |  |     case 'N': | 
					
						
							|  |  |  |     case 'v': | 
					
						
							|  |  |  |         [[fallthrough]];  // Deprecated field codes should be removed from the command line and ignored.
 | 
					
						
							|  |  |  |     case 'm': { | 
					
						
							|  |  |  |         execList.removeAt(location); | 
					
						
							|  |  |  |         task.command.append(std::move(execList)); | 
					
						
							| 
									
										
										
										
											2023-09-04 15:57:59 +08:00
										 |  |  |     } break; | 
					
						
							|  |  |  |     default: { | 
					
						
							|  |  |  |         qDebug() << "unrecognized file code."; | 
					
						
							| 
									
										
										
										
											2023-08-25 16:04:55 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-24 14:12:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (task.Resources.isEmpty()) { | 
					
						
							|  |  |  |         task.Resources.emplace_back(QString{""});  // mapReduce should run once at least
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return task; | 
					
						
							| 
									
										
										
										
											2023-07-21 14:47:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-08-30 15:21:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | QVariant ApplicationService::findEntryValue(const QString &group, | 
					
						
							|  |  |  |                                             const QString &valueKey, | 
					
						
							|  |  |  |                                             EntryValueType type, | 
					
						
							|  |  |  |                                             const QLocale &locale) const noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QVariant ret; | 
					
						
							|  |  |  |     auto tmp = m_entry->value(group, valueKey); | 
					
						
							|  |  |  |     if (!tmp.has_value()) { | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto val = std::move(tmp).value(); | 
					
						
							|  |  |  |     bool ok{false}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (type) { | 
					
						
							|  |  |  |     case EntryValueType::String: { | 
					
						
							|  |  |  |         auto valStr = val.toString(ok); | 
					
						
							|  |  |  |         if (ok) { | 
					
						
							|  |  |  |             ret = QVariant::fromValue(valStr); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } break; | 
					
						
							|  |  |  |     case EntryValueType::LocaleString: { | 
					
						
							|  |  |  |         auto valStr = val.toLocaleString(locale, ok); | 
					
						
							|  |  |  |         if (ok) { | 
					
						
							|  |  |  |             ret = QVariant::fromValue(valStr); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } break; | 
					
						
							|  |  |  |     case EntryValueType::Boolean: { | 
					
						
							|  |  |  |         auto valBool = val.toBoolean(ok); | 
					
						
							|  |  |  |         if (ok) { | 
					
						
							|  |  |  |             ret = QVariant::fromValue(valBool); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } break; | 
					
						
							|  |  |  |     case EntryValueType::IconString: { | 
					
						
							|  |  |  |         auto valStr = val.toIconString(ok); | 
					
						
							|  |  |  |         if (ok) { | 
					
						
							|  |  |  |             ret = QVariant::fromValue(valStr); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-09-07 15:55:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 17:16:10 +08:00
										 |  |  | void ApplicationService::updateAfterLaunch(bool isLaunch) noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!isLaunch) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto timestamp = QDateTime::currentMSecsSinceEpoch(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (auto ptr = m_storage.lock(); ptr) { | 
					
						
							|  |  |  |         ptr->updateApplicationValue( | 
					
						
							|  |  |  |             m_desktopSource.desktopId(), ApplicationPropertiesGroup, ::LastLaunchedTime, QVariant::fromValue(timestamp)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-07 15:55:25 +08:00
										 |  |  | QString getDeepinWineScaleFactor(const QString &appId) noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qCritical() << "Don't using env to control the window scale factor,  this function" | 
					
						
							|  |  |  |                    "should via using graphisc server(Wayland Compositor/Xorg Xft) in deepin wine."; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString factor{"1.0"}; | 
					
						
							|  |  |  |     auto objectPath = QString{"/dde_launcher/org_deepin_dde_launcher/%1"}.arg(getCurrentUID()); | 
					
						
							|  |  |  |     auto systemBus = QDBusConnection::systemBus(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto msg = QDBusMessage::createMethodCall( | 
					
						
							|  |  |  |         "org.desktopspec.ConfigManager", objectPath, "org.desktopspec.ConfigManager.Manager", "value"); | 
					
						
							|  |  |  |     msg.setArguments({QString{"Apps_Disable_Scaling"}}); | 
					
						
							|  |  |  |     auto reply = systemBus.call(msg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (reply.type() != QDBusMessage::ReplyMessage) { | 
					
						
							|  |  |  |         qWarning() << "get Apps_Disable_Scaling failed:" << reply.errorMessage(); | 
					
						
							|  |  |  |         return factor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QDBusReply<QDBusVariant> ret{reply}; | 
					
						
							|  |  |  |     if (!ret.isValid()) { | 
					
						
							|  |  |  |         qWarning() << "invalid reply:" << ret.error(); | 
					
						
							|  |  |  |         return factor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QVariantList appList; | 
					
						
							|  |  |  |     ret.value().variant().value<QDBusArgument>() >> appList; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const auto &val : appList) { | 
					
						
							|  |  |  |         if (val.value<QString>() == appId) { | 
					
						
							|  |  |  |             return factor; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto sessionBus = QDBusConnection::sessionBus(); | 
					
						
							|  |  |  |     QDBusMessage reply1 = sessionBus.call(QDBusMessage::createMethodCall( | 
					
						
							|  |  |  |         "org.deepin.dde.XSettings1", "/org/deepin/dde/XSettings1", "org.deepin.dde.XSettings1", "GetScaleFactor")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (reply1.type() != QDBusMessage::ReplyMessage) { | 
					
						
							|  |  |  |         qWarning() << "call GetScaleFactor Failed:" << reply1.errorMessage(); | 
					
						
							|  |  |  |         return factor; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QDBusReply<double> ret1(reply1); | 
					
						
							|  |  |  |     double scale = ret1.isValid() ? ret1.value() : 1.0; | 
					
						
							|  |  |  |     scale = scale > 0 ? scale : 1; | 
					
						
							|  |  |  |     factor = QString::number(scale, 'f', -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return factor; | 
					
						
							|  |  |  | } |