UI: Add front-end API library
Allows manipulating and modifying the front-end via plugins.
This commit is contained in:
parent
bfc21317bf
commit
8836592d92
@ -1,5 +1,3 @@
|
|||||||
project(obs)
|
|
||||||
|
|
||||||
option(ENABLE_UI "Enables the OBS user interfaces" ON)
|
option(ENABLE_UI "Enables the OBS user interfaces" ON)
|
||||||
if(DISABLE_UI)
|
if(DISABLE_UI)
|
||||||
message(STATUS "UI disabled")
|
message(STATUS "UI disabled")
|
||||||
@ -10,6 +8,12 @@ else()
|
|||||||
set(FIND_MODE QUIET)
|
set(FIND_MODE QUIET)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(obs-frontend-api)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
project(obs)
|
||||||
|
|
||||||
if(DEFINED QTDIR${_lib_suffix})
|
if(DEFINED QTDIR${_lib_suffix})
|
||||||
list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}")
|
list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}")
|
||||||
elseif(DEFINED QTDIR)
|
elseif(DEFINED QTDIR)
|
||||||
@ -40,6 +44,7 @@ if(NOT Qt5Widgets_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include_directories(SYSTEM "obs-frontend-api")
|
||||||
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
|
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
|
||||||
|
|
||||||
find_package(Libcurl REQUIRED)
|
find_package(Libcurl REQUIRED)
|
||||||
@ -97,6 +102,7 @@ endif()
|
|||||||
set(obs_SOURCES
|
set(obs_SOURCES
|
||||||
${obs_PLATFORM_SOURCES}
|
${obs_PLATFORM_SOURCES}
|
||||||
obs-app.cpp
|
obs-app.cpp
|
||||||
|
api-interface.cpp
|
||||||
window-basic-main.cpp
|
window-basic-main.cpp
|
||||||
window-basic-filters.cpp
|
window-basic-filters.cpp
|
||||||
window-basic-settings.cpp
|
window-basic-settings.cpp
|
||||||
@ -219,6 +225,7 @@ target_link_libraries(obs
|
|||||||
libobs
|
libobs
|
||||||
libff
|
libff
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
|
obs-frontend-api
|
||||||
${LIBCURL_LIBRARIES}
|
${LIBCURL_LIBRARIES}
|
||||||
${obs_PLATFORM_LIBRARIES})
|
${obs_PLATFORM_LIBRARIES})
|
||||||
|
|
||||||
|
362
UI/api-interface.cpp
Normal file
362
UI/api-interface.cpp
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
#include <obs-frontend-internal.hpp>
|
||||||
|
#include "obs-app.hpp"
|
||||||
|
#include "qt-wrappers.hpp"
|
||||||
|
#include "window-basic-main.hpp"
|
||||||
|
#include "window-basic-main-outputs.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(OBSScene);
|
||||||
|
Q_DECLARE_METATYPE(OBSSource);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T GetOBSRef(QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnumProfiles(function<bool (const char *, const char *)> &&cb);
|
||||||
|
void EnumSceneCollections(function<bool (const char *, const char *)> &&cb);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
template<typename T> struct OBSStudioCallback {
|
||||||
|
T callback;
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
inline OBSStudioCallback(T cb, void *p) :
|
||||||
|
callback(cb), private_data(p)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> inline size_t GetCallbackIdx(
|
||||||
|
vector<OBSStudioCallback<T>> &callbacks,
|
||||||
|
T callback, void *private_data)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < callbacks.size(); i++) {
|
||||||
|
OBSStudioCallback<T> curCB = callbacks[i];
|
||||||
|
if (curCB.callback == callback &&
|
||||||
|
curCB.private_data == private_data)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (size_t)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OBSStudioAPI : obs_frontend_callbacks {
|
||||||
|
OBSBasic *main;
|
||||||
|
vector<OBSStudioCallback<obs_frontend_event_cb>> callbacks;
|
||||||
|
vector<OBSStudioCallback<obs_frontend_save_cb>> saveCallbacks;
|
||||||
|
|
||||||
|
inline OBSStudioAPI(OBSBasic *main_) : main(main_) {}
|
||||||
|
|
||||||
|
void *obs_frontend_get_main_window(void) override
|
||||||
|
{
|
||||||
|
return (void*)main;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *obs_frontend_get_main_window_handle(void) override
|
||||||
|
{
|
||||||
|
return (void*)main->winId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_get_scenes(
|
||||||
|
struct obs_frontend_source_list *sources) override
|
||||||
|
{
|
||||||
|
for (int i = 0; i < main->ui->scenes->count(); i++) {
|
||||||
|
QListWidgetItem *item = main->ui->scenes->item(i);
|
||||||
|
OBSScene scene = GetOBSRef<OBSScene>(item);
|
||||||
|
obs_source_t *source = obs_scene_get_source(scene);
|
||||||
|
|
||||||
|
obs_source_addref(source);
|
||||||
|
da_push_back(sources->sources, &source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_t *obs_frontend_get_current_scene(void) override
|
||||||
|
{
|
||||||
|
OBSSource source;
|
||||||
|
|
||||||
|
if (main->IsPreviewProgramMode()) {
|
||||||
|
source = obs_weak_source_get_source(main->programScene);
|
||||||
|
} else {
|
||||||
|
source = main->GetCurrentSceneSource();
|
||||||
|
obs_source_addref(source);
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_scene(obs_source_t *scene) override
|
||||||
|
{
|
||||||
|
if (main->IsPreviewProgramMode()) {
|
||||||
|
QMetaObject::invokeMethod(main, "TransitionToScene",
|
||||||
|
Q_ARG(OBSSource, OBSSource(scene)));
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(main, "SetCurrentScene",
|
||||||
|
Q_ARG(OBSSource, OBSSource(scene)),
|
||||||
|
Q_ARG(bool, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_get_transitions(
|
||||||
|
struct obs_frontend_source_list *sources) override
|
||||||
|
{
|
||||||
|
for (int i = 0; i < main->ui->transitions->count(); i++) {
|
||||||
|
OBSSource tr = main->ui->transitions->itemData(i)
|
||||||
|
.value<OBSSource>();
|
||||||
|
|
||||||
|
obs_source_addref(tr);
|
||||||
|
da_push_back(sources->sources, &tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_t *obs_frontend_get_current_transition(void) override
|
||||||
|
{
|
||||||
|
OBSSource tr = main->GetCurrentTransition();
|
||||||
|
|
||||||
|
obs_source_addref(tr);
|
||||||
|
return tr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_transition(
|
||||||
|
obs_source_t *transition) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "SetTransition",
|
||||||
|
Q_ARG(OBSSource, OBSSource(transition)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_get_scene_collections(
|
||||||
|
std::vector<std::string> &strings) override
|
||||||
|
{
|
||||||
|
auto addCollection = [&](const char *name, const char *)
|
||||||
|
{
|
||||||
|
strings.emplace_back(name);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumSceneCollections(addCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *obs_frontend_get_current_scene_collection(void) override
|
||||||
|
{
|
||||||
|
const char *cur_name = config_get_string(App()->GlobalConfig(),
|
||||||
|
"Basic", "SceneCollection");
|
||||||
|
return bstrdup(cur_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_scene_collection(
|
||||||
|
const char *collection) override
|
||||||
|
{
|
||||||
|
QList<QAction*> menuActions =
|
||||||
|
main->ui->sceneCollectionMenu->actions();
|
||||||
|
QString qstrCollection = QT_UTF8(collection);
|
||||||
|
|
||||||
|
for (int i = 0; i < menuActions.count(); i++) {
|
||||||
|
QAction *action = menuActions[i];
|
||||||
|
QVariant v = action->property("file_name");
|
||||||
|
|
||||||
|
if (v.typeName() != nullptr) {
|
||||||
|
if (action->text() == qstrCollection) {
|
||||||
|
action->trigger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_get_profiles(
|
||||||
|
std::vector<std::string> &strings) override
|
||||||
|
{
|
||||||
|
auto addProfile = [&](const char *name, const char *)
|
||||||
|
{
|
||||||
|
strings.emplace_back(name);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumProfiles(addProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *obs_frontend_get_current_profile(void) override
|
||||||
|
{
|
||||||
|
const char *name = config_get_string(App()->GlobalConfig(),
|
||||||
|
"Basic", "Profile");
|
||||||
|
return bstrdup(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_profile(const char *profile) override
|
||||||
|
{
|
||||||
|
QList<QAction*> menuActions =
|
||||||
|
main->ui->profileMenu->actions();
|
||||||
|
QString qstrProfile = QT_UTF8(profile);
|
||||||
|
|
||||||
|
for (int i = 0; i < menuActions.count(); i++) {
|
||||||
|
QAction *action = menuActions[i];
|
||||||
|
QVariant v = action->property("file_name");
|
||||||
|
|
||||||
|
if (v.typeName() != nullptr) {
|
||||||
|
if (action->text() == qstrProfile) {
|
||||||
|
action->trigger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_streaming_start(void) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "StartStreaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_streaming_stop(void) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "StopStreaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_frontend_streaming_active(void) override
|
||||||
|
{
|
||||||
|
return main->outputHandler->StreamingActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_recording_start(void) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "StartRecording");
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_recording_stop(void) override
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(main, "StopRecording");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_frontend_recording_active(void) override
|
||||||
|
{
|
||||||
|
return main->outputHandler->StreamingActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *obs_frontend_add_tools_menu_qaction(const char *name) override
|
||||||
|
{
|
||||||
|
main->ui->menuTools->setEnabled(true);
|
||||||
|
return (void*)main->ui->menuTools->addAction(QT_UTF8(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_add_tools_menu_item(const char *name,
|
||||||
|
obs_frontend_cb callback, void *private_data) override
|
||||||
|
{
|
||||||
|
main->ui->menuTools->setEnabled(true);
|
||||||
|
|
||||||
|
auto func = [private_data, callback] ()
|
||||||
|
{
|
||||||
|
callback(private_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
QAction *action = main->ui->menuTools->addAction(QT_UTF8(name));
|
||||||
|
QObject::connect(action, &QAction::triggered, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||||
|
void *private_data) override
|
||||||
|
{
|
||||||
|
size_t idx = GetCallbackIdx(callbacks, callback, private_data);
|
||||||
|
if (idx == (size_t)-1)
|
||||||
|
callbacks.emplace_back(callback, private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||||
|
void *private_data) override
|
||||||
|
{
|
||||||
|
size_t idx = GetCallbackIdx(callbacks, callback, private_data);
|
||||||
|
if (idx == (size_t)-1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
callbacks.erase(callbacks.begin() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_output_t *obs_frontend_get_streaming_output(void) override
|
||||||
|
{
|
||||||
|
OBSOutput output = main->outputHandler->streamOutput;
|
||||||
|
obs_output_addref(output);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_output_t *obs_frontend_get_recording_output(void) override
|
||||||
|
{
|
||||||
|
OBSOutput out = main->outputHandler->fileOutput;
|
||||||
|
obs_output_addref(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_t *obs_frontend_get_profile_config(void) override
|
||||||
|
{
|
||||||
|
return main->basicConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_t *obs_frontend_get_global_config(void) override
|
||||||
|
{
|
||||||
|
return App()->GlobalConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_save(void) override
|
||||||
|
{
|
||||||
|
main->SaveProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||||
|
void *private_data) override
|
||||||
|
{
|
||||||
|
size_t idx = GetCallbackIdx(saveCallbacks, callback,
|
||||||
|
private_data);
|
||||||
|
if (idx == (size_t)-1)
|
||||||
|
saveCallbacks.emplace_back(callback, private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||||
|
void *private_data) override
|
||||||
|
{
|
||||||
|
size_t idx = GetCallbackIdx(saveCallbacks, callback,
|
||||||
|
private_data);
|
||||||
|
if (idx == (size_t)-1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
saveCallbacks.erase(saveCallbacks.begin() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_push_ui_translation(
|
||||||
|
obs_frontend_translate_ui_cb translate) override
|
||||||
|
{
|
||||||
|
App()->PushUITranslation(translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_pop_ui_translation(void) override
|
||||||
|
{
|
||||||
|
App()->PopUITranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_load(obs_data_t *settings) override
|
||||||
|
{
|
||||||
|
for (auto cb : saveCallbacks)
|
||||||
|
cb.callback(settings, false, cb.private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_save(obs_data_t *settings) override
|
||||||
|
{
|
||||||
|
for (auto cb : saveCallbacks)
|
||||||
|
cb.callback(settings, true, cb.private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_event(enum obs_frontend_event event) override
|
||||||
|
{
|
||||||
|
if (main->disableSaving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto cb : callbacks)
|
||||||
|
cb.callback(event, cb.private_data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main)
|
||||||
|
{
|
||||||
|
obs_frontend_callbacks *api = new OBSStudioAPI(main);
|
||||||
|
obs_frontend_set_callbacks_internal(api);
|
||||||
|
return api;
|
||||||
|
}
|
@ -354,6 +354,9 @@ Basic.MainMenu.View.StatusBar="&Status Bar"
|
|||||||
Basic.MainMenu.SceneCollection="&Scene Collection"
|
Basic.MainMenu.SceneCollection="&Scene Collection"
|
||||||
Basic.MainMenu.Profile="&Profile"
|
Basic.MainMenu.Profile="&Profile"
|
||||||
|
|
||||||
|
# basic mode help menu
|
||||||
|
Basic.MainMenu.Tools="&Tools"
|
||||||
|
|
||||||
# basic mode help menu
|
# basic mode help menu
|
||||||
Basic.MainMenu.Help="&Help"
|
Basic.MainMenu.Help="&Help"
|
||||||
Basic.MainMenu.Help.Website="Visit &Website"
|
Basic.MainMenu.Help.Website="Visit &Website"
|
||||||
|
@ -229,7 +229,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>201</width>
|
<width>215</width>
|
||||||
<height>16</height>
|
<height>16</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -913,11 +913,20 @@
|
|||||||
<addaction name="toggleSceneTransitions"/>
|
<addaction name="toggleSceneTransitions"/>
|
||||||
<addaction name="toggleStatusBar"/>
|
<addaction name="toggleStatusBar"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuTools">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Basic.MainMenu.Tools</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
<addaction name="menu_File"/>
|
<addaction name="menu_File"/>
|
||||||
<addaction name="menuBasic_MainMenu_Edit"/>
|
<addaction name="menuBasic_MainMenu_Edit"/>
|
||||||
<addaction name="viewMenu"/>
|
<addaction name="viewMenu"/>
|
||||||
<addaction name="profileMenu"/>
|
<addaction name="profileMenu"/>
|
||||||
<addaction name="sceneCollectionMenu"/>
|
<addaction name="sceneCollectionMenu"/>
|
||||||
|
<addaction name="menuTools"/>
|
||||||
<addaction name="menuBasic_MainMenu_Help"/>
|
<addaction name="menuBasic_MainMenu_Help"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="OBSBasicStatusBar" name="statusbar"/>
|
<widget class="OBSBasicStatusBar" name="statusbar"/>
|
||||||
|
@ -937,12 +937,22 @@ const char *OBSApp::GetCurrentLog() const
|
|||||||
return currentLogFile.c_str();
|
return currentLogFile.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OBSApp::TranslateString(const char *lookupVal, const char **out) const
|
||||||
|
{
|
||||||
|
for (obs_frontend_translate_ui_cb cb : translatorHooks) {
|
||||||
|
if (cb(lookupVal, out))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text_lookup_getstr(App()->GetTextLookup(), lookupVal, out);
|
||||||
|
}
|
||||||
|
|
||||||
QString OBSTranslator::translate(const char *context, const char *sourceText,
|
QString OBSTranslator::translate(const char *context, const char *sourceText,
|
||||||
const char *disambiguation, int n) const
|
const char *disambiguation, int n) const
|
||||||
{
|
{
|
||||||
const char *out = nullptr;
|
const char *out = nullptr;
|
||||||
if (!text_lookup_getstr(App()->GetTextLookup(), sourceText, &out))
|
if (!App()->TranslateString(sourceText, &out))
|
||||||
return QString();
|
return QString(sourceText);
|
||||||
|
|
||||||
UNUSED_PARAMETER(context);
|
UNUSED_PARAMETER(context);
|
||||||
UNUSED_PARAMETER(disambiguation);
|
UNUSED_PARAMETER(disambiguation);
|
||||||
|
@ -25,9 +25,11 @@
|
|||||||
#include <util/profiler.h>
|
#include <util/profiler.h>
|
||||||
#include <util/util.hpp>
|
#include <util/util.hpp>
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include "window-main.hpp"
|
#include "window-main.hpp"
|
||||||
|
|
||||||
@ -71,6 +73,8 @@ private:
|
|||||||
os_inhibit_t *sleepInhibitor = nullptr;
|
os_inhibit_t *sleepInhibitor = nullptr;
|
||||||
int sleepInhibitRefs = 0;
|
int sleepInhibitRefs = 0;
|
||||||
|
|
||||||
|
std::deque<obs_frontend_translate_ui_cb> translatorHooks;
|
||||||
|
|
||||||
bool InitGlobalConfig();
|
bool InitGlobalConfig();
|
||||||
bool InitGlobalConfigDefaults();
|
bool InitGlobalConfigDefaults();
|
||||||
bool InitLocale();
|
bool InitLocale();
|
||||||
@ -102,6 +106,8 @@ public:
|
|||||||
return textLookup.GetString(lookupVal);
|
return textLookup.GetString(lookupVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslateString(const char *lookupVal, const char **out) const;
|
||||||
|
|
||||||
profiler_name_store_t *GetProfilerNameStore() const
|
profiler_name_store_t *GetProfilerNameStore() const
|
||||||
{
|
{
|
||||||
return profilerNameStore;
|
return profilerNameStore;
|
||||||
@ -131,6 +137,16 @@ public:
|
|||||||
if (--sleepInhibitRefs == 0)
|
if (--sleepInhibitRefs == 0)
|
||||||
os_inhibit_sleep_set_active(sleepInhibitor, false);
|
os_inhibit_sleep_set_active(sleepInhibitor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void PushUITranslation(obs_frontend_translate_ui_cb cb)
|
||||||
|
{
|
||||||
|
translatorHooks.emplace_front(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PopUITranslation()
|
||||||
|
{
|
||||||
|
translatorHooks.pop_front();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int GetConfigPath(char *path, size_t size, const char *name);
|
int GetConfigPath(char *path, size_t size, const char *name);
|
||||||
|
20
UI/obs-frontend-api/CMakeLists.txt
Normal file
20
UI/obs-frontend-api/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
project(obs-frontend-api)
|
||||||
|
|
||||||
|
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
|
||||||
|
|
||||||
|
add_definitions(-DLIBOBS_EXPORTS)
|
||||||
|
|
||||||
|
set(obs-frontend-api_SOURCES
|
||||||
|
obs-frontend-api.cpp)
|
||||||
|
|
||||||
|
set(obs-frontend-api_HEADERS
|
||||||
|
obs-frontend-internal.hpp
|
||||||
|
obs-frontend-api.h)
|
||||||
|
|
||||||
|
add_library(obs-frontend-api SHARED
|
||||||
|
${obs-frontend-api_SOURCES}
|
||||||
|
${obs-frontend-api_HEADERS})
|
||||||
|
target_link_libraries(obs-frontend-api
|
||||||
|
libobs)
|
||||||
|
|
||||||
|
install_obs_core(obs-frontend-api)
|
295
UI/obs-frontend-api/obs-frontend-api.cpp
Normal file
295
UI/obs-frontend-api/obs-frontend-api.cpp
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
#include "obs-frontend-internal.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static unique_ptr<obs_frontend_callbacks> c;
|
||||||
|
|
||||||
|
void obs_frontend_set_callbacks_internal(obs_frontend_callbacks *callbacks)
|
||||||
|
{
|
||||||
|
c.reset(callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool callbacks_valid_(const char *func_name)
|
||||||
|
{
|
||||||
|
if (!c) {
|
||||||
|
blog(LOG_WARNING, "Tried to call %s with no callbacks!",
|
||||||
|
func_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define callbacks_valid() callbacks_valid_(__FUNCTION__)
|
||||||
|
|
||||||
|
static char **convert_string_list(vector<string> &strings)
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
size_t string_data_offset = (strings.size() + 1) * sizeof(char*);
|
||||||
|
uint8_t *out;
|
||||||
|
char **ptr_list;
|
||||||
|
char *string_data;
|
||||||
|
|
||||||
|
size += string_data_offset;
|
||||||
|
|
||||||
|
for (auto &str : strings)
|
||||||
|
size += str.size() + 1;
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out = (uint8_t*)bmalloc(size);
|
||||||
|
ptr_list = (char**)out;
|
||||||
|
string_data = (char*)(out + string_data_offset);
|
||||||
|
|
||||||
|
for (auto &str : strings) {
|
||||||
|
*ptr_list = string_data;
|
||||||
|
memcpy(string_data, str.c_str(), str.size() + 1);
|
||||||
|
|
||||||
|
ptr_list++;
|
||||||
|
string_data += str.size() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ptr_list = nullptr;
|
||||||
|
return (char**)out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void *obs_frontend_get_main_window(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_main_window()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *obs_frontend_get_main_window_handle(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_main_window_handle()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char **obs_frontend_get_scene_names(void)
|
||||||
|
{
|
||||||
|
if (!callbacks_valid())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct obs_frontend_source_list sources = {};
|
||||||
|
vector<string> names;
|
||||||
|
c->obs_frontend_get_scenes(&sources);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sources.sources.num; i++) {
|
||||||
|
obs_source_t *source = sources.sources.array[i];
|
||||||
|
const char *name = obs_source_get_name(source);
|
||||||
|
names.emplace_back(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_frontend_source_list_free(&sources);
|
||||||
|
return convert_string_list(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_get_scenes(struct obs_frontend_source_list *sources)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_get_scenes(sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_t *obs_frontend_get_current_scene(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_current_scene()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_scene(obs_source_t *scene)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_set_current_scene(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_get_transitions(struct obs_frontend_source_list *sources)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_get_transitions(sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_t *obs_frontend_get_current_transition(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_current_transition()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_transition(obs_source_t *transition)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_set_current_transition(transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
char **obs_frontend_get_scene_collections(void)
|
||||||
|
{
|
||||||
|
if (!callbacks_valid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
vector<string> strings;
|
||||||
|
c->obs_frontend_get_scene_collections(strings);
|
||||||
|
return convert_string_list(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *obs_frontend_get_current_scene_collection(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_current_scene_collection()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_scene_collection(const char *collection)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_set_current_scene_collection(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
char **obs_frontend_get_profiles(void)
|
||||||
|
{
|
||||||
|
if (!callbacks_valid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
vector<string> strings;
|
||||||
|
c->obs_frontend_get_profiles(strings);
|
||||||
|
return convert_string_list(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *obs_frontend_get_current_profile(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_current_profile()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_set_current_profile(const char *profile)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_set_current_profile(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_streaming_start(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_streaming_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_streaming_stop(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_streaming_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_frontend_streaming_active(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_streaming_active()
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_recording_start(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_recording_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_recording_stop(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid()) c->obs_frontend_recording_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool obs_frontend_recording_active(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_recording_active()
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *obs_frontend_add_tools_menu_qaction(const char *name)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_add_tools_menu_qaction(name)
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_add_tools_menu_item(const char *name,
|
||||||
|
obs_frontend_cb callback, void *private_data)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_add_tools_menu_item(name, callback,
|
||||||
|
private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_add_event_callback(callback, private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_remove_event_callback(callback, private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_output_t *obs_frontend_get_streaming_output(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_streaming_output()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_output_t *obs_frontend_get_recording_output(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_recording_output()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_t *obs_frontend_get_profile_config(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_profile_config()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_t *obs_frontend_get_global_config(void)
|
||||||
|
{
|
||||||
|
return !!callbacks_valid()
|
||||||
|
? c->obs_frontend_get_global_config()
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_save(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_add_save_callback(callback, private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_remove_save_callback(callback, private_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_push_ui_translation(translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obs_frontend_pop_ui_translation(void)
|
||||||
|
{
|
||||||
|
if (callbacks_valid())
|
||||||
|
c->obs_frontend_pop_ui_translation();
|
||||||
|
}
|
134
UI/obs-frontend-api/obs-frontend-api.h
Normal file
134
UI/obs-frontend-api/obs-frontend-api.h
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <obs.h>
|
||||||
|
#include <util/darray.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct config_data;
|
||||||
|
typedef struct config_data config_t;
|
||||||
|
|
||||||
|
struct obs_data;
|
||||||
|
typedef struct obs_data obs_data_t;
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
struct obs_frontend_source_list {
|
||||||
|
DARRAY(obs_source_t*) sources;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void obs_frontend_source_list_free(
|
||||||
|
struct obs_frontend_source_list *source_list)
|
||||||
|
{
|
||||||
|
size_t num = source_list->sources.num;
|
||||||
|
for (size_t i = 0; i < num; i++)
|
||||||
|
obs_source_release(source_list->sources.array[i]);
|
||||||
|
da_free(source_list->sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* NOTE: Functions that return char** string lists are a single allocation of
|
||||||
|
* memory with pointers to itself. Free with a single call to bfree on the
|
||||||
|
* base char** pointer. */
|
||||||
|
|
||||||
|
/* NOTE: User interface should not use typical Qt locale translation methods,
|
||||||
|
* as the OBS UI bypasses it to use a custom translation implementation. Use
|
||||||
|
* standard module translation methods, obs_module_text. For text in a Qt
|
||||||
|
* window, use obs_frontend_push_ui_translation when the text is about to be
|
||||||
|
* translated, and obs_frontend_pop_ui_translation when translation is
|
||||||
|
* complete. */
|
||||||
|
|
||||||
|
EXPORT void *obs_frontend_get_main_window(void);
|
||||||
|
EXPORT void *obs_frontend_get_main_window_handle(void);
|
||||||
|
|
||||||
|
EXPORT char **obs_frontend_get_scene_names(void);
|
||||||
|
EXPORT void obs_frontend_get_scenes(struct obs_frontend_source_list *sources);
|
||||||
|
EXPORT obs_source_t *obs_frontend_get_current_scene(void);
|
||||||
|
EXPORT void obs_frontend_set_current_scene(obs_source_t *scene);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_get_transitions(
|
||||||
|
struct obs_frontend_source_list *sources);
|
||||||
|
EXPORT obs_source_t *obs_frontend_get_current_transition(void);
|
||||||
|
EXPORT void obs_frontend_set_current_transition(obs_source_t *transition);
|
||||||
|
|
||||||
|
EXPORT char **obs_frontend_get_scene_collections(void);
|
||||||
|
EXPORT char *obs_frontend_get_current_scene_collection(void);
|
||||||
|
EXPORT void obs_frontend_set_current_scene_collection(const char *collection);
|
||||||
|
|
||||||
|
EXPORT char **obs_frontend_get_profiles(void);
|
||||||
|
EXPORT char *obs_frontend_get_current_profile(void);
|
||||||
|
EXPORT void obs_frontend_set_current_profile(const char *profile);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_streaming_start(void);
|
||||||
|
EXPORT void obs_frontend_streaming_stop(void);
|
||||||
|
EXPORT bool obs_frontend_streaming_active(void);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_recording_start(void);
|
||||||
|
EXPORT void obs_frontend_recording_stop(void);
|
||||||
|
EXPORT bool obs_frontend_recording_active(void);
|
||||||
|
|
||||||
|
typedef void (*obs_frontend_cb)(void *private_data);
|
||||||
|
|
||||||
|
EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name);
|
||||||
|
EXPORT void obs_frontend_add_tools_menu_item(const char *name,
|
||||||
|
obs_frontend_cb callback, void *private_data);
|
||||||
|
|
||||||
|
enum obs_frontend_event {
|
||||||
|
OBS_FRONTEND_EVENT_STREAMING_STARTING,
|
||||||
|
OBS_FRONTEND_EVENT_STREAMING_STARTED,
|
||||||
|
OBS_FRONTEND_EVENT_STREAMING_STOPPING,
|
||||||
|
OBS_FRONTEND_EVENT_STREAMING_STOPPED,
|
||||||
|
OBS_FRONTEND_EVENT_RECORDING_STARTING,
|
||||||
|
OBS_FRONTEND_EVENT_RECORDING_STARTED,
|
||||||
|
OBS_FRONTEND_EVENT_RECORDING_STOPPING,
|
||||||
|
OBS_FRONTEND_EVENT_RECORDING_STOPPED,
|
||||||
|
OBS_FRONTEND_EVENT_SCENE_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_TRANSITION_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_TRANSITION_STOPPED,
|
||||||
|
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_PROFILE_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED,
|
||||||
|
OBS_FRONTEND_EVENT_EXIT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event,
|
||||||
|
void *private_data);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
|
||||||
|
void *private_data);
|
||||||
|
EXPORT void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
|
||||||
|
void *private_data);
|
||||||
|
|
||||||
|
typedef void (*obs_frontend_save_cb)(obs_data_t *save_data, bool saving,
|
||||||
|
void *private_data);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_save(void);
|
||||||
|
EXPORT void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||||
|
void *private_data);
|
||||||
|
EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||||
|
void *private_data);
|
||||||
|
|
||||||
|
EXPORT obs_output_t *obs_frontend_get_streaming_output(void);
|
||||||
|
EXPORT obs_output_t *obs_frontend_get_recording_output(void);
|
||||||
|
|
||||||
|
EXPORT config_t *obs_frontend_get_profile_config(void);
|
||||||
|
EXPORT config_t *obs_frontend_get_global_config(void);
|
||||||
|
|
||||||
|
typedef bool (*obs_frontend_translate_ui_cb)(const char *text,
|
||||||
|
const char **out);
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_push_ui_translation(
|
||||||
|
obs_frontend_translate_ui_cb translate);
|
||||||
|
EXPORT void obs_frontend_pop_ui_translation(void);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
73
UI/obs-frontend-api/obs-frontend-internal.hpp
Normal file
73
UI/obs-frontend-api/obs-frontend-internal.hpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "obs-frontend-api.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct obs_frontend_callbacks {
|
||||||
|
virtual void *obs_frontend_get_main_window(void)=0;
|
||||||
|
virtual void *obs_frontend_get_main_window_handle(void)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_get_scenes(
|
||||||
|
struct obs_frontend_source_list *sources)=0;
|
||||||
|
virtual obs_source_t *obs_frontend_get_current_scene(void)=0;
|
||||||
|
virtual void obs_frontend_set_current_scene(obs_source_t *scene)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_get_transitions(
|
||||||
|
struct obs_frontend_source_list *sources)=0;
|
||||||
|
virtual obs_source_t *obs_frontend_get_current_transition(void)=0;
|
||||||
|
virtual void obs_frontend_set_current_transition(
|
||||||
|
obs_source_t *transition)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_get_scene_collections(
|
||||||
|
std::vector<std::string> &strings)=0;
|
||||||
|
virtual char *obs_frontend_get_current_scene_collection(void)=0;
|
||||||
|
virtual void obs_frontend_set_current_scene_collection(
|
||||||
|
const char *collection)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_get_profiles(
|
||||||
|
std::vector<std::string> &strings)=0;
|
||||||
|
virtual char *obs_frontend_get_current_profile(void)=0;
|
||||||
|
virtual void obs_frontend_set_current_profile(const char *profile)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_streaming_start(void)=0;
|
||||||
|
virtual void obs_frontend_streaming_stop(void)=0;
|
||||||
|
virtual bool obs_frontend_streaming_active(void)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_recording_start(void)=0;
|
||||||
|
virtual void obs_frontend_recording_stop(void)=0;
|
||||||
|
virtual bool obs_frontend_recording_active(void)=0;
|
||||||
|
|
||||||
|
virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0;
|
||||||
|
virtual void obs_frontend_add_tools_menu_item(const char *name,
|
||||||
|
obs_frontend_cb callback, void *private_data)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_add_event_callback(
|
||||||
|
obs_frontend_event_cb callback, void *private_data)=0;
|
||||||
|
virtual void obs_frontend_remove_event_callback(
|
||||||
|
obs_frontend_event_cb callback, void *private_data)=0;
|
||||||
|
|
||||||
|
virtual obs_output_t *obs_frontend_get_streaming_output(void)=0;
|
||||||
|
virtual obs_output_t *obs_frontend_get_recording_output(void)=0;
|
||||||
|
|
||||||
|
virtual config_t *obs_frontend_get_profile_config(void)=0;
|
||||||
|
virtual config_t *obs_frontend_get_global_config(void)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_save(void)=0;
|
||||||
|
virtual void obs_frontend_add_save_callback(
|
||||||
|
obs_frontend_save_cb callback, void *private_data)=0;
|
||||||
|
virtual void obs_frontend_remove_save_callback(
|
||||||
|
obs_frontend_save_cb callback, void *private_data)=0;
|
||||||
|
|
||||||
|
virtual void obs_frontend_push_ui_translation(
|
||||||
|
obs_frontend_translate_ui_cb translate)=0;
|
||||||
|
virtual void obs_frontend_pop_ui_translation(void)=0;
|
||||||
|
|
||||||
|
virtual void on_load(obs_data_t *settings)=0;
|
||||||
|
virtual void on_save(obs_data_t *settings)=0;
|
||||||
|
virtual void on_event(enum obs_frontend_event event)=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPORT void obs_frontend_set_callbacks_internal(
|
||||||
|
obs_frontend_callbacks *callbacks);
|
@ -239,6 +239,11 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
|
|||||||
|
|
||||||
config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
|
config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,6 +368,11 @@ void OBSBasic::on_actionRenameProfile_triggered()
|
|||||||
DeleteProfile(curName.c_str(), curDir.c_str());
|
DeleteProfile(curName.c_str(), curDir.c_str());
|
||||||
RefreshProfiles();
|
RefreshProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionRemoveProfile_triggered()
|
void OBSBasic::on_actionRemoveProfile_triggered()
|
||||||
@ -431,6 +441,11 @@ void OBSBasic::on_actionRemoveProfile_triggered()
|
|||||||
blog(LOG_INFO, "------------------------------------------------");
|
blog(LOG_INFO, "------------------------------------------------");
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED);
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::ChangeProfile()
|
void OBSBasic::ChangeProfile()
|
||||||
@ -481,4 +496,7 @@ void OBSBasic::ChangeProfile()
|
|||||||
blog(LOG_INFO, "Switched to profile '%s' (%s)",
|
blog(LOG_INFO, "Switched to profile '%s' (%s)",
|
||||||
newName, newDir);
|
newName, newDir);
|
||||||
blog(LOG_INFO, "------------------------------------------------");
|
blog(LOG_INFO, "------------------------------------------------");
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_PROFILE_CHANGED);
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,11 @@ void OBSBasic::AddSceneCollection(bool create_new)
|
|||||||
blog(LOG_INFO, "------------------------------------------------");
|
blog(LOG_INFO, "------------------------------------------------");
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::RefreshSceneCollections()
|
void OBSBasic::RefreshSceneCollections()
|
||||||
@ -267,6 +272,11 @@ void OBSBasic::on_actionRenameSceneCollection_triggered()
|
|||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
RefreshSceneCollections();
|
RefreshSceneCollections();
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
||||||
@ -330,6 +340,11 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
|
|||||||
blog(LOG_INFO, "------------------------------------------------");
|
blog(LOG_INFO, "------------------------------------------------");
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED);
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::ChangeSceneCollection()
|
void OBSBasic::ChangeSceneCollection()
|
||||||
@ -366,4 +381,7 @@ void OBSBasic::ChangeSceneCollection()
|
|||||||
blog(LOG_INFO, "------------------------------------------------");
|
blog(LOG_INFO, "------------------------------------------------");
|
||||||
|
|
||||||
UpdateTitleBar();
|
UpdateTitleBar();
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGED);
|
||||||
}
|
}
|
||||||
|
@ -234,6 +234,9 @@ void OBSBasic::TransitionStopped()
|
|||||||
SetCurrentScene(scene);
|
SetCurrentScene(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_STOPPED);
|
||||||
|
|
||||||
swapScene = nullptr;
|
swapScene = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,6 +284,9 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force)
|
|||||||
obs_scene_release(scene);
|
obs_scene_release(scene);
|
||||||
|
|
||||||
obs_source_release(transition);
|
obs_source_release(transition);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SetComboTransition(QComboBox *combo, obs_source_t *tr)
|
static inline void SetComboTransition(QComboBox *combo, obs_source_t *tr)
|
||||||
@ -317,6 +323,9 @@ void OBSBasic::SetTransition(OBSSource transition)
|
|||||||
bool configurable = obs_source_configurable(transition);
|
bool configurable = obs_source_configurable(transition);
|
||||||
ui->transitionRemove->setEnabled(configurable);
|
ui->transitionRemove->setEnabled(configurable);
|
||||||
ui->transitionProps->setEnabled(configurable);
|
ui->transitionProps->setEnabled(configurable);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSSource OBSBasic::GetCurrentTransition()
|
OBSSource OBSBasic::GetCurrentTransition()
|
||||||
@ -378,6 +387,9 @@ void OBSBasic::AddTransition()
|
|||||||
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
|
ui->transitions->setCurrentIndex(ui->transitions->count() - 1);
|
||||||
CreatePropertiesWindow(source);
|
CreatePropertiesWindow(source);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,6 +440,9 @@ void OBSBasic::on_transitionRemove_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->transitions->removeItem(idx);
|
ui->transitions->removeItem(idx);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::RenameTransition()
|
void OBSBasic::RenameTransition()
|
||||||
|
@ -373,6 +373,13 @@ void OBSBasic::Save(const char *file)
|
|||||||
|
|
||||||
obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
|
obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
obs_data_t *moduleObj = obs_data_create();
|
||||||
|
api->on_save(moduleObj);
|
||||||
|
obs_data_set_obj(saveData, "modules", moduleObj);
|
||||||
|
obs_data_release(moduleObj);
|
||||||
|
}
|
||||||
|
|
||||||
if (!obs_data_save_json_safe(saveData, file, "tmp", "bak"))
|
if (!obs_data_save_json_safe(saveData, file, "tmp", "bak"))
|
||||||
blog(LOG_ERROR, "Could not save scene data to %s", file);
|
blog(LOG_ERROR, "Could not save scene data to %s", file);
|
||||||
|
|
||||||
@ -655,6 +662,12 @@ retryScene:
|
|||||||
ui->preview->SetLocked(previewLocked);
|
ui->preview->SetLocked(previewLocked);
|
||||||
ui->actionLockPreview->setChecked(previewLocked);
|
ui->actionLockPreview->setChecked(previewLocked);
|
||||||
|
|
||||||
|
if (api) {
|
||||||
|
obs_data_t *modulesObj = obs_data_get_obj(data, "modules");
|
||||||
|
api->on_load(modulesObj);
|
||||||
|
obs_data_release(modulesObj);
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
|
|
||||||
if (!opt_starting_scene.empty())
|
if (!opt_starting_scene.empty())
|
||||||
@ -1019,6 +1032,8 @@ void OBSBasic::ResetOutputs()
|
|||||||
#define SHUTDOWN_SEPARATOR \
|
#define SHUTDOWN_SEPARATOR \
|
||||||
"==== Shutting down =================================================="
|
"==== Shutting down =================================================="
|
||||||
|
|
||||||
|
extern obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main);
|
||||||
|
|
||||||
void OBSBasic::OBSInit()
|
void OBSBasic::OBSInit()
|
||||||
{
|
{
|
||||||
ProfileScope("OBSBasic::OBSInit");
|
ProfileScope("OBSBasic::OBSInit");
|
||||||
@ -1065,6 +1080,8 @@ void OBSBasic::OBSInit()
|
|||||||
InitOBSCallbacks();
|
InitOBSCallbacks();
|
||||||
InitHotkeys();
|
InitHotkeys();
|
||||||
|
|
||||||
|
api = InitializeAPIInterface(this);
|
||||||
|
|
||||||
AddExtraModulePaths();
|
AddExtraModulePaths();
|
||||||
blog(LOG_INFO, "---------------------------------");
|
blog(LOG_INFO, "---------------------------------");
|
||||||
obs_load_all_modules();
|
obs_load_all_modules();
|
||||||
@ -2067,6 +2084,9 @@ void OBSBasic::DuplicateSelectedScene()
|
|||||||
AddScene(source);
|
AddScene(source);
|
||||||
SetCurrentScene(source, true);
|
SetCurrentScene(source, true);
|
||||||
obs_scene_release(scene);
|
obs_scene_release(scene);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2076,8 +2096,12 @@ void OBSBasic::RemoveSelectedScene()
|
|||||||
OBSScene scene = GetCurrentScene();
|
OBSScene scene = GetCurrentScene();
|
||||||
if (scene) {
|
if (scene) {
|
||||||
obs_source_t *source = obs_scene_get_source(scene);
|
obs_source_t *source = obs_scene_get_source(scene);
|
||||||
if (QueryRemoveSource(source))
|
if (QueryRemoveSource(source)) {
|
||||||
obs_source_remove(source);
|
obs_source_remove(source);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2639,6 +2663,10 @@ void OBSBasic::closeEvent(QCloseEvent *event)
|
|||||||
signalHandlers.clear();
|
signalHandlers.clear();
|
||||||
|
|
||||||
SaveProjectNow();
|
SaveProjectNow();
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_EXIT);
|
||||||
|
|
||||||
disableSaving++;
|
disableSaving++;
|
||||||
|
|
||||||
/* Clear all scene data (dialogs, widgets, widget sub-items, scenes,
|
/* Clear all scene data (dialogs, widgets, widget sub-items, scenes,
|
||||||
@ -3487,6 +3515,9 @@ void OBSBasic::SceneNameEdited(QWidget *editor,
|
|||||||
obs_source_t *source = obs_scene_get_source(scene);
|
obs_source_t *source = obs_scene_get_source(scene);
|
||||||
RenameListItem(this, ui->scenes, source, text);
|
RenameListItem(this, ui->scenes, source, text);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED);
|
||||||
|
|
||||||
UNUSED_PARAMETER(endHint);
|
UNUSED_PARAMETER(endHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3537,6 +3568,12 @@ void OBSBasic::OpenSceneFilters()
|
|||||||
|
|
||||||
void OBSBasic::StartStreaming()
|
void OBSBasic::StartStreaming()
|
||||||
{
|
{
|
||||||
|
if (outputHandler->StreamingActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STARTING);
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
|
|
||||||
ui->streamButton->setEnabled(false);
|
ui->streamButton->setEnabled(false);
|
||||||
@ -3684,6 +3721,9 @@ void OBSBasic::StreamingStart()
|
|||||||
sysTrayStream->setText(ui->streamButton->text());
|
sysTrayStream->setText(ui->streamButton->text());
|
||||||
sysTrayStream->setEnabled(true);
|
sysTrayStream->setEnabled(true);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STARTED);
|
||||||
|
|
||||||
OnActivate();
|
OnActivate();
|
||||||
|
|
||||||
blog(LOG_INFO, STREAMING_START);
|
blog(LOG_INFO, STREAMING_START);
|
||||||
@ -3693,6 +3733,9 @@ void OBSBasic::StreamStopping()
|
|||||||
{
|
{
|
||||||
ui->streamButton->setText(QTStr("Basic.Main.StoppingStreaming"));
|
ui->streamButton->setText(QTStr("Basic.Main.StoppingStreaming"));
|
||||||
sysTrayStream->setText(ui->streamButton->text());
|
sysTrayStream->setText(ui->streamButton->text());
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPING);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::StreamingStop(int code)
|
void OBSBasic::StreamingStop(int code)
|
||||||
@ -3730,6 +3773,9 @@ void OBSBasic::StreamingStop(int code)
|
|||||||
sysTrayStream->setText(ui->streamButton->text());
|
sysTrayStream->setText(ui->streamButton->text());
|
||||||
sysTrayStream->setEnabled(true);
|
sysTrayStream->setEnabled(true);
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_STREAMING_STOPPED);
|
||||||
|
|
||||||
OnDeactivate();
|
OnDeactivate();
|
||||||
|
|
||||||
blog(LOG_INFO, STREAMING_STOP);
|
blog(LOG_INFO, STREAMING_STOP);
|
||||||
@ -3754,6 +3800,9 @@ void OBSBasic::StartRecording()
|
|||||||
if (outputHandler->RecordingActive())
|
if (outputHandler->RecordingActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTING);
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
outputHandler->StartRecording();
|
outputHandler->StartRecording();
|
||||||
}
|
}
|
||||||
@ -3762,6 +3811,9 @@ void OBSBasic::RecordStopping()
|
|||||||
{
|
{
|
||||||
ui->recordButton->setText(QTStr("Basic.Main.StoppingRecording"));
|
ui->recordButton->setText(QTStr("Basic.Main.StoppingRecording"));
|
||||||
sysTrayRecord->setText(ui->recordButton->text());
|
sysTrayRecord->setText(ui->recordButton->text());
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STOPPING);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::StopRecording()
|
void OBSBasic::StopRecording()
|
||||||
@ -3780,6 +3832,9 @@ void OBSBasic::RecordingStart()
|
|||||||
ui->recordButton->setText(QTStr("Basic.Main.StopRecording"));
|
ui->recordButton->setText(QTStr("Basic.Main.StopRecording"));
|
||||||
sysTrayRecord->setText(ui->recordButton->text());
|
sysTrayRecord->setText(ui->recordButton->text());
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STARTED);
|
||||||
|
|
||||||
OnActivate();
|
OnActivate();
|
||||||
|
|
||||||
blog(LOG_INFO, RECORDING_START);
|
blog(LOG_INFO, RECORDING_START);
|
||||||
@ -3820,6 +3875,9 @@ void OBSBasic::RecordingStop(int code)
|
|||||||
QSystemTrayIcon::Warning);
|
QSystemTrayIcon::Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (api)
|
||||||
|
api->on_event(OBS_FRONTEND_EVENT_RECORDING_STOPPED);
|
||||||
|
|
||||||
OnDeactivate();
|
OnDeactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include "window-basic-adv-audio.hpp"
|
#include "window-basic-adv-audio.hpp"
|
||||||
#include "window-basic-filters.hpp"
|
#include "window-basic-filters.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-internal.hpp>
|
||||||
|
|
||||||
#include <util/platform.h>
|
#include <util/platform.h>
|
||||||
#include <util/threading.h>
|
#include <util/threading.h>
|
||||||
#include <util/util.hpp>
|
#include <util/util.hpp>
|
||||||
@ -83,6 +85,7 @@ class OBSBasic : public OBSMainWindow {
|
|||||||
friend class OBSBasicPreview;
|
friend class OBSBasicPreview;
|
||||||
friend class OBSBasicStatusBar;
|
friend class OBSBasicStatusBar;
|
||||||
friend class OBSBasicSourceSelect;
|
friend class OBSBasicSourceSelect;
|
||||||
|
friend struct OBSStudioAPI;
|
||||||
|
|
||||||
enum class MoveDir {
|
enum class MoveDir {
|
||||||
Up,
|
Up,
|
||||||
@ -92,6 +95,8 @@ class OBSBasic : public OBSMainWindow {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
obs_frontend_callbacks *api = nullptr;
|
||||||
|
|
||||||
std::vector<VolControl*> volumes;
|
std::vector<VolControl*> volumes;
|
||||||
|
|
||||||
std::vector<OBSSignal> signalHandlers;
|
std::vector<OBSSignal> signalHandlers;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user