xournal-qt architecture

Overview (README) · architecture.yaml
xournal-qt architecture The layers of xournal-qt, from the QML UI down to the Xournal++ core it builds on, and the edges between their blocks. Generated from qt/docs/architecture/architecture.yaml. xournal-qt: architecture Click a block for its responsibility, key files and edges. Dependencies point down. xournal-qt · qt/ qt/compat Xournal++ · src/ The whole user interface, in QML: one window per Main.qml, its parts each in a file of its own. QML talks to C++ only through the context properties app (an AppController) and win, the types registered under XournalQt.Canvas, the image providers and the list models. What the windows of the process share (AppServices), one window's QML API (AppController) and the program's start (main.cpp). Compiled into xqt-shell (the C++) and xournal-qt (main.cpp). Everything between the documents and the QML that is not a canvas: the library, the tabs, what acts on a canvas, the image providers and their caches, the list and settings models. One target, xqt-shell. A document shown in a view (canvas), the view in the Qt Quick scene graph (quick), and handwriting search (hwr), which reads the ink of the sessions. One open document without a view (session), and what it builds on: the Markdown engine, recordings, and the Qt-free render workers. The CLI and the tests use these without a window. Headers with upstream's names placed before upstream's include paths, so upstream's files compile without GTK and without edits: shadows of the GTK application classes (implemented by the fork), a GTK type shim, and GTK-free implementations of a few upstream files. Upstream Xournal++'s C++ core, compiled unmodified (apart from the seams of ADR 0002) from the explicit list in qt/cmake/XojSources.cmake into three static libraries: xoj-util, xoj-core and xoj-tools. Upstream's GTK GUI is not built. The headless CLI, the tests, the developer tools, the vendored libraries, the platform layers and CI. The files both programs read and write. A document written by xournal-qt opens in Xournal++ and the other way round; the fork's own attributes are ones Xournal++ ignores. Window → AppController (qml): every action and property through the context property app (QmlApiTest checks the names) Canvas chrome → AppController (qml): the tabs, the tools, app.edit (a CanvasActions) Canvas chrome → quick (qml): the DocumentCanvas item (import XournalQt.Canvas), AdaptiveLayout, TouchGestures Canvas chrome → Pictures and caches (qml): image://thumbnail and image://sketch in the sidebar and page grid Home and library → Library (qml): the library's list models (app.library, recent files, bookmarks, to-dos, tags) Home and library → Pictures and caches (qml): image://cover, image://hitpage, image://mdsnippet Settings → Models and settings (qml): SettingsModel, ShortcutsModel, ToolboxModel Dialogs and sheets → AppController (qml): the dialogs' actions through app Window → Canvas chrome (calls): Main.qml instantiates the parts Window → Home and library (calls): Main.qml instantiates the home view main and EngineSetup → Window (qml): loads the QML module XournalQt and its Main main and EngineSetup → AppServices (calls): makes the services before the first window, drops them after the last main and EngineSetup → quick (links): xournal-qt links xqt-quick (registers XournalQt.Canvas) main and EngineSetup → Pictures and caches (calls): EngineSetup registers the image providers AppServices → AppController (calls): the window factory makes one AppController per window AppServices → Library (calls): owns the library, its lists and the library's ink job AppServices → session (calls): owns the AppContext (settings, tool, render workers) AppServices → hwr (calls): owns the handwriting search AppController → CurrentDocument (calls): follows the current tab AppController → Tabs and canvas actions (calls): TabManager (its tabs), CanvasActions (app.edit), ReferenceMode, PresenterConsole AppController → Models and settings (calls): the per-document lists and the settings models AppController → audio (calls): AudioControl records and plays (app.audio) AppController → control (calls): upstream's Settings (the xournalQt part) and the ToolHandler CurrentDocument → session (calls): relays the current DocumentSession's signals CurrentDocument → canvas (calls): relays the current CanvasView's signals Tabs and canvas actions → canvas (links): xqt-shell links xqt-canvas: a tab owns its CanvasView, CanvasActions acts on one Tabs and canvas actions → session (calls): a tab owns its DocumentSession; SessionRecovery saves every tab Library → hwr (links): xqt-shell links xqt-hwr: LibraryInkJob reads the library's handwriting Library → session (calls): reads documents for the index (DocumentTextIndex, Tags, the PDF formats) Library → Library folder (data): the folder, its index and packs Pictures and caches → render (calls): RegionRender for pictures of areas Pictures and caches → view (calls): draws thumbnails and covers with DocumentView (as upstream's PreviewJob) Pictures and caches → pdf (calls): draws PDF pages for covers and hit pages Pictures and caches → Caches (data): stand-ins and covers on disk, named by page revision Models and settings → session (calls): pages, outline, layers, annotations, versions of a session Models and settings → control (calls): settings.xml through upstream's Settings; layers through LayerController Models and settings → settings.xml (data): the settings page writes settings.xml quick → canvas (links): xqt-quick links xqt-canvas: DocumentCanvasItem shows a CanvasView and passes it all input hwr → session (links): xqt-hwr links xqt-session: an indexer per open document reads its strokes canvas → session (links): xqt-canvas links xqt-session: a view shows a session; edits go through its undo canvas → render (calls): PageRaster per visible page, rendered by the RenderService's workers canvas → Tools and handlers (links): xqt-canvas links xoj-tools: CanvasPage drives StrokeHandler, EraseHandler, EditSelection, the shape handlers canvas → Shadow headers (shadows): CanvasPage implements XojPageView (gui/PageView.h); CanvasView implements XournalView and Layout; ViewController feeds ZoomControl canvas → undo (calls): upstream's undo actions for edits made outside the tools (groups, notes, page resize) canvas → model (calls): pages, layers and elements under the document lock canvas → control (calls): ToolHandler, LayerController, the shape recogniser, the settings AppController → plugins (links): xqt-shell links xqt-plugins: PluginControl runs a window's plugin commands, AppServices holds the host CLI → plugins (links): xournal-qt-cli plugin run: a plugin's command on documents without a window (qt/cli/PluginRun.cpp) plugins → ops (links): xqt-plugins links xqt-ops: every API call is an operation checked for the plugin ops → session (links): xqt-ops links xqt-session: operations act on a DocumentSession, a transaction is an UndoGathering ops → markdown (calls): Markdown boxes measured as drawn (labels placed by an anchor) ops → undo (calls): upstream's undo actions (InsertsUndoAction, DeleteUndoAction, InsertLayerUndoAction, …) for every change session → undo (seam): the undo stack's sink: UndoGathering gathers a command's steps into one SequenceUndoAction session → render (links): xqt-session links xoj-render: render workers in AppContext, drawing for exports session → markdown (links): xqt-session links xqt-markdown: text documents, Markdown boxes in exports session → audio (links): xqt-session links xqt-audio: recordings tied to elements session → control/xojfile (calls): loads with LoadHandler and saves with SaveHandler (in the background, on a page copy) session → control/xojfile (seam): the fork's attributes (xqt-group, xqt-created, xqt-data, xqt-bookmark, xqt-audio, xqt-fill-color, notespace); a document loaded from memory (an encrypted PDF's .xopp) session → undo (calls): one UndoRedoHandler per session, plus one for page order session → model (calls): the Document it owns; listens to its changes session → model (seam): Document::setDocumentHandler, setPdfPassword, DocumentOutline; NoteSpace, page bookmarks, groups and times of elements session → view (seam): StickyNote draws a note's layer (xoj::view::layerDrawer); PageMargins scales ruled paper (xoj::view::ruledScale) session → util (seam): AppContext sets the UI-thread dispatcher (Util::setUiThreadDispatcher) session → pdf (calls): opens PDFs and exports them (the PDF with notes builds on the cairo export) session → control (calls): Settings and ToolHandler in AppContext; LayerController; PdfCache session → Shadow headers (shadows): DocumentSession implements Control; HeadlessViews implement MainWindow, XournalView; SessionActions implements ActionDatabase session → .xopp / .xoj files (data): opens and saves documents (atomically, through FileIo) session → PDF files (data): annotates PDFs; writes the PDF with notes markdown → model (seam): MdBox registers xoj::markdown::renderer, sizer and layoutPainter (model/MarkdownText.h), so Text and TextView draw Markdown markdown → view (seam): TextView draws a Markdown text through the registered renderer; the emoji through layoutPainter markdown → Vendored libraries (links): md4c, MicroTeX audio → model (calls): the ts/fn of strokes and texts, a page's voice memos; an undo action audio → Vendored libraries (links): libogg, libvorbis hwr → Vendored libraries (calls): ONNX Runtime's C API, loaded at run time render → view (calls): draws with DocumentView, LayerView and the background views, as upstream's RenderJob render → view (seam): PaperTexture wraps backgrounds (xoj::view::backgroundDecorator) render → pdf (calls): PDF backgrounds drawn outside the document lock (PdfCache, poppler) render → model (calls): reads pages under std::shared_lock Tools and handlers → Shadow headers (shadows): the handlers call Control, XojPageView, ZoomControl, … through the shadow headers undo → Shadow headers (shadows): undo actions reach the views through Control control → Shadow headers (shadows): LayerController calls Control Shadow headers → GTK GUI (not built) (shadows): stand in for the GTK classes Control, MainWindow, XournalView, XojPageView, Layout (not built) GTK-free sources → util (shadows): compiled into xoj-util in place of upstream's XojMsgBox.cpp and VersionInfo.cpp (DeviceId.cpp into xoj-tools) GTK shim → GTK GUI (not built) (shadows): <gtk/gtk.h> and <gdk/gdk.h> of every xoj-* target resolve to the shim: GDK/GTK types without GTK Tools and handlers → model (links): xoj-tools links xoj-core: the handlers make and change elements Tools and handlers → undo (calls): every finished stroke or edit is an undo action view → model (calls): draws pages, layers and elements view → pdf (calls): PdfBackgroundView draws a PDF page through PdfCache control/xojfile → model (calls): builds and walks the Document undo → model (calls): changes the model model → util (links): xoj-core links xoj-util control/xojfile → .xopp / .xoj files (data): the format's reader and writer control → settings.xml (data): Settings reads and writes settings.xml GTK GUI (not built) → .xopp / .xoj files (data): Xournal++ itself opens the same files CLI → session (links): xournal-qt-cli links xqt-session: the PDF with notes and the archive PDF CLI → hwr (links): xournal-qt-cli links xqt-hwr: handwriting as text in exports; hwr-lines, hwr-form, hwr-bench CLI → control/xojfile (calls): loads documents as upstream's CLI does CLI → pdf (calls): PDF export with upstream's flags CLI → control (calls): PNG/SVG export (ImageExport) Tests → session (calls): one test binary per module, label per module Tests → Upstream tests (data): the fixtures in test/files (read only) Upstream tests → model (calls): upstream's suites run against the Qt-free core Upstream tests → render (links): xoj-unit-tests links xoj-render: the fork's PageRasterTest and RegionRenderTest run in the same binary Build and tools → GTK GUI (not built) (calls): XojSources.cmake lists what of src/ is built (GTK parts not) Android → main and EngineSetup (calls): AndroidSetup before the core starts; the activity hosts the app Windows → main and EngineSetup (calls): WindowsSetup, WindowsFonts before the core starts Linux → main and EngineSetup (calls): installs the program with its desktop files and MIME types; the .deb macOS → main and EngineSetup (calls): the app bundle around the program CI → Linux (calls): xqt-release.yml builds the packages; xqt-android, xqt-windows, xqt-macos the other platforms CI → Tests (calls): builds and runs the suite (xqt-build, xqt-block-tests) QT QUICK UI (QML)APP (C++ BEHIND THE UI)SHELL (LIBRARY, TABS, MODELS)CANVAS AND VIEWSDOCUMENTS, HEADLESSQT/COMPAT (THE GTK STAND-INS)XOURNAL++ CORE (SRC/, UPSTREAM)AROUND THE APPSHARED DATA Window: The window (win): its state objects (insets, view modes, chrome layout), its keys with the one ordered Esc/Back dispatcher, and the parts it instantiates.WindowMain.qml and its statexqt-ui Canvas chrome: What surrounds the canvas: the tab strip, the toolbox and top bar, the pills over the page (selection, note, view), the page sidebar and the page area that hosts the DocumentCanvas item.Canvas chrometoolbox, tabs, pills, sidebarxqt-ui Home and library: The home screen: the library grid, recent files, bookmarks, to-dos and tags, the library's search and its file operations.Home and libraryHomeView and its partsxqt-ui Settings: The settings page: one section per file (pen, touch, documents, display, search, storage, shortcuts, help) and the row types they are built of.SettingsSettingsPage, Settings*.qmlxqt-ui Dialogs and sheets: Dialogs, menus and sheets that adapt from a desktop window to a phone (a dialog on a desktop, a sheet from the bottom on a phone), and the dialogs built on them.Dialogs and sheetsadaptive dialogs, menusxqt-ui main and EngineSetup: Starts the program: the platform's setup, the AppServices, the QML engine with its image providers and the context property app, then the main window from the QML module XournalQt.main and EngineSetupstart, engine, windowxournal-qt AppServices: One per process: owns AppContext, the library and its lists, the toolbox, shortcuts, handwriting search, the window factory, the open documents of every window and the background jobs quitting waits for.AppServiceswhat the windows sharexqt-shell AppController: One window's QML API, the context property app: its tabs, the current document's properties and every action the UI offers; the App*.cpp files beside it hold one area each.AppControllerone window's QML API appxqt-shell CurrentDocument: The current tab's DocumentSession and CanvasView with their signals relayed in one place; a window follows a tab change with one call.CurrentDocumentthe current tab, relayedxqt-shell Tabs and canvas actions: The window's controllers: the tabs (each owns its session and view), what acts on one canvas, the reference view, version comparison, the presenter console, recovery after a crash.Tabs and canvas actionsTabManager, CanvasActionsxqt-shell Library: The library: a plain folder of documents, its index of every document's text and notes, its search, file operations, sharing and archives, and the list models of the home screen.Libraryfolder, index, searchxqt-shell Pictures and caches: The QML image providers (thumbnails, sketches, covers, hit pages, snippets, annotation pictures), their caches with one owner of their memory and one owner of their worker threads.Pictures and cachesimage providers, ImageMemoryxqt-shell Models and settings: The list models of one document (pages, outline, layers, annotations, versions) and the settings-like models (settings.xml's keys, shortcuts, the toolbox, palettes).Models and settingslist and settings modelsxqt-shell quick: The bridge between a CanvasView and the Qt Quick scene graph: page tiles as scene graph nodes, an event filter that takes all canvas input, dark pages on the GPU, the window's size class.quickthe canvas in the scene graphxqt-quick canvas: A DocumentSession shown in a view: the visible pages and their rendering, the input on them (pen, touch, mouse, palm rejection), and the tools and editors that work on a page. Qt Gui, no Qt Quick.canvasa document in a view; input, toolsxqt-canvas hwr: Reads handwriting in the background (ONNX Runtime, loaded at run time) so the search finds it; the ink is never converted.hwrhandwriting searchxqt-hwr audio: Records and plays Ogg Vorbis, compatible with Xournal++'s audio (a stroke tied to a moment of a recording).audiorecording and playingxqt-audio markdown: Parses (md4c), lays out (Pango), paginates and draws (cairo) Markdown text, with the same text stack as upstream's text elements; registers the renderer upstream's TextView asks for Markdown texts.markdownMarkdown enginexqt-markdown session: One open document without a view: load, new, save in the background, autosave, undo, page revisions; the fork's formats (the PDF with notes, incremental saves, version history), search; process-wide AppContext.sessionone open document, headlessxqt-session plugins: The plugins of the process: one QJSEngine per plugin with the frozen API module "xournal", commands run for a window as one transaction of the operations layer, permissions asked on first use, a watchdog (ADR 0008).pluginsJavaScript pluginsxqt-plugins ops: Every change a plugin (later a remote peer or an agent) makes to a document: an operation of the collaboration vocabulary, checked against what its principal may do, applied with undo, one undo step per transaction or rolled back (ADR 0008).opschecked operationsxqt-ops render: Turns a page of upstream's model into pixels with upstream's views and cairo, on worker threads; Qt-free, so the CLI and the tests use it too.renderpages drawn by wo…xoj-render GTK-free sources: GTK-free implementations of a few upstream headers, compiled into xoj-util and xoj-tools instead of upstream's: message boxes through a pluggable sink (QML dialogs in the app, stderr in the CLI), the version, device identity.GTK-free sourcesXojMsgBox, VersionInfo, DeviceIdqt/compat/XojMsgBox.cpp Shadow headers: Headers with the path and API of upstream's GTK application classes (Control, MainWindow, XournalView, XojPageView, Layout, ZoomControl, ActionDatabase, LaserPointerHandler), abstract or GTK-free: the reused upstream code calls them, the fork implements them.Shadow headersControl, PageView, Layout, …qt/compat/include/ GTK shim: Plain GDK/GTK types with GDK 3 values and pure-cairo helpers ported from GDK 3; any real GTK call in compiled upstream code is a compile error by design.GTK shim<gtk/gtk.h> without GTKqt/compat/gtkshim/ Tools and handlers: Upstream's input handlers (pen, eraser, shapes, spline, selection, PDF text selection) and the overlays that draw a stroke or a selection while it is made; compiled unmodified against the shadow headers.Tools and handlerscontrol/tools, view/overlaysxoj-tools model: The document model: a document of pages of layers of elements (strokes, texts, images, TeX images, links), page backgrounds, the document lock and the listeners told of every change.modelDocument, XojPage, Layer, Ele…xoj-core control/xojfile: Reading and writing Xournal++'s files: the XML parser that builds a document, the save handler that writes one, gzip and attached backgrounds.control/xojfile.xopp/.xoj load and savexoj-core view: Draws pages with cairo: a document, its layers and elements, the backgrounds (ruled, graph, PDF, image); what makes the fork's pixels identical to upstream's.viewrenderers (cairo)xoj-core pdf: Reading PDFs through poppler-glib (pages, text, links, outline) and exporting documents as PDF (cairo or qpdf backend).pdfpoppler, PDF exportxoj-core util: Upstream's utilities: paths (the config folder), colors, rectangles, gzip and zip streams, serializing, logging, and the UI-thread dispatch (a seam the fork sets).utilpaths, colors, streams, i18nxoj-util undo: Upstream's undo: one action class per kind of edit and the handler that stacks them; the fork adds its own actions of the same shape.undoundo actions, UndoRedoHandlerxoj-core control: The GTK-free parts of upstream's control layer: settings.xml, the tool in hand, page types, layers, the shape recogniser, the PDF page cache and the image export.controlsettings, tool state, layersxoj-core GTK GUI (not built): Upstream's GTK application: the main window, page views, input handlers, dialogs, Control, the jobs and the plugins. Not compiled by the Qt build; qt/compat stands in for what reused code needs of it, and the fork ported a few classes (ADR 0002, "Ported, not reused").GTK GUI (not built)gui/, Control, XournalMainsrc/core/gui/ CLI: Headless export with upstream's flags (PNG, SVG, PDF, the PDF with notes); the golden tests' driver.CLIxournal-qt-clixournal-qt-cli Tests: One GoogleTest binary per module and label (unit session canvas markdown audio hwr quick shell ui), shared helpers, the UI fixture that drives the real window off-screen, the golden tests.Testsone binary per labelxqt-*-tests Upstream tests: Upstream's unit tests, run against the Qt-free core, and its fixtures (read only: tests never write into test/files).Upstream teststest/unit_tests, test/filesxoj-unit-tests Build and tools: The build (which upstream sources become which library), the environment and CI scripts, the upstream merge and developer tools.Build and toolsqt/cmake, qt/scripts, qt/toolsqt/cmake/ Vendored libraries: Libraries compiled in: md4c and MicroTeX (Markdown), libogg and libvorbis (audio), ONNX Runtime's C headers (hwr), gemoji.Vendored librariesmd4c, MicroTeX, Ogg/Vorbis…qt/3rdparty/ Linux: Desktop files, MIME types and the .deb package; the main platform.Linux.deb, desktop filesqt/packaging/ Android: The APK: the manifest and Java activity, the setup before the core starts, Android's content:// files.AndroidAPK, content://qt/packaging/android/ Windows: The portable zip: the setup before the core starts, Pango's fonts, the deployment.Windowsportable zipqt/src/app/WindowsSetup… macOS: The unsigned .dmg: the bundle's Info.plist and the deployment.macOSunsigned .dmgqt/packaging/macos/ CI: The fork's workflows: the doc and architecture checks, both Linux Qt versions, the block tests in shards, the releases, the platform builds, this page on GitHub Pages.CI.github/workflows/xqt-*.github/workflows/xqt-b… Library folder: A plain folder of documents (synced by any sync client) with the library's index and covers in packs.Library folderdocuments, index, packsqt/src/shell/LibraryCac… Caches: Pictures of pages kept on disk (stand-ins, covers outside a library), autosaves; named by page revision.Caches~/.cache/xournal-qtqt/docs/architecture/im… PDF files: PDFs annotated (as background) and the PDF with notes: the ink as annotations other apps show, the .xopp embedded, version history inside the file.PDF filesbackgrounds, PDF with notesqt/src/session/HybridPd… .xopp / .xoj files: Xournal++'s documents (gzipped XML). Both programs read and write them; the fork's attributes (xqt-group, xqt-created, xqt-bookmark, xqt-fill-color, notespace) are ones Xournal++ ignores..xopp / .xoj filesshared with Xournal++src/core/control/xojfil… settings.xml: Upstream's settings file, in a config folder of the fork's own (~/.config/xournal-qt); the fork's keys live in its custom part xournalQt.settings.xmlupstream's format, own fold…src/core/control/settin… Edges links calls shadows seam data qml Blocks QML UI app C++ xournal-qt module qt/compat Xournal++ core Xournal++, not built shared data tools, tests, platforms, CI