ollie/kde/gui/main.cpp

129 lines
4.4 KiB
C++

// ollie-gui-9p: minimal Qt GUI using 9P for all communication.
// Uses ollie-9p subprocess for 9P transport.
#include <QApplication>
#include <QIcon>
#include <QMenu>
#include <QSystemTrayIcon>
#include <QAction>
#include <QQuickWindow>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickStyle>
#include <QStandardPaths>
#include <QUrl>
#include "ollie9pclient.h"
#include "sessionmodel.h"
#include "chatblockmodel.h"
#include "thememanager.h"
#include "clipboardhelper.h"
#include "plumber.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
QApplication app(argc, argv);
app.setApplicationName("ollie-gui");
// Locate the installed octopus SVG (user-local takes priority over system).
// Falls back to the Qt resource if not found on disk.
QIcon appIcon;
QString iconPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
QStringLiteral("icons/hicolor/scalable/apps/ollie.svg"));
if (!iconPath.isEmpty())
appIcon = QIcon(iconPath);
else
appIcon = QIcon(QStringLiteral(":/ollie.svg"));
app.setWindowIcon(appIcon);
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE"))
QQuickStyle::setStyle("Basic");
QQmlApplicationEngine engine;
auto *ollie = new Ollie9pClient(&app);
auto *sessionModel = new SessionModel(ollie, &app);
auto *chatModel = new ChatBlockModel(&app);
auto *theme = new ThemeManager(&app);
auto *clipboard = new ClipboardHelper(&app);
auto *plumber = new Plumber(&app);
QObject::connect(ollie, &Ollie9pClient::chatReceived,
chatModel, &ChatBlockModel::appendData);
// Handle ollie:// URLs from plumber — fetch block and display in chat
QObject::connect(plumber, &Plumber::ollieMessage, [ollie, chatModel](const QString &url) {
// Parse ollie://session/agent#blockid
QUrl parsed(url);
if (parsed.scheme() != QStringLiteral("ollie"))
return;
QString path = parsed.path();
if (path.startsWith('/'))
path = path.mid(1);
QStringList parts = path.split('/');
if (parts.size() < 2)
return;
QString sessionId = parts.value(0);
QString agentId = parts.value(1);
QString blockId = parsed.fragment();
if (blockId.isEmpty())
return;
QString block = ollie->fetchBlock(sessionId, agentId, blockId);
if (!block.isEmpty())
chatModel->appendData(block);
});
engine.rootContext()->setContextProperty("ollie", ollie);
engine.rootContext()->setContextProperty("sessionModel", sessionModel);
engine.rootContext()->setContextProperty("chatModel", chatModel);
engine.rootContext()->setContextProperty("theme", theme);
engine.rootContext()->setContextProperty("clipboard", clipboard);
engine.rootContext()->setContextProperty("plumber", plumber);
const QUrl url(QStringLiteral("qrc:/main.qml"));
engine.load(url);
if (engine.rootObjects().isEmpty())
return -1;
auto *window = qobject_cast<QQuickWindow *>(engine.rootObjects().constFirst());
auto *trayIcon = new QSystemTrayIcon(appIcon, &app);
auto *trayMenu = new QMenu;
auto *showAction = trayMenu->addAction("Show Ollie");
trayMenu->addSeparator();
auto *quitAction = trayMenu->addAction("Quit");
trayIcon->setContextMenu(trayMenu);
trayIcon->setToolTip("Ollie");
engine.rootContext()->setContextProperty("trayIcon", trayIcon);
// Start plumber reader for ollie port
plumber->startReader();
QObject::connect(showAction, &QAction::triggered, [window, trayIcon]() {
window->show();
window->raise();
window->requestActivate();
trayIcon->show();
});
QObject::connect(quitAction, &QAction::triggered, [window, &app]() {
window->setProperty("quitting", true);
app.quit();
});
QObject::connect(trayIcon, &QSystemTrayIcon::activated,
[showAction](QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger)
showAction->trigger();
});
QObject::connect(theme, &ThemeManager::closeToTrayChanged,
[theme, trayIcon]() { trayIcon->setVisible(theme->closeToTray()); });
trayIcon->setVisible(theme->closeToTray());
return app.exec();
}