From 9b88f3ce47d090df167263ce2b4b6b430694da72 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Thu, 4 Jun 2020 11:39:41 +0200 Subject: [feat] add qt gui Signed-off-by: kali kaneko (leap communications) --- gui/main.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 gui/main.cpp (limited to 'gui/main.cpp') diff --git a/gui/main.cpp b/gui/main.cpp new file mode 100644 index 0000000..f2545d3 --- /dev/null +++ b/gui/main.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include + +#include "handlers.h" +#include "qjsonmodel.h" +#include "lib/libgoshim.h" + +/* Hi! I'm Troy McClure and I'll be your guide today. You probably remember me + from blockbusters like "here be dragons" and "darling, I wrote a little + contraption". */ + +/* Our glorious global object state. In here we store a serialized snapshot of + the context from the application "backend", living in the linked Go-land + lib. */ + +static char *json; + +/* We are interested in observing changes to this global json variable. + The jsonWatchdog bridges the gap from pure c callbacks to the rest of the c++ + logic. QJsonWatch comes from QObject so it can emit signals. */ + +QJsonWatch *qw; + +struct jsonWatchdog { + jsonWatchdog() { qw = new QJsonWatch; } + void changed() { emit qw->jsonChanged(QString(json)); } +}; + +/* we need C wrappers around every C++ object, so that we can invoke their methods + from the function pointers passed as callbacks to CGO. */ +extern "C" { +static void *newWatchdog(void) { return (void *)(new jsonWatchdog); } +static void jsonChanged(void *ptr) { + if (ptr != NULL) { + jsonWatchdog *klsPtr = static_cast(ptr); + klsPtr->changed(); + } +} +} + +void *wd = newWatchdog(); + +/* onStatusChanged is the C function that we register as a callback with CGO, + to be called from the Go side. It pulls a string serialization of the + context object, than we then pass along to Qt objects and to Qml. */ +void onStatusChanged() { + char *ctx = RefreshContext(); + json = ctx; + /* the method wrapped emits a qt signal */ + jsonChanged(wd); + free(ctx); +} + +std::string getEnv(std::string const& key) +{ + char const* val = getenv(key.c_str()); + return val == NULL ? std::string() : std::string(val); +} + +int main(int argc, char **argv) { + + bool debugQml = getEnv("DEBUG_QML_DATA") == "yes"; + + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication app(argc, argv); + app.setQuitOnLastWindowClosed(false); + QQmlApplicationEngine engine; + QQmlContext *ctx = engine.rootContext(); + + QJsonModel *model = new QJsonModel; + std::string json = R"({"appName": "unknown", "provider": "unknown"})"; + model->loadJson(QByteArray::fromStdString(json)); + + /* the backend handler has slots for calling back to Go when triggered by + signals in Qml. */ + Backend backend; + ctx->setContextProperty("backend", &backend); + + /* set the json model, load the qml */ + ctx->setContextProperty("jsonModel", model); + ctx->setContextProperty("debugQml", debugQml); + + engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); + + /* connect the jsonChanged signal explicitely. + In the lambda, we reload the json in the model every time we receive an + update from Go */ + QObject::connect(qw, &QJsonWatch::jsonChanged, [ctx, model](QString js) { + model->loadJson(js.toUtf8()); + }); + + /* connect quitDone signal, exit app */ + QObject::connect(&backend, &Backend::quitDone, []() { + QGuiApplication::quit(); + }); + + /* register statusChanged callback with CGO */ + const char *stCh = "OnStatusChanged"; + GoString statusChangedEvt = {stCh, (long int)strlen(stCh)}; + SubscribeToEvent(statusChangedEvt, (void *)onStatusChanged); + + /* let the Go side initialize its internal state */ + InitializeBitmaskContext(); + + /* kick off your shoes, put your feet up */ + return app.exec(); +} -- cgit v1.2.3