Skip to content

Commit 3681850

Browse files
dsaedtlerRytoEX
authored andcommitted
frontend: Add support loading/saving additional canvases
1 parent afd7619 commit 3681850

File tree

5 files changed

+84
-3
lines changed

5 files changed

+84
-3
lines changed

frontend/cmake/ui-widgets.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ target_sources(
1515
widgets/OBSBasic.cpp
1616
widgets/OBSBasic.hpp
1717
widgets/OBSBasic_Browser.cpp
18+
widgets/OBSBasic_Canvases.cpp
1819
widgets/OBSBasic_Clipboard.cpp
1920
widgets/OBSBasic_ContextToolbar.cpp
2021
widgets/OBSBasic_Docks.cpp

frontend/widgets/OBSBasic.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ void OBSBasic::InitOBSCallbacks()
842842
{
843843
ProfileScope("OBSBasic::InitOBSCallbacks");
844844

845-
signalHandlers.reserve(signalHandlers.size() + 9);
845+
signalHandlers.reserve(signalHandlers.size() + 10);
846846
signalHandlers.emplace_back(obs_get_signal_handler(), "source_create", OBSBasic::SourceCreated, this);
847847
signalHandlers.emplace_back(obs_get_signal_handler(), "source_remove", OBSBasic::SourceRemoved, this);
848848
signalHandlers.emplace_back(obs_get_signal_handler(), "source_activate", OBSBasic::SourceActivated, this);
@@ -866,6 +866,7 @@ void OBSBasic::InitOBSCallbacks()
866866
Qt::QueuedConnection);
867867
},
868868
this);
869+
signalHandlers.emplace_back(obs_get_signal_handler(), "canvas_remove", OBSBasic::CanvasRemoved, this);
869870
}
870871

871872
#define STARTUP_SEPARATOR "==== Startup complete ==============================================="

frontend/widgets/OBSBasic.hpp

+18
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <OBSApp.hpp>
2424
#include <oauth/Auth.hpp>
2525
#include <utility/BasicOutputHandler.hpp>
26+
#include <utility/OBSCanvas.hpp>
2627
#include <utility/VCamConfig.hpp>
2728
#include <utility/platform.hpp>
2829
#include <utility/undo_stack.hpp>
@@ -1108,6 +1109,23 @@ private slots:
11081109
std::optional<SceneCollection> GetSceneCollectionByName(const std::string &collectionName) const;
11091110
std::optional<SceneCollection> GetSceneCollectionByFileName(const std::string &fileName) const;
11101111

1112+
/* -------------------------------------
1113+
* MARK: - OBSBasic_Canvases
1114+
* -------------------------------------
1115+
*/
1116+
private:
1117+
std::vector<OBS::Canvas> canvases;
1118+
1119+
static void CanvasRemoved(void *data, calldata_t *params);
1120+
1121+
public:
1122+
const std::vector<OBS::Canvas> &GetCanvases() const noexcept { return canvases; }
1123+
1124+
const OBS::Canvas &AddCanvas(const std::string &name, obs_video_info *ovi = nullptr, int flags = 0);
1125+
1126+
public slots:
1127+
bool RemoveCanvas(obs_canvas_t *canvas);
1128+
11111129
/* -------------------------------------
11121130
* MARK: - OBSBasic_SceneItems
11131131
* -------------------------------------
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/******************************************************************************
2+
Copyright (C) 2025 by Dennis Sädtler <[email protected]>
3+
4+
This program is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 2 of the License, or
7+
(at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
******************************************************************************/
17+
18+
#include "OBSBasic.hpp"
19+
20+
void OBSBasic::CanvasRemoved(void *data, calldata_t *params)
21+
{
22+
obs_canvas_t *canvas = static_cast<obs_canvas_t *>(calldata_ptr(params, "canvas"));
23+
QMetaObject::invokeMethod(static_cast<OBSBasic *>(data), "RemoveCanvas", Q_ARG(OBSCanvas, OBSCanvas(canvas)));
24+
}
25+
26+
const OBS::Canvas &OBSBasic::AddCanvas(const std::string &name, obs_video_info *ovi, int flags)
27+
{
28+
OBSCanvas canvas = obs_canvas_create(name.c_str(), ovi, flags);
29+
auto &it = canvases.emplace_back(canvas);
30+
OnEvent(OBS_FRONTEND_EVENT_CANVAS_ADDED);
31+
return it;
32+
}
33+
34+
bool OBSBasic::RemoveCanvas(obs_canvas_t *canvas)
35+
{
36+
if (!canvas)
37+
return false;
38+
39+
auto canvas_it = std::find(std::begin(canvases), std::end(canvases), canvas);
40+
if (canvas_it != std::end(canvases)) {
41+
canvases.erase(canvas_it);
42+
OnEvent(OBS_FRONTEND_EVENT_CANVAS_REMOVED);
43+
return true;
44+
}
45+
46+
return false;
47+
}

