phase 7a: desktop notifications on turn completion

- Daemon tracks per-session state transitions
- Fires freedesktop notification when any session goes non-idle→idle
- 5 second auto-dismiss timeout
This commit is contained in:
Levi Neely 2026-07-05 23:36:16 +02:00
parent aec392baf9
commit 2767387f8e
2 changed files with 45 additions and 4 deletions

View File

@ -1,6 +1,7 @@
#include "session_manager.h" #include "session_manager.h"
#include "libollie.h" #include "libollie.h"
#include <QDBusInterface>
#include <QDebug> #include <QDebug>
#include <QMetaObject> #include <QMetaObject>
@ -14,10 +15,9 @@ static void onStateChange(const char *session_id, const char *state)
if (!g_instance) return; if (!g_instance) return;
QString sid = QString::fromUtf8(session_id); QString sid = QString::fromUtf8(session_id);
QString st = QString::fromUtf8(state); QString st = QString::fromUtf8(state);
// Marshal to the Qt event loop thread QMetaObject::invokeMethod(g_instance, "handleStateChange",
QMetaObject::invokeMethod(g_instance, [sid, st]() { Qt::QueuedConnection,
emit g_instance->StateChanged(sid, st); Q_ARG(QString, sid), Q_ARG(QString, st));
}, Qt::QueuedConnection);
} }
static void onChatUpdate(const char *session_id, int64_t offset, const char *text, int len) static void onChatUpdate(const char *session_id, int64_t offset, const char *text, int len)
@ -103,6 +103,7 @@ bool SessionManager::KillSession(const QString &session_id)
QByteArray idUtf8 = session_id.toUtf8(); QByteArray idUtf8 = session_id.toUtf8();
int rc = ollie_kill_session(const_cast<char*>(idUtf8.constData())); int rc = ollie_kill_session(const_cast<char*>(idUtf8.constData()));
if (rc == 0) { if (rc == 0) {
m_sessionStates.remove(session_id);
emit SessionKilled(session_id); emit SessionKilled(session_id);
return true; return true;
} }
@ -306,3 +307,35 @@ bool SessionManager::PeerSubmit(const QString &session_id, const QString &peer_i
const_cast<char*>(promptUtf8.constData())); const_cast<char*>(promptUtf8.constData()));
return rc == 0; return rc == 0;
} }
// --- Notifications ---
void SessionManager::handleStateChange(const QString &session_id, const QString &new_state)
{
QString prev = m_sessionStates.value(session_id, "idle");
m_sessionStates[session_id] = new_state;
if (new_state == "idle" && prev != "idle") {
sendNotification("Ollie", "Session " + session_id.left(12) + " finished");
}
emit StateChanged(session_id, new_state);
}
void SessionManager::sendNotification(const QString &title, const QString &body)
{
QDBusInterface notifyIface(
"org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
QDBusConnection::sessionBus());
notifyIface.call("Notify",
"ollie-kde", // app_name
(uint)0, // replaces_id
"system-run", // app_icon
title, // summary
body, // body
QStringList(), // actions
QVariantMap(), // hints
(int)5000); // timeout ms
}

View File

@ -5,6 +5,8 @@
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusInterface>
#include <QHash>
// SessionManager is the D-Bus adaptee. The generated SessionManagerAdaptor // SessionManager is the D-Bus adaptee. The generated SessionManagerAdaptor
// (from qt6_add_dbus_adaptor) forwards D-Bus method calls to slots here. // (from qt6_add_dbus_adaptor) forwards D-Bus method calls to slots here.
@ -62,6 +64,12 @@ signals:
private: private:
void installCallbacks(); void installCallbacks();
void sendNotification(const QString &title, const QString &body);
QHash<QString, QString> m_sessionStates;
private slots:
void handleStateChange(const QString &session_id, const QString &new_state);
}; };
#endif // SESSION_MANAGER_H #endif // SESSION_MANAGER_H