Skip to content

Commit f2603e6

Browse files
committed
🎉 Add getOpenWindows and focusWindow methods
1 parent 1d144fb commit f2603e6

5 files changed

Lines changed: 67 additions & 2 deletions

File tree

changelog.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ Security - in case of vulnerabilities.
1414

1515
This changelog uses [semantic versioning](https://semver.org) and follows the rules of [Keep a Changelog](http://keepachangelog.com/).
1616

17-
## [unreleased]
17+
## [KWin Integration 0.2.0](https://github.com/kando-menu/kwin-integration/releases/tag/v0.2.0)
1818

19-
**Release Date:** TBD
19+
**Release Date:** 2026-06-17
20+
21+
### :tada: Added
22+
23+
- A method to list all open windows, which is used by the "Focus Window" action to find the window to focus. This method retrieves the stacking order of windows from KWin and returns their titles and classes.
24+
- A method to focus a window by its title and class. This method iterates through the open windows and activates the one that matches the given title and class.
2025

2126
## [KWin Integration 0.1.0](https://github.com/kando-menu/kwin-integration/releases/tag/v0.1.0)
2227

src/dbus/KandoIntegrationAdaptor.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,13 @@ KandoIntegrationAdaptor::KandoIntegrationAdaptor(KandoKWinIntegrationPlugin* plu
1717

1818
QVariantMap KandoIntegrationAdaptor::GetWMInfo() const { return mPlugin->getWMInfo(); }
1919

20+
QVariantList KandoIntegrationAdaptor::GetOpenWindows() const {
21+
return mPlugin->getOpenWindows();
22+
}
23+
24+
bool KandoIntegrationAdaptor::FocusWindow(const QString& windowName,
25+
const QString& appName) const {
26+
return mPlugin->focusWindow(windowName, appName);
27+
}
28+
2029
QString KandoIntegrationAdaptor::Ping() const { return QStringLiteral("pong"); }

src/dbus/KandoIntegrationAdaptor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include <QDBusAbstractAdaptor>
1414
#include <QObject>
15+
#include <QString>
16+
#include <QVariantList>
1517
#include <QVariantMap>
1618

1719
class KandoKWinIntegrationPlugin;
@@ -25,6 +27,8 @@ class KandoIntegrationAdaptor : public QDBusAbstractAdaptor {
2527

2628
public Q_SLOTS:
2729
QVariantMap GetWMInfo() const;
30+
QVariantList GetOpenWindows() const;
31+
bool FocusWindow(const QString& windowName, const QString& appName) const;
2832
QString Ping() const;
2933

3034
private:

src/plugin/KandoKWinIntegrationPlugin.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "KandoKWinIntegrationPlugin.h"
1212

1313
#include <effect/effecthandler.h>
14+
#include <effect/effectwindow.h>
1415

1516
#include <QDBusConnection>
1617
#include <QDBusError>
@@ -69,3 +70,46 @@ QVariantMap KandoKWinIntegrationPlugin::getWMInfo() const {
6970
{QStringLiteral("workAreaHeight"), qRound(workArea.height())},
7071
};
7172
}
73+
74+
QVariantList KandoKWinIntegrationPlugin::getOpenWindows() const {
75+
QVariantList windows;
76+
77+
for (const auto* window : KWin::effects->stackingOrder()) {
78+
if (!window || window->isDeleted() || !window->isManaged() ||
79+
window->isSpecialWindow() || window->isSkipSwitcher()) {
80+
continue;
81+
}
82+
83+
const auto windowName = window->caption();
84+
const auto appName = window->windowClass();
85+
86+
if (windowName.isEmpty() && appName.isEmpty()) {
87+
continue;
88+
}
89+
90+
windows.push_back(QVariantList{windowName, appName});
91+
}
92+
93+
return windows;
94+
}
95+
96+
bool KandoKWinIntegrationPlugin::focusWindow(const QString& windowName,
97+
const QString& appName) const {
98+
const auto windows = KWin::effects->stackingOrder();
99+
100+
// Iterate top-most first so we focus the window the user most likely expects.
101+
for (auto it = windows.rbegin(); it != windows.rend(); ++it) {
102+
auto* window = *it;
103+
104+
if (!window || window->isDeleted() || !window->isManaged()) {
105+
continue;
106+
}
107+
108+
if (window->caption() == windowName && window->windowClass() == appName) {
109+
KWin::effects->activateWindow(window);
110+
return true;
111+
}
112+
}
113+
114+
return false;
115+
}

src/plugin/KandoKWinIntegrationPlugin.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <effect/effect.h>
1414

15+
#include <QVariantList>
1516
#include <QVariantMap>
1617

1718
#include "input/PointerInput.h"
@@ -26,6 +27,8 @@ class KandoKWinIntegrationPlugin : public KWin::Effect {
2627
~KandoKWinIntegrationPlugin() override;
2728

2829
QVariantMap getWMInfo() const;
30+
QVariantList getOpenWindows() const;
31+
bool focusWindow(const QString& windowName, const QString& appName) const;
2932

3033
private:
3134
KandoIntegrationAdaptor* mAdaptor;

0 commit comments

Comments
 (0)