EngineCore (new app/coreengine.{h,cpp}) owns every engine-safe part of
the old Core singleton: CoreParams, lifecycle of the engine managers,
UndoStack, tool/snapping/timecode state, locale, autorecovery, recent
projects, footage filters, clipboard, project registry, type
declarations, and the proxy toggle. UI dependencies are inverted
through hooks instead: status-bar/cache-full signals and std::function
handlers for image-sequence confirmation, footage relink, OTIO import,
project save/close and layout load (same pattern as
Config::ErrorHandler).
Core (app/) now derives from EngineCore and keeps only UI behavior:
the main window, dialogs, panel heuristics, import/export flows and
project lifecycle presentation. Its public API is unchanged (all
inherited), and Core::instance() covariantly static_casts the engine
singleton. The render worker constructs EngineCore directly, making it
the first binary that no longer needs the UI side of Core.
~25 engine call sites move from core.h to coreengine.h; a dozen more
drop a vestigial core.h include (gaining direct includes for symbols
they were borrowing transitively). Full gtest suite green (1986 tests,
0 failures).
liboakcore is now a shared library that exposes only a C ABI:
- every value class (Rational, TimeRange, Color, Bezier, AudioParams,
SampleBuffer) and the free-function groups (StringUtils, fraction
utils, Timecode) is wrapped in an opaque-handle C API under
core/include/olive/core/oakcore/ (init/copy/free + self-first
functions), implemented in core/src/capi/
- consumers keep the original C++ API unchanged through same-name
wrapper classes that hold the handle and forward across the C
boundary; original implementations moved to core/src/oliveimpl
(namespace olive::core::internal) and are hidden from export
- TimeRangeList/TimeRangeListFrameIterator are reimplemented inline
over the wrapper (iterators/containers don't cross C ABI)
- generic Value container stays internal (unused by consumers) and is
no longer part of the public umbrella header
- hidden visibility + OAKCORE_BUILD export macro; nm shows zero
olive::* symbols exported
- install into the platform's standard libdir (GNUInstallDirs);
Windows DLLs next to the executables, macOS into the app bundle
- TimelineWorkArea::in/out/length now return by value: the wrapped
TimeRange getters return values, and forwarding them through const
references dangled (found via RenderWorkerFootageTest crash)
- tests: 9 new pure C ABI test executables (oakcore_*_test) covering
every public C function; 4 stale legacy core tests removed (they
targeted a long-renamed API and were never built due to a malformed
option() that also kept OLIVECORE_BUILD_TESTS off)
- CI/CD: oakcore.dll staged for NSIS, liboakcore.so added to the
AppImage validation list, build-tree DLL copies on Windows
- oak-render-worker now builds from worker/ (own CMakeLists.txt) as a
peer of app/; RenderWorkerPool resolves the new build-tree location
- deduplicated the Linux install() rules for the worker
- worker-spawning tests resolve build/worker instead of build/app
- cd.yml: Windows staging copies the worker from its new output path