Changeset View
Standalone View
libtaskmanager/tasktools.cpp
Show All 36 Lines | |||||
37 | #include <KWindowSystem> | 37 | #include <KWindowSystem> | ||
38 | 38 | | |||
39 | #include <processcore/processes.h> | 39 | #include <processcore/processes.h> | ||
40 | #include <processcore/process.h> | 40 | #include <processcore/process.h> | ||
41 | 41 | | |||
42 | #include <config-X11.h> | 42 | #include <config-X11.h> | ||
43 | 43 | | |||
44 | #include <QDir> | 44 | #include <QDir> | ||
45 | #include <QGuiApplication> | 45 | #include <QGuiApplication> | ||
cfeck: Can be removed? If not, sort correctly. | |||||
46 | #include <QRegularExpression> | 46 | #include <QRegularExpression> | ||
47 | #include <QScreen> | 47 | #include <QScreen> | ||
48 | #if HAVE_X11 | 48 | #if HAVE_X11 | ||
49 | #include <QX11Info> | 49 | #include <QX11Info> | ||
50 | #endif | 50 | #endif | ||
51 | 51 | | |||
52 | namespace TaskManager | 52 | namespace TaskManager | ||
53 | { | 53 | { | ||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Line(s) | 209 | { | |||
210 | if (!rulesConfig) { | 210 | if (!rulesConfig) { | ||
211 | return QUrl(); | 211 | return QUrl(); | ||
212 | } | 212 | } | ||
213 | 213 | | |||
214 | QUrl url; | 214 | QUrl url; | ||
215 | KService::List services; | 215 | KService::List services; | ||
216 | bool triedPid = false; | 216 | bool triedPid = false; | ||
217 | 217 | | |||
218 | // The code below this function goes on a hunt for services based on the metadata | ||||
219 | // that has been passed in. Occasionally, it will find more than one matching | ||||
220 | // service. In some scenarios (e.g. multiple identically-named .desktop files) | ||||
221 | // there's a need to pick the most useful one. The function below promises to "sort" | ||||
222 | // a list of services by how closely their KService::menuId() relates to the key that | ||||
223 | // has been passed in. The current naive implementation simply looks for a menuId | ||||
224 | // that starts with the key, prepends it to the list and returns it. In practice, | ||||
225 | // that means a KService with a menuId matching the appId will win over one with a | ||||
226 | // menuId that encodes a subfolder hierarchy. | ||||
227 | // A concrete example: Valve's Steam client is sometimes installed two times, once | ||||
This comment makes it sound like this pretends to be a generic solution to a particular workaround. But you told me there's also Telegram and others being affected (fixed) by this, right? broulik: This comment makes it sound like this pretends to be a generic solution to a particular… | |||||
I started doing this for the Wine thing based on a user bug report. But for some reason I did wind up with two .desktop files for Telegram on my system, I think one from the Fedora package and one from ... a Flatpak? Their tarball? Who knows. In any case, this algo helps pick the right one there, too. The general idea of "if we find more than one service, the one with a menuId that's more closely related to the search term we found them with" seems to be better than "just use whatever KSTT returns first", considering KSTT does no sorting whatsoever. hein: I started doing this for the Wine thing based on a user bug report. But for some reason I did… | |||||
228 | // natively as a Linux application, once via Wine. Both have .desktop files named | ||||
229 | // (S|)steam.desktop. The Linux native version is located in the menu by means of | ||||
230 | // categorization ("Games") and just has a menuId() matching the .desktop file name, | ||||
231 | // but the Wine version is placed in a folder hierarchy by Wine and gets a menuId() | ||||
232 | // of wine-Programs-Steam-Steam.desktop. The weighing done by this function makes | ||||
233 | // sure the Linux native version gets mapped to the former, while other heuristics | ||||
234 | // map the Wine version reliably to the latter. | ||||
235 | // In lieu of this weighing we just used whatever KServiceTypeTrader returned first, | ||||
236 | // so what we do here can be no worse. | ||||
237 | auto sortServicesByMenuId = [](KService::List &services, const QString &key) { | ||||
238 | if (services.count() == 1) { | ||||
239 | return; | ||||
240 | } | ||||
241 | | ||||
242 | for (const auto service : services) { | ||||
broulik: Is there some nicer algo in place of this loop? | |||||
hein: You tell me? :) | |||||
243 | if (service->menuId().startsWith(key, Qt::CaseInsensitive)) { | ||||
244 | services.prepend(service); | ||||
You're mutating the list (argument services is a non-const reference) and also returning it. Is this intentional? broulik: You're mutating the list (argument `services` is a non-`const` reference) and also returning it. | |||||
Yes. It's just faster and less costly than actually sorting the list. This is a bit ugly, but it takes the stance of "this is a private anonymous function so it can't hurt any lib user, and if this sorting algo ever needs to be more sophisticated we'll fill it in then". hein: Yes. It's just faster and less costly than actually sorting the list. This is a bit ugly, but… | |||||
245 | return; | ||||
246 | } | ||||
247 | } | ||||
248 | }; | ||||
249 | | ||||
218 | if (!(appId.isEmpty() && xWindowsWMClassName.isEmpty())) { | 250 | if (!(appId.isEmpty() && xWindowsWMClassName.isEmpty())) { | ||
219 | // Check to see if this wmClass matched a saved one ... | 251 | // Check to see if this wmClass matched a saved one ... | ||
220 | KConfigGroup grp(rulesConfig, "Mapping"); | 252 | KConfigGroup grp(rulesConfig, "Mapping"); | ||
221 | KConfigGroup set(rulesConfig, "Settings"); | 253 | KConfigGroup set(rulesConfig, "Settings"); | ||
222 | 254 | | |||
223 | // Evaluate MatchCommandLineFirst directives from config first. | 255 | // Evaluate MatchCommandLineFirst directives from config first. | ||
224 | // Some apps have different launchers depending upon command line ... | 256 | // Some apps have different launchers depending upon command line ... | ||
225 | QStringList matchCommandLineFirst = set.readEntry("MatchCommandLineFirst", QStringList()); | 257 | QStringList matchCommandLineFirst = set.readEntry("MatchCommandLineFirst", QStringList()); | ||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Line(s) | 270 | if (!appId.isEmpty()) { | |||
267 | // sensibly to instruct us what to do. Also, mapping rules | 299 | // sensibly to instruct us what to do. Also, mapping rules | ||
268 | // | 300 | // | ||
269 | // StartupWMClass=STRING | 301 | // StartupWMClass=STRING | ||
270 | // | 302 | // | ||
271 | // If true, it is KNOWN that the application will map at least one | 303 | // If true, it is KNOWN that the application will map at least one | ||
272 | // window with the given string as its WM class or WM name hint. | 304 | // window with the given string as its WM class or WM name hint. | ||
273 | // | 305 | // | ||
274 | // Source: https://specifications.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt | 306 | // Source: https://specifications.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt | ||
275 | if (services.empty()) { | 307 | if (services.isEmpty()) { | ||
276 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(appId)); | 308 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(appId)); | ||
309 | sortServicesByMenuId(services, appId); | ||||
277 | } | 310 | } | ||
278 | 311 | | |||
279 | if (services.empty()) { | 312 | if (services.isEmpty()) { | ||
280 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(xWindowsWMClassName)); | 313 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ StartupWMClass)").arg(xWindowsWMClassName)); | ||
314 | sortServicesByMenuId(services, xWindowsWMClassName); | ||||
281 | } | 315 | } | ||
282 | 316 | | |||
283 | // Evaluate rewrite rules from config. | 317 | // Evaluate rewrite rules from config. | ||
284 | if (services.empty()) { | 318 | if (services.isEmpty()) { | ||
285 | KConfigGroup rewriteRulesGroup(rulesConfig, QStringLiteral("Rewrite Rules")); | 319 | KConfigGroup rewriteRulesGroup(rulesConfig, QStringLiteral("Rewrite Rules")); | ||
286 | if (rewriteRulesGroup.hasGroup(appId)) { | 320 | if (rewriteRulesGroup.hasGroup(appId)) { | ||
287 | KConfigGroup rewriteGroup(&rewriteRulesGroup, appId); | 321 | KConfigGroup rewriteGroup(&rewriteRulesGroup, appId); | ||
288 | 322 | | |||
289 | const QStringList &rules = rewriteGroup.groupList(); | 323 | const QStringList &rules = rewriteGroup.groupList(); | ||
290 | for (const QString &rule : rules) { | 324 | for (const QString &rule : rules) { | ||
291 | KConfigGroup ruleGroup(&rewriteGroup, rule); | 325 | KConfigGroup ruleGroup(&rewriteGroup, rule); | ||
292 | 326 | | |||
Show All 26 Lines | 348 | if (match.hasMatch()) { | |||
319 | 353 | | |||
320 | QString rewrittenString = ruleGroup.readEntry(QStringLiteral("Target")).arg(actualMatch); | 354 | QString rewrittenString = ruleGroup.readEntry(QStringLiteral("Target")).arg(actualMatch); | ||
321 | // If no "Target" is provided, instead assume the matched property (appId/xWindowsWMClassName). | 355 | // If no "Target" is provided, instead assume the matched property (appId/xWindowsWMClassName). | ||
322 | if (rewrittenString.isEmpty()) { | 356 | if (rewrittenString.isEmpty()) { | ||
323 | rewrittenString = matchProperty; | 357 | rewrittenString = matchProperty; | ||
324 | } | 358 | } | ||
325 | 359 | | |||
326 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ %2)").arg(rewrittenString, serviceSearchIdentifier)); | 360 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ %2)").arg(rewrittenString, serviceSearchIdentifier)); | ||
361 | sortServicesByMenuId(services, serviceSearchIdentifier); | ||||
327 | 362 | | |||
328 | if (!services.isEmpty()) { | 363 | if (!services.isEmpty()) { | ||
329 | break; | 364 | break; | ||
330 | } | 365 | } | ||
331 | } | 366 | } | ||
332 | } | 367 | } | ||
333 | } | 368 | } | ||
334 | } | 369 | } | ||
335 | 370 | | |||
336 | // The appId looks like a path. | 371 | // The appId looks like a path. | ||
337 | if (appId.startsWith(QStringLiteral("/"))) { | 372 | if (services.isEmpty() && appId.startsWith(QStringLiteral("/"))) { | ||
broulik: `isEmpty` (unless consistent with the rest but it seems to be mixed already) | |||||
hein: Will change. | |||||
338 | // Check if it's a path to a .desktop file. | 373 | // Check if it's a path to a .desktop file. | ||
339 | if (KDesktopFile::isDesktopFile(appId) && QFile::exists(appId)) { | 374 | if (KDesktopFile::isDesktopFile(appId) && QFile::exists(appId)) { | ||
340 | return QUrl::fromLocalFile(appId); | 375 | return QUrl::fromLocalFile(appId); | ||
341 | } | 376 | } | ||
342 | 377 | | |||
343 | // Check if the appId passes as a .desktop file path if we add the extension. | 378 | // Check if the appId passes as a .desktop file path if we add the extension. | ||
344 | const QString appIdPlusExtension(appId + QStringLiteral(".desktop")); | 379 | const QString appIdPlusExtension(appId + QStringLiteral(".desktop")); | ||
345 | 380 | | |||
346 | if (KDesktopFile::isDesktopFile(appIdPlusExtension) && QFile::exists(appIdPlusExtension)) { | 381 | if (KDesktopFile::isDesktopFile(appIdPlusExtension) && QFile::exists(appIdPlusExtension)) { | ||
347 | return QUrl::fromLocalFile(appIdPlusExtension); | 382 | return QUrl::fromLocalFile(appIdPlusExtension); | ||
348 | } | 383 | } | ||
349 | } | 384 | } | ||
350 | 385 | | |||
351 | // Try matching mapped name against DesktopEntryName. | 386 | // Try matching mapped name against DesktopEntryName. | ||
352 | if (!mapped.isEmpty() && services.empty()) { | 387 | if (!mapped.isEmpty() && services.isEmpty()) { | ||
353 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(mapped)); | 388 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(mapped)); | ||
389 | sortServicesByMenuId(services, mapped); | ||||
354 | } | 390 | } | ||
355 | 391 | | |||
356 | // Try matching mapped name against 'Name'. | 392 | // Try matching mapped name against 'Name'. | ||
357 | if (!mapped.isEmpty() && services.empty()) { | 393 | if (!mapped.isEmpty() && services.isEmpty()) { | ||
358 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(mapped)); | 394 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(mapped)); | ||
395 | sortServicesByMenuId(services, mapped); | ||||
359 | } | 396 | } | ||
360 | 397 | | |||
361 | // Try matching appId against DesktopEntryName. | 398 | // Try matching appId against DesktopEntryName. | ||
362 | if (services.empty()) { | 399 | if (services.isEmpty()) { | ||
363 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(appId)); | 400 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ DesktopEntryName) and (not exist NoDisplay or not NoDisplay)").arg(appId)); | ||
401 | sortServicesByMenuId(services, appId); | ||||
364 | } | 402 | } | ||
365 | 403 | | |||
366 | // Try matching appId against 'Name'. | 404 | // Try matching appId against 'Name'. | ||
367 | // This has a shaky chance of success as appId is untranslated, but 'Name' may be localized. | 405 | // This has a shaky chance of success as appId is untranslated, but 'Name' may be localized. | ||
368 | if (services.empty()) { | 406 | if (services.isEmpty()) { | ||
369 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(appId)); | 407 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Name) and (not exist NoDisplay or not NoDisplay)").arg(appId)); | ||
408 | sortServicesByMenuId(services, appId); | ||||
370 | } | 409 | } | ||
371 | } | 410 | } | ||
372 | 411 | | |||
373 | // Ok, absolute *last* chance, try matching via pid (but only if we have not already tried this!) ... | 412 | // Ok, absolute *last* chance, try matching via pid (but only if we have not already tried this!) ... | ||
374 | if (services.empty() && !triedPid) { | 413 | if (services.isEmpty() && !triedPid) { | ||
375 | services = servicesFromPid(pid, rulesConfig); | 414 | services = servicesFromPid(pid, rulesConfig); | ||
376 | } | 415 | } | ||
377 | } | 416 | } | ||
378 | 417 | | |||
379 | // Try to improve on a possible from-binary fallback. | 418 | // Try to improve on a possible from-binary fallback. | ||
380 | // If no services were found or we got a fake-service back from getServicesViaPid() | 419 | // If no services were found or we got a fake-service back from getServicesViaPid() | ||
381 | // we attempt to improve on this by adding a loosely matched reverse-domain-name | 420 | // we attempt to improve on this by adding a loosely matched reverse-domain-name | ||
382 | // DesktopEntryName. Namely anything that is '*.appId.desktop' would qualify here. | 421 | // DesktopEntryName. Namely anything that is '*.appId.desktop' would qualify here. | ||
383 | // | 422 | // | ||
384 | // Illustrative example of a case where the above heuristics would fail to produce | 423 | // Illustrative example of a case where the above heuristics would fail to produce | ||
385 | // a reasonable result: | 424 | // a reasonable result: | ||
386 | // - org.kde.dragonplayer.desktop | 425 | // - org.kde.dragonplayer.desktop | ||
387 | // - binary is 'dragon' | 426 | // - binary is 'dragon' | ||
388 | // - qapp appname and thus appId is 'dragonplayer' | 427 | // - qapp appname and thus appId is 'dragonplayer' | ||
389 | // - appId cannot directly match the desktop file because of RDN | 428 | // - appId cannot directly match the desktop file because of RDN | ||
390 | // - appId also cannot match the binary because of name mismatch | 429 | // - appId also cannot match the binary because of name mismatch | ||
391 | // - in the following code *.appId can match org.kde.dragonplayer though | 430 | // - in the following code *.appId can match org.kde.dragonplayer though | ||
392 | if (services.empty() || services.at(0)->desktopEntryName().isEmpty()) { | 431 | if (services.isEmpty() || services.at(0)->desktopEntryName().isEmpty()) { | ||
393 | auto matchingServices = KServiceTypeTrader::self()->query(QStringLiteral("Application"), | 432 | auto matchingServices = KServiceTypeTrader::self()->query(QStringLiteral("Application"), | ||
394 | QStringLiteral("exist Exec and ('%1' ~~ DesktopEntryName)").arg(appId)); | 433 | QStringLiteral("exist Exec and ('%1' ~~ DesktopEntryName)").arg(appId)); | ||
395 | QMutableListIterator<KService::Ptr> it(matchingServices); | 434 | QMutableListIterator<KService::Ptr> it(matchingServices); | ||
396 | while (it.hasNext()) { | 435 | while (it.hasNext()) { | ||
397 | auto service = it.next(); | 436 | auto service = it.next(); | ||
398 | if (!service->desktopEntryName().endsWith("." + appId)) { | 437 | if (!service->desktopEntryName().endsWith("." + appId)) { | ||
399 | it.remove(); | 438 | it.remove(); | ||
400 | } | 439 | } | ||
401 | } | 440 | } | ||
402 | // Exactly one match is expected, otherwise we discard the results as to reduce | 441 | // Exactly one match is expected, otherwise we discard the results as to reduce | ||
403 | // the likelihood of false-positive mappings. Since we essentially eliminate the | 442 | // the likelihood of false-positive mappings. Since we essentially eliminate the | ||
404 | // uniqueness that RDN is meant to bring to the table we could potentially end | 443 | // uniqueness that RDN is meant to bring to the table we could potentially end | ||
405 | // up with more than one match here. | 444 | // up with more than one match here. | ||
406 | if (matchingServices.length() == 1) { | 445 | if (matchingServices.length() == 1) { | ||
407 | services = matchingServices; | 446 | services = matchingServices; | ||
408 | } | 447 | } | ||
409 | } | 448 | } | ||
410 | 449 | | |||
411 | if (!services.empty()) { | 450 | if (!services.isEmpty()) { | ||
412 | const QString &menuId = services.at(0)->menuId(); | 451 | const QString &menuId = services.at(0)->menuId(); | ||
413 | 452 | | |||
414 | // applications: URLs are used to refer to applications by their KService::menuId | 453 | // applications: URLs are used to refer to applications by their KService::menuId | ||
415 | // (i.e. .desktop file name) rather than the absolute path to a .desktop file. | 454 | // (i.e. .desktop file name) rather than the absolute path to a .desktop file. | ||
416 | if (!menuId.isEmpty()) { | 455 | if (!menuId.isEmpty()) { | ||
417 | return QUrl(QStringLiteral("applications:") + menuId); | 456 | return QUrl(QStringLiteral("applications:") + menuId); | ||
418 | } | 457 | } | ||
419 | 458 | | |||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Line(s) | 502 | if (!rulesConfig) { | |||
464 | return services; | 503 | return services; | ||
465 | } | 504 | } | ||
466 | 505 | | |||
467 | const int firstSpace = cmdLine.indexOf(' '); | 506 | const int firstSpace = cmdLine.indexOf(' '); | ||
468 | int slash = 0; | 507 | int slash = 0; | ||
469 | 508 | | |||
470 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); | 509 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); | ||
471 | 510 | | |||
472 | if (services.empty()) { | 511 | if (services.isEmpty()) { | ||
473 | // Could not find with complete command line, so strip out the path part ... | 512 | // Could not find with complete command line, so strip out the path part ... | ||
474 | slash = cmdLine.lastIndexOf('/', firstSpace); | 513 | slash = cmdLine.lastIndexOf('/', firstSpace); | ||
475 | 514 | | |||
476 | if (slash > 0) { | 515 | if (slash > 0) { | ||
477 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine.mid(slash + 1))); | 516 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine.mid(slash + 1))); | ||
478 | } | 517 | } | ||
479 | } | 518 | } | ||
480 | 519 | | |||
481 | if (services.empty() && firstSpace > 0) { | 520 | if (services.isEmpty() && firstSpace > 0) { | ||
482 | // Could not find with arguments, so try without ... | 521 | // Could not find with arguments, so try without ... | ||
483 | cmdLine = cmdLine.left(firstSpace); | 522 | cmdLine = cmdLine.left(firstSpace); | ||
484 | 523 | | |||
485 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); | 524 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine)); | ||
486 | 525 | | |||
487 | if (services.empty()) { | 526 | if (services.isEmpty()) { | ||
488 | slash = cmdLine.lastIndexOf('/'); | 527 | slash = cmdLine.lastIndexOf('/'); | ||
489 | 528 | | |||
490 | if (slash > 0) { | 529 | if (slash > 0) { | ||
491 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine.mid(slash + 1))); | 530 | services = KServiceTypeTrader::self()->query(QStringLiteral("Application"), QStringLiteral("exist Exec and ('%1' =~ Exec)").arg(cmdLine.mid(slash + 1))); | ||
492 | } | 531 | } | ||
493 | } | 532 | } | ||
494 | } | 533 | } | ||
495 | 534 | | |||
496 | if (services.empty()) { | 535 | if (services.isEmpty()) { | ||
497 | KConfigGroup set(rulesConfig, "Settings"); | 536 | KConfigGroup set(rulesConfig, "Settings"); | ||
498 | const QStringList &runtimes = set.readEntry("TryIgnoreRuntimes", QStringList()); | 537 | const QStringList &runtimes = set.readEntry("TryIgnoreRuntimes", QStringList()); | ||
499 | 538 | | |||
500 | bool ignore = runtimes.contains(cmdLine); | 539 | bool ignore = runtimes.contains(cmdLine); | ||
501 | 540 | | |||
502 | if (!ignore && slash > 0) { | 541 | if (!ignore && slash > 0) { | ||
503 | ignore = runtimes.contains(cmdLine.mid(slash + 1)); | 542 | ignore = runtimes.contains(cmdLine.mid(slash + 1)); | ||
504 | } | 543 | } | ||
505 | 544 | | |||
506 | if (ignore) { | 545 | if (ignore) { | ||
507 | return servicesFromCmdLine(_cmdLine.mid(firstSpace + 1), processName, rulesConfig); | 546 | return servicesFromCmdLine(_cmdLine.mid(firstSpace + 1), processName, rulesConfig); | ||
508 | } | 547 | } | ||
509 | } | 548 | } | ||
510 | 549 | | |||
511 | if (services.empty() && !processName.isEmpty() && !QStandardPaths::findExecutable(cmdLine).isEmpty()) { | 550 | if (services.isEmpty() && !processName.isEmpty() && !QStandardPaths::findExecutable(cmdLine).isEmpty()) { | ||
512 | // cmdLine now exists without arguments if there were any. | 551 | // cmdLine now exists without arguments if there were any. | ||
513 | services << QExplicitlySharedDataPointer<KService>(new KService(processName, cmdLine, QString())); | 552 | services << QExplicitlySharedDataPointer<KService>(new KService(processName, cmdLine, QString())); | ||
514 | } | 553 | } | ||
515 | 554 | | |||
516 | return services; | 555 | return services; | ||
517 | } | 556 | } | ||
518 | 557 | | |||
519 | QString defaultApplication(const QUrl &url) | 558 | QString defaultApplication(const QUrl &url) | ||
▲ Show 20 Lines • Show All 225 Lines • Show Last 20 Lines |
Can be removed? If not, sort correctly.