From 1c8a46791c4eda644920fd0b6abb6197aac423ce Mon Sep 17 00:00:00 2001 From: Eike Hein Date: Thu, 20 Apr 2017 19:22:01 +0900 Subject: [PATCH] Introduce a concept of runtime executables that can be ignored. Summary: This introduces a TryIgnoreRuntimes key in taskmanagerrulesrc's Settings group that can be used to list known runtime executables that can be ignored when trying to identify the application owning a window by the command line of the associated process. A concrete example is the Frozen Bubble application. Frozen Bubble installs a frozen-bubble.desktop with Exec=frozen-bubble, yet its WM_CLASS is ("perl", "perl") and its command line is as follows: /usr/bin/perl /usr/bin/frozen-bubble The existing servicesFromPid() (now split into servicesFromPid() and servicesFromCmdLine()) does not find the frozen-bubble service because it works with the leading executable in the command line. In this patch, TryIgnoreRuntimes is introduced with a default of "perl". In the new code, after the initial command line matching pass fails, TryIgnoreRuntimes is checked for whether the leading command line executable is on the list, and if so, a second command line matching pass is run with the remainder of the process' command line, now succeeding. Note that the approach of "try one more thing" rather than checking against TryIgnoreRuntimes first is deliberate: The Exec= key in many .desktop files contains a complete command line prefixed with the runtime executable. In those cases we don't want to ignore the runtime executable, or matching would fail. To complement this, the "perl" WM_CLASS is added to the MatchCommandLineFirst rc key. Due to the shoddy metadata Frozen Bubble already ended up in servicesFromPid() regardless, but this saves some busywork for this WM_CLASS, which can reliably be presumed bad. The patch also fixes a small logic error in the match-command-line- without-arguments block, where the result of a KServiceTypeTrader query was ignored and immediately overridden by another. Reviewers: #plasma, davidedmundson, broulik Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D5522 --- libtaskmanager/taskmanagerrulesrc | 2 + libtaskmanager/xwindowtasksmodel.cpp | 71 ++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/libtaskmanager/taskmanagerrulesrc b/libtaskmanager/taskmanagerrulesrc index 6bcb524af..fc6ea6cdf 100644 --- a/libtaskmanager/taskmanagerrulesrc +++ b/libtaskmanager/taskmanagerrulesrc @@ -8,3 +8,5 @@ Dragon=dragonplayer [Settings] ManualOnly=Wine +MatchCommandLineFirst=perl +TryIgnoreRuntimes=perl diff --git a/libtaskmanager/xwindowtasksmodel.cpp b/libtaskmanager/xwindowtasksmodel.cpp index 3c2b71992..47a64bdba 100644 --- a/libtaskmanager/xwindowtasksmodel.cpp +++ b/libtaskmanager/xwindowtasksmodel.cpp @@ -90,6 +90,7 @@ public: QUrl launcherUrl(WId window, bool encodeFallbackIcon = true); QUrl serviceUrl(int pid, const QString &type, const QStringList &cmdRemovals); KService::List servicesFromPid(int pid); + KService::List servicesFromCmdLine(const QString &cmdLine, const QString &processName); bool demandsAttention(WId window); private: @@ -788,49 +789,77 @@ QUrl XWindowTasksModel::Private::serviceUrl(int pid, const QString &type, const KService::List XWindowTasksModel::Private::servicesFromPid(int pid) { - // Attempt to find using commandline... - KService::List services; - if (pid == 0) { - return services; + return KService::List(); } KSysGuard::Processes procs; procs.updateOrAddProcess(pid); KSysGuard::Process *proc = procs.getProcess(pid); - QString cmdline = proc ? proc->command().simplified() : QString(); // proc->command has a trailing space??? + const QString &cmdLine = proc ? proc->command().simplified() : QString(); // proc->command has a trailing space??? - if (cmdline.isEmpty()) { - return services; + if (cmdLine.isEmpty()) { + return KService::List(); } - const int firstSpace = cmdline.indexOf(' '); + return servicesFromCmdLine(cmdLine, proc->name()); +} + +KService::List XWindowTasksModel::Private::servicesFromCmdLine(const QString &_cmdLine, const QString &processName) +{ + QString cmdLine = _cmdLine; + KService::List services; + + const int firstSpace = cmdLine.indexOf(' '); + int slash = 0; + + 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()) { - // Could not find with complete commandline, so strip out path part... - int slash = cmdline.lastIndexOf('/', firstSpace); + // Could not find with complete command line, so strip out the path part ... + slash = cmdLine.lastIndexOf('/', firstSpace); + if (slash > 0) { - services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdline.mid(slash + 1))); + services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine.mid(slash + 1))); } } if (services.empty() && firstSpace > 0) { - // Could not find with arguments, so try without... - cmdline = cmdline.left(firstSpace); - services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdline)); + // Could not find with arguments, so try without ... + cmdLine = cmdLine.left(firstSpace); - int slash = cmdline.lastIndexOf('/'); - if (slash > 0) { - services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdline.mid(slash + 1))); + services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); + + if (services.empty()) { + slash = cmdLine.lastIndexOf('/'); + + if (slash > 0) { + services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine.mid(slash + 1))); + } } } - if (services.empty() && proc && !QStandardPaths::findExecutable(cmdline).isEmpty()) { - // cmdline now exists without arguments if there were any - services << QExplicitlySharedDataPointer(new KService(proc->name(), cmdline, QString())); + if (services.empty()) { + KConfigGroup set(rulesConfig, "Settings"); + const QStringList &runtimes = set.readEntry("TryIgnoreRuntimes", QStringList()); + + bool ignore = runtimes.contains(cmdLine); + + if (!ignore && slash > 0) { + ignore = runtimes.contains(cmdLine.mid(slash + 1)); + } + + if (ignore) { + return servicesFromCmdLine(_cmdLine.mid(firstSpace + 1), processName); + } } + + if (services.empty() && !processName.isEmpty() && !QStandardPaths::findExecutable(cmdLine).isEmpty()) { + // cmdLine now exists without arguments if there were any. + services << QExplicitlySharedDataPointer(new KService(processName, cmdLine, QString())); + } + return services; }