looper/backend.hpp

128 lines
4 KiB
C++
Raw Permalink Normal View History

#pragma once
#include <vector>
#include <string>
#include <map>
#include <optional>
2024-04-09 10:15:05 -07:00
#include <atomic>
#include "playback.h"
#include "dbus.hpp"
2024-11-12 14:53:44 -08:00
#define BACKEND_TYPE(type) \
public: \
inline int64_t default_priority() { \
return (int64_t)UIBackend::PriorityType::type; \
} \
private:
class UIBackend {
protected:
std::vector<std::string> args;
Playback *playback;
2024-04-09 10:15:05 -07:00
std::atomic_bool exit_flag = false;
double new_speed = 1.0;
double new_tempo = 1.0;
double new_pitch = 1.0;
bool speed_set = false;
bool tempo_set = false;
bool pitch_set = false;
bool multi_instance = false;
bool daemon_found = false;
2024-11-12 14:53:44 -08:00
enum class PriorityType : int64_t {
Default = 0,
Native = 100,
MetaToolkit = 50,
NonNative = 0,
Fallback = -100
};
public:
DBusAPI *dbus_api;
2024-04-09 10:15:05 -07:00
inline virtual bool allow_multi_instance() {
return true;
}
virtual std::string get_id();
virtual std::string get_name();
UIBackend() = default;
2024-04-09 10:15:05 -07:00
/// @brief A hook to add any licenses of software packages used by the UI backend.
inline virtual void add_licenses() {
2024-03-26 18:39:02 -07:00
// Don't add any here, but leave this specified. That way, licenses specific to UI frontends are only added per UI frontend.
}
2024-11-12 14:53:44 -08:00
inline int64_t default_priority() {
return (int64_t)PriorityType::Default;
}
2024-04-09 10:15:05 -07:00
void init_libportal();
void init_playback();
void setup_playback_args();
void init_dbus();
bool parse_args(std::vector<std::string> realArgs, int argc, char **argv);
/// @brief The main loop of the UI. Be sure to call @ref UIBackend::run and be prepared for it to throw an integer exit code that needs to escape your implementation.
virtual int run(std::vector<std::string> realArgs, int argc, char **argv);
2024-04-09 10:15:05 -07:00
/// @brief A hook that is called when the D-Bus API receives a request to exit the program.
inline virtual void QuitHandler() {
// Set a flag for loops managed by the UI backend.
exit_flag.store(true);
}
static std::map<std::string, UIBackend*> backends;
2024-04-09 10:15:05 -07:00
template<class T>
static inline std::string get_backend_id() {
UIBackend *backend = new T();
auto output = backend->get_id();
delete backend;
return output;
}
static inline UIBackend* get_first_backend() {
if (backends.empty()) {
return nullptr;
}
return (*backends.begin()).second;
}
2024-04-09 10:15:05 -07:00
static void register_backend(UIBackend *backend) {
std::string backend_id = backend->get_id();
if (backends.contains(backend_id)) { // Guard against potential memory leak due to reassigning a new pointer without deallocating the previous one
delete backend;
return;
}
backends[backend_id] = backend;
}
2024-04-09 10:15:05 -07:00
template<class T>
static void register_backend() {
UIBackend *backend = new T();
backend->register_self();
}
static inline void unregister_backend(std::string id) {
if (backends.contains(id)) {
auto backend = backends[id];
delete backend;
backends.erase(id);
}
}
inline void unregister_self() {
UIBackend::unregister_backend(get_id());
}
inline void register_self() {
UIBackend::register_backend(this);
}
template<class T>
static void unregister_backend() {
unregister_backend(get_backend_id<T>());
}
static void deinit_backends();
2024-04-09 10:15:05 -07:00
static inline std::optional<UIBackend*> get_backend(std::string id) {
if (backends.contains(id)) {
return backends[id];
} else {
return {};
}
}
template<class T>
static inline std::optional<T*> get_backend() {
auto id = get_backend_id<T>();
auto output = get_backend(id);
if (output.has_value()) {
return (T*)output.value();
} else {
return {};
}
}
static UIBackend *running_ui_backend;
2024-03-26 18:39:02 -07:00
virtual ~UIBackend();
};
2024-11-12 14:53:44 -08:00
void init_backends();