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 VIEWS
DOCUMENTS, HEADLESS
QT/COMPAT (THE GTK STAND-INS)
XOURNAL++ CORE (SRC/, UPSTREAM)
AROUND THE APP
SHARED 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.
Window
Main.qml and its state
xqt-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 chrome
toolbox, tabs, pills, sidebar
xqt-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 library
HomeView and its parts
xqt-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.
Settings
SettingsPage, Settings*.qml
xqt-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 sheets
adaptive dialogs, menus
xqt-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 EngineSetup
start, engine, window
xournal-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.
AppServices
what the windows share
xqt-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.
AppController
one window's QML API app
xqt-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.
CurrentDocument
the current tab, relayed
xqt-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 actions
TabManager, CanvasActions
xqt-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.
Library
folder, index, search
xqt-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 caches
image providers, ImageMemory
xqt-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 settings
list and settings models
xqt-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.
quick
the canvas in the scene graph
xqt-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.
canvas
a document in a view; input, tools
xqt-canvas
hwr: Reads handwriting in the background (ONNX Runtime, loaded at run time) so the search finds it; the ink is never converted.
hwr
handwriting search
xqt-hwr
audio: Records and plays Ogg Vorbis, compatible with Xournal++'s audio (a stroke tied to a moment of a recording).
audio
recording and playing
xqt-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.
markdown
Markdown engine
xqt-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.
session
one open document, headless
xqt-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).
plugins
JavaScript plugins
xqt-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).
ops
checked operations
xqt-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.
render
pages 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 sources
XojMsgBox, VersionInfo, DeviceId
qt/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 headers
Control, 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 GTK
qt/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 handlers
control/tools, view/overlays
xoj-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.
model
Document, 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 save
xoj-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.
view
renderers (cairo)
xoj-core
pdf: Reading PDFs through poppler-glib (pages, text, links, outline) and exporting documents as PDF (cairo or qpdf backend).
pdf
poppler, PDF export
xoj-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).
util
paths, colors, streams, i18n
xoj-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.
undo
undo actions, UndoRedoHandler
xoj-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.
control
settings, tool state, layers
xoj-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, XournalMain
src/core/gui/
CLI: Headless export with upstream's flags (PNG, SVG, PDF, the PDF with notes); the golden tests' driver.
CLI
xournal-qt-cli
xournal-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.
Tests
one binary per label
xqt-*-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 tests
test/unit_tests, test/files
xoj-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 tools
qt/cmake, qt/scripts, qt/tools
qt/cmake/
Vendored libraries: Libraries compiled in: md4c and MicroTeX (Markdown), libogg and libvorbis (audio), ONNX Runtime's C headers (hwr), gemoji.
Vendored libraries
md4c, MicroTeX, Ogg/Vorbis…
qt/3rdparty/
Linux: Desktop files, MIME types and the .deb package; the main platform.
Linux
.deb, desktop files
qt/packaging/
Android: The APK: the manifest and Java activity, the setup before the core starts, Android's content:// files.
Android
APK, content://
qt/packaging/android/
Windows: The portable zip: the setup before the core starts, Pango's fonts, the deployment.
Windows
portable zip
qt/src/app/WindowsSetup…
macOS: The unsigned .dmg: the bundle's Info.plist and the deployment.
macOS
unsigned .dmg
qt/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 folder
documents, index, packs
qt/src/shell/LibraryCac…
Caches: Pictures of pages kept on disk (stand-ins, covers outside a library), autosaves; named by page revision.
Caches
~/.cache/xournal-qt
qt/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 files
backgrounds, PDF with notes
qt/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 files
shared 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.xml
upstream'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