summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/applicationmanager.cpp127
-rw-r--r--src/applicationmanager.h43
-rw-r--r--src/debug.cpp6
-rw-r--r--src/debug.h11
-rw-r--r--src/main.cpp70
-rw-r--r--src/org.freedesktop.DBus.xml17
-rw-r--r--src/vnc-keyboard-unstable-v1.cpp146
-rw-r--r--src/vnc-keyboard-unstable-v1.h46
-rw-r--r--src/waylandentries.cpp159
-rw-r--r--src/waylandentries.h53
-rw-r--r--src/waylandentriesfiltered.cpp63
-rw-r--r--src/waylandentriesfiltered.h41
12 files changed, 782 insertions, 0 deletions
diff --git a/src/applicationmanager.cpp b/src/applicationmanager.cpp
new file mode 100644
index 0000000..13158f3
--- /dev/null
+++ b/src/applicationmanager.cpp
@@ -0,0 +1,127 @@
+#include "applicationmanager.h"
+#include "waylandentries.h"
+#include <QWaylandXdgSurface>
+#include <QWaylandXdgToplevel>
+
+ApplicationManager::ApplicationManager(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+bool ApplicationManager::isHome() const
+{
+ return m_isHome;
+}
+
+QObject *ApplicationManager::currentSurface() const
+{
+ return m_currentSurface;
+}
+
+void ApplicationManager::setCurrentSurface(QObject *newCurrentSurface)
+{
+ if (m_currentSurface == newCurrentSurface)
+ {
+ emit currentSurfaceChanged();
+ return;
+ }
+ m_currentSurface = newCurrentSurface;
+ emit currentSurfaceChanged();
+}
+
+int ApplicationManager::count()
+{
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ if(!entries)
+ return 0;
+ return entries->rowCount();
+}
+
+QString ApplicationManager::applicationName(int id)
+{
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ if(!entries)
+ return "";
+ return entries->data(entries->index(id), WaylandEntries::TitleRole).toString();
+}
+
+int ApplicationManager::applicationPid(int id)
+{
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ if(!entries)
+ return 0;
+ return entries->data(entries->index(id), WaylandEntries::PidRole).toInt();
+}
+
+int ApplicationManager::applicationFocus(int id)
+{
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ if(!entries)
+ return -1;
+ if(id >= entries->rowCount())
+ return -2;
+ QVariant d = entries->data(entries->index(id), WaylandEntries::SurfaceRole);
+ if(!d.isValid())
+ return -3;
+ QWaylandXdgSurface *surface = qvariant_cast<QWaylandXdgSurface *>(d);
+ if(surface)
+ {
+ setCurrentSurface(surface);
+ return 0;
+ }
+ return -4;
+}
+
+int ApplicationManager::currentApplicationPid()
+{
+ if(isHome())
+ return -1;
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ for(int i = 0; i < entries->rowCount(); i++)
+ {
+ QVariant d = entries->data(entries->index(i), WaylandEntries::SurfaceRole);
+ QWaylandXdgSurface *surface = qvariant_cast<QWaylandXdgSurface *>(d);
+ QWaylandXdgSurface *current = qobject_cast<QWaylandXdgSurface*>(currentSurface());
+ if(surface != current)
+ continue;
+ return entries->data(entries->index(i), WaylandEntries::PidRole).toInt();
+ }
+ return -2;
+}
+
+void ApplicationManager::hideApplicationPid(qint64 pid)
+{
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ entries->addHidePid(pid);
+}
+
+void ApplicationManager::raiseApplicationPid(qint64 pid)
+{
+ WaylandEntries *entries = WaylandEntries::getInstance();
+ QObject *d = entries->getSurface(pid);
+ QWaylandXdgSurface *surface = qobject_cast<QWaylandXdgSurface *>(d);
+ if(surface)
+ {
+ setCurrentSurface(surface);
+ }
+}
+
+void ApplicationManager::backHome()
+{
+ emit gotoHome();
+}
+
+void ApplicationManager::setIsHome(bool isHome)
+{
+ if (m_isHome == isHome)
+ return;
+
+ m_isHome = isHome;
+ emit isHomeChanged(m_isHome);
+}
+
+QString ApplicationManager::virtualkeyboard()
+{
+ return qgetenv("QT_IM_MODULE");
+}
diff --git a/src/applicationmanager.h b/src/applicationmanager.h
new file mode 100644
index 0000000..b4568f0
--- /dev/null
+++ b/src/applicationmanager.h
@@ -0,0 +1,43 @@
+#ifndef APPLICATIONMANAGER_H
+#define APPLICATIONMANAGER_H
+
+#include <QObject>
+
+class ApplicationManager : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *currentSurface READ currentSurface WRITE setCurrentSurface NOTIFY currentSurfaceChanged)
+ Q_PROPERTY(bool isHome READ isHome WRITE setIsHome NOTIFY isHomeChanged)
+ Q_PROPERTY(QString virtualkeyboard READ virtualkeyboard CONSTANT)
+
+ QObject *m_currentSurface {nullptr};
+ bool m_isHome;
+
+public:
+ explicit ApplicationManager(QObject *parent = nullptr);
+
+ bool isHome() const;
+
+public slots:
+ QObject *currentSurface() const;
+ void setCurrentSurface(QObject *newCurrentSurface);
+
+ int count();
+ QString applicationName(int id);
+ int applicationPid(int id);
+ int applicationFocus(int id);
+ int currentApplicationPid();
+ void hideApplicationPid(qint64 pid);
+ void raiseApplicationPid(qint64 pid);
+ void backHome();
+ void setIsHome(bool isHome);
+
+ QString virtualkeyboard();
+
+signals:
+ void currentSurfaceChanged();
+ void gotoHome();
+ void isHomeChanged(bool isHome);
+};
+
+#endif // APPLICATIONMANAGER_H
diff --git a/src/debug.cpp b/src/debug.cpp
new file mode 100644
index 0000000..a07d815
--- /dev/null
+++ b/src/debug.cpp
@@ -0,0 +1,6 @@
+#include "debug.h"
+
+Q_LOGGING_CATEGORY(DESKTOP_MGR_CORE, "desktopmgr.core")
+Q_LOGGING_CATEGORY(DESKTOP_MGR_SCREEN_COPY, "desktopmgr.screencopy")
+Q_LOGGING_CATEGORY(DESKTOP_MGR_VNC_KEYBOARD, "desktopmgr.vnckeyboard")
+Q_LOGGING_CATEGORY(DESKTOP_MGR_VIRTUAL_POINTER, "desktopmgr.virtualpointer")
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..803192d
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,11 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <QLoggingCategory>
+
+Q_DECLARE_LOGGING_CATEGORY(DESKTOP_MGR_CORE)
+Q_DECLARE_LOGGING_CATEGORY(DESKTOP_MGR_SCREEN_COPY)
+Q_DECLARE_LOGGING_CATEGORY(DESKTOP_MGR_VNC_KEYBOARD)
+Q_DECLARE_LOGGING_CATEGORY(DESKTOP_MGR_VIRTUAL_POINTER)
+
+#endif // DEBUG_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..ca19b05
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,70 @@
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+#include <QDBusConnection>
+#include <QIcon>
+#include <QTimer>
+#include <QThread>
+#include <systemd/sd-daemon.h>
+#include <QDir>
+#include <QFileInfo>
+#include <xdgstatusnotifierwatcher.h>
+#include "applicationmanager.h"
+#include "applicationsadaptor.h"
+#include "waylandentries.h"
+#include "waylandentriesfiltered.h"
+
+int main(int argc, char *argv[])
+{
+ qputenv("QT_IM_MODULE", "qtvirtualkeyboard");
+ QDBusConnection bus = QDBusConnection::sessionBus();
+ QGuiApplication app(argc, argv);
+ ApplicationManager manager;
+ QTimer watchdog;
+ uint64_t watchdogPeriodUSec;
+
+ QFileInfo volatilapps("/var/volatile/applications");
+ if(!volatilapps.exists())
+ {
+ QDir().mkdir("/var/volatile/applications");
+ }
+
+ qmlRegisterType<WaylandEntries>("org.kazoe.desktop", 1, 0, "WaylandEntries");
+ qmlRegisterType<WaylandEntriesFiltered>("org.kazoe.desktop", 1, 0, "WaylandEntriesFiltered");
+
+ if (!bus.isConnected()) {
+ qWarning("Cannot connect to the D-Bus session bus.\n"
+ "Please check your system settings and try again.\n");
+ return 1;
+ }
+
+ QQmlApplicationEngine engine;
+ new ApplicationsAdaptor(&manager);
+ bus.registerObject("/applications", &manager);
+
+
+ bool conres = bus.registerService("org.kazoe.desktop");
+ if(!conres) qWarning() << "Can't register dbus service org.kazoe.desktop";
+
+ KaZoe::StatusNotifierWatcher notifierWatcher;
+
+ engine.rootContext()->setContextProperty("manager", &manager);
+ engine.loadFromModule("org.kazoe.desktop", "Main");
+
+ // signal systemd that the app the ready
+ QTimer::singleShot(0, [] () {
+ sd_notify(0, "READY=1");
+ }
+ );
+
+ // setup a timer to refresh the systemd'd watchdog if needed
+ if (sd_watchdog_enabled(0,&watchdogPeriodUSec) > 0) {
+ QObject::connect(&watchdog, &QTimer::timeout, [] () {
+ sd_notify(0, "WATCHDOG=1");
+ }
+ );
+ }
+ // configure the period of the QT timer for a half period of the watchdog timer
+ watchdog.start(watchdogPeriodUSec / 2000);
+ return app.exec();
+}
diff --git a/src/org.freedesktop.DBus.xml b/src/org.freedesktop.DBus.xml
new file mode 100644
index 0000000..68d5262
--- /dev/null
+++ b/src/org.freedesktop.DBus.xml
@@ -0,0 +1,17 @@
+<!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.freedesktop.DBus.Properties">
+ <method name="GetAll">
+ <arg name="interface_name" type="s" direction="in"/>
+ <arg name="properties" type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+ </method>
+ <signal name="PropertiesChanged">
+ <arg name="interface_name" type="s" direction="out"/>
+ <arg name="changed_properties" type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
+ <arg name="invalidated_properties" type="as" direction="out"/>
+ </signal>
+ </interface>
+</node>
diff --git a/src/vnc-keyboard-unstable-v1.cpp b/src/vnc-keyboard-unstable-v1.cpp
new file mode 100644
index 0000000..5dc8dd7
--- /dev/null
+++ b/src/vnc-keyboard-unstable-v1.cpp
@@ -0,0 +1,146 @@
+#include <QDebug>
+#include <QGuiApplication>
+#include <wayland-server-protocol.h>
+#include <linux/input-event-codes.h>
+#include "vnc-keyboard-unstable-v1.h"
+
+
+void toQtKey(uint32_t key, uint32_t *pkeycode, uint32_t *punicode)
+{
+ static const QMap<int, int> keyMap {
+ { 0xff08, Qt::Key_Backspace },
+ { 0xff09, Qt::Key_Tab },
+ { 0xff0d, Qt::Key_Return },
+ { 0xff1b, Qt::Key_Escape },
+ { 0xff63, Qt::Key_Insert },
+ { 0xffff, Qt::Key_Delete },
+ { 0xff50, Qt::Key_Home },
+ { 0xff57, Qt::Key_End },
+ { 0xff55, Qt::Key_PageUp },
+ { 0xff56, Qt::Key_PageDown },
+ { 0xff51, Qt::Key_Left },
+ { 0xff52, Qt::Key_Up },
+ { 0xff53, Qt::Key_Right },
+ { 0xff54, Qt::Key_Down },
+ { 0xffbe, Qt::Key_F1 },
+ { 0xffbf, Qt::Key_F2 },
+ { 0xffc0, Qt::Key_F3 },
+ { 0xffc1, Qt::Key_F4 },
+ { 0xffc2, Qt::Key_F5 },
+ { 0xffc3, Qt::Key_F6 },
+ { 0xffc4, Qt::Key_F7 },
+ { 0xffc5, Qt::Key_F8 },
+ { 0xffc6, Qt::Key_F9 },
+ { 0xffc7, Qt::Key_F10 },
+ { 0xffc8, Qt::Key_F11 },
+ { 0xffc9, Qt::Key_F12 },
+ { 0xffe1, Qt::Key_Shift },
+ { 0xffe2, Qt::Key_Shift },
+ { 0xffe3, Qt::Key_Control },
+ { 0xffe4, Qt::Key_Control },
+ { 0xffe7, Qt::Key_Meta },
+ { 0xffe8, Qt::Key_Meta },
+ { 0xffe9, Qt::Key_Alt },
+ { 0xffea, Qt::Key_Alt },
+
+ { 0xffb0, Qt::Key_0 },
+ { 0xffb1, Qt::Key_1 },
+ { 0xffb2, Qt::Key_2 },
+ { 0xffb3, Qt::Key_3 },
+ { 0xffb4, Qt::Key_4 },
+ { 0xffb5, Qt::Key_5 },
+ { 0xffb6, Qt::Key_6 },
+ { 0xffb7, Qt::Key_7 },
+ { 0xffb8, Qt::Key_8 },
+ { 0xffb9, Qt::Key_9 },
+
+ { 0xff8d, Qt::Key_Return },
+ { 0xffaa, Qt::Key_Asterisk },
+ { 0xffab, Qt::Key_Plus },
+ { 0xffad, Qt::Key_Minus },
+ { 0xffae, Qt::Key_Period },
+ { 0xffaf, Qt::Key_Slash },
+
+ { 0xff95, Qt::Key_Home },
+ { 0xff96, Qt::Key_Left },
+ { 0xff97, Qt::Key_Up },
+ { 0xff98, Qt::Key_Right },
+ { 0xff99, Qt::Key_Down },
+ { 0xff9a, Qt::Key_PageUp },
+ { 0xff9b, Qt::Key_PageDown },
+ { 0xff9c, Qt::Key_End },
+ { 0xff9e, Qt::Key_Insert },
+ { 0xff9f, Qt::Key_Delete },
+ };
+ uint32_t unicode = 0;
+ uint32_t keycode = keyMap.value(key, 0);
+
+ if (keycode >= ' ' && keycode <= '~')
+ unicode = keycode;
+
+ if (!keycode) {
+ if (key <= 0xff) {
+ unicode = key;
+ if (key >= 'a' && key <= 'z')
+ keycode = Qt::Key_A + key - 'a';
+ else if (key >= ' ' && key <= '~')
+ keycode = Qt::Key_Space + key - ' ';
+ }
+ }
+ *pkeycode = keycode;
+ *punicode = unicode;
+}
+
+
+VncKeyboardManager::VncKeyboardManager(QWaylandCompositor *compositor)
+ :QWaylandCompositorExtensionTemplate(compositor)
+{
+}
+
+void VncKeyboardManager::initialize()
+{
+ QWaylandCompositorExtensionTemplate::initialize();
+ QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer());
+ init(compositor->display(), 1);
+}
+
+void VncKeyboardManager::vnc_virtual_keyboard_manager_v1_create_virtual_keyboard(Resource *resource, uint32_t id)
+{
+ new VncKeyboard(m_window, resource->client(), id, 1);
+}
+
+VncKeyboard::VncKeyboard(QQuickWindow *window, struct ::wl_client *client, int id, int version):
+ QtWaylandServer::vnc_keyboard_v1(client, id, version),
+ m_window(window),
+ m_keymod(Qt::NoModifier)
+{
+}
+
+void VncKeyboard::vnc_keyboard_v1_key(Resource *resource, uint32_t time, uint32_t key, uint32_t state)
+{
+ bool down = !!state;
+ uint32_t keycode, unicode;
+
+ toQtKey(key, &keycode, &unicode);
+
+ if (keycode == Qt::Key_Shift)
+ m_keymod = down ? m_keymod | Qt::ShiftModifier :
+ m_keymod & ~Qt::ShiftModifier;
+ else if (keycode == Qt::Key_Control)
+ m_keymod = down ? m_keymod | Qt::ControlModifier :
+ m_keymod & ~Qt::ControlModifier;
+ else if (keycode == Qt::Key_Alt)
+ m_keymod = down ? m_keymod | Qt::AltModifier :
+ m_keymod & ~Qt::AltModifier;
+ if (unicode || keycode) {
+ QKeyEvent event(down ? QEvent::KeyPress : QEvent::KeyRelease, keycode, m_keymod, QString(QChar(unicode)));
+ QGuiApplication::sendEvent(m_window, &event);
+ } else {
+ qDebug() << __func__ << " no unicode or keycode. keysym is " << key << ". state is " << state;
+ }
+}
+
+void VncKeyboard::vnc_keyboard_v1_destroy(Resource *)
+{
+ delete this;
+}
diff --git a/src/vnc-keyboard-unstable-v1.h b/src/vnc-keyboard-unstable-v1.h
new file mode 100644
index 0000000..3728b3f
--- /dev/null
+++ b/src/vnc-keyboard-unstable-v1.h
@@ -0,0 +1,46 @@
+#ifndef VIRTUALKEYBOARD_H
+#define VIRTUALKEYBOARD_H
+
+#include "wayland-util.h"
+#include <QQuickWindow>
+#include <QtWaylandCompositor/QWaylandCompositorExtensionTemplate>
+#include <QtWaylandCompositor/QWaylandQuickExtension>
+#include <QtWaylandCompositor/QWaylandCompositor>
+#include "qwayland-server-vnc-keyboard-unstable-v1.h"
+
+class VncKeyboardManager : public QWaylandCompositorExtensionTemplate<VncKeyboardManager>
+ , public QtWaylandServer::vnc_virtual_keyboard_manager_v1
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickWindow *window MEMBER m_window);
+
+public:
+ VncKeyboardManager(QWaylandCompositor *compositor = nullptr);
+ void initialize() override;
+
+protected:
+ void vnc_virtual_keyboard_manager_v1_create_virtual_keyboard(Resource *resource, uint32_t id) override;
+
+private:
+ QQuickWindow *m_window;
+};
+
+class VncKeyboard : public QWaylandCompositorExtensionTemplate<VncKeyboard>
+ , public QtWaylandServer::vnc_keyboard_v1
+{
+ Q_OBJECT
+public:
+ VncKeyboard(QQuickWindow *window, struct ::wl_client *client, int id, int version);
+
+protected:
+ void vnc_keyboard_v1_key(Resource *resource, uint32_t time, uint32_t key, uint32_t state) override;
+ void vnc_keyboard_v1_destroy(Resource *resource) override;
+
+private:
+ QQuickWindow *m_window;
+ Qt::KeyboardModifiers m_keymod;
+};
+
+Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS(VncKeyboardManager)
+
+#endif // VIRTUALKEYBOARD_H
diff --git a/src/waylandentries.cpp b/src/waylandentries.cpp
new file mode 100644
index 0000000..42808bb
--- /dev/null
+++ b/src/waylandentries.cpp
@@ -0,0 +1,159 @@
+#include "waylandentries.h"
+#include <QWaylandXdgSurface>
+#include <QWaylandSurface>
+#include <QMutexLocker>
+#include <qdebug.h>
+
+WaylandEntries *m_instance = nullptr;
+
+WaylandEntries::WaylandEntries(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ if(m_instance != nullptr)
+ {
+ qWarning() << "Many instance of WaylandEntries";
+ }
+ m_instance = this;
+}
+
+int WaylandEntries::rowCount(const QModelIndex &parent) const
+{
+ QMutexLocker locker(&m_lock);
+ return m_surfaces.count();
+}
+
+QVariant WaylandEntries::data(const QModelIndex &index, int role) const
+{
+ QMutexLocker locker(&m_lock);
+ if(index.row() > m_surfaces.count())
+ return QVariant();
+
+ QWaylandXdgSurface *surface = m_surfaces[index.row()];
+ if(surface == nullptr)
+ return QVariant();
+
+ switch(role) {
+ case Qt::DisplayRole:
+ case TitleRole:
+ return surface->toplevel()->title();
+ case AppIdRole:
+ return surface->toplevel()->appId();
+ case SurfaceRole:
+ return QVariant::fromValue<QWaylandXdgSurface*>(surface);
+ case PidRole:
+ return surface->surface()->client()->processId();
+ }
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> WaylandEntries::roleNames() const
+{
+ QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
+ roles[SurfaceRole] = "wl_surface";
+ roles[TitleRole] = "title";
+ roles[PidRole] = "pid";
+ roles[AppIdRole] = "appId";
+ return roles;
+}
+
+// Need only for application manager interface for cli
+WaylandEntries *WaylandEntries::getInstance()
+{
+ return m_instance;
+}
+
+void WaylandEntries::addSurface(QObject *obj)
+{
+ QMutexLocker locker(&m_lock);
+ QWaylandXdgSurface *s = qobject_cast<QWaylandXdgSurface*>(obj);
+ if(s)
+ {
+ QObject::connect(s, &QWaylandXdgSurface::destroyed, this, &WaylandEntries::surfaceDestroyed);
+ if(m_hidden.contains(s->surface()->client()->processId()))
+ {
+ m_surfaces_hidden.append(s);
+ }
+ else
+ {
+ int id = m_surfaces.count();
+ beginInsertRows(QModelIndex(), m_surfaces.count(), m_surfaces.count());
+ QObject::connect(s->toplevel(), &QWaylandXdgToplevel::titleChanged, this, [this, id](){
+ const QVector<int> roles = {TitleRole};
+ emit dataChanged(index(id), index(id), roles);
+ });
+ QObject::connect(s->toplevel(), &QWaylandXdgToplevel::appIdChanged, this, [this, id, s](){
+ const QVector<int> roles = {AppIdRole};
+
+ emit topWindowRegistered(s, s->toplevel()->appId());
+ emit dataChanged(index(id), index(id), roles);
+ });
+ m_surfaces.append(s);
+ endInsertRows();
+ emit nbAppsChanged();
+ }
+ }
+}
+
+void WaylandEntries::addHidePid(qint64 pid)
+{
+ QMutexLocker locker(&m_lock);
+ m_hidden.append(pid);
+ QWaylandXdgSurface *surfaceToHide = nullptr;
+
+ for(QWaylandXdgSurface *surface: m_surfaces)
+ {
+ if(surface->surface()->client()->processId() == pid)
+ {
+ surfaceToHide = surface;
+ break;
+ }
+ }
+ if(surfaceToHide)
+ {
+ beginRemoveRows(QModelIndex(), m_surfaces.indexOf(surfaceToHide), m_surfaces.indexOf(surfaceToHide));
+ m_surfaces.removeAll(surfaceToHide);
+ endRemoveRows();
+ m_surfaces_hidden.append(surfaceToHide);
+ emit nbAppsChanged();
+ }
+}
+
+void WaylandEntries::surfaceDestroyed()
+{
+ QObject *obj = QObject::sender();
+ QWaylandXdgSurface *s = static_cast<QWaylandXdgSurface*>(obj);
+ emit topWindowDestroyed(s, s->toplevel()->appId());
+ QMutexLocker locker(&m_lock);
+ beginRemoveRows(QModelIndex(), m_surfaces.indexOf(s), m_surfaces.indexOf(s));
+ m_surfaces.removeAll(s);
+ endRemoveRows();
+ emit nbAppsChanged();
+}
+
+void WaylandEntries::stop(int pid)
+{
+ kill(pid, SIGTERM);
+}
+
+QObject *WaylandEntries::getSurface(int pid)
+{
+ QMutexLocker locker(&m_lock);
+ for(QWaylandXdgSurface *surface: m_surfaces)
+ {
+ if(surface->surface()->client()->processId() == pid)
+ return surface;
+ }
+ for(QWaylandXdgSurface *surface: m_surfaces_hidden)
+ {
+ if(surface->surface()->client()->processId() == pid)
+ return surface;
+ }
+ return nullptr;
+}
+
+int WaylandEntries::nbApps() const
+{
+ QMutexLocker locker(&m_lock);
+ return m_surfaces.count();
+}
diff --git a/src/waylandentries.h b/src/waylandentries.h
new file mode 100644
index 0000000..ce98ade
--- /dev/null
+++ b/src/waylandentries.h
@@ -0,0 +1,53 @@
+#ifndef WAYLANDENTRIES_H
+#define WAYLANDENTRIES_H
+
+#include <QAbstractListModel>
+#include <QRecursiveMutex>
+#include <QObject>
+
+class QWaylandXdgSurface;
+
+class WaylandEntries : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(int nbApps READ nbApps NOTIFY nbAppsChanged)
+
+
+ QList<QWaylandXdgSurface *> m_surfaces;
+ QList<QWaylandXdgSurface *> m_surfaces_hidden;
+ QList<qint64> m_hidden;
+ mutable QRecursiveMutex m_lock;
+
+public:
+ explicit WaylandEntries(QObject *parent = nullptr);
+
+ enum WaylandEntryRoles {
+ SurfaceRole = Qt::UserRole + 1,
+ TitleRole,
+ PidRole,
+ AppIdRole
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ static WaylandEntries* getInstance();
+
+ int nbApps() const;
+ void setNbApps(int newNbApps);
+
+public slots:
+ void addSurface(QObject *obj);
+ void addHidePid(qint64 pid);
+ void surfaceDestroyed();
+ void stop(int pid);
+ QObject *getSurface(int pid);
+
+signals:
+ void nbAppsChanged();
+ void topWindowRegistered(QObject *surface, QString appid);
+ void topWindowDestroyed(QObject *surface, QString appid);
+};
+
+#endif // WAYLANDENTRIES_H
diff --git a/src/waylandentriesfiltered.cpp b/src/waylandentriesfiltered.cpp
new file mode 100644
index 0000000..f1f2ebc
--- /dev/null
+++ b/src/waylandentriesfiltered.cpp
@@ -0,0 +1,63 @@
+#include "waylandentriesfiltered.h"
+#include "waylandentries.h"
+#include "xdgdesktopentries.h"
+#include <QDebug>
+
+WaylandEntriesFiltered::WaylandEntriesFiltered(QObject *parent)
+ : QSortFilterProxyModel{parent}
+{
+ m_entries = new KaZoe::DesktopEntries(this);
+ QObject::connect(this, &WaylandEntriesFiltered::rowsInserted, this, &WaylandEntriesFiltered::lengthChanged);
+ QObject::connect(this, &WaylandEntriesFiltered::rowsRemoved, this, &WaylandEntriesFiltered::lengthChanged);
+}
+
+QString WaylandEntriesFiltered::roleFilter() const
+{
+ return m_roleFilter.join(";");
+}
+
+void WaylandEntriesFiltered::setRoleFilter(const QString &roles)
+{
+ QStringList newlist = roles.split(";");
+ if (m_roleFilter == newlist)
+ return;
+ m_roleFilter = newlist;
+ emit roleFilterChanged();
+}
+
+bool WaylandEntriesFiltered::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+ QVariant appid = sourceModel()->data(index, WaylandEntries::AppIdRole);
+ QString role = m_entries->appIdData(appid.toString(), "Desktop Entry/X-DESKTOPMGR-ROLE");
+
+ if(appid.isNull())
+ return false;
+
+ if(m_roleFilter.contains(role))
+ {
+ return false;
+ }
+ return true;
+}
+
+QObject *WaylandEntriesFiltered::model() const
+{
+ return static_cast<QObject*>(m_model);
+}
+
+void WaylandEntriesFiltered::setModel(QObject *newModel)
+{
+ WaylandEntries *entries = qobject_cast<WaylandEntries*>(newModel);
+ if (entries)
+ {
+ m_model = entries;
+ setSourceModel(m_model);
+ emit modelChanged(m_model);
+ }
+}
+
+int WaylandEntriesFiltered::length()
+{
+ return rowCount();
+}
diff --git a/src/waylandentriesfiltered.h b/src/waylandentriesfiltered.h
new file mode 100644
index 0000000..e562a7d
--- /dev/null
+++ b/src/waylandentriesfiltered.h
@@ -0,0 +1,41 @@
+#ifndef WAYLANDENTIRESFILTERED_H
+#define WAYLANDENTIRESFILTERED_H
+
+#include <QSortFilterProxyModel>
+#include <QObject>
+
+class WaylandEntries;
+namespace KaZoe {
+ class DesktopEntries;
+}
+
+class WaylandEntriesFiltered : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QString roleFilter READ roleFilter WRITE setRoleFilter NOTIFY roleFilterChanged)
+ Q_PROPERTY(int length READ length NOTIFY lengthChanged)
+ KaZoe::DesktopEntries *m_entries {nullptr};
+
+public:
+ explicit WaylandEntriesFiltered(QObject *parent = nullptr);
+ QString roleFilter() const;
+ void setRoleFilter(const QString &roles);
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
+
+ QObject *model() const;
+ void setModel(QObject *newModel);
+
+ int length();
+
+signals:
+ void roleFilterChanged();
+ void modelChanged(QObject * model);
+ void lengthChanged();
+
+private:
+ QStringList m_roleFilter;
+ WaylandEntries *m_model = nullptr;
+};
+
+#endif // WAYLANDENTIRESFILTERED_H