// Chatter — Qt Quick app with a direct-framebuffer ink pipeline. // Pen strokes are drawn straight into the e-paper framebuffer (captured by // FbCapture) and refreshed with an explicit solid swap (InkEngine). Qt Quick is // used only for the static UI (Back / Clear). This is what gives stock-quality // solid, low-latency ink — the Qt scene graph can't. #include #include #include #include #include #include #include #include #include #include "PenDevice.h" #include "AppControl.h" #include "InkEngine.h" #include "FbCapture.h" // links the setBuffers interposer into the executable struct PenStyle { int type = 2; qreal size = 2.0; QColor color = Qt::black; }; // Read the pen the user last selected in the standard GUI (xochitl.conf, // [General]/LastWritingTool — flushed when xochitl stops, i.e. on Back). static PenStyle readPenStyle() { PenStyle ps; QSettings xs(QStringLiteral("/home/root/.config/remarkable/xochitl.conf"), QSettings::IniFormat); const QVariantMap t = xs.value(QStringLiteral("LastWritingTool")).toMap(); if (t.isEmpty()) { qWarning("readPenStyle: LastWritingTool unreadable; using defaults"); return ps; } ps.type = t.value("LastPen").toInt(); ps.size = t.value("LastPenSize").toDouble(); const uint code = t.value("LastPenColorCode").toUInt(); if (code != 0) ps.color = QColor::fromRgba(QRgb(code)); qInfo("readPenStyle: pen=%d size=%.2f color=%s", ps.type, ps.size, qPrintable(ps.color.name(QColor::HexArgb))); return ps; } int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); const PenStyle penStyle = readPenStyle(); const QSize screen = app.primaryScreen()->geometry().size(); PenDevice pen(screen.width(), screen.height()); AppControl appControl; InkEngine ink; ink.setInkColor(penStyle.color); // reMarkable exposes only the size CATEGORY (LastPenSize 1/2/3 = // thin/thicker/thickest). Calibrate to measured widths on this 264-PPI panel: // thicker ~1mm, thickest ~2mm, thinnest ~2px. px/mm = 264/25.4 ~= 10.4. constexpr double pxPerMm = 264.0 / 25.4; const double maxMm = qMax(0.2, (penStyle.size - 1.0) * 1.0); // sz3->2mm, sz2->1mm ink.setWidthRange(2.0, maxMm * pxPerMm); ink.setPenType(penStyle.type); // Back button (finger or stylus) → return to the standard GUI. QObject::connect(&ink, &InkEngine::backRequested, &appControl, &AppControl::returnToStandard); // Pen drives the ink engine directly (no QML in the ink loop). QObject::connect(&pen, &PenDevice::strokeStart, &ink, &InkEngine::strokeStart); QObject::connect(&pen, &PenDevice::strokeMove, &ink, &InkEngine::strokeMove); QObject::connect(&pen, &PenDevice::strokeEnd, &ink, &InkEngine::strokeEnd); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("appControl", &appControl); engine.rootContext()->setContextProperty("ink", &ink); QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("Chatter", "Main"); return app.exec(); }