فهرست منبع

Merge pull request #1195 from admshao/fix-save-projectors-on-exit

Save Windowed Projectors on exit
Jim 7 سال پیش
والد
کامیت
7481f5b389
4فایلهای تغییر یافته به همراه290 افزوده شده و 375 حذف شده
  1. 139 261
      UI/window-basic-main.cpp
  2. 10 26
      UI/window-basic-main.hpp
  3. 122 82
      UI/window-projector.cpp
  4. 19 6
      UI/window-projector.hpp

+ 139 - 261
UI/window-basic-main.cpp

@@ -137,11 +137,6 @@ OBSBasic::OBSBasic(QWidget *parent)
 {
 	setAttribute(Qt::WA_NativeWindow);
 
-	projectorArray.resize(10, "");
-	previewProjectorArray.resize(10, 0);
-	multiviewProjectorArray.resize(10, 0);
-	studioProgramProjectorArray.resize(10, 0);
-
 	setAcceptDrops(true);
 
 	ui->setupUi(this);
@@ -319,10 +314,7 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
 		obs_data_array_t *quickTransitionData, int transitionDuration,
 		obs_data_array_t *transitions,
 		OBSScene &scene, OBSSource &curProgramScene,
-		obs_data_array_t *savedProjectorList,
-		obs_data_array_t *savedPreviewProjectorList,
-		obs_data_array_t *savedStudioProgramProjectorList,
-		obs_data_array_t *savedMultiviewProjectorList)
+		obs_data_array_t *savedProjectorList)
 {
 	obs_data_t *saveData = obs_data_create();
 
@@ -364,12 +356,6 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder,
 	obs_data_set_array(saveData, "quick_transitions", quickTransitionData);
 	obs_data_set_array(saveData, "transitions", transitions);
 	obs_data_set_array(saveData, "saved_projectors", savedProjectorList);
-	obs_data_set_array(saveData, "saved_preview_projectors",
-			savedPreviewProjectorList);
-	obs_data_set_array(saveData, "saved_studio_preview_projectors",
-			savedStudioProgramProjectorList);
-	obs_data_set_array(saveData, "saved_multiview_projectors",
-			savedMultiviewProjectorList);
 	obs_data_array_release(sourcesArray);
 
 	obs_data_set_string(saveData, "current_transition",
@@ -439,62 +425,41 @@ obs_data_array_t *OBSBasic::SaveSceneListOrder()
 
 obs_data_array_t *OBSBasic::SaveProjectors()
 {
-	obs_data_array_t *saveProjector = obs_data_array_create();
-
-	for (size_t i = 0; i < projectorArray.size(); i++) {
-		obs_data_t *data = obs_data_create();
-		obs_data_set_string(data, "saved_projectors",
-			projectorArray.at(i).c_str());
-		obs_data_array_push_back(saveProjector, data);
-		obs_data_release(data);
-	}
-
-	return saveProjector;
-}
-
-obs_data_array_t *OBSBasic::SavePreviewProjectors()
-{
-	obs_data_array_t *saveProjector = obs_data_array_create();
-
-	for (size_t i = 0; i < previewProjectorArray.size(); i++) {
-		obs_data_t *data = obs_data_create();
-		obs_data_set_int(data, "saved_preview_projectors",
-			previewProjectorArray.at(i));
-		obs_data_array_push_back(saveProjector, data);
-		obs_data_release(data);
-	}
-
-	return saveProjector;
-}
+	obs_data_array_t *savedProjectors = obs_data_array_create();
 
-obs_data_array_t *OBSBasic::SaveStudioProgramProjectors()
-{
-	obs_data_array_t *saveProjector = obs_data_array_create();
+	auto saveProjector = [savedProjectors](OBSProjector *projector) {
+		if (!projector)
+			return;
 
-	for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) {
 		obs_data_t *data = obs_data_create();
-		obs_data_set_int(data, "saved_studio_preview_projectors",
-			studioProgramProjectorArray.at(i));
-		obs_data_array_push_back(saveProjector, data);
+		ProjectorType type = projector->GetProjectorType();
+		switch (type) {
+		case ProjectorType::Scene:
+		case ProjectorType::Source: {
+			obs_source_t *source = projector->GetSource();
+			const char *name = obs_source_get_name(source);
+			obs_data_set_string(data, "name", name);
+			break;
+		}
+		default:
+			break;
+		}
+		obs_data_set_int(data, "monitor", projector->GetMonitor());
+		obs_data_set_int(data, "type", static_cast<int>(type));
+		obs_data_set_string(data, "geometry",
+				projector->saveGeometry().toBase64()
+						.constData());
+		obs_data_array_push_back(savedProjectors, data);
 		obs_data_release(data);
-	}
-
-	return saveProjector;
-}
+	};
 
-obs_data_array_t *OBSBasic::SaveMultiviewProjectors()
-{
-	obs_data_array_t *saveProjector = obs_data_array_create();
+	for (QPointer<QWidget> &proj : projectors)
+		saveProjector(static_cast<OBSProjector *>(proj.data()));
 
-	for (size_t i = 0; i < multiviewProjectorArray.size(); i++) {
-		obs_data_t *data = obs_data_create();
-		obs_data_set_int(data, "saved_multiview_projectors",
-			multiviewProjectorArray.at(i));
-		obs_data_array_push_back(saveProjector, data);
-		obs_data_release(data);
-	}
+	for (QPointer<QWidget> &proj : windowProjectors)
+		saveProjector(static_cast<OBSProjector *>(proj.data()));
 
-	return saveProjector;
+	return savedProjectors;
 }
 
 void OBSBasic::Save(const char *file)
@@ -508,17 +473,9 @@ void OBSBasic::Save(const char *file)
 	obs_data_array_t *transitions = SaveTransitions();
 	obs_data_array_t *quickTrData = SaveQuickTransitions();
 	obs_data_array_t *savedProjectorList = SaveProjectors();
-	obs_data_array_t *savedPreviewProjectorList = SavePreviewProjectors();
-	obs_data_array_t *savedStudioProgramProjectorList =
-			SaveStudioProgramProjectors();
-	obs_data_array_t *savedMultiviewProjectorList =
-			SaveMultiviewProjectors();
 	obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData,
 			ui->transitionDuration->value(), transitions,
-			scene, curProgramScene, savedProjectorList,
-			savedPreviewProjectorList,
-			savedStudioProgramProjectorList,
-			savedMultiviewProjectorList);
+			scene, curProgramScene, savedProjectorList);
 
 	obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
 	obs_data_set_bool(saveData, "scaling_enabled",
@@ -545,9 +502,6 @@ void OBSBasic::Save(const char *file)
 	obs_data_array_release(quickTrData);
 	obs_data_array_release(transitions);
 	obs_data_array_release(savedProjectorList);
-	obs_data_array_release(savedPreviewProjectorList);
-	obs_data_array_release(savedStudioProgramProjectorList);
-	obs_data_array_release(savedMultiviewProjectorList);
 }
 
 void OBSBasic::DeferSaveBegin()
