151 lines
4.9 KiB
C++
151 lines
4.9 KiB
C++
#include <QApplication>
|
|
#include <QQmlApplicationEngine>
|
|
#include <QQmlContext>
|
|
#include <QQuickStyle>
|
|
#include <QIcon>
|
|
#include <QPixmap>
|
|
#include <QPainter>
|
|
#include <QFont>
|
|
#include <QFontDatabase>
|
|
#include <QSystemTrayIcon>
|
|
#include <QMenu>
|
|
#include <QAction>
|
|
#include <QWindow>
|
|
|
|
#include "olliedbusclient.h"
|
|
#include "thememanager.h"
|
|
#include "chatblockmodel.h"
|
|
|
|
static QIcon makeBrainIcon()
|
|
{
|
|
// Use the theme icon if available (from hicolor scalable/apps/ollie.svg)
|
|
if (QIcon::hasThemeIcon("ollie"))
|
|
return QIcon::fromTheme("ollie");
|
|
|
|
// Fallback: render FA6 brain glyph from installed font
|
|
QFont fa("Font Awesome 6 Free Solid");
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
if (!QFontDatabase::hasFamily("Font Awesome 6 Free Solid")) {
|
|
#else
|
|
if (!QFontDatabase().families().contains("Font Awesome 6 Free Solid")) {
|
|
#endif
|
|
fa = QFont("Font Awesome 6 Free");
|
|
fa.setWeight(QFont::Black);
|
|
}
|
|
|
|
QIcon icon;
|
|
for (int size : {16, 22, 32, 48, 64, 128}) {
|
|
QPixmap pix(size, size);
|
|
pix.fill(Qt::transparent);
|
|
QPainter p(&pix);
|
|
fa.setPixelSize(size - 2);
|
|
p.setFont(fa);
|
|
p.setPen(QColor(0xe9, 0x1e, 0x63));
|
|
p.drawText(pix.rect(), Qt::AlignCenter, QString(QChar(0xf5dc)));
|
|
p.end();
|
|
icon.addPixmap(pix);
|
|
}
|
|
return icon;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
// HiDPI support
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
#endif
|
|
QApplication::setHighDpiScaleFactorRoundingPolicy(
|
|
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
|
|
QApplication app(argc, argv);
|
|
app.setApplicationName("ollie-gui");
|
|
app.setDesktopFileName("org.ollie.gui");
|
|
app.setOrganizationName("ollie");
|
|
app.setWindowIcon(makeBrainIcon());
|
|
|
|
// Don't force org.kde.desktop style — it ignores explicit palette overrides.
|
|
// Let the platform theme provide the style, or fall back to Basic which
|
|
// properly respects the QML palette {} block.
|
|
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE"))
|
|
QQuickStyle::setStyle("Basic");
|
|
|
|
// Theme manager — reads KDE color schemes, applies palette
|
|
auto *theme = new ThemeManager(&app);
|
|
|
|
QQmlApplicationEngine engine;
|
|
|
|
// Register OllieDBusClient as a singleton
|
|
auto *dbus = new OllieDBusClient(&app);
|
|
auto *chatModel = new ChatBlockModel(&app);
|
|
engine.rootContext()->setContextProperty("dbus", dbus);
|
|
engine.rootContext()->setContextProperty("theme", theme);
|
|
engine.rootContext()->setContextProperty("chatModel", chatModel);
|
|
engine.rootContext()->setContextProperty("systemTrayAvailable",
|
|
QSystemTrayIcon::isSystemTrayAvailable());
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
const QUrl url(QStringLiteral("qrc:/gui/main.qml"));
|
|
#else
|
|
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
|
#endif
|
|
|
|
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
|
&app, [url](QObject *obj, const QUrl &objUrl) {
|
|
if (!obj && url == objUrl)
|
|
QCoreApplication::exit(-1);
|
|
}, Qt::QueuedConnection);
|
|
|
|
engine.load(url);
|
|
|
|
// --- System tray icon (shown when close-to-tray is enabled) ---
|
|
auto *trayIcon = new QSystemTrayIcon(&app);
|
|
trayIcon->setIcon(app.windowIcon());
|
|
trayIcon->setToolTip("Ollie");
|
|
|
|
auto *trayMenu = new QMenu();
|
|
auto *showAction = trayMenu->addAction("Show");
|
|
trayMenu->addSeparator();
|
|
auto *quitAction = trayMenu->addAction("Quit");
|
|
trayIcon->setContextMenu(trayMenu);
|
|
|
|
// Toggle window visibility on tray icon activation
|
|
QObject::connect(trayIcon, &QSystemTrayIcon::activated,
|
|
[&engine](QSystemTrayIcon::ActivationReason reason) {
|
|
if (reason != QSystemTrayIcon::Trigger)
|
|
return;
|
|
auto roots = engine.rootObjects();
|
|
if (roots.isEmpty()) return;
|
|
auto *window = qobject_cast<QWindow *>(roots.first());
|
|
if (!window) return;
|
|
if (window->isVisible()) {
|
|
window->hide();
|
|
} else {
|
|
window->show();
|
|
window->raise();
|
|
window->requestActivate();
|
|
}
|
|
});
|
|
|
|
QObject::connect(showAction, &QAction::triggered, [&engine]() {
|
|
auto roots = engine.rootObjects();
|
|
if (roots.isEmpty()) return;
|
|
auto *window = qobject_cast<QWindow *>(roots.first());
|
|
if (!window) return;
|
|
window->show();
|
|
window->raise();
|
|
window->requestActivate();
|
|
});
|
|
|
|
QObject::connect(quitAction, &QAction::triggered, &app, &QApplication::quit);
|
|
|
|
// Show/hide tray icon based on setting
|
|
auto updateTrayVisibility = [trayIcon, theme]() {
|
|
trayIcon->setVisible(theme->closeToTray());
|
|
};
|
|
updateTrayVisibility();
|
|
QObject::connect(theme, &ThemeManager::closeToTrayChanged, updateTrayVisibility);
|
|
|
|
return app.exec();
|
|
}
|