Verified Commit 4a1be932 authored by Alexander Lohnau's avatar Alexander Lohnau 💬
Browse files

Implement Activities Runner as DBus Runner

This MR implements the activities runner using the DBus API.
The runner allows one to view and switch to other activities.

Because the data is already available in the kactivitymanagerd
process it makes very little sense to have a KRunner plugin which
fetches this data and produces the results when we can provide this
functionality in the actual running process.

See https://phabricator.kde.org/T12031 for more discussion
about the topic in general.
parent e53f5dd6
......@@ -8,3 +8,4 @@ add_subdirectory (globalshortcuts)
add_subdirectory (eventspy)
add_subdirectory (gtk-eventspy)
add_subdirectory (runapplication)
add_subdirectory (krunner)
/*
* SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
* SPDX-FileCopyrightText: 2011 Aaron Seigo <aseigo@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "ActivityRunner.h"
#include <Activities.h>
#include <KLocalizedString>
#include <krunner1adaptor.h>
KAMD_EXPORT_PLUGIN(activityrunner, ActivityRunner, "kactivitymanagerd-plugin-activityrunner.json")
ActivityRunner::ActivityRunner(QObject *parent, const QVariantList &args)
: Plugin(parent)
, m_activitiesService(nullptr)
, m_keywordi18n(i18nc("KRunner keyword", "activity"))
, m_keyword(QStringLiteral("activity"))
{
Q_UNUSED(args)
setName(QStringLiteral("org.kde.ActivityManager.ActivityRunner"));
new Krunner1Adaptor(this);
qDBusRegisterMetaType<RemoteMatch>();
qDBusRegisterMetaType<RemoteMatches>();
qDBusRegisterMetaType<RemoteAction>();
qDBusRegisterMetaType<RemoteActions>();
QDBusConnection::sessionBus().registerObject(QStringLiteral("/runner"), this);
QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.runners.activities"));
}
ActivityRunner::~ActivityRunner() = default;
bool ActivityRunner::init(QHash<QString, QObject *> &modules)
{
Plugin::init(modules);
m_activitiesService = modules[QStringLiteral("activities")];
return true;
}
RemoteMatches ActivityRunner::Match(const QString &query)
{
Q_ASSERT(m_activitiesService);
const auto currentActivity = Plugin::retrieve<QString>(m_activitiesService, "CurrentActivity", "QString");
auto activities = Plugin::retrieve<ActivityInfoList>(m_activitiesService, "ListActivitiesWithInformation", "ActivityInfoList");
const QString term = query.trimmed();
bool list = false;
QString name;
if (term == m_keyword || term == m_keywordi18n) {
list = true;
} else if (term.startsWith(m_keyword, Qt::CaseInsensitive)) {
name = term.right(term.size() - m_keyword.size()).trimmed();
} else if (term.startsWith(m_keywordi18n, Qt::CaseInsensitive)) {
name = term.right(term.size() - m_keywordi18n.size()).trimmed();
} else {
return {};
}
QList<RemoteMatch> matches;
for (const ActivityInfo &activityInfo : qAsConst(activities)) {
if (currentActivity != activityInfo.id) {
auto info = Plugin::retrieve<ActivityInfo>(m_activitiesService, "ActivityInformation", "ActivityInfo", Q_ARG(QString, activityInfo.id));
if (list || info.name.startsWith(name, Qt::CaseInsensitive)) {
RemoteMatch m;
m.id = activityInfo.id;
m.text = i18n("Switch to \"%1\"", info.name);
m.iconName = info.icon;
m.type = Type::ExactMatch;
m.relevance = 0.7 + ((activityInfo.state == Activities::State::Running || activityInfo.state == Activities::State::Starting) ? 0.1 : 0);
matches.append(m);
}
}
}
return matches;
}
RemoteActions ActivityRunner::Actions()
{
return {};
}
void ActivityRunner::Run(const QString &matchId, const QString &actionId)
{
Q_UNUSED(actionId)
QMetaObject::invokeMethod(m_activitiesService, "SetCurrentActivity", Q_ARG(QString, matchId));
}
#include "ActivityRunner.moc"
/*
* SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef PLUGINS_RUN_APPLICATION_PLUGIN_H
#define PLUGINS_RUN_APPLICATION_PLUGIN_H
#include <Plugin.h>
#include "dbusutils.h"
class ActivityRunner : public Plugin {
Q_OBJECT
public:
explicit ActivityRunner(QObject *parent = nullptr, const QVariantList &args = QVariantList());
~ActivityRunner() override;
bool init(QHash<QString, QObject *> &modules) override;
void Run(const QString &matchId, const QString &actionId);
RemoteMatches Match(const QString &query);
RemoteActions Actions();
private:
QObject *m_activitiesService;
const QString m_keywordi18n;
const QString m_keyword;
};
#endif // PLUGINS_RUN_APPLICATION_PLUGIN_H
# vim:set softtabstop=3 shiftwidth=3 tabstop=3 expandtab:
project (kactivitymanagerd-activityrunner)
set (
activityrunner_SRCS
ActivityRunner.cpp
${debug_SRCS}
${plugin_implementation_SRCS}
)
qt5_add_dbus_adaptor(activityrunner_SRCS "org.kde.krunner1.xml" ActivityRunner.h ActivityRunner)
kcoreaddons_add_plugin (
kactivitymanagerd_plugin_activityrunner
JSON kactivitymanagerd-plugin-activityrunner.json
SOURCES ${activityrunner_SRCS}
INSTALL_NAMESPACE ${KAMD_PLUGIN_DIR}
)
target_link_libraries (
kactivitymanagerd_plugin_activityrunner
Qt::Core
Qt::DBus
KF5::CoreAddons
KF5::I18n
kactivitymanagerd_plugin
)
set_target_properties (
kactivitymanagerd_plugin_activityrunner
PROPERTIES PREFIX ""
)
install(
FILES plasma-runnners-activities.desktop
DESTINATION "${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins"
)
/*
* SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QDBusArgument>
#include <QList>
#include <QString>
#include <QVariantMap>
enum Type {
NoMatch = 0,
CompletionMatch = 10,
PossibleMatch = 30,
InformationalMatch = 50,
HelperMatch = 70,
ExactMatch = 100,
};
struct RemoteMatch {
// sssuda{sv}
QString id;
QString text;
QString iconName;
Type type = NoMatch;
qreal relevance = 0;
QVariantMap properties;
};
typedef QList<RemoteMatch> RemoteMatches;
struct RemoteAction {
QString id;
QString text;
QString iconName;
};
typedef QList<RemoteAction> RemoteActions;
inline QDBusArgument &operator<<(QDBusArgument &argument, const RemoteMatch &match)
{
argument.beginStructure();
argument << match.id;
argument << match.text;
argument << match.iconName;
argument << match.type;
argument << match.relevance;
argument << match.properties;
argument.endStructure();
return argument;
}
inline const QDBusArgument &operator>>(const QDBusArgument &argument, RemoteMatch &match)
{
argument.beginStructure();
argument >> match.id;
argument >> match.text;
argument >> match.iconName;
uint type;
argument >> type;
match.type = (Type)type;
argument >> match.relevance;
argument >> match.properties;
argument.endStructure();
return argument;
}
inline QDBusArgument &operator<<(QDBusArgument &argument, const RemoteAction &action)
{
argument.beginStructure();
argument << action.id;
argument << action.text;
argument << action.iconName;
argument.endStructure();
return argument;
}
inline const QDBusArgument &operator>>(const QDBusArgument &argument, RemoteAction &action)
{
argument.beginStructure();
argument >> action.id;
argument >> action.text;
argument >> action.iconName;
argument.endStructure();
return argument;
}
Q_DECLARE_METATYPE(RemoteMatch)
Q_DECLARE_METATYPE(RemoteMatches)
Q_DECLARE_METATYPE(RemoteAction)
Q_DECLARE_METATYPE(RemoteActions)
{
"KPlugin": {
"Authors": [
{
"Email": "alexander.lohnau@gmx.de",
"Name": "Alexander Lohnau"
}
],
"Category": "",
"Dependencies": [],
"Description": "KRunner plugin to list and switch activities",
"EnabledByDefault": true,
"Icon": "preferences-system-windows",
"Id": "org.kde.ActivityManager.ActivityRunner",
"License": "GPL",
"Name": "Activity Runner",
"ServiceTypes": [
"ActivityManager/Plugin"
],
"Version": "1.0",
"Website": "https://invent.kde.org/plasma/kactivitymanagerd"
}
}
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.krunner1">
<!--
Returns a list of actions supported by this runner.
For example, a song match returned by a music player runner can be queued, added to the playlist, or played.
This should be constant
Structure is:
- ID
- Text
- IconName
-->
<method name="Actions">
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="RemoteActions" />
<arg name="matches" type="a(sss)" direction="out">
</arg>
</method>
<!--
Execute an action
-->
<method name="Run">
<!--
The Unique ID from Match.
-->
<arg name="matchId" type="s" direction="in"/>
<!--
The action ID to run. For the default action this will be empty.
-->
<arg name="actionId" type="s" direction="in"/>
</method>
<!--
Fetch matching results for a given query.
Note: Multiple Match calls may be made with new queries before a call has returned
has returned.
-->
<method name="Match">
<arg name="query" type="s" direction="in"/>
<!--
Return a list of items that match the
Structure is:
- Id
- Text
- IconName
- Type (see PlasmaQuery::Type)
- Relevance
- Properties (VariantMap)
-->
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="RemoteMatches"/>
<arg name="matches" type="a(sssuda{sv})" direction="out"/>
</method>
</interface>
</node>
[Desktop Entry]
Name=Activities
Name[ar]=الأنشطة
Name[ast]=Actividaes
Name[az]=İş Otaqları
Name[bg]=Дейности
Name[bs]=Motor aktivnosti
Name[ca]=Activitats
Name[ca@valencia]=Activitats
Name[cs]=Aktivity
Name[da]=Aktiviteter
Name[de]=Aktivitäten
Name[el]=Δραστηριότητες
Name[en_GB]=Activities
Name[es]=Actividades
Name[et]=Tegevused
Name[eu]=Jarduerak
Name[fa]=فعالیتها
Name[fi]=Aktiviteetit
Name[fr]=Activités
Name[ga]=Gníomhaíochtaí
Name[gl]=Actividades
Name[he]=פעילויות
Name[hr]=Aktivnosti
Name[hu]=Aktivitások
Name[ia]=Activitates
Name[id]=Activities
Name[is]=Virknistjóri
Name[it]=Attività
Name[ja]=アクティビティ
Name[kk]=Белсенділіктер
Name[km]=សកម្មភាព
Name[ko]=활동
Name[lt]=Veiklos
Name[lv]=Aktivitātes
Name[mr]=कार्यपध्दती
Name[nb]=Aktiviteter
Name[nds]=Aktiviteten
Name[nl]=Activiteiten
Name[nn]=Aktivitetar
Name[pa]=ਸਰਗਰਮੀਆਂ
Name[pl]=Aktywności
Name[pt]=Actividades
Name[pt_BR]=Atividades
Name[ro]=Activități
Name[ru]=Комнаты
Name[sk]=Aktivity
Name[sl]=Dejavnosti
Name[sr]=активности
Name[sr@ijekavian]=активности
Name[sr@ijekavianlatin]=aktivnosti
Name[sr@latin]=aktivnosti
Name[sv]=Aktiviteter
Name[tg]=Фаъолиятҳо
Name[tr]=Etkinlikler
Name[ug]=پائالىيەتلەر
Name[uk]=Простори дій
Name[vi]=Hoạt động
Name[wa]=Activités
Name[x-test]=xxActivitiesxx
Name[zh_CN]=活动
Name[zh_TW]=活動
Comment=List and switch between desktop activities
Comment[ar]=اسرد أنشطة سطح المكتب وبدّل بينها
Comment[az]=İş Masasına aid İş Otaqlarının siyahısı və onlar arasında keçid
Comment[bg]=Списък и превключване между дейностите
Comment[bs]=Prikaz i prebacivanje između aktivnosti radne površine
Comment[ca]=Llista i commuta entre les activitats d'escriptori
Comment[ca@valencia]=Llista i commuta entre activitats d'escriptori
Comment[cs]=Zobrazení a přepínač aktivit pracovní plochy
Comment[da]=Vis og skift mellem skrivebordsaktiviteter
Comment[de]=Aktivitäten anzeigen und zwischen ihnen umschalten
Comment[el]=Εμφάνιση και εναλλαγή μεταξύ των δραστηριοτήτων της επιφάνειας εργασίας
Comment[en_GB]=List and switch between desktop activities
Comment[es]=Ver y cambiar entre las actividades de escritorio
Comment[et]=Töölauategevuste näitamine ja nende vahel lülitamine
Comment[eu]=Zerrendatu mahaigaineko jarduerak eta batetik bestera aldatu
Comment[fi]=Luettele aktiviteetit ja vaihda niiden välillä
Comment[fr]=Affiche les activités du bureau et permet d'en changer
Comment[gl]=Lista e cambia entre actividades o escritorio
Comment[he]=הצגה והחלפה בין פעילויות שולחן עבודה
Comment[hr]=Izlistaj i prebacuj između aktivnosti radne površine
Comment[hu]=Asztali aktivitások listázása és váltás közöttük
Comment[ia]=Lista e commuta inter activitates de scriptorio
Comment[id]=Daftar dan beralih antara aktivitas desktop
Comment[is]=Telur upp og skiptir milli skjáborðsvirkni
Comment[it]=Elenca e passa tra le attività del desktop
Comment[ja]=デスクトップアクティビティを一覧表示して切り替える
Comment[kk]=Белсенділіктерді тізімдеу және ауыстыру
Comment[km]=មើល ហើយ​ប្ដូរ​ប្លង់​ផ្ទៃតុ​សកម្ម​
Comment[ko]=데스크톱 활동을 보거나 바꾸기
Comment[lt]=Išvardyti ir perjungti tarp darbalaukio veiklų
Comment[lv]=Parādīt un pārslēgties starp virtuālajām darbvirsmām
Comment[mr]=वेगळ्या डेस्कटॉप कार्यपध्दतीवर जाण्यासाठी यादी दर्शवा व बदला
Comment[nb]=Vis og bytt mellom skrivebordsaktiviteter
Comment[nds]=Aktiv Schriefdischakschonen ankieken un wesseln
Comment[nl]=Bureaubladactiviteiten laten zien en er tussen schakelen
Comment[nn]=Vis og byt mellom skrivebordsaktiviteter
Comment[pa]=ਡੈਸਕਟਾਪ ਸਰਗਰਮੀਆਂ ਵੇਖੋ ਅਤੇ ਉਹਨਾਂ ਵਿੱਚ ਜਾਓ
Comment[pl]=Wypisuje aktywności pulpitu oraz przełącza pomiędzy nimi
Comment[pt]=Ver e mudar de actividades no ambiente de trabalho
Comment[pt_BR]=Lista e alterna entre as atividades da área de trabalho
Comment[ro]=Vizualizează și schimbă între activitățile biroului
Comment[ru]=Просмотр и переключение между комнатами
Comment[sk]=Vypísať a prepínať medzi aktivitami pracovnej plochy
Comment[sl]=Oglejte si namizne dejavnosti in preklopite med njimi
Comment[sr]=Приказ и пребацивање између активности површи
Comment[sr@ijekavian]=Приказ и пребацивање између активности површи
Comment[sr@ijekavianlatin]=Prikaz i prebacivanje između aktivnosti površi
Comment[sr@latin]=Prikaz i prebacivanje između aktivnosti površi
Comment[sv]=Visa och byt mellan skrivbordsaktiviteter
Comment[tr]=Listele ve masaüstü eylemleri arasında değiştir
Comment[ug]=ئۈستەلئۈستى پائالىيەتلىرى ئارىسىدىكى تىزىم ۋە ئالماشتۇرۇش
Comment[uk]=Перегляд і перемикання між просторами дій стільниці
Comment[vi]=Liệt kê và chuyển giữa các Hoạt động ở bàn làm việc
Comment[wa]=Fé l' djivêye eyet passer d' ene activité do scribanne a ene ôte
Comment[x-test]=xxList and switch between desktop activitiesxx
Comment[zh_CN]=显示和切换桌面活动
Comment[zh_TW]=列出並在桌面活動間切換
X-KDE-ServiceTypes=Plasma/Runner
Type=Service
Icon=preferences-desktop-activities
X-KDE-PluginInfo-Author=Plasma Team
X-KDE-PluginInfo-Email=plasma-devel@kde.org
X-KDE-PluginInfo-Name=org.kde.activities2
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-License=LGPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-AdvertiseSingleRunnerQueryMode=true
X-Plasma-API=DBus
X-Plasma-DBusRunner-Service=org.kde.runners.activities
X-Plasma-DBusRunner-Path=/runner
X-Plasma-Request-Actions-Once=true
X-Plasma-Runner-Min-Letter-Count=3
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment