Add Qt5/KDE based "application host" (systray icon, native notifications)
This commit is contained in:
parent
b8bc284c8d
commit
00281a1a0d
7 changed files with 365 additions and 19 deletions
194
yttui-qt5.cpp
Normal file
194
yttui-qt5.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
#include <QApplication>
|
||||
|
||||
#include <QIcon>
|
||||
#include <QMainWindow>
|
||||
#include <QMenu>
|
||||
#include <QMetaEnum>
|
||||
#include <QMetaObject>
|
||||
#include <QMouseEvent>
|
||||
#include <QString>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QThread>
|
||||
|
||||
#include <KParts/Part>
|
||||
#include <KParts/ReadOnlyPart>
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginLoader>
|
||||
#include <KService>
|
||||
|
||||
#include <kde_terminal_interface.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pty.h>
|
||||
|
||||
#include "application.h"
|
||||
|
||||
application_host *host = nullptr;
|
||||
|
||||
class AppThread: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
int app_fd;
|
||||
public:
|
||||
AppThread(int fd): QThread(), app_fd(fd){}
|
||||
~AppThread() = default;
|
||||
|
||||
friend bool app_quit(void*);
|
||||
protected:
|
||||
void run() override
|
||||
{
|
||||
run_embedded(app_fd, host);
|
||||
}
|
||||
};
|
||||
|
||||
class RightClickFilter: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if((event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if(mouseEvent->buttons() & Qt::RightButton) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(event->type() == QEvent::ContextMenu) {
|
||||
return true;
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
};
|
||||
|
||||
QObject* find_obj_by_classname(QObject *in, const char* name)
|
||||
{
|
||||
if(strcmp(name, in->metaObject()->className()) == 0)
|
||||
return in;
|
||||
|
||||
for(QObject *child: in->children())
|
||||
{
|
||||
QObject *maybe = find_obj_by_classname(child, name);
|
||||
if(maybe)
|
||||
return maybe;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class ApplicationWindow: public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QIcon icon;
|
||||
QSystemTrayIcon *systray = nullptr;
|
||||
KParts::ReadOnlyPart *terminal = nullptr;
|
||||
QWidget *konsole = nullptr;
|
||||
|
||||
public:
|
||||
ApplicationWindow(int fd);
|
||||
|
||||
void showMessage(const QString &title, const QString &message);
|
||||
|
||||
// QWidget interface
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
};
|
||||
|
||||
ApplicationWindow::ApplicationWindow(int fd): icon(":/icons/icon_0.png"), systray(new QSystemTrayIcon(icon, this))
|
||||
{
|
||||
setWindowTitle("yttui-qt5");
|
||||
setWindowIcon(icon);
|
||||
|
||||
KService::Ptr service = KService::serviceByDesktopName(QStringLiteral("konsolepart"));
|
||||
Q_ASSERT(service);
|
||||
KPluginFactory* factory = KPluginLoader(service->library()).factory();
|
||||
Q_ASSERT(factory);
|
||||
|
||||
terminal = factory->create<KParts::ReadOnlyPart>(this);
|
||||
if(!QMetaObject::invokeMethod(terminal, "openTeletype", Qt::AutoConnection, Q_ARG(int, fd), Q_ARG(bool, false))) {
|
||||
fputs("Failed to set KonsolePart PTY\n", stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
konsole = terminal->widget();
|
||||
setCentralWidget(konsole);
|
||||
|
||||
QObject *td = find_obj_by_classname(konsole, "Konsole::TerminalDisplay");
|
||||
if(td) {
|
||||
td->installEventFilter(new RightClickFilter());
|
||||
}
|
||||
|
||||
QMenu *systrayContextMenu = new QMenu(this);
|
||||
systrayContextMenu->addAction(QIcon::fromTheme("application-exit"), "Exit", QApplication::instance(), &QApplication::quit);
|
||||
|
||||
systray->setContextMenu(systrayContextMenu);
|
||||
connect(systray, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
|
||||
if(reason == QSystemTrayIcon::Trigger) {
|
||||
if(isVisible()) {
|
||||
hide();
|
||||
} else {
|
||||
show();
|
||||
}
|
||||
}
|
||||
});
|
||||
systray->show();
|
||||
}
|
||||
|
||||
void ApplicationWindow::showMessage(const QString &title, const QString &message)
|
||||
{
|
||||
systray->showMessage(title, message, icon);
|
||||
}
|
||||
|
||||
void ApplicationWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
QMainWindow::closeEvent(event);
|
||||
systray->hide();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
int term_fd = -1, app_fd = -1;
|
||||
if(openpty(&term_fd, &app_fd, 0, 0, 0)) {
|
||||
perror("openpty");
|
||||
}
|
||||
|
||||
ApplicationWindow window(term_fd);
|
||||
window.show();
|
||||
|
||||
bool app_quit = false;
|
||||
|
||||
AppThread appthread(app_fd);
|
||||
QObject::connect(&appthread, &AppThread::finished, [&] {
|
||||
window.close();
|
||||
});
|
||||
QObject::connect(&app, &QApplication::aboutToQuit, [&] {
|
||||
app_quit = true;
|
||||
appthread.wait();
|
||||
});
|
||||
|
||||
host = new application_host;
|
||||
host->quit = [&]{ return app_quit; };
|
||||
host->notify_channel_single_video = [&](const std::string &channel, const std::string &title) {
|
||||
window.showMessage(QStringLiteral("New video from %1").arg(QString::fromStdString(channel)), QString::fromStdString(title));
|
||||
};
|
||||
host->notify_channel_multiple_videos = [&](const std::string &channel, const int videos) {
|
||||
window.showMessage(QStringLiteral("New videos from %1").arg(QString::fromStdString(channel)),
|
||||
QStringLiteral("There are %1 new videos.").arg(QString::number(videos)));
|
||||
};
|
||||
host->notify_channels_multiple_videos = [&](const int channels, const int videos) {
|
||||
window.showMessage("New videos from multiple channels",
|
||||
QStringLiteral("There are %2 new videos from %1 channels.").arg(QString::number(channels), QString::number(videos)));
|
||||
};
|
||||
|
||||
appthread.start();
|
||||
int rc = app.exec();
|
||||
close(term_fd);
|
||||
close(app_fd);
|
||||
|
||||
delete host;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#include "yttui-qt5.moc"
|
Loading…
Add table
Add a link
Reference in a new issue