Merge branch 'Plasma/5.13'

wilder-5.14
Eike Hein 8 years ago
commit c77be185d7
  1. 71
      libtaskmanager/tasktools.cpp

@ -215,6 +215,38 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
KService::List services; KService::List services;
bool triedPid = false; bool triedPid = false;
// The code below this function goes on a hunt for services based on the metadata
// that has been passed in. Occasionally, it will find more than one matching
// service. In some scenarios (e.g. multiple identically-named .desktop files)
// there's a need to pick the most useful one. The function below promises to "sort"
// a list of services by how closely their KService::menuId() relates to the key that
// has been passed in. The current naive implementation simply looks for a menuId
// that starts with the key, prepends it to the list and returns it. In practice,
// that means a KService with a menuId matching the appId will win over one with a
// menuId that encodes a subfolder hierarchy.
// A concrete example: Valve's Steam client is sometimes installed two times, once
// natively as a Linux application, once via Wine. Both have .desktop files named
// (S|)steam.desktop. The Linux native version is located in the menu by means of
// categorization ("Games") and just has a menuId() matching the .desktop file name,
// but the Wine version is placed in a folder hierarchy by Wine and gets a menuId()
// of wine-Programs-Steam-Steam.desktop. The weighing done by this function makes
// sure the Linux native version gets mapped to the former, while other heuristics
// map the Wine version reliably to the latter.
// In lieu of this weighing we just used whatever KServiceTypeTrader returned first,
// so what we do here can be no worse.
auto sortServicesByMenuId = [](KService::List &services, const QString &key) {
if (services.count() == 1) {
return;
}
for (const auto service : services) {
if (service->menuId().startsWith(key, Qt::CaseInsensitive)) {
services.prepend(service);
return;
}
}
};
if (!(appId.isEmpty() && xWindowsWMClassName.isEmpty())) { if (!(appId.isEmpty() && xWindowsWMClassName.isEmpty())) {
// Check to see if this wmClass matched a saved one ... // Check to see if this wmClass matched a saved one ...
KConfigGroup grp(rulesConfig, "Mapping"); KConfigGroup grp(rulesConfig, "Mapping");
@ -272,16 +304,18 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
// window with the given string as its WM class or WM name hint. // window with the given string as its WM class or WM name hint.
// //
// Source: https://specifications.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt // Source: https://specifications.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt
if (services.empty()) { if (services.isEmpty()) {
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(appId)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(appId));
sortServicesByMenuId(services, appId);
} }
if (services.empty()) { if (services.isEmpty()) {
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(xWindowsWMClassName)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(xWindowsWMClassName));
sortServicesByMenuId(services, xWindowsWMClassName);
} }
// Evaluate rewrite rules from config. // Evaluate rewrite rules from config.
if (services.empty()) { if (services.isEmpty()) {
KConfigGroup rewriteRulesGroup(rulesConfig, QStringLiteral("Rewrite Rules")); KConfigGroup rewriteRulesGroup(rulesConfig, QStringLiteral("Rewrite Rules"));
if (rewriteRulesGroup.hasGroup(appId)) { if (rewriteRulesGroup.hasGroup(appId)) {
KConfigGroup rewriteGroup(&rewriteRulesGroup, appId); KConfigGroup rewriteGroup(&rewriteRulesGroup, appId);
@ -324,6 +358,7 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
} }
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ %2)").arg(rewrittenString, serviceSearchIdentifier)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ %2)").arg(rewrittenString, serviceSearchIdentifier));
sortServicesByMenuId(services, serviceSearchIdentifier);
if (!services.isEmpty()) { if (!services.isEmpty()) {
break; break;
@ -334,7 +369,7 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
} }
// The appId looks like a path. // The appId looks like a path.
if (appId.startsWith(QStringLiteral("/"))) { if (services.isEmpty() && appId.startsWith(QStringLiteral("/"))) {
// Check if it's a path to a .desktop file. // Check if it's a path to a .desktop file.
if (KDesktopFile::isDesktopFile(appId) && QFile::exists(appId)) { if (KDesktopFile::isDesktopFile(appId) && QFile::exists(appId)) {
return QUrl::fromLocalFile(appId); return QUrl::fromLocalFile(appId);
@ -349,29 +384,33 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
} }
// Try matching mapped name against DesktopEntryName. // Try matching mapped name against DesktopEntryName.
if (!mapped.isEmpty() && services.empty()) { if (!mapped.isEmpty() && services.isEmpty()) {
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(mapped)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(mapped));
sortServicesByMenuId(services, mapped);
} }
// Try matching mapped name against 'Name'. // Try matching mapped name against 'Name'.
if (!mapped.isEmpty() && services.empty()) { if (!mapped.isEmpty() && services.isEmpty()) {
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(mapped)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(mapped));
sortServicesByMenuId(services, mapped);
} }
// Try matching appId against DesktopEntryName. // Try matching appId against DesktopEntryName.
if (services.empty()) { if (services.isEmpty()) {
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(appId)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(appId));
sortServicesByMenuId(services, appId);
} }
// Try matching appId against 'Name'. // Try matching appId against 'Name'.
// This has a shaky chance of success as appId is untranslated, but 'Name' may be localized. // This has a shaky chance of success as appId is untranslated, but 'Name' may be localized.
if (services.empty()) { if (services.isEmpty()) {
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(appId)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(appId));
sortServicesByMenuId(services, appId);
} }
} }
// Ok, absolute *last* chance, try matching via pid (but only if we have not already tried this!) ... // Ok, absolute *last* chance, try matching via pid (but only if we have not already tried this!) ...
if (services.empty() && !triedPid) { if (services.isEmpty() && !triedPid) {
services = servicesFromPid(pid, rulesConfig); services = servicesFromPid(pid, rulesConfig);
} }
} }
@ -389,7 +428,7 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
// - appId cannot directly match the desktop file because of RDN // - appId cannot directly match the desktop file because of RDN
// - appId also cannot match the binary because of name mismatch // - appId also cannot match the binary because of name mismatch
// - in the following code *.appId can match org.kde.dragonplayer though // - in the following code *.appId can match org.kde.dragonplayer though
if (services.empty() || services.at(0)->desktopEntryName().isEmpty()) { if (services.isEmpty() || services.at(0)->desktopEntryName().isEmpty()) {
auto matchingServices = KServiceTypeTrader::self()->query(QStringLiteral("Application"), auto matchingServices = KServiceTypeTrader::self()->query(QStringLiteral("Application"),
QStringLiteral("exist Exec and ('%1' ~~ DesktopEntryName)").arg(appId)); QStringLiteral("exist Exec and ('%1' ~~ DesktopEntryName)").arg(appId));
QMutableListIterator<KService::Ptr> it(matchingServices); QMutableListIterator<KService::Ptr> it(matchingServices);
@ -408,7 +447,7 @@ QUrl windowUrlFromMetadata(const QString &appId, quint32 pid,
} }
} }
if (!services.empty()) { if (!services.isEmpty()) {
const QString &menuId = services.at(0)->menuId(); const QString &menuId = services.at(0)->menuId();
// applications: URLs are used to refer to applications by their KService::menuId // applications: URLs are used to refer to applications by their KService::menuId
@ -469,7 +508,7 @@ KService::List servicesFromCmdLine(const QString &_cmdLine, const QString &proce
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine));
if (services.empty()) { if (services.isEmpty()) {
// Could not find with complete command line, so strip out the path part ... // Could not find with complete command line, so strip out the path part ...
slash = cmdLine.lastIndexOf('/', firstSpace); slash = cmdLine.lastIndexOf('/', firstSpace);
@ -478,13 +517,13 @@ KService::List servicesFromCmdLine(const QString &_cmdLine, const QString &proce
} }
} }
if (services.empty() && firstSpace > 0) { if (services.isEmpty() && firstSpace > 0) {
// Could not find with arguments, so try without ... // Could not find with arguments, so try without ...
cmdLine = cmdLine.left(firstSpace); cmdLine = cmdLine.left(firstSpace);
services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine));
if (services.empty()) { if (services.isEmpty()) {
slash = cmdLine.lastIndexOf('/'); slash = cmdLine.lastIndexOf('/');
if (slash > 0) { if (slash > 0) {
@ -493,7 +532,7 @@ KService::List servicesFromCmdLine(const QString &_cmdLine, const QString &proce
} }
} }
if (services.empty()) { if (services.isEmpty()) {
KConfigGroup set(rulesConfig, "Settings"); KConfigGroup set(rulesConfig, "Settings");
const QStringList &runtimes = set.readEntry("TryIgnoreRuntimes", QStringList()); const QStringList &runtimes = set.readEntry("TryIgnoreRuntimes", QStringList());
@ -508,7 +547,7 @@ KService::List servicesFromCmdLine(const QString &_cmdLine, const QString &proce
} }
} }
if (services.empty() && !processName.isEmpty() && !QStandardPaths::findExecutable(cmdLine).isEmpty()) { if (services.isEmpty() && !processName.isEmpty() && !QStandardPaths::findExecutable(cmdLine).isEmpty()) {
// cmdLine now exists without arguments if there were any. // cmdLine now exists without arguments if there were any.
services << QExplicitlySharedDataPointer<KService>(new KService(processName, cmdLine, QString())); services << QExplicitlySharedDataPointer<KService>(new KService(processName, cmdLine, QString()));
} }

Loading…
Cancel
Save