The Problem
Users need a native, cross‑platform note‑taking tool that can capture pen pressure, annotate PDFs and embed audio, all without relying on heavyweight office suites. Existing open‑source options often lack stable GTK 3 integration or extensibility via plugins.
What This Does
Xournal++ is a C++/GTK 3 application that renders a canvas for free‑hand strokes, shapes, and text, then layers those on top of PDF pages. Core UI files live in ui/ (e.g. ui/MainWindow.cpp), while the drawing engine and audio subsystem are in src/core/ (src/core/audio/AudioPlayer.cpp, src/core/audio/AudioRecorder.cpp). Plugin support is provided through the plugins/ directory, each plugin exposing a Lua script (e.g. plugins/Export/main.lua). Build configuration is driven by the top‑level CMakeLists.txt and subsidiary CMake files under src/ and test/.
How It Is Wired
Execution for a normal launch starts in the generated binary built from src/main.cpp (the CMake target xournalpp). The main function creates a GtkApplication, registers UI resources, and instantiates MainWindow (ui/MainWindow.cpp). MainWindow loads tool definitions from resources/default_template.tex and populates the toolbar. User actions (pen strokes, shape tools) are dispatched to src/core/Control.cpp, which forwards them to the AudioRecorder/AudioPlayer when audio capture is active.
The static import graph shows only two internal modules with no import edges and no circular dependencies, indicating a flat module hierarchy. The most connected files are the standalone scripts scripts/compare_license and scripts/lua_def_file, each with zero inbound/outbound imports, so they do not affect the application runtime.
Deeply nested control flow appears in three audio files (src/core/audio/DeviceInfo.cpp, PortAudioConsumer.cpp, PortAudioProducer.cpp) where indentation reaches 22 levels, making those paths harder to follow and a likely hotspot for future bugs.
How To Use It
# Clone the repository
git clone https://github.com/moses-y/xournalpp.git
cd xournalpp
# Build (requires CMake, GTK3, and typical dev packages)
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
# Run the GUI
./src/xournalpp # binary produced by the build
Configuration files such as src/config-features.h.in control optional features; they are processed by CMake into config.h. Translation files reside under po/ and are compiled into the binary at build time. Plugins are automatically discovered from the plugins/ directory at runtime.
Real‑World Use
A research lab can integrate Xournal++ into its digital notebook workflow: a scientist opens a PDF of a paper, annotates with a pressure‑sensitive stylus, records a voice note (AudioRecorder), and later exports the combined page to PDF via the menu command implemented in src/core/Export.cpp. The exported file can be shared without requiring the original application.
Code Health & Issues
- HIGH – Pin third‑party GitHub Actions to a commit SHA (
.github/workflows/*). - HIGH – CI does not run the test suite (
.github/workflows/*). - HIGH – Translation workflow pushes directly to the default branch (
.github/workflows/download-translations-from-crowdin.yml). - HIGH –
scripts/compare_license.pybuilds a shell string withos.popen(risk of injection). - MEDIUM – No explicit
permissionsforGITHUB_TOKENincontinuous-integration.yml. - MEDIUM – Large test binaries (
test/files/big-test.xoj,big-test.xopp) should be moved to Git LFS. - LOW – Workflow jobs lack
timeout‑minutes(.github/workflows/check-translations-build.yml).
Static analysis also reports 216 HIGH cognitive‑load findings, the most common being deep nesting (e.g., the three audio files above).
The Bottom Line
Xournal++ delivers a fully featured, extensible handwriting and PDF‑annotation suite with a clean CMake build and a modest codebase. The project is functional but suffers from CI gaps, insecure action references, and some overly complex functions that would benefit from refactoring. It is well‑suited for teams needing a customizable on‑premise note‑taking tool and comfortable working in C++/GTK 3 environments.