/***
Oak - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
***/
#ifndef OAKENGINE_TASK_H
#define OAKENGINE_TASK_H
#include
#include "encoding.h"
#include "init.h"
#include "node.h"
#include "project.h"
#include "timeline.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file task.h
* @brief C ABI for the engine background-task system (olive::Task /
* olive::TaskManager)
*
* Tasks are engine objects that run a job (project load/save, footage
* import, proxy generation, export) on a worker thread. This family lets
* C consumers create the concrete task they need, run it synchronously or
* hand it to the global TaskManager queue, and observe its lifecycle
* through the event mechanism (oakengine/events.h, task family
* OAKENGINE_EVENT_TASK_* and manager family
* OAKENGINE_EVENT_TASK_MANAGER_*), without ever seeing the C++ classes.
*
* Conventions (matching oakengine/project.h):
* - OakEngineTask is an opaque borrowed/owned pointer to an
* olive::Task subclass.
* - A task returned by an oakengine_task_create_*() function is OWNED by
* the caller until either oakengine_task_manager_add() (the manager
* takes ownership and deletes the task when done) or
* oakengine_task_free() (the caller deletes it). A task that ran via
* oakengine_task_start_sync() is still owned by the caller and must be
* released with oakengine_task_free() (or handed to the manager,
* though re-running is unusual).
* - Once a task was added to the manager its handle must be treated as
* borrowed: the manager may delete it at any time after the
* OAKENGINE_EVENT_TASK_MANAGER_TASK_REMOVED notification.
* - Return codes: 0 (OAKENGINE_OK) on success, negative OAKENGINE_E_*
* on failure. String output uses the buf/size convention (return value
* is the length that would have been written excluding the NUL; a
* negative value is an OAKENGINE_E_* error).
*/
/**
* @brief Opaque task handle (an olive::Task subclass instance).
*/
typedef struct OakEngineTask OakEngineTask;
/* ---- Global task manager ------------------------------------------------- */
/**
* @brief Borrowed handle of the global TaskManager singleton, for use as
* the subscription handle of the OAKENGINE_EVENT_TASK_MANAGER_* events.
* Returns NULL when the engine is not initialized.
*/
OAKENGINE_API void *oakengine_task_manager_handle(void);
/**
* @brief Number of tasks currently known to the manager (running plus
* failed-but-kept), or OAKENGINE_E_INVALID when no manager exists.
*/
OAKENGINE_API int oakengine_task_manager_count(void);
/**
* @brief Borrowed handle of an arbitrary running task (the manager's
* "first" task, used by the status bar), or NULL when the queue is empty
* or no manager exists.
*/
OAKENGINE_API OakEngineTask *oakengine_task_manager_first(void);
/**
* @brief Hand `task` to the global manager queue (takes ownership). The
* task starts as soon as a worker thread is available.
*
* @return OAKENGINE_OK, OAKENGINE_E_INVALID for NULL, OAKENGINE_E_STATE
* when no manager exists.
*/
OAKENGINE_API int oakengine_task_manager_add(OakEngineTask *task);
/**
* @brief Ask the manager to cancel `task` (TaskManager::cancel_task
* semantics: a running task is signalled; a failed-but-kept task is
* removed and deleted).
*/
OAKENGINE_API int oakengine_task_manager_cancel(OakEngineTask *task);
/* ---- Task accessors ------------------------------------------------------ */
/**
* @brief Title of `task` (buf/size convention).
*/
OAKENGINE_API int oakengine_task_title(OakEngineTask *task, char *buf,
int buf_size);
/**
* @brief Error message of `task` (buf/size convention). Meaningful after a
* failed run.
*/
OAKENGINE_API int oakengine_task_error(OakEngineTask *task, char *buf,
int buf_size);
/**
* @brief Start timestamp of `task` (milliseconds since epoch), 0 when the
* task never started, OAKENGINE_E_INVALID for NULL.
*/
OAKENGINE_API int64_t oakengine_task_start_time(OakEngineTask *task);
/**
* @brief 1 when `task` was asked to cancel, 0 otherwise,
* OAKENGINE_E_INVALID for NULL.
*/
OAKENGINE_API int oakengine_task_is_cancelled(OakEngineTask *task);
/**
* @brief Signal `task` to cancel as soon as possible (Task::Cancel).
*/
OAKENGINE_API int oakengine_task_cancel(OakEngineTask *task);
/**
* @brief Run `task` synchronously on the CALLING thread (Task::start).
* Emits the task events on this thread. Ownership stays with the caller.
*
* @return 1 when the task succeeded, 0 when it failed or was cancelled
* (read oakengine_task_error()), OAKENGINE_E_INVALID for NULL.
*/
OAKENGINE_API int oakengine_task_start_sync(OakEngineTask *task);
/**
* @brief Delete a task that was never added to the manager.
*/
OAKENGINE_API int oakengine_task_free(OakEngineTask *task);
/**
* @brief Run `task` through the engine's CLI modal progress dialog and return
* 1 when it succeeds, 0 when it fails or is cancelled.
*
* The dialog shows the task's title and progress on the terminal. `parent`
* is an optional QObject parent (may be NULL). The task is started
* synchronously; the caller retains ownership and must free it with
* oakengine_task_free() when done.
*/
OAKENGINE_API int oakengine_cli_task_dialog_run(OakEngineTask *task,
void *parent_or_NULL);
/* ---- Task creators --------------------------------------------------------
*
* All creators return an OWNED task (NULL on invalid input). The task is
* not started by creation.
*/
/**
* @brief Task that loads an OVE project from `filename`.
*/
OAKENGINE_API OakEngineTask *
oakengine_task_create_project_load(const char *filename);
/**
* @brief Task that loads an OpenTimelineIO project from `filename`.
* Returns NULL when the engine was built without OTIO support.
*/
OAKENGINE_API OakEngineTask *
oakengine_task_create_project_load_otio(const char *filename);
/**
* @brief Task that saves `project` (ProjectSaveTask semantics).
*
* `use_compression` selects the compressed .ove writer (0 writes the
* uncompressed .ovexml form). `override_filename` may be NULL to save to
* the project's own filename. `layout` is an opaque
* `const olive::SerializedLayoutInfo *` (may be NULL) whose contents are
* copied into the saved file.
*/
OAKENGINE_API OakEngineTask *oakengine_task_create_project_save(
OakEngineProject *project, int use_compression,
const char *override_filename, const void *layout);
/**
* @brief Task that saves `project` in OpenTimelineIO format. Returns NULL
* when the engine was built without OTIO support.
*/
OAKENGINE_API OakEngineTask *
oakengine_task_create_project_save_otio(OakEngineProject *project);
/**
* @brief Task that imports `url_count` media files into `folder` (a folder
* node of the target project; use oakengine_project_root() for the top
* level). The URL array is copied during the call.
*/
OAKENGINE_API OakEngineTask *oakengine_task_create_project_import(
OakEngineNode *folder, const char **urls, int url_count);
/**
* @brief Task that generates the proxy media for `footage` (a footage node
* handle, as accepted by oakengine_footage_borrow(); the task keeps the
* underlying node).
*/
OAKENGINE_API OakEngineTask *
oakengine_task_create_proxy(OakEngineNode *footage);
/**
* @brief Task that renders an export of `sequence` with `params`.
*
* Takes ownership of `params` (destroyed with the task). Progress is
* reported through the OAKENGINE_EVENT_TASK_PROGRESS event; cancelling
* the task cancels the engine export render.
*/
OAKENGINE_API OakEngineTask *oakengine_task_create_export(
OakEngineSequence *sequence, OakEngineEncodingParams *params);
/* ---- Import task results --------------------------------------------------
*
* Valid on a task created by oakengine_task_create_project_import() after
* it ran; all return OAKENGINE_E_INVALID (or 0/NULL) for other tasks.
*/
/**
* @brief Number of files the import task will process (valid right after
* creation; 0 means "nothing to import" and the task should be freed
* instead of run).
*/
OAKENGINE_API int oakengine_task_import_file_count(OakEngineTask *task);
/**
* @brief The undo command built by a successful import run as an opaque
* `olive::MultiUndoCommand *` (NULL before the run, after a cancelled
* run, or on a second call). Ownership is DETACHED from the task and
* passes to the caller: push it with oakengine_undo_push() or delete it.
*/
OAKENGINE_API void *oakengine_task_import_get_command(OakEngineTask *task);
/**
* @brief Number of footage items a successful import run created.
*/
OAKENGINE_API int oakengine_task_import_footage_count(OakEngineTask *task);
/**
* @brief Borrowed node handle of the imported footage item at `index`
* (NULL when out of range).
*/
OAKENGINE_API OakEngineNode *
oakengine_task_import_footage_at(OakEngineTask *task, int index);
/**
* @brief Number of files the import task rejected.
*/
OAKENGINE_API int
oakengine_task_import_invalid_files_count(OakEngineTask *task);
/**
* @brief Rejected file path at `index` (buf/size convention).
*/
OAKENGINE_API int oakengine_task_import_invalid_file_at(OakEngineTask *task,
int index, char *buf,
int buf_size);
/* ---- Save task results ---------------------------------------------------- */
/**
* @brief Borrowed handle of the project a save task wrote (NULL for other
* tasks).
*/
OAKENGINE_API OakEngineProject *
oakengine_task_save_get_project(OakEngineTask *task);
#ifdef __cplusplus
}
#endif
#endif /* OAKENGINE_TASK_H */