This repository has been archived on 2026-08-16. You can view files and clone it, but cannot push or open issues or pull requests.
ollie-kde/tray/ollie_tray.cpp

135 lines
3.8 KiB
C++

#include "ollie_tray.h"
#include <QApplication>
#include <QDir>
#include <QStandardPaths>
static QString ninepBin()
{
QString bin = QStandardPaths::findExecutable("9p");
if (!bin.isEmpty()) return bin;
QString plan9 = qEnvironmentVariable("PLAN9");
if (!plan9.isEmpty() && QFileInfo::exists(plan9 + "/bin/9p"))
return plan9 + "/bin/9p";
return "9p";
}
OllieTray::OllieTray(QObject *parent)
: QObject(parent)
{
m_sni = new KStatusNotifierItem("ollie-kde", this);
m_sni->setCategory(KStatusNotifierItem::ApplicationStatus);
m_sni->setTitle("Ollie");
m_sni->setIconByName("system-run");
m_sni->setStatus(KStatusNotifierItem::Active);
connect(m_sni, &KStatusNotifierItem::activateRequested, this, &OllieTray::openGui);
setupMenu();
refreshSessions();
// Poll session state every 5 seconds (lightweight — single 9p read)
m_pollTimer = new QTimer(this);
connect(m_pollTimer, &QTimer::timeout, this, &OllieTray::refreshSessions);
m_pollTimer->start(5000);
}
OllieTray::~OllieTray()
{
}
QString OllieTray::serverAddr()
{
QString ns = qEnvironmentVariable("NAMESPACE");
if (ns.isEmpty()) {
QString user = qEnvironmentVariable("USER");
QString display = qEnvironmentVariable("DISPLAY");
ns = "/tmp/ns." + user + "." + display;
}
return "unix!" + ns + "/ollie";
}
QByteArray OllieTray::run9p(const QStringList &args)
{
QProcess proc;
QStringList fullArgs = {"-a", serverAddr()};
fullArgs.append(args);
proc.start(ninepBin(), fullArgs);
if (!proc.waitForFinished(5000)) return {};
return proc.readAllStandardOutput();
}
void OllieTray::write9p(const QString &path, const QByteArray &data)
{
QProcess proc;
proc.start(ninepBin(), {"-a", serverAddr(), "write", path});
proc.waitForStarted(3000);
proc.write(data);
proc.closeWriteChannel();
proc.waitForFinished(3000);
}
void OllieTray::setupMenu()
{
m_menu = new QMenu();
m_sessionsMenu = m_menu->addMenu("Sessions");
m_menu->addSeparator();
m_menu->addAction("Open GUI", this, &OllieTray::openGui);
m_menu->addAction("Stop All", this, &OllieTray::stopAll);
m_menu->addSeparator();
m_menu->addAction("Quit", qApp, &QApplication::quit);
m_sni->setContextMenu(m_menu);
}
void OllieTray::refreshSessions()
{
QByteArray out = run9p({"read", "session/idx"});
QString raw = QString::fromUtf8(out).trimmed();
m_sessionsMenu->clear();
if (raw.isEmpty()) {
m_sessionsMenu->addAction("(no sessions)")->setEnabled(false);
m_sni->setToolTip("system-run", "Ollie", "No active sessions");
return;
}
QStringList lines = raw.split('\n');
int active = 0;
for (const QString &line : lines) {
QStringList parts = line.split('\t');
if (parts.size() < 2) continue;
QString id = parts[0];
QString state = parts[1];
if (state != "idle") active++;
QString label = (state == "idle" ? "○ " : "● ") + id;
m_sessionsMenu->addAction(label);
}
m_sni->setToolTip("system-run", "Ollie",
QString("%1 sessions, %2 active").arg(lines.size()).arg(active));
}
void OllieTray::openGui()
{
QProcess::startDetached("ollie-gui", {});
}
void OllieTray::stopAll()
{
QByteArray out = run9p({"read", "session/idx"});
QString raw = QString::fromUtf8(out).trimmed();
for (const QString &line : raw.split('\n')) {
QStringList parts = line.split('\t');
if (parts.size() < 2 || parts[1] == "idle") continue;
QString id = parts[0];
// Find agent, send stop
QByteArray agentOut = run9p({"ls", "session/" + id + "/agent"});
QString agentId = QString::fromUtf8(agentOut).trimmed().split('\n').value(0);
if (!agentId.isEmpty())
write9p("session/" + id + "/agent/" + agentId + "/ctl", "stop");
}
}