frontend/widgets/OBSBasic_SceneCollections.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,8 @@ static void SaveAudioDevice(const char *name, int channel, obs_data_t *parent, v
808808

809809
static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder, obs_data_array_t *quickTransitionData,
810810
int transitionDuration, obs_data_array_t *transitions, OBSScene &scene,
811-
OBSSource &curProgramScene, obs_data_array_t *savedProjectorList)
811+
OBSSource &curProgramScene, obs_data_array_t *savedProjectorList,
812+
obs_data_array_t *savedCanvases)
812813
{
813814
obs_data_t *saveData = obs_data_create();
814815

@@ -865,6 +866,7 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder, obs_data_array
865866
obs_data_set_array(saveData, "quick_transitions", quickTransitionData);
866867
obs_data_set_array(saveData, "transitions", transitions);
867868
obs_data_set_array(saveData, "saved_projectors", savedProjectorList);
869+
obs_data_set_array(saveData, "canvases", savedCanvases);
868870
obs_data_array_release(sourcesArray);
869871
obs_data_array_release(groupsArray);
870872

@@ -885,8 +887,10 @@ void OBSBasic::Save(SceneCollection &collection)
885887
OBSDataArrayAutoRelease transitions = SaveTransitions();
886888
OBSDataArrayAutoRelease quickTrData = SaveQuickTransitions();
887889
OBSDataArrayAutoRelease savedProjectorList = SaveProjectors();
890+
OBSDataArrayAutoRelease savedCanvases = OBS::Canvas::SaveCanvases(canvases);
888891
OBSDataAutoRelease saveData = GenerateSaveData(sceneOrder, quickTrData, ui->transitionDuration->value(),
889-
transitions, scene, curProgramScene, savedProjectorList);
892+
transitions, scene, curProgramScene, savedProjectorList,
893+
savedCanvases);
890894

891895
obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
892896
obs_data_set_bool(saveData, "scaling_enabled", ui->preview->IsFixedScaling());
@@ -1171,6 +1175,7 @@ void OBSBasic::LoadData(obs_data_t *data, SceneCollection &collection)
11711175
OBSDataArrayAutoRelease sources = obs_data_get_array(data, "sources");
11721176
OBSDataArrayAutoRelease groups = obs_data_get_array(data, "groups");
11731177
OBSDataArrayAutoRelease transitions = obs_data_get_array(data, "transitions");
1178+
OBSDataArrayAutoRelease collection_canvases = obs_data_get_array(data, "canvases");
11741179
const char *sceneName = obs_data_get_string(data, "current_scene");
11751180
const char *programSceneName = obs_data_get_string(data, "current_program_scene");
11761181
const char *transitionName = obs_data_get_string(data, "current_transition");
@@ -1207,6 +1212,9 @@ void OBSBasic::LoadData(obs_data_t *data, SceneCollection &collection)
12071212
LoadAudioDevice(AUX_AUDIO_3, 5, data);
12081213
LoadAudioDevice(AUX_AUDIO_4, 6, data);
12091214

1215+
if (collection_canvases)
1216+
canvases = OBS::Canvas::LoadCanvases(collection_canvases);
1217+
12101218
if (!sources) {
12111219
sources = std::move(groups);
12121220
} else {
@@ -1525,6 +1533,12 @@ void OBSBasic::ClearSceneData()
15251533
obs_enum_scenes(cb, nullptr);
15261534
obs_enum_sources(cb, nullptr);
15271535

1536+
for (const auto &canvas : canvases) {
1537+
obs_canvas_enum_scenes(canvas, cb, nullptr);
1538+
}
1539+
1540+
canvases.clear();
1541+
15281542
OnEvent(OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP);
15291543

15301544
undo_s.clear();

0 commit comments

Comments
 (0)