plasmoid: async D-Bus calls to prevent panel freezes
All synchronous QDBusInterface::call() replaced with asyncCall() + QDBusPendingCallWatcher. Adds coalescing flags to prevent piling up refreshSessions/fetchChat requests during rapid signal bursts. Also removes build dependency from install targets to prevent cmake re-running over read-only installed artifacts.
This commit is contained in:
parent
d457be9524
commit
327030293b
8
Makefile
8
Makefile
|
|
@ -24,7 +24,7 @@ kf5:
|
|||
|
||||
# --- KF6 Install (default) ---
|
||||
|
||||
install: build
|
||||
install:
|
||||
@echo "=== Installing ollie-kde (KF6) ==="
|
||||
# Tray binary
|
||||
install -m755 $(BUILD_DIR)/ollie-tray /usr/bin/
|
||||
|
|
@ -77,7 +77,7 @@ uninstall:
|
|||
|
||||
# --- Individual component installs ---
|
||||
|
||||
krunner-install: build
|
||||
krunner-install:
|
||||
mkdir -p /usr/lib64/qt6/plugins/kf6/krunner
|
||||
install -m755 $(BUILD_DIR)/lib/kf6/krunner/krunner_ollie.so \
|
||||
/usr/lib64/qt6/plugins/kf6/krunner/
|
||||
|
|
@ -92,7 +92,7 @@ dolphin-install:
|
|||
install -m755 dolphin/ollie-session-here /usr/local/bin/
|
||||
@echo "Dolphin menus installed. Restart Dolphin or re-open context menu."
|
||||
|
||||
plasmoid-install: build
|
||||
plasmoid-install:
|
||||
kpackagetool6 -t Plasma/Applet -r org.ollie.plasmoid 2>/dev/null; true
|
||||
kpackagetool6 -t Plasma/Applet -i plasmoid/
|
||||
mkdir -p /usr/lib64/qt6/qml/org/ollie/private
|
||||
|
|
@ -115,7 +115,7 @@ plasmoid-uninstall:
|
|||
|
||||
# --- KF5 Install ---
|
||||
|
||||
kf5-install: kf5
|
||||
kf5-install:
|
||||
@echo "=== Installing ollie-kde (KF5) ==="
|
||||
# Tray binary
|
||||
install -m755 $(KF5_BUILD_DIR)/ollie-tray /usr/bin/
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <QDBusReply>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusServiceWatcher>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QDir>
|
||||
|
||||
static const char *SERVICE = "org.ollie.SessionManager";
|
||||
|
|
@ -63,13 +64,34 @@ void OllieDBusClient::setActiveSessionId(const QString &id)
|
|||
fetchConfig();
|
||||
}
|
||||
|
||||
// --- Async refresh sessions ---
|
||||
|
||||
void OllieDBusClient::refreshSessions()
|
||||
{
|
||||
QDBusReply<QStringList> reply = m_iface->call("ListSessions");
|
||||
if (!reply.isValid()) return;
|
||||
if (m_refreshPending) return; // coalesce rapid-fire signals
|
||||
m_refreshPending = true;
|
||||
|
||||
QDBusPendingCall pending = m_iface->asyncCall("ListSessions");
|
||||
auto *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished,
|
||||
this, &OllieDBusClient::onRefreshSessionsFinished);
|
||||
}
|
||||
|
||||
void OllieDBusClient::onRefreshSessionsFinished(QDBusPendingCallWatcher *watcher)
|
||||
{
|
||||
m_refreshPending = false;
|
||||
watcher->deleteLater();
|
||||
|
||||
QDBusPendingReply<QStringList> reply = *watcher;
|
||||
if (reply.isError()) return;
|
||||
|
||||
processSessionList(reply.value());
|
||||
}
|
||||
|
||||
void OllieDBusClient::processSessionList(const QStringList &entries)
|
||||
{
|
||||
m_sessions.clear();
|
||||
for (const QString &entry : reply.value()) {
|
||||
for (const QString &entry : entries) {
|
||||
QStringList parts = entry.split('\t');
|
||||
if (parts.size() >= 4) {
|
||||
QVariantMap session;
|
||||
|
|
@ -112,20 +134,32 @@ void OllieDBusClient::refreshSessions()
|
|||
}
|
||||
}
|
||||
|
||||
// --- Async fetch chat ---
|
||||
|
||||
void OllieDBusClient::fetchChat()
|
||||
{
|
||||
if (m_activeSessionId.isEmpty()) return;
|
||||
if (m_fetchChatPending) return; // don't pile up requests
|
||||
m_fetchChatPending = true;
|
||||
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(SERVICE, OBJ_PATH, IFACE, "GetChat");
|
||||
msg << m_activeSessionId << m_chatOffset;
|
||||
QDBusMessage reply = QDBusConnection::sessionBus().call(msg);
|
||||
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(msg);
|
||||
auto *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished,
|
||||
this, &OllieDBusClient::onFetchChatFinished);
|
||||
}
|
||||
|
||||
if (reply.type() != QDBusMessage::ReplyMessage) return;
|
||||
QList<QVariant> args = reply.arguments();
|
||||
if (args.size() < 2) return;
|
||||
void OllieDBusClient::onFetchChatFinished(QDBusPendingCallWatcher *watcher)
|
||||
{
|
||||
m_fetchChatPending = false;
|
||||
watcher->deleteLater();
|
||||
|
||||
QString text = args[0].toString();
|
||||
qlonglong newOffset = args[1].toLongLong();
|
||||
QDBusPendingReply<QString, qlonglong> reply = *watcher;
|
||||
if (reply.isError()) return;
|
||||
|
||||
QString text = reply.argumentAt<0>();
|
||||
qlonglong newOffset = reply.argumentAt<1>();
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
if (m_chatOffset == 0) {
|
||||
|
|
@ -138,6 +172,8 @@ void OllieDBusClient::fetchChat()
|
|||
}
|
||||
}
|
||||
|
||||
// --- Async fetch config ---
|
||||
|
||||
void OllieDBusClient::fetchConfig()
|
||||
{
|
||||
if (m_activeSessionId.isEmpty()) {
|
||||
|
|
@ -150,13 +186,20 @@ void OllieDBusClient::fetchConfig()
|
|||
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(SERVICE, OBJ_PATH, IFACE, "GetConfig");
|
||||
msg << m_activeSessionId;
|
||||
QDBusMessage reply = QDBusConnection::sessionBus().call(msg);
|
||||
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(msg);
|
||||
auto *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished,
|
||||
this, &OllieDBusClient::onFetchConfigFinished);
|
||||
}
|
||||
|
||||
if (reply.type() != QDBusMessage::ReplyMessage) return;
|
||||
QList<QVariant> args = reply.arguments();
|
||||
if (args.isEmpty()) return;
|
||||
void OllieDBusClient::onFetchConfigFinished(QDBusPendingCallWatcher *watcher)
|
||||
{
|
||||
watcher->deleteLater();
|
||||
|
||||
QString config = args[0].toString();
|
||||
QDBusPendingReply<QString> reply = *watcher;
|
||||
if (reply.isError()) return;
|
||||
|
||||
QString config = reply.value();
|
||||
QString newCwd;
|
||||
const QStringList lines = config.split('\n', Qt::SkipEmptyParts);
|
||||
for (const QString &line : lines) {
|
||||
|
|
@ -172,77 +215,63 @@ void OllieDBusClient::fetchConfig()
|
|||
}
|
||||
}
|
||||
|
||||
// --- User-initiated actions (fire-and-forget async) ---
|
||||
|
||||
QString OllieDBusClient::createSession(const QString &cwd)
|
||||
{
|
||||
QString dir = cwd.isEmpty() ? QDir::homePath() : cwd;
|
||||
QDBusReply<QString> reply = m_iface->call("CreateSession", dir, QString(), QString(), "default");
|
||||
if (reply.isValid()) {
|
||||
QString id = reply.value();
|
||||
refreshSessions();
|
||||
setActiveSessionId(id);
|
||||
return id;
|
||||
}
|
||||
return QString();
|
||||
// Use asyncCall — we'll pick up the new session via the SessionCreated signal
|
||||
m_iface->asyncCall("CreateSession", dir, QString(), QString(), QString("default"));
|
||||
return QString(); // ID not available synchronously; signal will trigger refresh
|
||||
}
|
||||
|
||||
bool OllieDBusClient::killSession(const QString &sessionId)
|
||||
{
|
||||
QDBusReply<bool> reply = m_iface->call("KillSession", sessionId);
|
||||
if (reply.isValid() && reply.value()) {
|
||||
if (sessionId == m_activeSessionId) {
|
||||
m_activeSessionId.clear();
|
||||
m_chatText.clear();
|
||||
m_chatOffset = 0;
|
||||
m_activeState = "idle";
|
||||
m_activeCwd.clear();
|
||||
emit activeSessionIdChanged();
|
||||
emit chatTextChanged();
|
||||
emit activeStateChanged();
|
||||
emit activeCwdChanged();
|
||||
}
|
||||
refreshSessions();
|
||||
return true;
|
||||
if (sessionId == m_activeSessionId) {
|
||||
m_activeSessionId.clear();
|
||||
m_chatText.clear();
|
||||
m_chatOffset = 0;
|
||||
m_activeState = "idle";
|
||||
m_activeCwd.clear();
|
||||
emit activeSessionIdChanged();
|
||||
emit chatTextChanged();
|
||||
emit activeStateChanged();
|
||||
emit activeCwdChanged();
|
||||
}
|
||||
return false;
|
||||
m_iface->asyncCall("KillSession", sessionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OllieDBusClient::renameSession(const QString &sessionId, const QString &newName)
|
||||
{
|
||||
QDBusReply<bool> reply = m_iface->call("RenameSession", sessionId, newName);
|
||||
if (reply.isValid() && reply.value()) {
|
||||
if (sessionId == m_activeSessionId) {
|
||||
m_activeSessionId = newName;
|
||||
emit activeSessionIdChanged();
|
||||
}
|
||||
refreshSessions();
|
||||
return true;
|
||||
if (sessionId == m_activeSessionId) {
|
||||
m_activeSessionId = newName;
|
||||
emit activeSessionIdChanged();
|
||||
}
|
||||
return false;
|
||||
m_iface->asyncCall("RenameSession", sessionId, newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OllieDBusClient::setConfig(const QString &sessionId, const QString &key, const QString &value)
|
||||
{
|
||||
QDBusReply<bool> reply = m_iface->call("SetConfig", sessionId, key, value);
|
||||
if (reply.isValid() && reply.value()) {
|
||||
if (sessionId == m_activeSessionId && key == "cwd") {
|
||||
m_activeCwd = value;
|
||||
emit activeCwdChanged();
|
||||
}
|
||||
return true;
|
||||
if (sessionId == m_activeSessionId && key == "cwd") {
|
||||
m_activeCwd = value;
|
||||
emit activeCwdChanged();
|
||||
}
|
||||
return false;
|
||||
m_iface->asyncCall("SetConfig", sessionId, key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OllieDBusClient::submit(const QString &sessionId, const QString &prompt)
|
||||
{
|
||||
QDBusReply<bool> reply = m_iface->call("Submit", sessionId, prompt);
|
||||
return reply.isValid() && reply.value();
|
||||
m_iface->asyncCall("Submit", sessionId, prompt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OllieDBusClient::interrupt(const QString &sessionId)
|
||||
{
|
||||
QDBusReply<bool> reply = m_iface->call("Interrupt", sessionId);
|
||||
return reply.isValid() && reply.value();
|
||||
m_iface->asyncCall("Interrupt", sessionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- D-Bus signal handlers ---
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <QObject>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QStringList>
|
||||
#include <QVariantList>
|
||||
#include <QTimer>
|
||||
|
|
@ -57,6 +58,10 @@ private slots:
|
|||
void onStateChanged(const QString &session_id, const QString &new_state);
|
||||
void onChatUpdated(const QString &session_id, qlonglong offset, const QString &new_text);
|
||||
|
||||
void onRefreshSessionsFinished(QDBusPendingCallWatcher *watcher);
|
||||
void onFetchChatFinished(QDBusPendingCallWatcher *watcher);
|
||||
void onFetchConfigFinished(QDBusPendingCallWatcher *watcher);
|
||||
|
||||
private:
|
||||
QDBusInterface *m_iface;
|
||||
QVariantList m_sessions;
|
||||
|
|
@ -66,7 +71,11 @@ private:
|
|||
QString m_activeState = "idle";
|
||||
QString m_activeCwd;
|
||||
|
||||
bool m_refreshPending = false;
|
||||
bool m_fetchChatPending = false;
|
||||
|
||||
void fetchConfig();
|
||||
void processSessionList(const QStringList &entries);
|
||||
};
|
||||
|
||||
#endif // OLLIE_DBUS_CLIENT_H
|
||||
|
|
|
|||
Reference in New Issue