@@ -666,47 +620,15 @@ void OBSBasic::LoadSavedProjectors(obs_data_array_t *array)
 
 	for (size_t i = 0; i < num; i++) {
 		obs_data_t *data = obs_data_array_item(array, i);
-		projectorArray.at(i) = obs_data_get_string(data,
-				"saved_projectors");
 
-		obs_data_release(data);
-	}
-}
-
-void OBSBasic::LoadSavedPreviewProjectors(obs_data_array_t *array)
-{
-	size_t num = obs_data_array_count(array);
-
-	for (size_t i = 0; i < num; i++) {
-		obs_data_t *data = obs_data_array_item(array, i);
-		previewProjectorArray.at(i) = obs_data_get_int(data,
-				"saved_preview_projectors");
-
-		obs_data_release(data);
-	}
-}
-
-void OBSBasic::LoadSavedStudioProgramProjectors(obs_data_array_t *array)
-{
-	size_t num = obs_data_array_count(array);
-
-	for (size_t i = 0; i < num; i++) {
-		obs_data_t *data = obs_data_array_item(array, i);
-		studioProgramProjectorArray.at(i) = obs_data_get_int(data,
-				"saved_studio_preview_projectors");
-
-		obs_data_release(data);
-	}
-}
-
-void OBSBasic::LoadSavedMultiviewProjectors(obs_data_array_t *array)
-{
-	size_t num = obs_data_array_count(array);
-
-	for (size_t i = 0; i < num; i++) {
-		obs_data_t *data = obs_data_array_item(array, i);
-		multiviewProjectorArray.at(i) = obs_data_get_int(data,
-				"saved_multiview_projectors");
+		SavedProjectorInfo *info = new SavedProjectorInfo();
+		info->monitor = obs_data_get_int(data, "monitor");
+		info->type = static_cast<ProjectorType>(obs_data_get_int(data,
+				"type"));
+		info->geometry = std::string(
+				obs_data_get_string(data, "geometry"));
+		info->name = std::string(obs_data_get_string(data, "name"));
+		savedProjectorsArray.emplace_back(info);
 
 		obs_data_release(data);
 	}
@@ -847,47 +769,6 @@ void OBSBasic::Load(const char *file)
 	ui->transitionDuration->setValue(newDuration);
 	SetTransition(curTransition);
 
-	/* ------------------- */
-
-	obs_data_array_t *savedProjectors = obs_data_get_array(data,
-			"saved_projectors");
-
-	if (savedProjectors)
-		LoadSavedProjectors(savedProjectors);
-
-	obs_data_array_release(savedProjectors);
-
-	/* ------------------- */
-
-	obs_data_array_t *savedPreviewProjectors = obs_data_get_array(data,
-			"saved_preview_projectors");
-
-	if (savedPreviewProjectors)
-		LoadSavedPreviewProjectors(savedPreviewProjectors);
-
-	obs_data_array_release(savedPreviewProjectors);
-
-	/* ------------------- */
-
-	obs_data_array_t *savedStudioProgramProjectors = obs_data_get_array(data,
-			"saved_studio_preview_projectors");
-
-	if (savedStudioProgramProjectors)
-		LoadSavedStudioProgramProjectors(savedStudioProgramProjectors);
-
-	obs_data_array_release(savedStudioProgramProjectors);
-
-	/* ------------------- */
-
-	obs_data_array_t *savedMultiviewProjectors = obs_data_get_array(data,
-			"saved_multiview_projectors");
-
-	if (savedMultiviewProjectors)
-		LoadSavedMultiviewProjectors(savedMultiviewProjectors);
-
-	obs_data_array_release(savedMultiviewProjectors);
-
-
 retryScene:
 	curScene = obs_get_source_by_name(sceneName);
 	curProgramScene = obs_get_source_by_name(programSceneName);
@@ -918,6 +799,23 @@ retryScene:
 	obs_data_array_release(sources);
 	obs_data_array_release(sceneOrder);
 
+	/* ------------------- */
+
+	bool projectorSave = config_get_bool(GetGlobalConfig(), "BasicWindow",
+			"SaveProjectors");
+
+	if (projectorSave) {
+		obs_data_array_t *savedProjectors = obs_data_get_array(data,
+				"saved_projectors");
+
+		if (savedProjectors)
+			LoadSavedProjectors(savedProjectors);
+
+		obs_data_array_release(savedProjectors);
+	}
+
+	/* ------------------- */
+
 	std::string file_base = strrchr(file, '/') + 1;
 	file_base.erase(file_base.size() - 5, 5);
 
@@ -1608,8 +1506,6 @@ void OBSBasic::OBSInit()
 
 	SystemTray(true);
 
-	OpenSavedProjectors();
-
 	if (windowState().testFlag(Qt::WindowFullScreen))
 		fullscreenInterface = true;
 
@@ -2365,13 +2261,7 @@ void OBSBasic::RenameSources(OBSSource source, QString newName,
 			volumes[i]->SetName(newName);
 	}
 
-	std::string newText = newName.toUtf8().constData();
-	std::string prevText = prevName.toUtf8().constData();
-
-	for (size_t j = 0; j < projectorArray.size(); j++) {
-		if (projectorArray.at(j) == prevText)
-			projectorArray.at(j) = newText;
-	}
+	OBSProjector::RenameProjector(prevName, newName);
 
 	SaveProject();
 
@@ -5615,40 +5505,17 @@ void OBSBasic::NudgeDown()     {Nudge(1,  MoveDir::Down);}
 void OBSBasic::NudgeLeft()     {Nudge(1,  MoveDir::Left);}
 void OBSBasic::NudgeRight()    {Nudge(1,  MoveDir::Right);}
 
-void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
+OBSProjector *OBSBasic::OpenProjector(obs_source_t *source, int monitor,
 		QString title, ProjectorType type)
 {
 	/* seriously?  10 monitors? */
 	if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1)
-		return;
-
-	if (!window) {
-		delete projectors[monitor];
-		projectors[monitor].clear();
-		RemoveSavedProjectors(monitor);
-	}
-
-	OBSProjector *projector = new OBSProjector(nullptr, source, !!window);
-	const char *name = obs_source_get_name(source);
+		return nullptr;
 
-	if (!window) {
-		if (type == ProjectorType::StudioProgram) {
-			studioProgramProjectorArray.at((size_t)monitor) = 1;
-		} else if (type == ProjectorType::Preview) {
-			previewProjectorArray.at((size_t)monitor) = 1;
-		} else if (type == ProjectorType::Multiview) {
-			multiviewProjectorArray.at((size_t)monitor) = 1;
-		} else {
-			projectorArray.at((size_t)monitor) = name;
-		}
-	}
-
-	if (!window) {
-		projector->Init(monitor, false, nullptr, type);
-		projectors[monitor] = projector;
-	} else {
-		projector->Init(monitor, true, title, type);
+	OBSProjector *projector = new OBSProjector(nullptr, source, monitor,
+			title, type);
 
+	if (monitor < 0) {
 		for (auto &projPtr : windowProjectors) {
 			if (!projPtr) {
 				projPtr = projector;
@@ -5658,20 +5525,27 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window,
 
 		if (projector)
 			windowProjectors.push_back(projector);
+	} else {
+		delete projectors[monitor];
+		projectors[monitor].clear();
+
+		projectors[monitor] = projector;
 	}
+
+	projector->Init();
+	return projector;
 }
 
 void OBSBasic::OpenStudioProgramProjector()
 {
 	int monitor = sender()->property("monitor").toInt();
-	OpenProjector(nullptr, monitor, false, nullptr,
-			ProjectorType::StudioProgram);
+	OpenProjector(nullptr, monitor, nullptr, ProjectorType::StudioProgram);
 }
 
 void OBSBasic::OpenPreviewProjector()
 {
 	int monitor = sender()->property("monitor").toInt();
-	OpenProjector(nullptr, monitor, false, nullptr, ProjectorType::Preview);
+	OpenProjector(nullptr, monitor, nullptr, ProjectorType::Preview);
 }
 
 void OBSBasic::OpenSourceProjector()
@@ -5681,14 +5555,14 @@ void OBSBasic::OpenSourceProjector()
 	if (!item)
 		return;
 
-	OpenProjector(obs_sceneitem_get_source(item), monitor, false);
+	OpenProjector(obs_sceneitem_get_source(item), monitor, nullptr,
+			ProjectorType::Source);
 }
 
 void OBSBasic::OpenMultiviewProjector()
 {
 	int monitor = sender()->property("monitor").toInt();
-	OpenProjector(nullptr, monitor, false, nullptr,
-			ProjectorType::Multiview);
+	OpenProjector(nullptr, monitor, nullptr, ProjectorType::Multiview);
 }
 
 void OBSBasic::OpenSceneProjector()
@@ -5698,59 +5572,52 @@ void OBSBasic::OpenSceneProjector()
 	if (!scene)
 		return;
 
-	OpenProjector(obs_scene_get_source(scene), monitor, false);
+	OpenProjector(obs_scene_get_source(scene), monitor, nullptr,
+			ProjectorType::Scene);
 }
 
 void OBSBasic::OpenStudioProgramWindow()
 {
-	int monitor = sender()->property("monitor").toInt();
-	QString title = QTStr("StudioProgramWindow");
-	OpenProjector(nullptr, monitor, true, title,
+	OpenProjector(nullptr, -1, QTStr("StudioProgramWindow"),
 			ProjectorType::StudioProgram);
 }
 
 void OBSBasic::OpenPreviewWindow()
 {
-	int monitor = sender()->property("monitor").toInt();
-	QString title = QTStr("PreviewWindow");
-	OpenProjector(nullptr, monitor, true, nullptr, ProjectorType::Preview);
+	OpenProjector(nullptr, -1, QTStr("PreviewWindow"),
+			ProjectorType::Preview);
 }
 
 void OBSBasic::OpenSourceWindow()
 {
-	int monitor = sender()->property("monitor").toInt();
 	OBSSceneItem item = GetCurrentSceneItem();
-	OBSSource source = obs_sceneitem_get_source(item);
-	QString text = QString::fromUtf8(obs_source_get_name(source));
-
-	QString title = QTStr("SourceWindow") + " - " + text;
-
 	if (!item)
 		return;
 
-	OpenProjector(obs_sceneitem_get_source(item), monitor, true, title);
+	OBSSource source = obs_sceneitem_get_source(item);
+	QString title = QString::fromUtf8(obs_source_get_name(source));
+
+	OpenProjector(obs_sceneitem_get_source(item), -1, title,
+			ProjectorType::Source);
 }
 
 void OBSBasic::OpenMultiviewWindow()
 {
-	int monitor = sender()->property("monitor").toInt();
-	OpenProjector(nullptr, monitor, true, "Multiview",
+	OpenProjector(nullptr, -1, QTStr("MultiviewWindowed"),
 			ProjectorType::Multiview);
 }
 
 void OBSBasic::OpenSceneWindow()
 {
-	int monitor = sender()->property("monitor").toInt();
 	OBSScene scene = GetCurrentScene();
-	OBSSource source = obs_scene_get_source(scene);
-	QString text = QString::fromUtf8(obs_source_get_name(source));
-
-	QString title = QTStr("SceneWindow") + " - " + text;
-
 	if (!scene)
 		return;
 
-	OpenProjector(obs_scene_get_source(scene), monitor, true, title);
+	OBSSource source = obs_scene_get_source(scene);
+	QString title = QString::fromUtf8(obs_source_get_name(source));
+
+	OpenProjector(obs_scene_get_source(scene), -1, title,
+			ProjectorType::Scene);
 }
 
 void OBSBasic::OpenSavedProjectors()
@@ -5758,54 +5625,65 @@ void OBSBasic::OpenSavedProjectors()
 	bool projectorSave = config_get_bool(GetGlobalConfig(),
 			"BasicWindow", "SaveProjectors");
 
-	if (projectorSave) {
-		for (size_t i = 0; i < projectorArray.size(); i++) {
-			if (projectorArray.at(i).empty() == false) {
-				OBSSource source = obs_get_source_by_name(
-					projectorArray.at(i).c_str());
-
-				if (!source) {
-					RemoveSavedProjectors((int)i);
-					obs_source_release(source);
-					continue;
-				}
+	if (!projectorSave)
+		return;
 
-				OpenProjector(source, (int)i, false);
-				obs_source_release(source);
-			}
-		}
+	for (SavedProjectorInfo *info : savedProjectorsArray) {
+		OBSProjector *projector = nullptr;
+		switch (info->type) {
+		case ProjectorType::Source:
+		case ProjectorType::Scene: {
+			OBSSource source = obs_get_source_by_name(
+					info->name.c_str());
+			if (!source)
+				continue;
 
-		for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) {
-			if (studioProgramProjectorArray.at(i) == 1) {
-				OpenProjector(nullptr, (int)i, false, nullptr,
-						ProjectorType::StudioProgram);
-			}
-		}
+			QString title = nullptr;
+			if (info->monitor < 0)
+				title = QString::fromUtf8(
+						obs_source_get_name(source));
 
-		for (size_t i = 0; i < previewProjectorArray.size(); i++) {
-			if (previewProjectorArray.at(i) == 1) {
-				OpenProjector(nullptr, (int)i, false, nullptr,
-						ProjectorType::Preview);
-			}
+			projector = OpenProjector(source, info->monitor, title,
+					info->type);
+
+			obs_source_release(source);
+			break;
 		}
+		case ProjectorType::Preview: {
+			projector = OpenProjector(nullptr, info->monitor,
+					QTStr("PreviewWindow"),
+					ProjectorType::Preview);
+			break;
+		}
+		case ProjectorType::StudioProgram: {
+			projector = OpenProjector(nullptr, info->monitor,
+					QTStr("StudioProgramWindow"),
+					ProjectorType::StudioProgram);
+			break;
+		}
+		case ProjectorType::Multiview: {
+			projector = OpenProjector(nullptr, info->monitor,
+					QTStr("MultiviewWindowed"),
+					ProjectorType::Multiview);
+			break;
+		}
+		}
+
+		if (!info->geometry.empty()) {
+			QByteArray byteArray = QByteArray::fromBase64(
+					QByteArray(info->geometry.c_str()));
+			projector->restoreGeometry(byteArray);
 
-		for (size_t i = 0; i < multiviewProjectorArray.size(); i++) {
-			if (multiviewProjectorArray.at(i) == 1) {
-				OpenProjector(nullptr, (int)i, false, nullptr,
-						ProjectorType::Multiview);
+			if (!WindowPositionValid(projector->normalGeometry())) {
+				QRect rect = App()->desktop()->geometry();
+				projector->setGeometry(QStyle::alignedRect(
+						Qt::LeftToRight,
+						Qt::AlignCenter, size(), rect));
 			}
 		}
 	}
 }
 
-void OBSBasic::RemoveSavedProjectors(int monitor)
-{
-	studioProgramProjectorArray.at((size_t)monitor) = 0;
-	multiviewProjectorArray.at((size_t)monitor) = 0;
-	previewProjectorArray.at((size_t)monitor) = 0;
-	projectorArray.at((size_t)monitor) = "";
-}
-
 void OBSBasic::on_actionFullscreenInterface_triggered()
 {
 	if (!fullscreenInterface)

+ 10 - 26
UI/window-basic-main.hpp

@@ -29,6 +29,7 @@
 #include "window-basic-transform.hpp"
 #include "window-basic-adv-audio.hpp"
 #include "window-basic-filters.hpp"
+#include "window-projector.hpp"
 
 #include <obs-frontend-internal.hpp>
 
@@ -67,11 +68,11 @@ enum class QtDataRole {
 	OBSSignals,
 };
 
-enum class ProjectorType {
-	Source,
-	Preview,
-	StudioProgram,
-	Multiview
+struct SavedProjectorInfo {
+	ProjectorType type;
+	int monitor;
+	std::string geometry;
+	std::string name;
 };
 
 struct QuickTransition {
@@ -120,11 +121,6 @@ private:
 
 	std::vector<OBSSignal> signalHandlers;
 
-	std::vector<std::string> projectorArray;
-	std::vector<int> studioProgramProjectorArray;
-	std::vector<int> multiviewProjectorArray;
-	std::vector<int> previewProjectorArray;
-
 	bool loaded = false;
 	long disableSaving = 1;
 	bool projectChanged = false;
@@ -169,6 +165,7 @@ private:
 
 	ConfigFile    basicConfig;
 
+	std::vector<SavedProjectorInfo*> savedProjectorsArray;
 	QPointer<QWidget> projectors[10];
 	QList<QPointer<QWidget>> windowProjectors;
 
@@ -252,9 +249,9 @@ private:
 	void ClearSceneData();
 
 	void Nudge(int dist, MoveDir dir);
-	void OpenProjector(obs_source_t *source, int monitor, bool window,
-			QString title = nullptr,
-			ProjectorType type = ProjectorType::Source);
+
+	OBSProjector *OpenProjector(obs_source_t *source, int monitor,
+			QString title, ProjectorType type);
 
 	void GetAudioSourceFilters();
 	void GetAudioSourceProperties();
@@ -367,18 +364,6 @@ private:
 	obs_data_array_t *SaveProjectors();
 	void LoadSavedProjectors(obs_data_array_t *savedProjectors);
 
-	obs_data_array_t *SavePreviewProjectors();
-	void LoadSavedPreviewProjectors(
-		obs_data_array_t *savedPreviewProjectors);
-
-	obs_data_array_t *SaveStudioProgramProjectors();
-	void LoadSavedStudioProgramProjectors(
-		obs_data_array_t *savedStudioProgramProjectors);
-
-	obs_data_array_t *SaveMultiviewProjectors();
-	void LoadSavedMultiviewProjectors(
-		obs_data_array_t *savedMultiviewProjectors);
-
 public slots:
 	void DeferSaveBegin();
 	void DeferSaveEnd();
@@ -571,7 +556,6 @@ public:
 	void SystemTray(bool firstStarted);
 
 	void OpenSavedProjectors();
-	void RemoveSavedProjectors(int monitor);
 
 protected:
 	virtual void closeEvent(QCloseEvent *event) override;

+ 122 - 82
UI/window-projector.cpp

@@ -3,7 +3,8 @@
 #include <QMouseEvent>
 #include <QMenu>
 #include <QScreen>
-#include "window-projector.hpp"
+#include "obs-app.hpp"
+#include "window-basic-main.hpp"
 #include "display-helpers.hpp"
 #include "qt-wrappers.hpp"
 #include "platform.hpp"
@@ -13,18 +14,25 @@
 #define VERTICAL_LEFT     2
 #define VERTICAL_RIGHT    3
 
+static QList<OBSProjector *> windowedProjectors;
 static QList<OBSProjector *> multiviewProjectors;
 static bool updatingMultiview = false;
 static int multiviewLayout = HORIZONTAL_TOP;
 
-OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
+OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
+		QString title, ProjectorType type_)
 	: OBSQTDisplay                 (widget,
 	                                Qt::Window),
 	  source                       (source_),
 	  removedSignal                (obs_source_get_signal_handler(source),
 	                                "remove", OBSSourceRemoved, this)
 {
-	if (!window) {
+	projectorTitle = title;
+	savedMonitor   = monitor;
+	isWindow       = savedMonitor < 0;
+	type           = type_;
+
+	if (!isWindow) {
 		setWindowFlags(Qt::FramelessWindowHint |
 				Qt::X11BypassWindowManagerHint);
 	}
@@ -49,12 +57,61 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
 
 	bool hideCursor = config_get_bool(GetGlobalConfig(),
 			"BasicWindow", "HideProjectorCursor");
-	if (hideCursor && !window) {
+	if (hideCursor && !isWindow) {
 		QPixmap empty(16, 16);
 		empty.fill(Qt::transparent);
 		setCursor(QCursor(empty));
 	}
 
+	if (type == ProjectorType::Multiview) {
+		obs_enter_graphics();
+		gs_render_start(true);
+		gs_vertex2f(0.001f, 0.001f);
+		gs_vertex2f(0.001f, 0.997f);
+		gs_vertex2f(0.997f, 0.997f);
+		gs_vertex2f(0.997f, 0.001f);
+		gs_vertex2f(0.001f, 0.001f);
+		outerBox = gs_render_save();
+
+		gs_render_start(true);
+		gs_vertex2f(0.04f, 0.04f);
+		gs_vertex2f(0.04f, 0.96f);
+		gs_vertex2f(0.96f, 0.96f);
+		gs_vertex2f(0.96f, 0.04f);
+		gs_vertex2f(0.04f, 0.04f);
+		innerBox = gs_render_save();
+
+		gs_render_start(true);
+		gs_vertex2f(0.15f, 0.04f);
+		gs_vertex2f(0.15f, 0.96f);
+		leftVLine = gs_render_save();
+
+		gs_render_start(true);
+		gs_vertex2f(0.85f, 0.04f);
+		gs_vertex2f(0.85f, 0.96f);
+		rightVLine = gs_render_save();
+
+		gs_render_start(true);
+		gs_vertex2f(0.0f, 0.5f);
+		gs_vertex2f(0.075f, 0.5f);
+		leftLine = gs_render_save();
+
+		gs_render_start(true);
+		gs_vertex2f(0.5f, 0.0f);
+		gs_vertex2f(0.5f, 0.09f);
+		topLine = gs_render_save();
+
+		gs_render_start(true);
+		gs_vertex2f(0.925f, 0.5f);
+		gs_vertex2f(1.0f, 0.5f);
+		rightLine = gs_render_save();
+		obs_leave_graphics();
+
+		UpdateMultiview();
+
+		multiviewProjectors.push_back(this);
+	}
+
 	App()->IncrementSleepInhibition();
 	resize(480, 270);
 }
@@ -89,6 +146,9 @@ OBSProjector::~OBSProjector()
 	if (type == ProjectorType::Multiview)
 		multiviewProjectors.removeAll(this);
 
+	if (isWindow)
+		windowedProjectors.removeAll(this);
+
 	App()->DecrementSleepInhibition();
 }
 
@@ -132,28 +192,22 @@ static OBSSource CreateLabel(const char *name, size_t h)
 	return txtSource;
 }
 
-void OBSProjector::Init(int monitor, bool window, QString title,
-		ProjectorType type_)
+void OBSProjector::Init()
 {
-	QScreen *screen = QGuiApplication::screens()[monitor];
-
-	if (!window)
-		setGeometry(screen->geometry());
-
 	bool alwaysOnTop = config_get_bool(GetGlobalConfig(),
 			"BasicWindow", "ProjectorAlwaysOnTop");
-	if (alwaysOnTop && !window)
+	if (alwaysOnTop && !isWindow)
 		SetAlwaysOnTop(this, true);
 
-	if (window)
-		setWindowTitle(title);
-
 	show();
 
-	if (source)
-		obs_source_inc_showing(source);
+	if (isWindow) {
+		UpdateProjectorTitle(projectorTitle);
+		windowedProjectors.push_back(this);
+	} else {
+		QScreen *screen = QGuiApplication::screens()[savedMonitor];
+		setGeometry(screen->geometry());
 
-	if (!window) {
 		QAction *action = new QAction(this);
 		action->setShortcut(Qt::Key_Escape);
 		addAction(action);
@@ -162,58 +216,8 @@ void OBSProjector::Init(int monitor, bool window, QString title,
 		activateWindow();
 	}
 
-	savedMonitor = monitor;
-	isWindow     = window;
-	type         = type_;
-
-	if (type == ProjectorType::Multiview) {
-		obs_enter_graphics();
-		gs_render_start(true);
-		gs_vertex2f(0.001f, 0.001f);
-		gs_vertex2f(0.001f, 0.997f);
-		gs_vertex2f(0.997f, 0.997f);
-		gs_vertex2f(0.997f, 0.001f);
-		gs_vertex2f(0.001f, 0.001f);
-		outerBox = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.04f, 0.04f);
-		gs_vertex2f(0.04f, 0.96f);
-		gs_vertex2f(0.96f, 0.96f);
-		gs_vertex2f(0.96f, 0.04f);
-		gs_vertex2f(0.04f, 0.04f);
-		innerBox = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.15f, 0.04f);
-		gs_vertex2f(0.15f, 0.96f);
-		leftVLine = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.85f, 0.04f);
-		gs_vertex2f(0.85f, 0.96f);
-		rightVLine = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.0f, 0.5f);
-		gs_vertex2f(0.075f, 0.5f);
-		leftLine = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.5f, 0.0f);
-		gs_vertex2f(0.5f, 0.09f);
-		topLine = gs_render_save();
-
-		gs_render_start(true);
-		gs_vertex2f(0.925f, 0.5f);
-		gs_vertex2f(1.0f, 0.5f);
-		rightLine = gs_render_save();
-		obs_leave_graphics();
-
-		UpdateMultiview();
-
-		multiviewProjectors.push_back(this);
-	}
+	if (source)
+		obs_source_inc_showing(source);
 
 	ready = true;
 }
@@ -588,6 +592,7 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
 		return;
 
 	OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
+	OBSSource source = window->source;
 
 	uint32_t targetCX;
 	uint32_t targetCY;
@@ -595,9 +600,9 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
 	int      newCX, newCY;
 	float    scale;
 
-	if (window->source) {
-		targetCX = std::max(obs_source_get_width(window->source), 1u);
-		targetCY = std::max(obs_source_get_height(window->source), 1u);
+	if (source) {
+		targetCX = std::max(obs_source_get_width(source), 1u);
+		targetCY = std::max(obs_source_get_height(source), 1u);
 	} else {
 		struct obs_video_info ovi;
 		obs_get_video_info(&ovi);
@@ -615,14 +620,12 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy)
 	gs_ortho(0.0f, float(targetCX), 0.0f, float(targetCY), -100.0f, 100.0f);
 	gs_set_viewport(x, y, newCX, newCY);
 
-	OBSSource source = window->source;
-
 	if (window->type == ProjectorType::Preview &&
 	    main->IsPreviewProgramMode()) {
 		OBSSource curSource = main->GetCurrentSceneSource();
 
-		if (window->source != curSource) {
-			obs_source_dec_showing(window->source);
+		if (source != curSource) {
+			obs_source_dec_showing(source);
 			obs_source_inc_showing(curSource);
 			source = curSource;
 		}
@@ -796,11 +799,6 @@ void OBSProjector::mousePressEvent(QMouseEvent *event)
 
 void OBSProjector::EscapeTriggered()
 {
-	if (!isWindow) {
-		OBSBasic *main = (OBSBasic*)obs_frontend_get_main_window();
-		main->RemoveSavedProjectors(savedMonitor);
-	}
-
 	deleteLater();
 }
 
@@ -861,6 +859,41 @@ void OBSProjector::UpdateMultiview()
 		multiviewLayout = HORIZONTAL_TOP;
 }
 
+void OBSProjector::UpdateProjectorTitle(QString name)
+{
+	projectorTitle = name;
+
+	QString title = nullptr;
+	switch (type) {
+	case ProjectorType::Scene:
+		title = QTStr("SceneWindow") + " - " + name;
+		break;
+	case ProjectorType::Source:
+		title = QTStr("SourceWindow") + " - " + name;
+		break;
+	default:
+		title = name;
+		break;
+	}
+
+	setWindowTitle(title);
+}
+
+OBSSource OBSProjector::GetSource()
+{
+	return source;
+}
+
+ProjectorType OBSProjector::GetProjectorType()
+{
+	return type;
+}
+
+int OBSProjector::GetMonitor()
+{
+	return savedMonitor;
+}
+
 void OBSProjector::UpdateMultiviewProjectors()
 {
 	obs_enter_graphics();
@@ -874,3 +907,10 @@ void OBSProjector::UpdateMultiviewProjectors()
 	updatingMultiview = false;
 	obs_leave_graphics();
 }
+
+void OBSProjector::RenameProjector(QString oldName, QString newName)
+{
+	for (auto &projector : windowedProjectors)
+		if (projector->projectorTitle == oldName)
+			projector->UpdateProjectorTitle(newName);
+}

+ 19 - 6
UI/window-projector.hpp

@@ -2,7 +2,14 @@
 
 #include <obs.hpp>
 #include "qt-display.hpp"
-#include "window-basic-main.hpp"
+
+enum class ProjectorType {
+	Source,
+	Scene,
+	Preview,
+	StudioProgram,
+	Multiview
+};
 
 class QMouseEvent;
 
@@ -20,8 +27,9 @@ private:
 	void mousePressEvent(QMouseEvent *event) override;
 	void mouseDoubleClickEvent(QMouseEvent *event) override;
 
-	int savedMonitor = 0;
-	bool isWindow = false;
+	int savedMonitor;
+	bool isWindow;
+	QString projectorTitle;
 	ProjectorType type = ProjectorType::Source;
 	OBSWeakSource multiviewScenes[8];
 	OBSSource     multiviewLabels[10];
@@ -35,16 +43,21 @@ private:
 	bool ready = false;
 
 	void UpdateMultiview();
+	void UpdateProjectorTitle(QString name);
 
 private slots:
 	void EscapeTriggered();
 
 public:
-	OBSProjector(QWidget *parent, obs_source_t *source, bool window);
+	OBSProjector(QWidget *widget, obs_source_t *source_, int monitor,
+			QString title, ProjectorType type_);
 	~OBSProjector();
 
-	void Init(int monitor, bool window, QString title,
-			ProjectorType type = ProjectorType::Source);
+	void Init();
 
+	OBSSource GetSource();
+	ProjectorType GetProjectorType();
+	int GetMonitor();
 	static void UpdateMultiviewProjectors();
+	static void RenameProjector(QString oldName, QString newName);
 };