diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index b73be8a3f..6c11e499e 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -186,6 +186,9 @@ struct obs_source { signal_handler_t signals; proc_handler_t procs; + /* ensures activate/deactivate are only called once */ + int activate_refs; + /* prevents infinite recursion when enumerating sources */ int enum_refs; diff --git a/libobs/obs-scene.c b/libobs/obs-scene.c index 109383e7d..73953dd59 100644 --- a/libobs/obs-scene.c +++ b/libobs/obs-scene.c @@ -298,17 +298,26 @@ void obs_scene_enum_items(obs_scene_t scene, obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source) { struct obs_scene_item *last; - struct obs_scene_item *item = bzalloc(sizeof(struct obs_scene_item)); + struct obs_scene_item *item; struct calldata params = {0}; + if (!scene) + return NULL; + + if (!source) { + blog(LOG_WARNING, "Tried to add a NULL source to a scene"); + return NULL; + } + + item = bzalloc(sizeof(struct obs_scene_item)); item->source = source; item->visible = true; item->parent = scene; item->ref = 1; vec2_set(&item->scale, 1.0f, 1.0f); - if (source) - obs_source_addref(source); + obs_source_addref(source); + obs_source_add_child(scene->source, source); pthread_mutex_lock(&scene->mutex); @@ -377,11 +386,12 @@ void obs_sceneitem_remove(obs_sceneitem_t item) item->removed = true; + obs_source_remove_child(scene->source, item->source); + signal_item_remove(item); detach_sceneitem(item); - if (scene) - pthread_mutex_unlock(&scene->mutex); + pthread_mutex_unlock(&scene->mutex); obs_sceneitem_release(item); } @@ -420,8 +430,8 @@ void obs_sceneitem_setorder(obs_sceneitem_t item, enum order_movement movement) { struct obs_scene *scene = item->parent; - pthread_mutex_lock(&scene->mutex); obs_scene_addref(scene); + pthread_mutex_lock(&scene->mutex); detach_sceneitem(item); @@ -446,8 +456,8 @@ void obs_sceneitem_setorder(obs_sceneitem_t item, enum order_movement movement) attach_sceneitem(item, NULL); } - obs_scene_release(scene); pthread_mutex_unlock(&scene->mutex); + obs_scene_release(scene); } void obs_sceneitem_getpos(obs_sceneitem_t item, struct vec2 *pos) diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 800b05c0f..f0182f0fa 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -294,16 +294,63 @@ void obs_source_update(obs_source_t source, obs_data_t settings) source->info.update(source->data, source->settings); } -void obs_source_activate(obs_source_t source) +static void activate_source(obs_source_t source) { + struct calldata data = {0}; + if (source->info.activate) source->info.activate(source->data); + + calldata_setptr(&data, "source", source); + signal_handler_signal(obs->signals, "source-activate", &data); + signal_handler_signal(source->signals, "activate", &data); + calldata_free(&data); +} + +static void deactivate_source(obs_source_t source) +{ + struct calldata data = {0}; + + if (source->info.deactivate) + source->info.deactivate(source->data); + + calldata_setptr(&data, "source", source); + signal_handler_signal(obs->signals, "source-deactivate", &data); + signal_handler_signal(source->signals, "deactivate", &data); + calldata_free(&data); +} + +static void activate_tree(obs_source_t parent, obs_source_t child, void *param) +{ + if (++child->activate_refs == 1) + activate_source(child); +} + +static void deactivate_tree(obs_source_t parent, obs_source_t child, + void *param) +{ + if (--child->activate_refs == 0) + deactivate_source(child); +} + +void obs_source_activate(obs_source_t source) +{ + if (!source) return; + + if (++source->activate_refs == 1) { + activate_source(source); + obs_source_enum_tree(source, activate_tree, NULL); + } } void obs_source_deactivate(obs_source_t source) { - if (source->info.deactivate) - source->info.deactivate(source->data); + if (!source) return; + + if (--source->activate_refs == 0) { + deactivate_source(source); + obs_source_enum_tree(source, deactivate_tree, NULL); + } } void obs_source_video_tick(obs_source_t source, float seconds) @@ -1219,3 +1266,19 @@ void obs_source_enum_tree(obs_source_t source, obs_source_release(source); } + +void obs_source_add_child(obs_source_t parent, obs_source_t child) +{ + if (!parent || !child) return; + + if (parent->activate_refs > 0) + obs_source_activate(child); +} + +void obs_source_remove_child(obs_source_t parent, obs_source_t child) +{ + if (!parent || !child) return; + + if (parent->activate_refs > 0) + obs_source_deactivate(child); +} diff --git a/libobs/obs-view.c b/libobs/obs-view.c index 959dfb72a..b22211dd9 100644 --- a/libobs/obs-view.c +++ b/libobs/obs-view.c @@ -93,10 +93,15 @@ void obs_view_setsource(obs_view_t view, uint32_t channel, prev_source = view->channels[channel]; view->channels[channel] = source; - if (source) + if (source) { obs_source_addref(source); - if (prev_source) + obs_source_activate(source); + } + + if (prev_source) { + obs_source_deactivate(prev_source); obs_source_release(prev_source); + } pthread_mutex_unlock(&view->channels_mutex); } diff --git a/libobs/obs.c b/libobs/obs.c index 1cfbef0be..b914d8af4 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -678,10 +678,15 @@ void obs_set_output_source(uint32_t channel, obs_source_t source) view->channels[channel] = source; - if (source) + if (source) { obs_source_addref(source); - if (prev_source) + obs_source_activate(source); + } + + if (prev_source) { + obs_source_deactivate(prev_source); obs_source_release(prev_source); + } pthread_mutex_unlock(&view->channels_mutex); } diff --git a/libobs/obs.h b/libobs/obs.h index 5cc527706..ae8ad2a98 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -520,6 +520,9 @@ EXPORT void obs_source_enum_tree(obs_source_t source, obs_source_enum_proc_t enum_callback, void *param); +/** Returns true if active, false if not */ +EXPORT bool obs_source_active(obs_source_t source); + /* ------------------------------------------------------------------------- */ /* Functions used by sources */ @@ -543,6 +546,20 @@ EXPORT void obs_source_process_filter(obs_source_t filter, effect_t effect, uint32_t width, uint32_t height, enum gs_color_format format, enum allow_direct_render allow_direct); +/** + * Adds a child source. Must be called by parent sources on child sources + * when the child is added. This ensures that the source is properly activated + * if the parent is active. + */ +EXPORT void obs_source_add_child(obs_source_t parent, obs_source_t child); + +/** + * Removes a child source. Must be called by parent sources on child sources + * when the child is removed. This ensures that the source is properly + * deactivated if the parent is active. + */ +EXPORT void obs_source_remove_child(obs_source_t parent, obs_source_t child); + /* ------------------------------------------------------------------------- */ /* Scenes */ diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index 277f0b045..c408b2e1c 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -37,6 +37,7 @@ Q_DECLARE_METATYPE(OBSSceneItem); OBSBasic::OBSBasic(QWidget *parent) : OBSMainWindow (parent), outputTest (NULL), + sceneChanging (false), ui (new Ui::OBSBasic) { ui->setupUi(this); @@ -194,12 +195,14 @@ void OBSBasic::UpdateSceneSelection(OBSSource source) obs_scene_t scene = obs_scene_fromsource(source); const char *name = obs_source_getname(source); - QListWidgetItem *sel = ui->scenes->currentItem(); QList items = ui->scenes->findItems(QT_UTF8(name), Qt::MatchExactly); - if (items.contains(sel)) { - ui->scenes->setCurrentItem(sel); + if (items.count()) { + sceneChanging = true; + ui->scenes->setCurrentItem(items.first()); + sceneChanging = false; + UpdateSources(scene); } } @@ -384,20 +387,26 @@ void OBSBasic::on_action_Save_triggered() /* TODO */ } -void OBSBasic::on_scenes_itemChanged(QListWidgetItem *item) +void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current, + QListWidgetItem *prev) { obs_source_t source = NULL; - if (item) { + if (sceneChanging) + return; + + if (current) { obs_scene_t scene; - scene = item->data(Qt::UserRole).value(); + scene = current->data(Qt::UserRole).value(); source = obs_scene_getsource(scene); UpdateSources(scene); } /* TODO: allow transitions */ obs_set_output_source(0, source); + + UNUSED_PARAMETER(prev); } void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos) @@ -462,10 +471,12 @@ void OBSBasic::on_actionSceneDown_triggered() /* TODO */ } -void OBSBasic::on_sources_itemChanged(QListWidgetItem *item) +void OBSBasic::on_sources_currentItemChanged(QListWidgetItem *current, + QListWidgetItem *prev) { /* TODO */ - UNUSED_PARAMETER(item); + UNUSED_PARAMETER(current); + UNUSED_PARAMETER(prev); } void OBSBasic::on_sources_customContextMenuRequested(const QPoint &pos) diff --git a/obs/window-basic-main.hpp b/obs/window-basic-main.hpp index 3ce9a52a5..a7bc78a96 100644 --- a/obs/window-basic-main.hpp +++ b/obs/window-basic-main.hpp @@ -32,6 +32,7 @@ class OBSBasic : public OBSMainWindow { private: std::unordered_map sourceSceneRefs; obs_output_t outputTest; + bool sceneChanging; OBSScene GetCurrentScene(); OBSSceneItem GetCurrentSceneItem(); @@ -75,14 +76,16 @@ private slots: void on_action_New_triggered(); void on_action_Open_triggered(); void on_action_Save_triggered(); - void on_scenes_itemChanged(QListWidgetItem *item); + void on_scenes_currentItemChanged(QListWidgetItem *current, + QListWidgetItem *prev); void on_scenes_customContextMenuRequested(const QPoint &pos); void on_actionAddScene_triggered(); void on_actionRemoveScene_triggered(); void on_actionSceneProperties_triggered(); void on_actionSceneUp_triggered(); void on_actionSceneDown_triggered(); - void on_sources_itemChanged(QListWidgetItem *item); + void on_sources_currentItemChanged(QListWidgetItem *current, + QListWidgetItem *prev); void on_sources_customContextMenuRequested(const QPoint &pos); void on_actionAddSource_triggered(); void on_actionRemoveSource_triggered();