diff --git a/libtaskmanager/launchertasksmodel.cpp b/libtaskmanager/launchertasksmodel.cpp --- a/libtaskmanager/launchertasksmodel.cpp +++ b/libtaskmanager/launchertasksmodel.cpp @@ -124,14 +124,17 @@ AppData LauncherTasksModel::Private::appData(const QUrl &url) { - if (!appDataCache.contains(url)) { - const AppData &data = appDataFromUrl(url, QIcon::fromTheme(QLatin1String("unknown"))); - appDataCache.insert(url, data); + const auto &it = appDataCache.constFind(url); - return data; + if (it != appDataCache.constEnd()) { + return *it; } - return appDataCache.value(url); + const AppData &data = appDataFromUrl(url, QIcon::fromTheme(QLatin1String("unknown"))); + + appDataCache.insert(url, data); + + return data; } bool LauncherTasksModel::Private::requestAddLauncherToActivities(const QUrl &_url, const QStringList &_activities) diff --git a/libtaskmanager/tasktools.h b/libtaskmanager/tasktools.h --- a/libtaskmanager/tasktools.h +++ b/libtaskmanager/tasktools.h @@ -65,6 +65,22 @@ TASKMANAGER_EXPORT AppData appDataFromUrl(const QUrl &url, const QIcon &fallbackIcon = QIcon()); /** + * Fills in and returns an AppData struct based on the given application + * id. + * + * Application ids are .desktop file names sans extension or an absolute + * path to a .desktop file. + * + * NOTE: Unlike appDataFromUrl(), this makes no attempt to procure icon + * data at this time. + * + * @see appDataFromUrl + * @param appId An application id. + * @returns @c AppData filled in based on the given application id. + */ +TASKMANAGER_EXPORT AppData appDataFromAppId(const QString &appId); + +/** * Returns an application id for an URL using the preferred:// scheme. * * Recognized values for the host component of the URL are: diff --git a/libtaskmanager/tasktools.cpp b/libtaskmanager/tasktools.cpp --- a/libtaskmanager/tasktools.cpp +++ b/libtaskmanager/tasktools.cpp @@ -116,6 +116,44 @@ return data; } +AppData appDataFromAppId(const QString &appId) +{ + AppData data; + + KService::Ptr service = KService::serviceByStorageId(appId); + + if (service) { + data.id = service->storageId(); + data.name = service->name(); + data.genericName = service->genericName(); + data.url = QUrl::fromLocalFile(service->entryPath()); + + return data; + } + + QString desktopFile = appId; + + if (!desktopFile.endsWith(QLatin1String(".desktop"))) { + desktopFile.append(QLatin1String(".desktop")); + } + + if (KDesktopFile::isDesktopFile(desktopFile) && QFile::exists(desktopFile)) { + KDesktopFile f(desktopFile); + + data.id = QUrl::fromLocalFile(f.fileName()).fileName(); + + if (data.id.endsWith(QLatin1String(".desktop"))) { + data.id = data.id.left(data.id.length() - 8); + } + + data.name = f.readName(); + data.genericName = f.readGenericName(); + data.url = QUrl::fromLocalFile(desktopFile); + } + + return data; +} + QString defaultApplication(const QUrl &url) { if (url.scheme() != QLatin1String("preferred")) { diff --git a/libtaskmanager/waylandtasksmodel.cpp b/libtaskmanager/waylandtasksmodel.cpp --- a/libtaskmanager/waylandtasksmodel.cpp +++ b/libtaskmanager/waylandtasksmodel.cpp @@ -45,11 +45,14 @@ public: Private(WaylandTasksModel *q); QList windows; - QHash serviceCache; + QHash appDataCache; KWayland::Client::PlasmaWindowManagement *windowManagement = nullptr; void initWayland(); void addWindow(KWayland::Client::PlasmaWindow *window); + + AppData appData(KWayland::Client::PlasmaWindow *window); + void dataChanged(KWayland::Client::PlasmaWindow *window, int role); void dataChanged(KWayland::Client::PlasmaWindow *window, const QVector &roles); @@ -116,20 +119,14 @@ windows.append(window); - KService::Ptr service = KService::serviceByStorageId(window->appId()); - - if (service) { - serviceCache.insert(window, service); - } - q->endInsertRows(); auto removeWindow = [window, this] { const int row = windows.indexOf(window); if (row != -1) { q->beginRemoveRows(QModelIndex(), row, row); windows.removeAt(row); - serviceCache.remove(window); + appDataCache.remove(window); q->endRemoveRows(); } }; @@ -147,13 +144,7 @@ QObject::connect(window, &KWayland::Client::PlasmaWindow::appIdChanged, q, [window, this] { - KService::Ptr service = KService::serviceByStorageId(window->appId()); - - if (service) { - serviceCache.insert(window, service); - } else { - serviceCache.remove(window); - } + appDataCache.remove(window); dataChanged(window, QVector{AppId, AppName, GenericName, LauncherUrl, LauncherUrlWithoutIcon}); @@ -237,6 +228,21 @@ ); } +AppData WaylandTasksModel::Private::appData(KWayland::Client::PlasmaWindow *window) +{ + const auto &it = appDataCache.constFind(window); + + if (it != appDataCache.constEnd()) { + return *it; + } + + const AppData &data = appDataFromAppId(window->appId()); + + appDataCache.insert(window, data); + + return data; +} + void WaylandTasksModel::Private::dataChanged(KWayland::Client::PlasmaWindow *window, int role) { QModelIndex idx = q->index(windows.indexOf(window)); @@ -273,19 +279,11 @@ } else if (role == AppId) { return window->appId(); } else if (role == AppName) { - if (d->serviceCache.contains(window)) { - return d->serviceCache.value(window)->name(); - } else { - return window->title(); - } + return d->appData(window).name; } else if (role == GenericName) { - if (d->serviceCache.contains(window)) { - return d->serviceCache.value(window)->genericName(); - } + return d->appData(window).genericName; } else if (role == LauncherUrl || role == LauncherUrlWithoutIcon) { - if (d->serviceCache.contains(window)) { - return QUrl::fromLocalFile(d->serviceCache.value(window)->entryPath()); - } + return d->appData(window).url; } else if (role == IsWindow) { return true; } else if (role == IsActive) { @@ -368,13 +366,15 @@ KWayland::Client::PlasmaWindow* window = d->windows.at(index.row()); - if (d->serviceCache.contains(window)) { - const KService::Ptr service = d->serviceCache.value(window); + if (d->appDataCache.contains(window)) { + const AppData &data = d->appData(window); - new KRun(QUrl::fromLocalFile(service->entryPath()), 0, false); + new KRun(data.url, 0, false); - KActivities::ResourceInstance::notifyAccessed(QUrl("applications:" + service->storageId()), - "org.kde.libtaskmanager"); + if (!data.id.isEmpty()) { + KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + data.id), + QStringLiteral("org.kde.libtaskmanager")); + } } } @@ -386,15 +386,14 @@ return; } - KWayland::Client::PlasmaWindow *window = d->windows.at(index.row()); - - if (d->serviceCache.contains(window)) { - const KService::Ptr service = d->serviceCache.value(window); + const QUrl &url = d->appData(d->windows.at(index.row())).url; + const KService::Ptr service = KService::serviceByDesktopPath(url.toLocalFile()); + if (service) { KRun::runApplication(*service, urls, nullptr, 0); - KActivities::ResourceInstance::notifyAccessed(QUrl("applications:" + service->storageId()), - "org.kde.libtaskmanager"); + KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + service->storageId()), + QStringLiteral("org.kde.libtaskmanager")); } } diff --git a/libtaskmanager/xwindowtasksmodel.cpp b/libtaskmanager/xwindowtasksmodel.cpp --- a/libtaskmanager/xwindowtasksmodel.cpp +++ b/libtaskmanager/xwindowtasksmodel.cpp @@ -22,6 +22,7 @@ #include "xwindowtasksmodel.h" #include "tasktools.h" +#include #include #include #include @@ -414,41 +415,45 @@ KWindowInfo* XWindowTasksModel::Private::windowInfo(WId window) { - if (!windowInfoCache.contains(window)) { - KWindowInfo *info = new KWindowInfo(window, windowInfoFlags, windowInfoFlags2); - windowInfoCache.insert(window, info); + const auto &it = windowInfoCache.constFind(window); - return info; + if (it != windowInfoCache.constEnd()) { + return *it; } - return windowInfoCache.value(window); + KWindowInfo *info = new KWindowInfo(window, windowInfoFlags, windowInfoFlags2); + windowInfoCache.insert(window, info); + + return info; } AppData XWindowTasksModel::Private::appData(WId window) { - if (!appDataCache.contains(window)) { - const AppData &data = appDataFromUrl(windowUrl(window)); + const auto &it = appDataCache.constFind(window); - // If we weren't able to derive a launcher URL from the window meta data, - // fall back to WM_CLASS Class string as app id. This helps with apps we - // can't map to an URL due to existing outside the regular system - // environment, e.g. wine clients. - if (data.id.isEmpty() && data.url.isEmpty()) { - AppData dataCopy = data; + if (it != appDataCache.constEnd()) { + return *it; + } - dataCopy.id = windowInfo(window)->windowClassClass(); + const AppData &data = appDataFromUrl(windowUrl(window)); - appDataCache.insert(window, dataCopy); + // If we weren't able to derive a launcher URL from the window meta data, + // fall back to WM_CLASS Class string as app id. This helps with apps we + // can't map to an URL due to existing outside the regular system + // environment, e.g. wine clients. + if (data.id.isEmpty() && data.url.isEmpty()) { + AppData dataCopy = data; - return dataCopy; - } + dataCopy.id = windowInfo(window)->windowClassClass(); - appDataCache.insert(window, data); + appDataCache.insert(window, dataCopy); - return data; + return dataCopy; } - return appDataCache.value(window); + appDataCache.insert(window, data); + + return data; } QIcon XWindowTasksModel::Private::icon(WId window) @@ -970,10 +975,15 @@ return; } - const QUrl &url = d->appData(d->windows.at(index.row())).url; + const AppData &data = d->appData(d->windows.at(index.row())); - if (url.isValid()) { - new KRun(url, 0, false, KStartupInfo::createNewStartupIdForTimestamp(QX11Info::appUserTime())); + if (data.url.isValid()) { + new KRun(data.url, 0, false, KStartupInfo::createNewStartupIdForTimestamp(QX11Info::appUserTime())); + + if (!data.id.isEmpty()) { + KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + data.id), + QStringLiteral("org.kde.libtaskmanager")); + } } } @@ -987,8 +997,12 @@ const QUrl &url = d->appData(d->windows.at(index.row())).url; const KService::Ptr service = KService::serviceByDesktopPath(url.toLocalFile()); + if (service) { KRun::runApplication(*service, urls, nullptr, 0, {}, KStartupInfo::createNewStartupIdForTimestamp(QX11Info::appUserTime())); + + KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + service->storageId()), + QStringLiteral("org.kde.libtaskmanager")); } }