Commit cf4335ca authored by Benjamin Port's avatar Benjamin Port Committed by Benjamin Port

Add windows runner

Move windows runner from plasma-workspace to kwin (convert it to dbus runner)

This will allow to interract with windows on wayland too
parent 648dab44
......@@ -111,6 +111,13 @@ set_package_properties(KF5DocTools PROPERTIES
)
add_feature_info("KF5DocTools" KF5DocTools_FOUND "Enable building documentation")
find_package(KF5Runner ${KF5_MIN_VERSION} CONFIG)
set_package_properties(KF5Runner PROPERTIES
PURPOSE "Enable building of KWin with krunner support"
TYPE OPTIONAL
)
add_feature_info("KF5Runner" KF5Runner_FOUND "Enable building of KWin with krunner support")
find_package(KF5Kirigami2 ${KF5_MIN_VERSION} CONFIG)
set_package_properties(KF5Kirigami2 PROPERTIES
DESCRIPTION "A QtQuick based components set"
......@@ -336,6 +343,7 @@ option(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON)
option(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON)
option(KWIN_BUILD_XRENDER_COMPOSITING "Enable building of KWin with XRender Compositing support" ON)
cmake_dependent_option(KWIN_BUILD_ACTIVITIES "Enable building of KWin with kactivities support" ON "KF5Activities_FOUND" OFF)
cmake_dependent_option(KWIN_BUILD_RUNNERS "Enable building of KWin with krunner support" ON "KF5Runner_FOUND" OFF)
# Binary name of KWin
set(KWIN_NAME "kwin")
......@@ -590,6 +598,12 @@ if (KWIN_BUILD_ACTIVITIES)
)
endif()
if (KWIN_BUILD_RUNNERS)
set(kwin_SRCS ${kwin_SRCS}
runners/windowsrunnerinterface.cpp
)
endif()
if (HAVE_LINUX_VT_H)
set(kwin_SRCS ${kwin_SRCS}
virtual_terminal.cpp
......@@ -619,6 +633,9 @@ qt5_add_dbus_adaptor(kwin_SRCS org.kde.kwin.ColorCorrect.xml colorcorrection/col
qt5_add_dbus_adaptor(kwin_SRCS ${kwin_effects_dbus_xml} effects.h KWin::EffectsHandlerImpl)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.KWin.VirtualDesktopManager.xml dbusinterface.h KWin::VirtualDesktopManagerDBusInterface)
qt5_add_dbus_adaptor(kwin_SRCS org.kde.KWin.Session.xml sm.h KWin::SessionManager)
if (KWIN_BUILD_RUNNERS)
qt5_add_dbus_adaptor(kwin_SRCS "runners/org.kde.krunner1.xml" runners/windowsrunnerinterface.h KWin::WindowsRunner)
endif()
qt5_add_dbus_interface(kwin_SRCS ${KSCREENLOCKER_DBUS_INTERFACES_DIR}/kf5_org.freedesktop.ScreenSaver.xml screenlocker_interface)
qt5_add_dbus_interface(kwin_SRCS ${KSCREENLOCKER_DBUS_INTERFACES_DIR}/org.kde.screensaver.xml kscreenlocker_interface)
......@@ -695,6 +712,10 @@ if (KWIN_BUILD_ACTIVITIES)
set(kwin_KDE_LIBS ${kwin_KDE_LIBS} KF5::Activities)
endif()
if (KWIN_BUILD_RUNNERS)
set(kwin_KDE_LIBS ${kwin_KDE_LIBS} KF5::Runner)
endif()
set(kwinLibs
${kwin_OWN_LIBS}
${kwin_QT_LIBS}
......@@ -826,6 +847,11 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kwin_export.h DESTINATION ${INCLUDE_IN
# Install the KWin/Script service type
install(FILES scripting/kwinscript.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR})
# install KWin krunner runner
if (KWIN_BUILD_RUNNERS)
install(FILES runners/kwin-runner-windows.desktop DESTINATION ${KDE_INSTALL_DATAROOTDIR}/krunner/dbusplugins)
endif()
add_subdirectory(qml)
if (BUILD_TESTING)
......
#! /usr/bin/env bash
$EXTRACTRC *.kcfg *.ui >> rc.cpp
$XGETTEXT *.h *.cpp colorcorrection/*.cpp helpers/killer/*.cpp plugins/scenes/opengl/*.cpp tabbox/*.cpp scripting/*.cpp -o $podir/kwin.pot
$XGETTEXT *.h *.cpp colorcorrection/*.cpp helpers/killer/*.cpp plugins/scenes/opengl/*.cpp tabbox/*.cpp scripting/*.cpp runners/*.cpp -o $podir/kwin.pot
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2017 David Edmundson <kde@davidedmundson.co.uk>
SPDX-FileCopyrightText: 2018 Laurent Montel <montel@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QList>
#include <QString>
#include <QDBusArgument>
#include <QVariantMap>
#include <KRunner/QueryMatch>
struct RemoteMatch
{
//sssuda{sv}
QString id;
QString text;
QString iconName;
Plasma::QueryMatch::Type type = Plasma::QueryMatch::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 = (Plasma::QueryMatch::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)
[Desktop Entry]
# ctxt: plasma runner
Name=Windows
Name[ar]=النوافذ
Name[ast]=Ventanes
Name[az]=Pəncərələr
Name[bg]=Прозорци
Name[bn]=উইণ্ডো
Name[bs]=Prozori
Name[ca]=Finestres
Name[ca@valencia]=Finestres
Name[cs]=Okna
Name[csb]=Òkna
Name[da]=Vinduer
Name[de]=Fenster
Name[el]=Παράθυρα
Name[en_GB]=Windows
Name[eo]=Fenestroj
Name[es]=Ventanas
Name[et]=Aknad
Name[eu]=Leihoak
Name[fa]=پنجره‌ها
Name[fi]=Ikkunat
Name[fr]=Fenêtres
Name[fy]=Finsters
Name[ga]=Fuinneoga
Name[gl]=Xanelas
Name[gu]=વિન્ડોઝ
Name[he]=חלונות
Name[hi]=विंडोज़
Name[hr]=Prozori
Name[hu]=Ablakok
Name[ia]=Fenestras
Name[id]=Windows
Name[is]=Gluggar
Name[it]=Finestre
Name[ja]=ウィンドウ
Name[kk]=Терезелер
Name[km]=បង្អួច
Name[kn]=ಕಿಟಕಿಗಳು
Name[ko]=창
Name[lt]=Langai
Name[lv]=Logi
Name[mk]=Прозорци
Name[ml]=ജാലകങ്ങള്‍
Name[mr]=चौकटी
Name[nb]=Vinduer
Name[nds]=Finstern
Name[nl]=Vensters
Name[nn]=Vindauge
Name[pa]=ਵਿੰਡੋਆਂ
Name[pl]=Okna
Name[pt]=Janelas
Name[pt_BR]=Janelas
Name[ro]=Ferestre
Name[ru]=Окна
Name[si]=කවුළු
Name[sk]=Okná
Name[sl]=Okna
Name[sr]=прозори
Name[sr@ijekavian]=прозори
Name[sr@ijekavianlatin]=prozori
Name[sr@latin]=prozori
Name[sv]=Fönster
Name[th]=หน้าต่างต่าง ๆ
Name[tr]=Pencereler
Name[ug]=كۆزنەكلەر
Name[uk]=Вікна
Name[wa]=Finiesses
Name[x-test]=xxWindowsxx
Name[zh_CN]=窗口
Name[zh_TW]=視窗
Comment=List windows and desktops and switch them
Comment[ar]=اسرد النوافذ وأسطح المكتب وبدّل بينها
Comment[az]=Pəncərələrin, İş Masalarının siyahısı və onlar arası keçid
Comment[bg]=Показване и превключване на прозорци и работни плотове
Comment[bs]=Nabrajanje i prebacivanje između prozora i površî
Comment[ca]=Llista finestres i escriptoris, i canvia entre ells
Comment[ca@valencia]=Llista finestres i escriptoris i canvia entre ells
Comment[cs]=Seznam oken a ploch k přepínání
Comment[da]=Oplist vinduer og skriveborde og skift mellem dem
Comment[de]=Listet Fenster und Arbeitsflächen auf und wechselt zwischen ihnen.
Comment[el]=Εμφάνιση λίστας παραθύρων και επιφανειών εργασίας για εναλλαγή
Comment[en_GB]=List windows and desktops and switch them
Comment[eo]=Listi fenestrojn kaj labortablojn kaj ŝanĝi ilin
Comment[es]=Lista ventanas y escritorios y cambia entre ellos
Comment[et]=Akende ja töölauade näitamine võimalusega neile lülituda
Comment[eu]=Zerrendatu leihoak eta mahaigainak, eta batetik bestera aldatu
Comment[fi]=Luettele ikkunat ja työpöydät ja vaihda niitä
Comment[fr]=Liste les fenêtres / bureaux et passe de l'un à l'autre
Comment[fy]=Sommet finsters en buroblêden en wikselt har
Comment[ga]=Taispeáin fuinneoga agus deasca agus athraigh eatarthu
Comment[gl]=Lista as xanelas e escritorio e salta entre eles
Comment[he]=משמש להצגת חלונות ושולחנות עבודה ולהחלפה ביניהם
Comment[hr]=Popis prozora i radnih površina za laku promjenu među njima
Comment[hu]=Kilistázza az ablakokat és asztalokat, és vált rájuk
Comment[ia]=Lista fenestras e scriptorios e commuta los
Comment[id]=Daftar window dan desktop dan alihkan mereka
Comment[is]=Telur upp glugga og skjáborð og skiptir á milli þeirra
Comment[it]=Elenca e passa tra le finestre ed i desktop
Comment[ja]=ウィンドウとデスクトップの一覧表示と切り替えを行います
Comment[kk]=Бар терезе мен үстелдерді ұсынып оларға ауысу
Comment[km]=រាយ​​បង្អួច និង​ផ្ទៃតុ​ ហើយ​ប្ដូរ​ពួកវា
Comment[kn]=ವಿಂಡೊ ಹಾಗು ಗಣಕತೆರೆಗಳನ್ನು ಪಟ್ಟಿಮಾಡು ಹಾಗು ಅವುಗಳನ್ನು ಬದಲಾಯಿಸು
Comment[ko]=창 및 바탕 화면 목록을 보여 주고 전환합니다
Comment[lt]=Išvardyti langus ir darbalaukius bei perjungti į juos
Comment[lv]=Parāda logus un darbvirsmas un pārslēdz tos
Comment[mk]=Приказ на прозорци и раб. површини и преминување меѓу нив
Comment[ml]=ജാലകങ്ങളും പണിയിടങ്ങളും പട്ടികയായി കണ്ടു് പരസ്പരം മാറുക
Comment[mr]=वेगळ्या चौकट व डेस्कटॉप वर जाण्यासाठी यादी दर्शवा व बदला
Comment[nb]=List vinduer og skrivebord og bytt mellom dem
Comment[nds]=Finstern un Schriefdischen oplisten un wesseln
Comment[nl]=Toon vensters en bureaubladen en schakel ze om
Comment[nn]=Vis vindauge og skrivebord, og byt mellom dei
Comment[pa]=ਵਿੰਡੋ ਅਤੇ ਡੈਸਕਟਾਪ ਦੀ ਲਿਸਟ ਅਤੇ ਉਹਨਾਂ ਵਿੱਚ ਬਦਲੋ
Comment[pl]=Wypisuje okna i pulpity oraz przełącza pomiędzy nimi
Comment[pt]=Listar as janelas e ecrãs e mudar entre eles
Comment[pt_BR]=Lista as janelas e áreas de trabalho e alterna entre elas
Comment[ro]=Enumeră ferestre și birouri și le comută
Comment[ru]=Список окон и рабочих столов с возможностью переключения между ними
Comment[si]=කවුළු හා වැඩතල ලැයිස්තුගත කර ඒවා මාරුකරන්න
Comment[sk]=Zoznam okien a plôch a ich prepínanie
Comment[sl]=Seznam oken in namizij ter preklop med njimi
Comment[sr]=Набрајање и пребацивање између прозора и површи̂
Comment[sr@ijekavian]=Набрајање и пребацивање између прозора и површи̂
Comment[sr@ijekavianlatin]=Nabrajanje i prebacivanje između prozora i površî
Comment[sr@latin]=Nabrajanje i prebacivanje između prozora i površî
Comment[sv]=Lista fönster och skrivbord, och byt mellan dem
Comment[th]=รายการหน้าต่างและพื้นที่ทำงานต่าง ๆ ที่สามารถสลับไปใช้งานได้
Comment[tr]=Pencereleri ve masaüstlerini listele ve seç
Comment[ug]=ھەممە كۆزنەكلەر ۋە ئۈستەلئۈستى تىزىمىنى كۆرسىتىپ، ئۇلارنى ئالماشتۇرىدۇ
Comment[uk]=Показує список вікон і стільниць і перемикає їх
Comment[vi]=Liệt kê các cửa sổ, màn hình làm việc và chuyển đổi chúng
Comment[wa]=Fé l' djivêye des fniesses eyet des scribannes eyet passer d' n' onk a l' ôte
Comment[x-test]=xxList windows and desktops and switch themxx
Comment[zh_CN]=列出所有窗口和桌面,并可供切换
Comment[zh_TW]=列出視窗與桌面並切換
X-KDE-ServiceTypes=Plasma/Runner
Type=Service
Icon=preferences-system-windows
X-KDE-PluginInfo-Author=Martin Gräßlin
X-KDE-PluginInfo-Email=kde@martin-graesslin.com
X-KDE-PluginInfo-Name=windows
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-AdvertiseSingleRunnerQueryMode=true
X-Plasma-API=DBus
X-Plasma-DBusRunner-Service=org.kde.KWin
X-Plasma-DBusRunner-Path=/WindowsRunner
X-Plasma-Request-Actions-Once=true
X-Plasma-Runner-Min-Letter-Count=3
X-Plasma-Runner-Syntaxes=:q:,:q:,:q:,window,desktop
X-Plasma-Runner-Syntax-Descriptions=Finds windows whose name or window application match :q:. It is possible to interact with the windows by using one of the following keywords: activate\\, close\\, min(imize)\\, max(imize)\\, fullscreen\\, shade\\, keep above and keep below.,Finds windows which are on desktop named :q:,Switch to desktop named :q:,Lists all windows and allows to activate them.,Lists all other desktops and allows to switch to them.
<!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>
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2009 Martin Gräßlin <kde@martin-graesslin.com>
SPDX-FileCopyrightText: 2020 Benjamin Port <benjamin.port@enioka.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "windowsrunnerinterface.h"
#include "abstract_client.h"
#include "workspace.h"
#include "krunner1adaptor.h"
#include <KLocalizedString>
namespace KWin
{
WindowsRunner::WindowsRunner(QObject *parent)
: QObject(parent)
{
new Krunner1Adaptor(this);
qDBusRegisterMetaType<RemoteMatch>();
qDBusRegisterMetaType<RemoteMatches>();
qDBusRegisterMetaType<RemoteAction>();
qDBusRegisterMetaType<RemoteActions>();
QDBusConnection::sessionBus().registerObject(QStringLiteral("/WindowsRunner"), this);
QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.KWin"));
}
WindowsRunner::~WindowsRunner()
{
}
RemoteActions WindowsRunner::Actions()
{
RemoteActions actions;
return actions;
}
RemoteMatches WindowsRunner::Match(const QString &searchTerm)
{
RemoteMatches matches;
auto term = searchTerm;
WindowsRunnerAction action = ActivateAction;
if (term.endsWith(i18nc("Note this is a KRunner keyword", "activate") , Qt::CaseInsensitive)) {
action = ActivateAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "activate")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "close") , Qt::CaseInsensitive)) {
action = CloseAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "close")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "min") , Qt::CaseInsensitive)) {
action = MinimizeAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "min")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "minimize") , Qt::CaseInsensitive)) {
action = MinimizeAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "minimize")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "max") , Qt::CaseInsensitive)) {
action = MaximizeAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "max")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "maximize") , Qt::CaseInsensitive)) {
action = MaximizeAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "maximize")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "fullscreen") , Qt::CaseInsensitive)) {
action = FullscreenAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "fullscreen")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "shade") , Qt::CaseInsensitive)) {
action = ShadeAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "shade")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "keep above") , Qt::CaseInsensitive)) {
action = KeepAboveAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "keep above")) - 1);
} else if (term.endsWith(i18nc("Note this is a KRunner keyword", "keep below") , Qt::CaseInsensitive)) {
action = KeepBelowAction;
term = term.left(term.lastIndexOf(i18nc("Note this is a KRunner keyword", "keep below")) - 1);
}
// keyword match: when term starts with "window" we list all windows
// the list can be restricted to windows matching a given name, class, role or desktop
if (term.startsWith(i18nc("Note this is a KRunner keyword", "window") , Qt::CaseInsensitive)) {
const QStringList keywords = term.split(QLatin1Char(' '));
QString windowName;
QString windowAppName;
VirtualDesktop *targetDesktop = nullptr;
QVariant desktopId;
for (const QString& keyword : keywords) {
if (keyword.endsWith(QLatin1Char('='))) {
continue;
}
if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "name") + QStringLiteral("=") , Qt::CaseInsensitive)) {
windowName = keyword.split(QStringLiteral("="))[1];
} else if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "appname") + QStringLiteral("=") , Qt::CaseInsensitive)) {
windowAppName = keyword.split(QStringLiteral("="))[1];
} else if (keyword.startsWith(i18nc("Note this is a KRunner keyword", "desktop") + QStringLiteral("=") , Qt::CaseInsensitive)) {
desktopId = keyword.split(QStringLiteral("="))[1];
for (const auto desktop : VirtualDesktopManager::self()->desktops()) {
if (desktop->name().contains(desktopId.toString(), Qt::CaseInsensitive) || desktop->x11DesktopNumber() == desktopId.toUInt()) {
targetDesktop = desktop;
}
}
} else {
// not a keyword - use as name if name is unused, but another option is set
if (windowName.isEmpty() && !keyword.contains(QLatin1Char('=')) && (!windowAppName.isEmpty() || targetDesktop)) {
windowName = keyword;
}
}
}
for (const AbstractClient *client : Workspace::self()->allClientList()) {
if (!client->isNormalWindow()) {
continue;
}
const QString appName = client->resourceClass();
const QString name = client->caption();
if (!windowName.isEmpty() && !name.startsWith(windowName, Qt::CaseInsensitive)) {
continue;
}
if (!windowAppName.isEmpty() && !appName.contains(windowAppName, Qt::CaseInsensitive)) {
continue;
}
if (targetDesktop && !client->desktops().contains(targetDesktop) && !client->isOnAllDesktops()) {
continue;
}
// check for windows when no keywords were used
// check the name and app name for containing the query without the keyword
if (windowName.isEmpty() && windowAppName.isEmpty() && !targetDesktop) {
const QString& test = term.mid(keywords[0].length() + 1);
if (!name.contains(test, Qt::CaseInsensitive) && !appName.contains(test, Qt::CaseInsensitive)) {
continue;
}
}
// blacklisted everything else: we have a match
if (actionSupported(client, action)){
matches << windowsMatch(client, action);
}
}
if (!matches.isEmpty()) {
// the window keyword found matches - do not process other syntax possibilities
return matches;
}
}
bool desktopAdded = false;
// check for desktop keyword
if (term.startsWith(i18nc("Note this is a KRunner keyword", "desktop") , Qt::CaseInsensitive)) {
const QStringList parts = term.split(QLatin1Char(' '));
if (parts.size() == 1) {
// only keyword - list all desktops
for (auto desktop : VirtualDesktopManager::self()->desktops()) {
matches << desktopMatch(desktop);
desktopAdded = true;
}
}
}
// check for matching desktops by name
for (const AbstractClient *client : Workspace::self()->allClientList()) {
if (!client->isNormalWindow()) {
continue;
}
const QString appName = client->resourceClass();
const QString name = client->caption();
if (name.startsWith(term, Qt::CaseInsensitive) || appName.startsWith(term, Qt::CaseInsensitive)) {
matches << windowsMatch(client, action, 0.8, Plasma::QueryMatch::ExactMatch);
} else if ((name.contains(term, Qt::CaseInsensitive) || appName.contains(term, Qt::CaseInsensitive)) && actionSupported(client, action)) {
matches << windowsMatch(client, action, 0.7, Plasma::QueryMatch::PossibleMatch);
}
}
for (auto *desktop : VirtualDesktopManager::self()->desktops()) {
if (desktop->name().contains(term, Qt::CaseInsensitive)) {
if (!desktopAdded && desktop != VirtualDesktopManager::self()->currentDesktop()) {
matches << desktopMatch(desktop, ActivateDesktopAction, 0.8);
}
// search for windows on desktop and list them with less relevance
for (const AbstractClient *client : Workspace::self()->allClientList()) {
if (!client->isNormalWindow()) {
continue;
}
if ((client->desktops().contains(desktop) || client->isOnAllDesktops()) && actionSupported(client, action)) {
matches << windowsMatch(client, action, 0.5, Plasma::QueryMatch::PossibleMatch);
}
}
}
}
return matches;
}
void WindowsRunner::Run(const QString &id, const QString &actionId)
{
// Split id to get actionId and realId. We don't use actionId because our actions list is not constant
const QStringList parts = id.split(QLatin1Char('_'));
auto action = WindowsRunnerAction(parts[0].toInt());
auto objectId = parts[1];
if (action == ActivateDesktopAction) {
QByteArray desktopId = objectId.toLocal8Bit();
auto desktop = VirtualDesktopManager::self()->desktopForId(desktopId);
VirtualDesktopManager::self()->setCurrent(desktop);
return;
}
const auto uuid = QUuid::fromString(objectId);
const auto client = workspace()->findAbstractClient(uuid);
switch (action) {
case ActivateAction:
workspace()->activateClient(client);
break;
case CloseAction:
client->closeWindow();
break;
case MinimizeAction:
client->setMinimized(!client->isMinimized());
break;
case MaximizeAction:
client->setMaximize(client->maximizeMode() == MaximizeRestore, client->maximizeMode() == MaximizeRestore);
break;
case FullscreenAction:
client->setFullScreen(!client->isFullScreen());
break;
case ShadeAction:
client->toggleShade();
break;
case KeepAboveAction:
client->setKeepAbove(!client->keepAbove());
break;
case KeepBelowAction:
client->setKeepBelow(!client->keepBelow());
break;
}