2024-03-23 18:41:26 -07:00
# pragma once
# include <vector>
# include <string>
# include <map>
# include <optional>
2024-04-09 10:15:05 -07:00
# include <atomic>
2024-03-23 18:41:26 -07:00
# include "playback.h"
# include "dbus.hpp"
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-03-23 18:41:26 -07:00
public :
DBusAPI * dbus_api ;
2024-04-09 10:15:05 -07:00
inline virtual bool allow_multi_instance ( ) {
return true ;
}
2024-03-23 18:41:26 -07:00
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-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.
2024-03-23 18:41:26 -07:00
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 ) ;
}
2024-03-23 18:41:26 -07:00
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 ;
2024-03-23 18:41:26 -07:00
}
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 ) {
2024-03-23 18:41:26 -07:00
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 > ( ) ) ;
}
2024-03-23 18:41:26 -07:00
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-03-23 18:41:26 -07:00
} ;
void init_backends ( ) ;