clang-format: Apply formatting

Code submissions have continually suffered from formatting
inconsistencies that constantly have to be addressed.  Using
clang-format simplifies this by making code formatting more consistent,
and allows automation of the code formatting so that maintainers can
focus more on the code itself instead of code formatting.
This commit is contained in:
jp9000 committed 2019-06-23 23:49:10 -07:00
1 parent 53615ee10f
commit f53df7da64
565 files changed
+34024 -32859

No files matched your search

+83 -82
View File
@@ -26,34 +26,34 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
uint32_t flags = obs_source_get_flags(source); uint32_t flags = obs_source_get_flags(source);
uint32_t mixers = obs_source_get_audio_mixers(source); uint32_t mixers = obs_source_get_audio_mixers(source);
forceMonoContainer = new QWidget(); forceMonoContainer = new QWidget();
mixerContainer = new QWidget(); mixerContainer = new QWidget();
balanceContainer = new QWidget(); balanceContainer = new QWidget();
labelL = new QLabel(); labelL = new QLabel();
labelR = new QLabel(); labelR = new QLabel();
nameLabel = new QLabel(); nameLabel = new QLabel();
volume = new QDoubleSpinBox(); volume = new QDoubleSpinBox();
forceMono = new QCheckBox(); forceMono = new QCheckBox();
balance = new BalanceSlider(); balance = new BalanceSlider();
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO #if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
monitoringType = new QComboBox(); monitoringType = new QComboBox();
#endif #endif
syncOffset = new QSpinBox(); syncOffset = new QSpinBox();
mixer1 = new QCheckBox(); mixer1 = new QCheckBox();
mixer2 = new QCheckBox(); mixer2 = new QCheckBox();
mixer3 = new QCheckBox(); mixer3 = new QCheckBox();
mixer4 = new QCheckBox(); mixer4 = new QCheckBox();
mixer5 = new QCheckBox(); mixer5 = new QCheckBox();
mixer6 = new QCheckBox(); mixer6 = new QCheckBox();
volChangedSignal.Connect(handler, "volume", OBSSourceVolumeChanged, volChangedSignal.Connect(handler, "volume", OBSSourceVolumeChanged,
this); this);
syncOffsetSignal.Connect(handler, "audio_sync", OBSSourceSyncChanged, syncOffsetSignal.Connect(handler, "audio_sync", OBSSourceSyncChanged,
this); this);
flagsSignal.Connect(handler, "update_flags", OBSSourceFlagsChanged, flagsSignal.Connect(handler, "update_flags", OBSSourceFlagsChanged,
this); this);
mixersSignal.Connect(handler, "audio_mixers", OBSSourceMixersChanged, mixersSignal.Connect(handler, "audio_mixers", OBSSourceMixersChanged,
this); this);
hlayout = new QHBoxLayout(); hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0, 0, 0, 0); hlayout->setContentsMargins(0, 0, 0, 0);
@@ -87,8 +87,8 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
forceMono->setChecked((flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0); forceMono->setChecked((flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0);
forceMonoContainer->layout()->addWidget(forceMono); forceMonoContainer->layout()->addWidget(forceMono);
forceMonoContainer->layout()->setAlignment(forceMono, forceMonoContainer->layout()->setAlignment(
Qt::AlignHCenter | Qt::AlignVCenter); forceMono, Qt::AlignHCenter | Qt::AlignVCenter);
balance->setOrientation(Qt::Horizontal); balance->setOrientation(Qt::Horizontal);
balance->setMinimum(0); balance->setMinimum(0);
@@ -96,10 +96,10 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
balance->setTickPosition(QSlider::TicksAbove); balance->setTickPosition(QSlider::TicksAbove);
balance->setTickInterval(50); balance->setTickInterval(50);
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
const char *speakers = config_get_string(main->Config(), "Audio", const char *speakers =
"ChannelSetup"); config_get_string(main->Config(), "Audio", "ChannelSetup");
if (strcmp(speakers, "Mono") == 0) if (strcmp(speakers, "Mono") == 0)
balance->setEnabled(false); balance->setEnabled(false);
@@ -117,28 +117,28 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
int idx; int idx;
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO #if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.None"), monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.None"),
(int)OBS_MONITORING_TYPE_NONE); (int)OBS_MONITORING_TYPE_NONE);
monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.MonitorOnly"), monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.MonitorOnly"),
(int)OBS_MONITORING_TYPE_MONITOR_ONLY); (int)OBS_MONITORING_TYPE_MONITOR_ONLY);
monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.Both"), monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.Both"),
(int)OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT); (int)OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT);
int mt = (int)obs_source_get_monitoring_type(source); int mt = (int)obs_source_get_monitoring_type(source);
idx = monitoringType->findData(mt); idx = monitoringType->findData(mt);
monitoringType->setCurrentIndex(idx); monitoringType->setCurrentIndex(idx);
#endif #endif
mixer1->setText("1"); mixer1->setText("1");
mixer1->setChecked(mixers & (1<<0)); mixer1->setChecked(mixers & (1 << 0));
mixer2->setText("2"); mixer2->setText("2");
mixer2->setChecked(mixers & (1<<1)); mixer2->setChecked(mixers & (1 << 1));
mixer3->setText("3"); mixer3->setText("3");
mixer3->setChecked(mixers & (1<<2)); mixer3->setChecked(mixers & (1 << 2));
mixer4->setText("4"); mixer4->setText("4");
mixer4->setChecked(mixers & (1<<3)); mixer4->setChecked(mixers & (1 << 3));
mixer5->setText("5"); mixer5->setText("5");
mixer5->setChecked(mixers & (1<<4)); mixer5->setChecked(mixers & (1 << 4));
mixer6->setText("6"); mixer6->setText("6");
mixer6->setChecked(mixers & (1<<5)); mixer6->setChecked(mixers & (1 << 5));
speaker_layout sl = obs_source_get_speaker_layout(source); speaker_layout sl = obs_source_get_speaker_layout(source);
@@ -156,32 +156,32 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *, obs_source_t *source_)
mixerContainer->layout()->addWidget(mixer5); mixerContainer->layout()->addWidget(mixer5);
mixerContainer->layout()->addWidget(mixer6); mixerContainer->layout()->addWidget(mixer6);
QWidget::connect(volume, SIGNAL(valueChanged(double)), QWidget::connect(volume, SIGNAL(valueChanged(double)), this,
this, SLOT(volumeChanged(double))); SLOT(volumeChanged(double)));
QWidget::connect(forceMono, SIGNAL(clicked(bool)), QWidget::connect(forceMono, SIGNAL(clicked(bool)), this,
this, SLOT(downmixMonoChanged(bool))); SLOT(downmixMonoChanged(bool)));
QWidget::connect(balance, SIGNAL(valueChanged(int)), QWidget::connect(balance, SIGNAL(valueChanged(int)), this,
this, SLOT(balanceChanged(int))); SLOT(balanceChanged(int)));
QWidget::connect(balance, SIGNAL(doubleClicked()), QWidget::connect(balance, SIGNAL(doubleClicked()), this,
this, SLOT(ResetBalance())); SLOT(ResetBalance()));
QWidget::connect(syncOffset, SIGNAL(valueChanged(int)), QWidget::connect(syncOffset, SIGNAL(valueChanged(int)), this,
this, SLOT(syncOffsetChanged(int))); SLOT(syncOffsetChanged(int)));
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO #if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
QWidget::connect(monitoringType, SIGNAL(currentIndexChanged(int)), QWidget::connect(monitoringType, SIGNAL(currentIndexChanged(int)), this,
this, SLOT(monitoringTypeChanged(int))); SLOT(monitoringTypeChanged(int)));
#endif #endif
QWidget::connect(mixer1, SIGNAL(clicked(bool)), QWidget::connect(mixer1, SIGNAL(clicked(bool)), this,
this, SLOT(mixer1Changed(bool))); SLOT(mixer1Changed(bool)));
QWidget::connect(mixer2, SIGNAL(clicked(bool)), QWidget::connect(mixer2, SIGNAL(clicked(bool)), this,
this, SLOT(mixer2Changed(bool))); SLOT(mixer2Changed(bool)));
QWidget::connect(mixer3, SIGNAL(clicked(bool)), QWidget::connect(mixer3, SIGNAL(clicked(bool)), this,
this, SLOT(mixer3Changed(bool))); SLOT(mixer3Changed(bool)));
QWidget::connect(mixer4, SIGNAL(clicked(bool)), QWidget::connect(mixer4, SIGNAL(clicked(bool)), this,
this, SLOT(mixer4Changed(bool))); SLOT(mixer4Changed(bool)));
QWidget::connect(mixer5, SIGNAL(clicked(bool)), QWidget::connect(mixer5, SIGNAL(clicked(bool)), this,
this, SLOT(mixer5Changed(bool))); SLOT(mixer5Changed(bool)));
QWidget::connect(mixer6, SIGNAL(clicked(bool)), QWidget::connect(mixer6, SIGNAL(clicked(bool)), this,
this, SLOT(mixer6Changed(bool))); SLOT(mixer6Changed(bool)));
setObjectName(sourceName); setObjectName(sourceName);
} }
@@ -214,7 +214,7 @@ void OBSAdvAudioCtrl::ShowAudioControl(QGridLayout *layout)
#endif #endif
layout->addWidget(mixerContainer, lastRow, idx++); layout->addWidget(mixerContainer, lastRow, idx++);
layout->layout()->setAlignment(mixerContainer, layout->layout()->setAlignment(mixerContainer,
Qt::AlignHCenter | Qt::AlignVCenter); Qt::AlignHCenter | Qt::AlignVCenter);
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -223,30 +223,30 @@ void OBSAdvAudioCtrl::ShowAudioControl(QGridLayout *layout)
void OBSAdvAudioCtrl::OBSSourceFlagsChanged(void *param, calldata_t *calldata) void OBSAdvAudioCtrl::OBSSourceFlagsChanged(void *param, calldata_t *calldata)
{ {
uint32_t flags = (uint32_t)calldata_int(calldata, "flags"); uint32_t flags = (uint32_t)calldata_int(calldata, "flags");
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
"SourceFlagsChanged", Q_ARG(uint32_t, flags)); "SourceFlagsChanged", Q_ARG(uint32_t, flags));
} }
void OBSAdvAudioCtrl::OBSSourceVolumeChanged(void *param, calldata_t *calldata) void OBSAdvAudioCtrl::OBSSourceVolumeChanged(void *param, calldata_t *calldata)
{ {
float volume = (float)calldata_float(calldata, "volume"); float volume = (float)calldata_float(calldata, "volume");
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
"SourceVolumeChanged", Q_ARG(float, volume)); "SourceVolumeChanged", Q_ARG(float, volume));
} }
void OBSAdvAudioCtrl::OBSSourceSyncChanged(void *param, calldata_t *calldata) void OBSAdvAudioCtrl::OBSSourceSyncChanged(void *param, calldata_t *calldata)
{ {
int64_t offset = calldata_int(calldata, "offset"); int64_t offset = calldata_int(calldata, "offset");
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
"SourceSyncChanged", Q_ARG(int64_t, offset)); "SourceSyncChanged", Q_ARG(int64_t, offset));
} }
void OBSAdvAudioCtrl::OBSSourceMixersChanged(void *param, calldata_t *calldata) void OBSAdvAudioCtrl::OBSSourceMixersChanged(void *param, calldata_t *calldata)
{ {
uint32_t mixers = (uint32_t)calldata_int(calldata, "mixers"); uint32_t mixers = (uint32_t)calldata_int(calldata, "mixers");
QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl *>(param),
"SourceMixersChanged", Q_ARG(uint32_t, mixers)); "SourceMixersChanged",
Q_ARG(uint32_t, mixers));
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -279,12 +279,12 @@ void OBSAdvAudioCtrl::SourceSyncChanged(int64_t offset)
void OBSAdvAudioCtrl::SourceMixersChanged(uint32_t mixers) void OBSAdvAudioCtrl::SourceMixersChanged(uint32_t mixers)
{ {
setCheckboxState(mixer1, mixers & (1<<0)); setCheckboxState(mixer1, mixers & (1 << 0));
setCheckboxState(mixer2, mixers & (1<<1)); setCheckboxState(mixer2, mixers & (1 << 1));
setCheckboxState(mixer3, mixers & (1<<2)); setCheckboxState(mixer3, mixers & (1 << 2));
setCheckboxState(mixer4, mixers & (1<<3)); setCheckboxState(mixer4, mixers & (1 << 3));
setCheckboxState(mixer5, mixers & (1<<4)); setCheckboxState(mixer5, mixers & (1 << 4));
setCheckboxState(mixer6, mixers & (1<<5)); setCheckboxState(mixer6, mixers & (1 << 5));
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -335,14 +335,13 @@ void OBSAdvAudioCtrl::ResetBalance()
balance->setValue(50); balance->setValue(50);
} }
void OBSAdvAudioCtrl::syncOffsetChanged(int milliseconds) void OBSAdvAudioCtrl::syncOffsetChanged(int milliseconds)
{ {
int64_t cur_val = obs_source_get_sync_offset(source); int64_t cur_val = obs_source_get_sync_offset(source);
if (cur_val / NSEC_PER_MSEC != milliseconds) if (cur_val / NSEC_PER_MSEC != milliseconds)
obs_source_set_sync_offset(source, obs_source_set_sync_offset(source, int64_t(milliseconds) *
int64_t(milliseconds) * NSEC_PER_MSEC); NSEC_PER_MSEC);
} }
void OBSAdvAudioCtrl::monitoringTypeChanged(int index) void OBSAdvAudioCtrl::monitoringTypeChanged(int index)
@@ -365,17 +364,19 @@ void OBSAdvAudioCtrl::monitoringTypeChanged(int index)
} }
blog(LOG_INFO, "User changed audio monitoring for source '%s' to: %s", blog(LOG_INFO, "User changed audio monitoring for source '%s' to: %s",
obs_source_get_name(source), type); obs_source_get_name(source), type);
} }
static inline void setMixer(obs_source_t *source, const int mixerIdx, static inline void setMixer(obs_source_t *source, const int mixerIdx,
const bool checked) const bool checked)
{ {
uint32_t mixers = obs_source_get_audio_mixers(source); uint32_t mixers = obs_source_get_audio_mixers(source);
uint32_t new_mixers = mixers; uint32_t new_mixers = mixers;
if (checked) new_mixers |= (1<<mixerIdx); if (checked)
else new_mixers &= ~(1<<mixerIdx); new_mixers |= (1 << mixerIdx);
else
new_mixers &= ~(1 << mixerIdx);
obs_source_set_audio_mixers(source, new_mixers); obs_source_set_audio_mixers(source, new_mixers);
} }
+22 -22
View File
@@ -16,31 +16,31 @@ class OBSAdvAudioCtrl : public QObject {
Q_OBJECT Q_OBJECT
private: private:
OBSSource source; OBSSource source;
QPointer<QWidget> forceMonoContainer; QPointer<QWidget> forceMonoContainer;
QPointer<QWidget> mixerContainer; QPointer<QWidget> mixerContainer;
QPointer<QWidget> balanceContainer; QPointer<QWidget> balanceContainer;
QPointer<QLabel> nameLabel; QPointer<QLabel> nameLabel;
QPointer<QDoubleSpinBox> volume; QPointer<QDoubleSpinBox> volume;
QPointer<QCheckBox> forceMono; QPointer<QCheckBox> forceMono;
QPointer<BalanceSlider>balance; QPointer<BalanceSlider> balance;
QPointer<QLabel> labelL; QPointer<QLabel> labelL;
QPointer<QLabel> labelR; QPointer<QLabel> labelR;
QPointer<QSpinBox> syncOffset; QPointer<QSpinBox> syncOffset;
QPointer<QComboBox> monitoringType; QPointer<QComboBox> monitoringType;
QPointer<QCheckBox> mixer1; QPointer<QCheckBox> mixer1;
QPointer<QCheckBox> mixer2; QPointer<QCheckBox> mixer2;
QPointer<QCheckBox> mixer3; QPointer<QCheckBox> mixer3;
QPointer<QCheckBox> mixer4; QPointer<QCheckBox> mixer4;
QPointer<QCheckBox> mixer5; QPointer<QCheckBox> mixer5;
QPointer<QCheckBox> mixer6; QPointer<QCheckBox> mixer6;
OBSSignal volChangedSignal; OBSSignal volChangedSignal;
OBSSignal syncOffsetSignal; OBSSignal syncOffsetSignal;
OBSSignal flagsSignal; OBSSignal flagsSignal;
OBSSignal mixersSignal; OBSSignal mixersSignal;
static void OBSSourceFlagsChanged(void *param, calldata_t *calldata); static void OBSSourceFlagsChanged(void *param, calldata_t *calldata);
static void OBSSourceVolumeChanged(void *param, calldata_t *calldata); static void OBSSourceVolumeChanged(void *param, calldata_t *calldata);
@@ -51,7 +51,7 @@ public:
OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_); OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_);
virtual ~OBSAdvAudioCtrl(); virtual ~OBSAdvAudioCtrl();
inline obs_source_t *GetSource() const {return source;} inline obs_source_t *GetSource() const { return source; }
void ShowAudioControl(QGridLayout *layout); void ShowAudioControl(QGridLayout *layout);
public slots: public slots:
+70 -76
View File
@@ -11,14 +11,13 @@ using namespace std;
Q_DECLARE_METATYPE(OBSScene); Q_DECLARE_METATYPE(OBSScene);
Q_DECLARE_METATYPE(OBSSource); Q_DECLARE_METATYPE(OBSSource);
template <typename T> template<typename T> static T GetOBSRef(QListWidgetItem *item)
static T GetOBSRef(QListWidgetItem *item)
{ {
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>(); return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
} }
void EnumProfiles(function<bool (const char *, const char *)> &&cb); void EnumProfiles(function<bool(const char *, const char *)> &&cb);
void EnumSceneCollections(function<bool (const char *, const char *)> &&cb); void EnumSceneCollections(function<bool(const char *, const char *)> &&cb);
extern volatile bool streaming_active; extern volatile bool streaming_active;
extern volatile bool recording_active; extern volatile bool recording_active;
@@ -30,18 +29,18 @@ template<typename T> struct OBSStudioCallback {
T callback; T callback;
void *private_data; void *private_data;
inline OBSStudioCallback(T cb, void *p) : inline OBSStudioCallback(T cb, void *p) : callback(cb), private_data(p)
callback(cb), private_data(p) {
{} }
}; };
template <typename T> inline size_t GetCallbackIdx( template<typename T>
vector<OBSStudioCallback<T>> &callbacks, inline size_t GetCallbackIdx(vector<OBSStudioCallback<T>> &callbacks,
T callback, void *private_data) T callback, void *private_data)
{ {
for (size_t i = 0; i < callbacks.size(); i++) { for (size_t i = 0; i < callbacks.size(); i++) {
OBSStudioCallback<T> curCB = callbacks[i]; OBSStudioCallback<T> curCB = callbacks[i];
if (curCB.callback == callback && if (curCB.callback == callback &&
curCB.private_data == private_data) curCB.private_data == private_data)
return i; return i;
} }
@@ -59,21 +58,21 @@ struct OBSStudioAPI : obs_frontend_callbacks {
void *obs_frontend_get_main_window(void) override void *obs_frontend_get_main_window(void) override
{ {
return (void*)main; return (void *)main;
} }
void *obs_frontend_get_main_window_handle(void) override void *obs_frontend_get_main_window_handle(void) override
{ {
return (void*)main->winId(); return (void *)main->winId();
} }
void *obs_frontend_get_system_tray(void) override void *obs_frontend_get_system_tray(void) override
{ {
return (void*)main->trayIcon.data(); return (void *)main->trayIcon.data();
} }
void obs_frontend_get_scenes( void obs_frontend_get_scenes(
struct obs_frontend_source_list *sources) override struct obs_frontend_source_list *sources) override
{ {
for (int i = 0; i < main->ui->scenes->count(); i++) { for (int i = 0; i < main->ui->scenes->count(); i++) {
QListWidgetItem *item = main->ui->scenes->item(i); QListWidgetItem *item = main->ui->scenes->item(i);
@@ -101,23 +100,23 @@ struct OBSStudioAPI : obs_frontend_callbacks {
void obs_frontend_set_current_scene(obs_source_t *scene) override void obs_frontend_set_current_scene(obs_source_t *scene) override
{ {
if (main->IsPreviewProgramMode()) { if (main->IsPreviewProgramMode()) {
QMetaObject::invokeMethod(main, "TransitionToScene", QMetaObject::invokeMethod(
WaitConnection(), main, "TransitionToScene", WaitConnection(),
Q_ARG(OBSSource, OBSSource(scene))); Q_ARG(OBSSource, OBSSource(scene)));
} else { } else {
QMetaObject::invokeMethod(main, "SetCurrentScene", QMetaObject::invokeMethod(
WaitConnection(), main, "SetCurrentScene", WaitConnection(),
Q_ARG(OBSSource, OBSSource(scene)), Q_ARG(OBSSource, OBSSource(scene)),
Q_ARG(bool, false)); Q_ARG(bool, false));
} }
} }
void obs_frontend_get_transitions( void obs_frontend_get_transitions(
struct obs_frontend_source_list *sources) override struct obs_frontend_source_list *sources) override
{ {
for (int i = 0; i < main->ui->transitions->count(); i++) { for (int i = 0; i < main->ui->transitions->count(); i++) {
OBSSource tr = main->ui->transitions->itemData(i) OBSSource tr = main->ui->transitions->itemData(i)
.value<OBSSource>(); .value<OBSSource>();
obs_source_addref(tr); obs_source_addref(tr);
da_push_back(sources->sources, &tr); da_push_back(sources->sources, &tr);
@@ -132,11 +131,12 @@ struct OBSStudioAPI : obs_frontend_callbacks {
return tr; return tr;
} }
void obs_frontend_set_current_transition( void
obs_source_t *transition) override obs_frontend_set_current_transition(obs_source_t *transition) override
{ {
QMetaObject::invokeMethod(main, "SetTransition", QMetaObject::invokeMethod(main, "SetTransition",
Q_ARG(OBSSource, OBSSource(transition))); Q_ARG(OBSSource,
OBSSource(transition)));
} }
int obs_frontend_get_transition_duration(void) override int obs_frontend_get_transition_duration(void) override
@@ -146,15 +146,14 @@ struct OBSStudioAPI : obs_frontend_callbacks {
void obs_frontend_set_transition_duration(int duration) override void obs_frontend_set_transition_duration(int duration) override
{ {
QMetaObject::invokeMethod(main->ui->transitionDuration, "setValue", QMetaObject::invokeMethod(main->ui->transitionDuration,
Q_ARG(int, duration)); "setValue", Q_ARG(int, duration));
} }
void obs_frontend_get_scene_collections( void obs_frontend_get_scene_collections(
std::vector<std::string> &strings) override std::vector<std::string> &strings) override
{ {
auto addCollection = [&](const char *name, const char *) auto addCollection = [&](const char *name, const char *) {
{
strings.emplace_back(name); strings.emplace_back(name);
return true; return true;
}; };
@@ -164,15 +163,15 @@ struct OBSStudioAPI : obs_frontend_callbacks {
char *obs_frontend_get_current_scene_collection(void) override char *obs_frontend_get_current_scene_collection(void) override
{ {
const char *cur_name = config_get_string(App()->GlobalConfig(), const char *cur_name = config_get_string(
"Basic", "SceneCollection"); App()->GlobalConfig(), "Basic", "SceneCollection");
return bstrdup(cur_name); return bstrdup(cur_name);
} }
void obs_frontend_set_current_scene_collection( void obs_frontend_set_current_scene_collection(
const char *collection) override const char *collection) override
{ {
QList<QAction*> menuActions = QList<QAction *> menuActions =
main->ui->sceneCollectionMenu->actions(); main->ui->sceneCollectionMenu->actions();
QString qstrCollection = QT_UTF8(collection); QString qstrCollection = QT_UTF8(collection);
@@ -189,24 +188,21 @@ struct OBSStudioAPI : obs_frontend_callbacks {
} }
} }
bool obs_frontend_add_scene_collection( bool obs_frontend_add_scene_collection(const char *name) override
const char *name) override
{ {
bool success = false; bool success = false;
QMetaObject::invokeMethod(main, QMetaObject::invokeMethod(main, "AddSceneCollection",
"AddSceneCollection", WaitConnection(),
WaitConnection(), Q_RETURN_ARG(bool, success),
Q_RETURN_ARG(bool, success), Q_ARG(bool, true),
Q_ARG(bool, true), Q_ARG(QString, QT_UTF8(name)));
Q_ARG(QString, QT_UTF8(name)));
return success; return success;
} }
void obs_frontend_get_profiles( void
std::vector<std::string> &strings) override obs_frontend_get_profiles(std::vector<std::string> &strings) override
{ {
auto addProfile = [&](const char *name, const char *) auto addProfile = [&](const char *name, const char *) {
{
strings.emplace_back(name); strings.emplace_back(name);
return true; return true;
}; };
@@ -217,14 +213,13 @@ struct OBSStudioAPI : obs_frontend_callbacks {
char *obs_frontend_get_current_profile(void) override char *obs_frontend_get_current_profile(void) override
{ {
const char *name = config_get_string(App()->GlobalConfig(), const char *name = config_get_string(App()->GlobalConfig(),
"Basic", "Profile"); "Basic", "Profile");
return bstrdup(name); return bstrdup(name);
} }
void obs_frontend_set_current_profile(const char *profile) override void obs_frontend_set_current_profile(const char *profile) override
{ {
QList<QAction*> menuActions = QList<QAction *> menuActions = main->ui->profileMenu->actions();
main->ui->profileMenu->actions();
QString qstrProfile = QT_UTF8(profile); QString qstrProfile = QT_UTF8(profile);
for (int i = 0; i < menuActions.count(); i++) { for (int i = 0; i < menuActions.count(); i++) {
@@ -293,16 +288,16 @@ struct OBSStudioAPI : obs_frontend_callbacks {
void *obs_frontend_add_tools_menu_qaction(const char *name) override void *obs_frontend_add_tools_menu_qaction(const char *name) override
{ {
main->ui->menuTools->setEnabled(true); main->ui->menuTools->setEnabled(true);
return (void*)main->ui->menuTools->addAction(QT_UTF8(name)); return (void *)main->ui->menuTools->addAction(QT_UTF8(name));
} }
void obs_frontend_add_tools_menu_item(const char *name, void obs_frontend_add_tools_menu_item(const char *name,
obs_frontend_cb callback, void *private_data) override obs_frontend_cb callback,
void *private_data) override
{ {
main->ui->menuTools->setEnabled(true); main->ui->menuTools->setEnabled(true);
auto func = [private_data, callback] () auto func = [private_data, callback]() {
{
callback(private_data); callback(private_data);
}; };
@@ -312,11 +307,11 @@ struct OBSStudioAPI : obs_frontend_callbacks {
void *obs_frontend_add_dock(void *dock) override void *obs_frontend_add_dock(void *dock) override
{ {
return (void*)main->AddDockWidget((QDockWidget *)dock); return (void *)main->AddDockWidget((QDockWidget *)dock);
} }
void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
void *private_data) override void *private_data) override
{ {
size_t idx = GetCallbackIdx(callbacks, callback, private_data); size_t idx = GetCallbackIdx(callbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1)
@@ -324,7 +319,7 @@ struct OBSStudioAPI : obs_frontend_callbacks {
} }
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
void *private_data) override void *private_data) override
{ {
size_t idx = GetCallbackIdx(callbacks, callback, private_data); size_t idx = GetCallbackIdx(callbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1)
@@ -364,10 +359,7 @@ struct OBSStudioAPI : obs_frontend_callbacks {
return App()->GlobalConfig(); return App()->GlobalConfig();
} }
void obs_frontend_save(void) override void obs_frontend_save(void) override { main->SaveProject(); }
{
main->SaveProject();
}
void obs_frontend_defer_save_begin(void) override void obs_frontend_defer_save_begin(void) override
{ {
@@ -380,19 +372,19 @@ struct OBSStudioAPI : obs_frontend_callbacks {
} }
void obs_frontend_add_save_callback(obs_frontend_save_cb callback, void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
void *private_data) override void *private_data) override
{ {
size_t idx = GetCallbackIdx(saveCallbacks, callback, size_t idx =
private_data); GetCallbackIdx(saveCallbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1)
saveCallbacks.emplace_back(callback, private_data); saveCallbacks.emplace_back(callback, private_data);
} }
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
void *private_data) override void *private_data) override
{ {
size_t idx = GetCallbackIdx(saveCallbacks, callback, size_t idx =
private_data); GetCallbackIdx(saveCallbacks, callback, private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1)
return; return;
@@ -400,19 +392,19 @@ struct OBSStudioAPI : obs_frontend_callbacks {
} }
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
void *private_data) override void *private_data) override
{ {
size_t idx = GetCallbackIdx(preloadCallbacks, callback, size_t idx = GetCallbackIdx(preloadCallbacks, callback,
private_data); private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1)
preloadCallbacks.emplace_back(callback, private_data); preloadCallbacks.emplace_back(callback, private_data);
} }
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
void *private_data) override void *private_data) override
{ {
size_t idx = GetCallbackIdx(preloadCallbacks, callback, size_t idx = GetCallbackIdx(preloadCallbacks, callback,
private_data); private_data);
if (idx == (size_t)-1) if (idx == (size_t)-1)
return; return;
@@ -420,7 +412,7 @@ struct OBSStudioAPI : obs_frontend_callbacks {
} }
void obs_frontend_push_ui_translation( void obs_frontend_push_ui_translation(
obs_frontend_translate_ui_cb translate) override obs_frontend_translate_ui_cb translate) override
{ {
App()->PushUITranslation(translate); App()->PushUITranslation(translate);
} }
@@ -483,12 +475,14 @@ struct OBSStudioAPI : obs_frontend_callbacks {
return source; return source;
} }
void obs_frontend_set_current_preview_scene(obs_source_t *scene) override void
obs_frontend_set_current_preview_scene(obs_source_t *scene) override
{ {
if (main->IsPreviewProgramMode()) { if (main->IsPreviewProgramMode()) {
QMetaObject::invokeMethod(main, "SetCurrentScene", QMetaObject::invokeMethod(main, "SetCurrentScene",
Q_ARG(OBSSource, OBSSource(scene)), Q_ARG(OBSSource,
Q_ARG(bool, false)); OBSSource(scene)),
Q_ARG(bool, false));
} }
} }
+37 -40
View File
@@ -32,7 +32,7 @@ static const char *EncoderName(const char *id)
return NullToEmpty(obs_encoder_get_display_name(id)); return NullToEmpty(obs_encoder_get_display_name(id));
} }
static map<int, const char*> bitrateMap; static map<int, const char *> bitrateMap;
static once_flag populateBitrateMap; static once_flag populateBitrateMap;
static void HandleIntProperty(obs_property_t *prop, const char *id) static void HandleIntProperty(obs_property_t *prop, const char *id)
@@ -48,10 +48,11 @@ static void HandleListProperty(obs_property_t *prop, const char *id)
{ {
obs_combo_format format = obs_property_list_format(prop); obs_combo_format format = obs_property_list_format(prop);
if (format != OBS_COMBO_FORMAT_INT) { if (format != OBS_COMBO_FORMAT_INT) {
blog(LOG_ERROR, "Encoder '%s' (%s) returned bitrate " blog(LOG_ERROR,
"OBS_PROPERTY_LIST property of unhandled " "Encoder '%s' (%s) returned bitrate "
"format %d", "OBS_PROPERTY_LIST property of unhandled "
EncoderName(id), id, static_cast<int>(format)); "format %d",
EncoderName(id), id, static_cast<int>(format));
return; return;
} }
@@ -60,38 +61,35 @@ static void HandleListProperty(obs_property_t *prop, const char *id)
if (obs_property_list_item_disabled(prop, i)) if (obs_property_list_item_disabled(prop, i))
continue; continue;
int bitrate = static_cast<int>( int bitrate =
obs_property_list_item_int(prop, i)); static_cast<int>(obs_property_list_item_int(prop, i));
bitrateMap[bitrate] = id; bitrateMap[bitrate] = id;
} }
} }
static void HandleSampleRate(obs_property_t* prop, const char *id) static void HandleSampleRate(obs_property_t *prop, const char *id)
{ {
auto ReleaseData = [](obs_data_t *data) auto ReleaseData = [](obs_data_t *data) { obs_data_release(data); };
{
obs_data_release(data);
};
std::unique_ptr<obs_data_t, decltype(ReleaseData)> data{ std::unique_ptr<obs_data_t, decltype(ReleaseData)> data{
obs_encoder_defaults(id), obs_encoder_defaults(id), ReleaseData};
ReleaseData};
if (!data) { if (!data) {
blog(LOG_ERROR, "Failed to get defaults for encoder '%s' (%s) " blog(LOG_ERROR,
"while populating bitrate map", "Failed to get defaults for encoder '%s' (%s) "
EncoderName(id), id); "while populating bitrate map",
EncoderName(id), id);
return; return;
} }
auto main = reinterpret_cast<OBSMainWindow*>(App()->GetMainWindow()); auto main = reinterpret_cast<OBSMainWindow *>(App()->GetMainWindow());
if (!main) { if (!main) {
blog(LOG_ERROR, "Failed to get main window while populating " blog(LOG_ERROR, "Failed to get main window while populating "
"bitrate map"); "bitrate map");
return; return;
} }
uint32_t sampleRate = config_get_uint(main->Config(), "Audio", uint32_t sampleRate =
"SampleRate"); config_get_uint(main->Config(), "Audio", "SampleRate");
obs_data_set_int(data.get(), "samplerate", sampleRate); obs_data_set_int(data.get(), "samplerate", sampleRate);
@@ -100,23 +98,22 @@ static void HandleSampleRate(obs_property_t* prop, const char *id)
static void HandleEncoderProperties(const char *id) static void HandleEncoderProperties(const char *id)
{ {
auto DestroyProperties = [](obs_properties_t *props) auto DestroyProperties = [](obs_properties_t *props) {
{
obs_properties_destroy(props); obs_properties_destroy(props);
}; };
std::unique_ptr<obs_properties_t, decltype(DestroyProperties)> props{ std::unique_ptr<obs_properties_t, decltype(DestroyProperties)> props{
obs_get_encoder_properties(id), obs_get_encoder_properties(id), DestroyProperties};
DestroyProperties};
if (!props) { if (!props) {
blog(LOG_ERROR, "Failed to get properties for encoder " blog(LOG_ERROR,
"'%s' (%s)", "Failed to get properties for encoder "
EncoderName(id), id); "'%s' (%s)",
EncoderName(id), id);
return; return;
} }
obs_property_t *samplerate = obs_properties_get(props.get(), obs_property_t *samplerate =
"samplerate"); obs_properties_get(props.get(), "samplerate");
if (samplerate) if (samplerate)
HandleSampleRate(samplerate, id); HandleSampleRate(samplerate, id);
@@ -130,12 +127,14 @@ static void HandleEncoderProperties(const char *id)
case OBS_PROPERTY_LIST: case OBS_PROPERTY_LIST:
return HandleListProperty(bitrate, id); return HandleListProperty(bitrate, id);
default: break; default:
break;
} }
blog(LOG_ERROR, "Encoder '%s' (%s) returned bitrate property " blog(LOG_ERROR,
"of unhandled type %d", EncoderName(id), id, "Encoder '%s' (%s) returned bitrate property "
static_cast<int>(type)); "of unhandled type %d",
EncoderName(id), id, static_cast<int>(type));
} }
static const char *GetCodec(const char *id) static const char *GetCodec(const char *id)
@@ -146,8 +145,7 @@ static const char *GetCodec(const char *id)
static const string aac_ = "AAC"; static const string aac_ = "AAC";
static void PopulateBitrateMap() static void PopulateBitrateMap()
{ {
call_once(populateBitrateMap, []() call_once(populateBitrateMap, []() {
{
struct obs_audio_info aoi; struct obs_audio_info aoi;
obs_get_audio_info(&aoi); obs_get_audio_info(&aoi);
uint32_t output_channels = get_audio_channels(aoi.speakers); uint32_t output_channels = get_audio_channels(aoi.speakers);
@@ -156,13 +154,12 @@ static void PopulateBitrateMap()
const char *id = nullptr; const char *id = nullptr;
for (size_t i = 0; obs_enum_encoder_types(i, &id); i++) { for (size_t i = 0; obs_enum_encoder_types(i, &id); i++) {
auto Compare = [=](const string &val) auto Compare = [=](const string &val) {
{
return val == NullToEmpty(id); return val == NullToEmpty(id);
}; };
if (find_if(begin(encoders), end(encoders), Compare) != if (find_if(begin(encoders), end(encoders), Compare) !=
end(encoders)) end(encoders))
continue; continue;
if (aac_ != GetCodec(id)) if (aac_ != GetCodec(id))
@@ -198,11 +195,11 @@ static void PopulateBitrateMap()
<< entry.second << ')'; << entry.second << ')';
blog(LOG_DEBUG, "AAC encoder bitrate mapping:%s", blog(LOG_DEBUG, "AAC encoder bitrate mapping:%s",
ss.str().c_str()); ss.str().c_str());
}); });
} }
const map<int, const char*> &GetAACEncoderBitrateMap() const map<int, const char *> &GetAACEncoderBitrateMap()
{ {
PopulateBitrateMap(); PopulateBitrateMap();
return bitrateMap; return bitrateMap;
+1 -1
View File
@@ -4,6 +4,6 @@
#include <map> #include <map>
const std::map<int, const char*> &GetAACEncoderBitrateMap(); const std::map<int, const char *> &GetAACEncoderBitrateMap();
const char *GetAACEncoderForBitrate(int bitrate); const char *GetAACEncoderForBitrate(int bitrate);
int FindClosestAvailableAACBitrate(int bitrate); int FindClosestAvailableAACBitrate(int bitrate);
+2 -1
View File
@@ -43,7 +43,8 @@ void Auth::Load()
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
const char *typeStr = config_get_string(main->Config(), "Auth", "Type"); const char *typeStr = config_get_string(main->Config(), "Auth", "Type");
if (!typeStr) typeStr = ""; if (!typeStr)
typeStr = "";
main->auth = Create(typeStr); main->auth = Create(typeStr);
if (main->auth) { if (main->auth) {
+8 -7
View File
@@ -8,8 +8,8 @@ class Auth : public QObject {
Q_OBJECT Q_OBJECT
protected: protected:
virtual void SaveInternal()=0; virtual void SaveInternal() = 0;
virtual bool LoadInternal()=0; virtual bool LoadInternal() = 0;
bool firstLoad = true; bool firstLoad = true;
@@ -19,13 +19,14 @@ protected:
ErrorInfo(std::string message_, std::string error_) ErrorInfo(std::string message_, std::string error_)
: message(message_), error(error_) : message(message_), error(error_)
{} {
}
}; };
public: public:
enum class Type { enum class Type {
None, None,
OAuth_StreamKey OAuth_StreamKey,
}; };
struct Def { struct Def {
@@ -33,13 +34,13 @@ public:
Type type; Type type;
}; };
typedef std::function<std::shared_ptr<Auth> ()> create_cb; typedef std::function<std::shared_ptr<Auth>()> create_cb;
inline Auth(const Def &d) : def(d) {} inline Auth(const Def &d) : def(d) {}
virtual ~Auth() {} virtual ~Auth() {}
inline Type type() const {return def.type;} inline Type type() const { return def.type; }
inline const char *service() const {return def.service.c_str();} inline const char *service() const { return def.service.c_str(); }
virtual void LoadUI() {} virtual void LoadUI() {}
+35 -62
View File
@@ -26,24 +26,16 @@ extern QCefCookieManager *panel_cookies;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#define MIXER_AUTH_URL \ #define MIXER_AUTH_URL "https://obsproject.com/app-auth/mixer?action=redirect"
"https://obsproject.com/app-auth/mixer?action=redirect" #define MIXER_TOKEN_URL "https://obsproject.com/app-auth/mixer-token"
#define MIXER_TOKEN_URL \
"https://obsproject.com/app-auth/mixer-token"
#define MIXER_SCOPE_VERSION 1 #define MIXER_SCOPE_VERSION 1
static Auth::Def mixerDef = { static Auth::Def mixerDef = {"Mixer", Auth::Type::OAuth_StreamKey};
"Mixer",
Auth::Type::OAuth_StreamKey
};
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
MixerAuth::MixerAuth(const Def &d) MixerAuth::MixerAuth(const Def &d) : OAuthStreamKey(d) {}
: OAuthStreamKey(d)
{
}
bool MixerAuth::GetChannelInfo(bool allow_retry) bool MixerAuth::GetChannelInfo(bool allow_retry)
try { try {
@@ -71,23 +63,16 @@ try {
bool success; bool success;
if (id.empty()) { if (id.empty()) {
auto func = [&] () { auto func = [&]() {
success = GetRemoteFile( success = GetRemoteFile(
"https://mixer.com/api/v1/users/current", "https://mixer.com/api/v1/users/current",
output, output, error, nullptr, "application/json",
error, nullptr, headers, nullptr, 5);
nullptr,
"application/json",
nullptr,
headers,
nullptr,
5);
}; };
ExecThreadedWithoutBlocking( ExecThreadedWithoutBlocking(
func, func, QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Title"), QTStr("Auth.LoadingChannel.Text").arg(service()));
QTStr("Auth.LoadingChannel.Text").arg(service()));
if (!success || output.empty()) if (!success || output.empty())
throw ErrorInfo("Failed to get user info from remote", throw ErrorInfo("Failed to get user info from remote",
error); error);
@@ -98,11 +83,12 @@ try {
error = json["error"].string_value(); error = json["error"].string_value();
if (!error.empty()) if (!error.empty())
throw ErrorInfo(error, throw ErrorInfo(
json["error_description"].string_value()); error,
json["error_description"].string_value());
id = std::to_string(json["channel"]["id"].int_value()); id = std::to_string(json["channel"]["id"].int_value());
name = json["channel"]["token"].string_value(); name = json["channel"]["token"].string_value();
} }
/* ------------------ */ /* ------------------ */
@@ -114,23 +100,15 @@ try {
output.clear(); output.clear();
auto func = [&] () { auto func = [&]() {
success = GetRemoteFile( success = GetRemoteFile(url.c_str(), output, error, nullptr,
url.c_str(), "application/json", nullptr, headers,
output, nullptr, 5);
error,
nullptr,
"application/json",
nullptr,
headers,
nullptr,
5);
}; };
ExecThreadedWithoutBlocking( ExecThreadedWithoutBlocking(
func, func, QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Title"), QTStr("Auth.LoadingChannel.Text").arg(service()));
QTStr("Auth.LoadingChannel.Text").arg(service()));
if (!success || output.empty()) if (!success || output.empty())
throw ErrorInfo("Failed to get stream key from remote", error); throw ErrorInfo("Failed to get stream key from remote", error);
@@ -140,7 +118,8 @@ try {
error = json["error"].string_value(); error = json["error"].string_value();
if (!error.empty()) if (!error.empty())
throw ErrorInfo(error, json["error_description"].string_value()); throw ErrorInfo(error,
json["error_description"].string_value());
std::string key_suffix = json["streamKey"].string_value(); std::string key_suffix = json["streamKey"].string_value();
@@ -161,14 +140,13 @@ try {
} catch (ErrorInfo info) { } catch (ErrorInfo info) {
QString title = QTStr("Auth.ChannelFailure.Title"); QString title = QTStr("Auth.ChannelFailure.Title");
QString text = QTStr("Auth.ChannelFailure.Text") QString text = QTStr("Auth.ChannelFailure.Text")
.arg(service(), info.message.c_str(), info.error.c_str()); .arg(service(), info.message.c_str(),
info.error.c_str());
QMessageBox::warning(OBSBasic::Get(), title, text); QMessageBox::warning(OBSBasic::Get(), title, text);
blog(LOG_WARNING, "%s: %s: %s", blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
__FUNCTION__, info.error.c_str());
info.message.c_str(),
info.error.c_str());
return false; return false;
} }
@@ -179,15 +157,13 @@ void MixerAuth::SaveInternal()
config_set_string(main->Config(), service(), "Id", id.c_str()); config_set_string(main->Config(), service(), "Id", id.c_str());
if (uiLoaded) { if (uiLoaded) {
config_set_string(main->Config(), service(), "DockState", config_set_string(main->Config(), service(), "DockState",
main->saveState().toBase64().constData()); main->saveState().toBase64().constData());
} }
OAuthStreamKey::SaveInternal(); OAuthStreamKey::SaveInternal();
} }
static inline std::string get_config_str( static inline std::string get_config_str(OBSBasic *main, const char *section,
OBSBasic *main, const char *name)
const char *section,
const char *name)
{ {
const char *val = config_get_string(main->Config(), section, name); const char *val = config_get_string(main->Config(), section, name);
return val ? val : ""; return val ? val : "";
@@ -252,8 +228,8 @@ void MixerAuth::LoadUI()
if (firstLoad) { if (firstLoad) {
chat->setVisible(true); chat->setVisible(true);
} else { } else {
const char *dockStateStr = config_get_string(main->Config(), const char *dockStateStr = config_get_string(
service(), "DockState"); main->Config(), service(), "DockState");
QByteArray dockState = QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr)); QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState); main->restoreState(dockState);
@@ -301,7 +277,7 @@ std::shared_ptr<Auth> MixerAuth::Login(QWidget *parent)
deobfuscate_str(&client_id[0], MIXER_HASH); deobfuscate_str(&client_id[0], MIXER_HASH);
if (!auth->GetToken(MIXER_TOKEN_URL, client_id, MIXER_SCOPE_VERSION, if (!auth->GetToken(MIXER_TOKEN_URL, client_id, MIXER_SCOPE_VERSION,
QT_TO_UTF8(login.GetCode()))) { QT_TO_UTF8(login.GetCode()))) {
return nullptr; return nullptr;
} }
@@ -328,9 +304,6 @@ static void DeleteCookies()
void RegisterMixerAuth() void RegisterMixerAuth()
{ {
OAuth::RegisterOAuth( OAuth::RegisterOAuth(mixerDef, CreateMixerAuth, MixerAuth::Login,
mixerDef, DeleteCookies);
CreateMixerAuth,
MixerAuth::Login,
DeleteCookies);
} }
+33 -46
View File
@@ -23,8 +23,7 @@ extern QCefCookieManager *panel_cookies;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token) OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token)
: QDialog (parent), : QDialog(parent), get_token(token)
get_token (token)
{ {
if (!cef) { if (!cef) {
return; return;
@@ -46,14 +45,13 @@ OAuthLogin::OAuthLogin(QWidget *parent, const std::string &url, bool token)
return; return;
} }
connect(cefWidget, SIGNAL(titleChanged(const QString &)), connect(cefWidget, SIGNAL(titleChanged(const QString &)), this,
this, SLOT(setWindowTitle(const QString &))); SLOT(setWindowTitle(const QString &)));
connect(cefWidget, SIGNAL(urlChanged(const QString &)), connect(cefWidget, SIGNAL(urlChanged(const QString &)), this,
this, SLOT(urlChanged(const QString &))); SLOT(urlChanged(const QString &)));
QPushButton *close = new QPushButton(QTStr("Cancel")); QPushButton *close = new QPushButton(QTStr("Cancel"));
connect(close, &QAbstractButton::clicked, connect(close, &QAbstractButton::clicked, this, &QDialog::reject);
this, &QDialog::reject);
QHBoxLayout *bottomLayout = new QHBoxLayout(); QHBoxLayout *bottomLayout = new QHBoxLayout();
bottomLayout->addStretch(); bottomLayout->addStretch();
@@ -111,7 +109,7 @@ struct OAuthInfo {
static std::vector<OAuthInfo> loginCBs; static std::vector<OAuthInfo> loginCBs;
void OAuth::RegisterOAuth(const Def &d, create_cb create, login_cb login, void OAuth::RegisterOAuth(const Def &d, create_cb create, login_cb login,
delete_cookies_cb delete_cookies) delete_cookies_cb delete_cookies)
{ {
OAuthInfo info = {d, login, delete_cookies}; OAuthInfo info = {d, login, delete_cookies};
loginCBs.push_back(info); loginCBs.push_back(info);
@@ -142,16 +140,14 @@ void OAuth::SaveInternal()
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
config_set_string(main->Config(), service(), "RefreshToken", config_set_string(main->Config(), service(), "RefreshToken",
refresh_token.c_str()); refresh_token.c_str());
config_set_string(main->Config(), service(), "Token", token.c_str()); config_set_string(main->Config(), service(), "Token", token.c_str());
config_set_uint(main->Config(), service(), "ExpireTime", expire_time); config_set_uint(main->Config(), service(), "ExpireTime", expire_time);
config_set_int(main->Config(), service(), "ScopeVer", currentScopeVer); config_set_int(main->Config(), service(), "ScopeVer", currentScopeVer);
} }
static inline std::string get_config_str( static inline std::string get_config_str(OBSBasic *main, const char *section,
OBSBasic *main, const char *name)
const char *section,
const char *name)
{ {
const char *val = config_get_string(main->Config(), section, name); const char *val = config_get_string(main->Config(), section, name);
return val ? val : ""; return val ? val : "";
@@ -163,11 +159,9 @@ bool OAuth::LoadInternal()
refresh_token = get_config_str(main, service(), "RefreshToken"); refresh_token = get_config_str(main, service(), "RefreshToken");
token = get_config_str(main, service(), "Token"); token = get_config_str(main, service(), "Token");
expire_time = config_get_uint(main->Config(), service(), "ExpireTime"); expire_time = config_get_uint(main->Config(), service(), "ExpireTime");
currentScopeVer = (int)config_get_int(main->Config(), service(), currentScopeVer =
"ScopeVer"); (int)config_get_int(main->Config(), service(), "ScopeVer");
return implicit return implicit ? !token.empty() : !refresh_token.empty();
? !token.empty()
: !refresh_token.empty();
} }
bool OAuth::TokenExpired() bool OAuth::TokenExpired()
@@ -180,7 +174,7 @@ bool OAuth::TokenExpired()
} }
bool OAuth::GetToken(const char *url, const std::string &client_id, bool OAuth::GetToken(const char *url, const std::string &client_id,
int scope_ver, const std::string &auth_code, bool retry) int scope_ver, const std::string &auth_code, bool retry)
try { try {
std::string output; std::string output;
std::string error; std::string error;
@@ -191,8 +185,8 @@ try {
return true; return true;
} else { } else {
QString title = QTStr("Auth.InvalidScope.Title"); QString title = QTStr("Auth.InvalidScope.Title");
QString text = QTStr("Auth.InvalidScope.Text") QString text =
.arg(service()); QTStr("Auth.InvalidScope.Text").arg(service());
QMessageBox::warning(OBSBasic::Get(), title, text); QMessageBox::warning(OBSBasic::Get(), title, text);
} }
@@ -216,23 +210,15 @@ try {
bool success = false; bool success = false;
auto func = [&] () { auto func = [&]() {
success = GetRemoteFile( success = GetRemoteFile(url, output, error, nullptr,
url, "application/x-www-form-urlencoded",
output, post_data.c_str(),
error, std::vector<std::string>(), nullptr, 5);
nullptr,
"application/x-www-form-urlencoded",
post_data.c_str(),
std::vector<std::string>(),
nullptr,
5);
}; };
ExecThreadedWithoutBlocking( ExecThreadedWithoutBlocking(func, QTStr("Auth.Authing.Title"),
func, QTStr("Auth.Authing.Text").arg(service()));
QTStr("Auth.Authing.Title"),
QTStr("Auth.Authing.Text").arg(service()));
if (!success || output.empty()) if (!success || output.empty())
throw ErrorInfo("Failed to get token from remote", error); throw ErrorInfo("Failed to get token from remote", error);
@@ -250,13 +236,14 @@ try {
} }
} }
if (!error.empty()) if (!error.empty())
throw ErrorInfo(error, json["error_description"].string_value()); throw ErrorInfo(error,
json["error_description"].string_value());
/* -------------------------- */ /* -------------------------- */
/* success! */ /* success! */
expire_time = (uint64_t)time(nullptr) + json["expires_in"].int_value(); expire_time = (uint64_t)time(nullptr) + json["expires_in"].int_value();
token = json["access_token"].string_value(); token = json["access_token"].string_value();
if (token.empty()) if (token.empty())
throw ErrorInfo("Failed to get token from remote", error); throw ErrorInfo("Failed to get token from remote", error);
@@ -264,7 +251,8 @@ try {
refresh_token = json["refresh_token"].string_value(); refresh_token = json["refresh_token"].string_value();
if (refresh_token.empty()) if (refresh_token.empty())
throw ErrorInfo("Failed to get refresh token from " throw ErrorInfo("Failed to get refresh token from "
"remote", error); "remote",
error);
currentScopeVer = scope_ver; currentScopeVer = scope_ver;
} }
@@ -275,15 +263,14 @@ try {
if (!retry) { if (!retry) {
QString title = QTStr("Auth.AuthFailure.Title"); QString title = QTStr("Auth.AuthFailure.Title");
QString text = QTStr("Auth.AuthFailure.Text") QString text = QTStr("Auth.AuthFailure.Text")
.arg(service(), info.message.c_str(), info.error.c_str()); .arg(service(), info.message.c_str(),
info.error.c_str());
QMessageBox::warning(OBSBasic::Get(), title, text); QMessageBox::warning(OBSBasic::Get(), title, text);
} }
blog(LOG_WARNING, "%s: %s: %s", blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
__FUNCTION__, info.error.c_str());
info.message.c_str(),
info.error.c_str());
return false; return false;
} }
@@ -301,7 +288,7 @@ void OAuthStreamKey::OnStreamConfig()
if (bwtest && strcmp(this->service(), "Twitch") == 0) if (bwtest && strcmp(this->service(), "Twitch") == 0)
obs_data_set_string(settings, "key", obs_data_set_string(settings, "key",
(key_ + "?bandwidthtest=true").c_str()); (key_ + "?bandwidthtest=true").c_str());
else else
obs_data_set_string(settings, "key", key_.c_str()); obs_data_set_string(settings, "key", key_.c_str());
+11 -10
View File
@@ -20,8 +20,8 @@ public:
OAuthLogin(QWidget *parent, const std::string &url, bool token); OAuthLogin(QWidget *parent, const std::string &url, bool token);
~OAuthLogin(); ~OAuthLogin();
inline QString GetCode() const {return code;} inline QString GetCode() const { return code; }
inline bool LoadFail() const {return fail;} inline bool LoadFail() const { return fail; }
virtual int exec() override; virtual int exec() override;
@@ -35,15 +35,16 @@ class OAuth : public Auth {
public: public:
inline OAuth(const Def &d) : Auth(d) {} inline OAuth(const Def &d) : Auth(d) {}
typedef std::function<std::shared_ptr<Auth> (QWidget *)> login_cb; typedef std::function<std::shared_ptr<Auth>(QWidget *)> login_cb;
typedef std::function<void()> delete_cookies_cb; typedef std::function<void()> delete_cookies_cb;
static std::shared_ptr<Auth> Login(QWidget *parent, static std::shared_ptr<Auth> Login(QWidget *parent,
const std::string &service); const std::string &service);
static void DeleteCookies(const std::string &service); static void DeleteCookies(const std::string &service);
static void RegisterOAuth(const Def &d, create_cb create, static void RegisterOAuth(const Def &d, create_cb create,
login_cb login, delete_cookies_cb delete_cookies); login_cb login,
delete_cookies_cb delete_cookies);
protected: protected:
std::string refresh_token; std::string refresh_token;
@@ -55,12 +56,12 @@ protected:
virtual void SaveInternal() override; virtual void SaveInternal() override;
virtual bool LoadInternal() override; virtual bool LoadInternal() override;
virtual bool RetryLogin()=0; virtual bool RetryLogin() = 0;
bool TokenExpired(); bool TokenExpired();
bool GetToken(const char *url, const std::string &client_id, bool GetToken(const char *url, const std::string &client_id,
int scope_ver, int scope_ver,
const std::string &auth_code = std::string(), const std::string &auth_code = std::string(),
bool retry = false); bool retry = false);
}; };
class OAuthStreamKey : public OAuth { class OAuthStreamKey : public OAuth {
@@ -72,7 +73,7 @@ protected:
public: public:
inline OAuthStreamKey(const Def &d) : OAuth(d) {} inline OAuthStreamKey(const Def &d) : OAuth(d) {}
inline const std::string &key() const {return key_;} inline const std::string &key() const { return key_; }
virtual void OnStreamConfig() override; virtual void OnStreamConfig() override;
}; };
+27 -48
View File
@@ -22,23 +22,17 @@ extern QCefCookieManager *panel_cookies;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#define RESTREAM_AUTH_URL "https://obsproject.com/app-auth/restream?action=redirect" #define RESTREAM_AUTH_URL \
"https://obsproject.com/app-auth/restream?action=redirect"
#define RESTREAM_TOKEN_URL "https://obsproject.com/app-auth/restream-token" #define RESTREAM_TOKEN_URL "https://obsproject.com/app-auth/restream-token"
#define RESTREAM_STREAMKEY_URL "https://api.restream.io/v2/user/streamKey" #define RESTREAM_STREAMKEY_URL "https://api.restream.io/v2/user/streamKey"
#define RESTREAM_SCOPE_VERSION 1 #define RESTREAM_SCOPE_VERSION 1
static Auth::Def restreamDef = {"Restream", Auth::Type::OAuth_StreamKey};
static Auth::Def restreamDef = {
"Restream",
Auth::Type::OAuth_StreamKey
};
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
RestreamAuth::RestreamAuth(const Def &d) RestreamAuth::RestreamAuth(const Def &d) : OAuthStreamKey(d) {}
: OAuthStreamKey(d)
{
}
bool RestreamAuth::GetChannelInfo() bool RestreamAuth::GetChannelInfo()
try { try {
@@ -65,23 +59,15 @@ try {
Json json; Json json;
bool success; bool success;
auto func = [&] () { auto func = [&]() {
success = GetRemoteFile( success = GetRemoteFile(RESTREAM_STREAMKEY_URL, output, error,
RESTREAM_STREAMKEY_URL, nullptr, "application/json", nullptr,
output, headers, nullptr, 5);
error,
nullptr,
"application/json",
nullptr,
headers,
nullptr,
5);
}; };
ExecThreadedWithoutBlocking( ExecThreadedWithoutBlocking(
func, func, QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Title"), QTStr("Auth.LoadingChannel.Text").arg(service()));
QTStr("Auth.LoadingChannel.Text").arg(service()));
if (!success || output.empty()) if (!success || output.empty())
throw ErrorInfo("Failed to get stream key from remote", error); throw ErrorInfo("Failed to get stream key from remote", error);
@@ -91,7 +77,8 @@ try {
error = json["error"].string_value(); error = json["error"].string_value();
if (!error.empty()) if (!error.empty())
throw ErrorInfo(error, json["error_description"].string_value()); throw ErrorInfo(error,
json["error_description"].string_value());
key_ = json["streamKey"].string_value(); key_ = json["streamKey"].string_value();
@@ -99,14 +86,13 @@ try {
} catch (ErrorInfo info) { } catch (ErrorInfo info) {
QString title = QTStr("Auth.ChannelFailure.Title"); QString title = QTStr("Auth.ChannelFailure.Title");
QString text = QTStr("Auth.ChannelFailure.Text") QString text = QTStr("Auth.ChannelFailure.Text")
.arg(service(), info.message.c_str(), info.error.c_str()); .arg(service(), info.message.c_str(),
info.error.c_str());
QMessageBox::warning(OBSBasic::Get(), title, text); QMessageBox::warning(OBSBasic::Get(), title, text);
blog(LOG_WARNING, "%s: %s: %s", blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
__FUNCTION__, info.error.c_str());
info.message.c_str(),
info.error.c_str());
return false; return false;
} }
@@ -114,14 +100,12 @@ void RestreamAuth::SaveInternal()
{ {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
config_set_string(main->Config(), service(), "DockState", config_set_string(main->Config(), service(), "DockState",
main->saveState().toBase64().constData()); main->saveState().toBase64().constData());
OAuthStreamKey::SaveInternal(); OAuthStreamKey::SaveInternal();
} }
static inline std::string get_config_str( static inline std::string get_config_str(OBSBasic *main, const char *section,
OBSBasic *main, const char *name)
const char *section,
const char *name)
{ {
const char *val = config_get_string(main->Config(), section, name); const char *val = config_get_string(main->Config(), section, name);
return val ? val : ""; return val ? val : "";
@@ -201,10 +185,9 @@ void RestreamAuth::LoadUI()
if (firstLoad) { if (firstLoad) {
chat->setVisible(true); chat->setVisible(true);
info->setVisible(true); info->setVisible(true);
} } else {
else { const char *dockStateStr = config_get_string(
const char *dockStateStr = config_get_string(main->Config(), main->Config(), service(), "DockState");
service(), "DockState");
QByteArray dockState = QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr)); QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState); main->restoreState(dockState);
@@ -227,8 +210,7 @@ bool RestreamAuth::RetryLogin()
std::string client_id = RESTREAM_CLIENTID; std::string client_id = RESTREAM_CLIENTID;
deobfuscate_str(&client_id[0], RESTREAM_HASH); deobfuscate_str(&client_id[0], RESTREAM_HASH);
return GetToken(RESTREAM_TOKEN_URL, client_id, return GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION,
RESTREAM_SCOPE_VERSION,
QT_TO_UTF8(login.GetCode()), true); QT_TO_UTF8(login.GetCode()), true);
} }
@@ -248,8 +230,8 @@ std::shared_ptr<Auth> RestreamAuth::Login(QWidget *parent)
deobfuscate_str(&client_id[0], RESTREAM_HASH); deobfuscate_str(&client_id[0], RESTREAM_HASH);
if (!auth->GetToken(RESTREAM_TOKEN_URL, client_id, if (!auth->GetToken(RESTREAM_TOKEN_URL, client_id,
RESTREAM_SCOPE_VERSION, RESTREAM_SCOPE_VERSION,
QT_TO_UTF8(login.GetCode()))) { QT_TO_UTF8(login.GetCode()))) {
return nullptr; return nullptr;
} }
@@ -275,9 +257,6 @@ static void DeleteCookies()
void RegisterRestreamAuth() void RegisterRestreamAuth()
{ {
OAuth::RegisterOAuth( OAuth::RegisterOAuth(restreamDef, CreateRestreamAuth,
restreamDef, RestreamAuth::Login, DeleteCookies);
CreateRestreamAuth,
RestreamAuth::Login,
DeleteCookies);
} }
+54 -73
View File
@@ -24,35 +24,28 @@ extern QCefCookieManager *panel_cookies;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#define TWITCH_AUTH_URL \ #define TWITCH_AUTH_URL "https://obsproject.com/app-auth/twitch?action=redirect"
"https://obsproject.com/app-auth/twitch?action=redirect" #define TWITCH_TOKEN_URL "https://obsproject.com/app-auth/twitch-token"
#define TWITCH_TOKEN_URL \ #define ACCEPT_HEADER "Accept: application/vnd.twitchtv.v5+json"
"https://obsproject.com/app-auth/twitch-token"
#define ACCEPT_HEADER \
"Accept: application/vnd.twitchtv.v5+json"
#define TWITCH_SCOPE_VERSION 1 #define TWITCH_SCOPE_VERSION 1
static Auth::Def twitchDef = { static Auth::Def twitchDef = {"Twitch", Auth::Type::OAuth_StreamKey};
"Twitch",
Auth::Type::OAuth_StreamKey
};
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
TwitchAuth::TwitchAuth(const Def &d) TwitchAuth::TwitchAuth(const Def &d) : OAuthStreamKey(d)
: OAuthStreamKey(d)
{ {
if (!cef) if (!cef)
return; return;
cef->add_popup_whitelist_url( cef->add_popup_whitelist_url(
"https://twitch.tv/popout/frankerfacez/chat?ffz-settings", "https://twitch.tv/popout/frankerfacez/chat?ffz-settings",
this); this);
uiLoadTimer.setSingleShot(true); uiLoadTimer.setSingleShot(true);
uiLoadTimer.setInterval(500); uiLoadTimer.setInterval(500);
connect(&uiLoadTimer, &QTimer::timeout, connect(&uiLoadTimer, &QTimer::timeout, this,
this, &TwitchAuth::TryLoadSecondaryUIPanes); &TwitchAuth::TryLoadSecondaryUIPanes);
} }
bool TwitchAuth::GetChannelInfo() bool TwitchAuth::GetChannelInfo()
@@ -82,33 +75,25 @@ try {
bool success = false; bool success = false;
auto func = [&] () { auto func = [&]() {
success = GetRemoteFile( success = GetRemoteFile("https://api.twitch.tv/kraken/channel",
"https://api.twitch.tv/kraken/channel", output, error, &error_code,
output, "application/json", nullptr, headers,
error, nullptr, 5);
&error_code,
"application/json",
nullptr,
headers,
nullptr,
5);
}; };
ExecThreadedWithoutBlocking( ExecThreadedWithoutBlocking(
func, func, QTStr("Auth.LoadingChannel.Title"),
QTStr("Auth.LoadingChannel.Title"), QTStr("Auth.LoadingChannel.Text").arg(service()));
QTStr("Auth.LoadingChannel.Text").arg(service()));
if (error_code == 403) { if (error_code == 403) {
OBSMessageBox::warning(OBSBasic::Get(), OBSMessageBox::warning(OBSBasic::Get(),
Str("TwitchAuth.TwoFactorFail.Title"), Str("TwitchAuth.TwoFactorFail.Title"),
Str("TwitchAuth.TwoFactorFail.Text"), Str("TwitchAuth.TwoFactorFail.Text"),
true); true);
blog(LOG_WARNING, "%s: %s", blog(LOG_WARNING, "%s: %s", __FUNCTION__,
__FUNCTION__, "Got 403 from Twitch, user probably does not "
"Got 403 from Twitch, user probably does not " "have two-factor authentication enabled on "
"have two-factor authentication enabled on " "their account");
"their account");
return false; return false;
} }
@@ -125,10 +110,10 @@ try {
if (RetryLogin()) { if (RetryLogin()) {
return GetChannelInfo(); return GetChannelInfo();
} }
throw ErrorInfo(error, throw ErrorInfo(error, json["message"].string_value());
json["message"].string_value());
} }
throw ErrorInfo(error, json["error_description"].string_value()); throw ErrorInfo(error,
json["error_description"].string_value());
} }
name = json["name"].string_value(); name = json["name"].string_value();
@@ -138,14 +123,13 @@ try {
} catch (ErrorInfo info) { } catch (ErrorInfo info) {
QString title = QTStr("Auth.ChannelFailure.Title"); QString title = QTStr("Auth.ChannelFailure.Title");
QString text = QTStr("Auth.ChannelFailure.Text") QString text = QTStr("Auth.ChannelFailure.Text")
.arg(service(), info.message.c_str(), info.error.c_str()); .arg(service(), info.message.c_str(),
info.error.c_str());
QMessageBox::warning(OBSBasic::Get(), title, text); QMessageBox::warning(OBSBasic::Get(), title, text);
blog(LOG_WARNING, "%s: %s: %s", blog(LOG_WARNING, "%s: %s: %s", __FUNCTION__, info.message.c_str(),
__FUNCTION__, info.error.c_str());
info.message.c_str(),
info.error.c_str());
return false; return false;
} }
@@ -155,15 +139,13 @@ void TwitchAuth::SaveInternal()
config_set_string(main->Config(), service(), "Name", name.c_str()); config_set_string(main->Config(), service(), "Name", name.c_str());
if (uiLoaded) { if (uiLoaded) {
config_set_string(main->Config(), service(), "DockState", config_set_string(main->Config(), service(), "DockState",
main->saveState().toBase64().constData()); main->saveState().toBase64().constData());
} }
OAuthStreamKey::SaveInternal(); OAuthStreamKey::SaveInternal();
} }
static inline std::string get_config_str( static inline std::string get_config_str(OBSBasic *main, const char *section,
OBSBasic *main, const char *name)
const char *section,
const char *name)
{ {
const char *val = config_get_string(main->Config(), section, name); const char *val = config_get_string(main->Config(), section, name);
return val ? val : ""; return val ? val : "";
@@ -266,8 +248,8 @@ void TwitchAuth::LoadUI()
if (firstLoad) { if (firstLoad) {
chat->setVisible(true); chat->setVisible(true);
} else { } else {
const char *dockStateStr = config_get_string(main->Config(), const char *dockStateStr = config_get_string(
service(), "DockState"); main->Config(), service(), "DockState");
QByteArray dockState = QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr)); QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState); main->restoreState(dockState);
@@ -367,8 +349,8 @@ void TwitchAuth::LoadSecondaryUIPanes()
QSize statSize = stat->frameSize(); QSize statSize = stat->frameSize();
info->move(pos.x() + 50, pos.y() + 50); info->move(pos.x() + 50, pos.y() + 50);
stat->move(pos.x() + size.width() / 2 - statSize.width() / 2, stat->move(pos.x() + size.width() / 2 - statSize.width() / 2,
pos.y() + size.height() / 2 - statSize.height() / 2); pos.y() + size.height() / 2 - statSize.height() / 2);
feed->move(pos.x() + 100, pos.y() + 100); feed->move(pos.x() + 100, pos.y() + 100);
if (firstLoad) { if (firstLoad) {
@@ -376,15 +358,15 @@ void TwitchAuth::LoadSecondaryUIPanes()
stat->setVisible(false); stat->setVisible(false);
feed->setVisible(false); feed->setVisible(false);
} else { } else {
uint32_t lastVersion = config_get_int(App()->GlobalConfig(), "General", uint32_t lastVersion = config_get_int(App()->GlobalConfig(),
"LastVersion"); "General", "LastVersion");
if (lastVersion <= MAKE_SEMANTIC_VERSION(23, 0, 2)) { if (lastVersion <= MAKE_SEMANTIC_VERSION(23, 0, 2)) {
feed->setVisible(false); feed->setVisible(false);
} }
const char *dockStateStr = config_get_string(main->Config(), const char *dockStateStr = config_get_string(
service(), "DockState"); main->Config(), service(), "DockState");
QByteArray dockState = QByteArray dockState =
QByteArray::fromBase64(QByteArray(dockStateStr)); QByteArray::fromBase64(QByteArray(dockStateStr));
main->restoreState(dockState); main->restoreState(dockState);
@@ -405,21 +387,21 @@ void TwitchAuth::TryLoadSecondaryUIPanes()
{ {
QPointer<TwitchAuth> this_ = this; QPointer<TwitchAuth> this_ = this;
auto cb = [this_] (bool found) auto cb = [this_](bool found) {
{
if (!this_) { if (!this_) {
return; return;
} }
if (!found) { if (!found) {
QMetaObject::invokeMethod(&this_->uiLoadTimer, QMetaObject::invokeMethod(&this_->uiLoadTimer, "start");
"start");
} else { } else {
QMetaObject::invokeMethod(this_, "LoadSecondaryUIPanes"); QMetaObject::invokeMethod(this_,
"LoadSecondaryUIPanes");
} }
}; };
panel_cookies->CheckForCookie("https://www.twitch.tv", "auth-token", cb); panel_cookies->CheckForCookie("https://www.twitch.tv", "auth-token",
cb);
} }
bool TwitchAuth::RetryLogin() bool TwitchAuth::RetryLogin()
@@ -429,7 +411,8 @@ bool TwitchAuth::RetryLogin()
return false; return false;
} }
std::shared_ptr<TwitchAuth> auth = std::make_shared<TwitchAuth>(twitchDef); std::shared_ptr<TwitchAuth> auth =
std::make_shared<TwitchAuth>(twitchDef);
std::string client_id = TWITCH_CLIENTID; std::string client_id = TWITCH_CLIENTID;
deobfuscate_str(&client_id[0], TWITCH_HASH); deobfuscate_str(&client_id[0], TWITCH_HASH);
@@ -444,13 +427,14 @@ std::shared_ptr<Auth> TwitchAuth::Login(QWidget *parent)
return nullptr; return nullptr;
} }
std::shared_ptr<TwitchAuth> auth = std::make_shared<TwitchAuth>(twitchDef); std::shared_ptr<TwitchAuth> auth =
std::make_shared<TwitchAuth>(twitchDef);
std::string client_id = TWITCH_CLIENTID; std::string client_id = TWITCH_CLIENTID;
deobfuscate_str(&client_id[0], TWITCH_HASH); deobfuscate_str(&client_id[0], TWITCH_HASH);
if (!auth->GetToken(TWITCH_TOKEN_URL, client_id, TWITCH_SCOPE_VERSION, if (!auth->GetToken(TWITCH_TOKEN_URL, client_id, TWITCH_SCOPE_VERSION,
QT_TO_UTF8(login.GetCode()))) { QT_TO_UTF8(login.GetCode()))) {
return nullptr; return nullptr;
} }
@@ -475,9 +459,6 @@ static void DeleteCookies()
void RegisterTwitchAuth() void RegisterTwitchAuth()
{ {
OAuth::RegisterOAuth( OAuth::RegisterOAuth(twitchDef, CreateTwitchAuth, TwitchAuth::Login,
twitchDef, DeleteCookies);
CreateTwitchAuth,
TwitchAuth::Login,
DeleteCookies);
} }
+1 -1
View File
@@ -4,7 +4,7 @@
#include <QMouseEvent> #include <QMouseEvent>
class ClickableLabel : public QLabel { class ClickableLabel : public QLabel {
Q_OBJECT Q_OBJECT
public: public:
inline ClickableLabel(QWidget *parent = 0) : QLabel(parent) {} inline ClickableLabel(QWidget *parent = 0) : QLabel(parent) {}
+4 -4
View File
@@ -32,10 +32,10 @@ OBSCrashReport::OBSCrashReport(QWidget *parent, const char *text)
setLayout(mainLayout); setLayout(mainLayout);
QWidget::connect(copyButton, SIGNAL(clicked()), QWidget::connect(copyButton, SIGNAL(clicked()), this,
this, SLOT(CopyClicked())); SLOT(CopyClicked()));
QWidget::connect(exitButton, SIGNAL(clicked()), QWidget::connect(exitButton, SIGNAL(clicked()), this,
this, SLOT(ExitClicked())); SLOT(ExitClicked()));
resize(800, 600); resize(800, 600);
setWindowTitle("Oops, OBS has crashed!"); setWindowTitle("Oops, OBS has crashed!");
+11 -11
View File
@@ -21,15 +21,15 @@
#define SUPPORTS_FRACTIONAL_SCALING #define SUPPORTS_FRACTIONAL_SCALING
#endif #endif
static inline void GetScaleAndCenterPos( static inline void GetScaleAndCenterPos(int baseCX, int baseCY, int windowCX,
int baseCX, int baseCY, int windowCX, int windowCY, int windowCY, int &x, int &y,
int &x, int &y, float &scale) float &scale)
{ {
double windowAspect, baseAspect; double windowAspect, baseAspect;
int newCX, newCY; int newCX, newCY;
windowAspect = double(windowCX) / double(windowCY); windowAspect = double(windowCX) / double(windowCY);
baseAspect = double(baseCX) / double(baseCY); baseAspect = double(baseCX) / double(baseCY);
if (windowAspect > baseAspect) { if (windowAspect > baseAspect) {
scale = float(windowCY) / float(baseCY); scale = float(windowCY) / float(baseCY);
@@ -41,16 +41,16 @@ static inline void GetScaleAndCenterPos(
newCY = int(float(windowCX) / baseAspect); newCY = int(float(windowCX) / baseAspect);
} }
x = windowCX/2 - newCX/2; x = windowCX / 2 - newCX / 2;
y = windowCY/2 - newCY/2; y = windowCY / 2 - newCY / 2;
} }
static inline void GetCenterPosFromFixedScale( static inline void GetCenterPosFromFixedScale(int baseCX, int baseCY,
int baseCX, int baseCY, int windowCX, int windowCY, int windowCX, int windowCY,
int &x, int &y, float scale) int &x, int &y, float scale)
{ {
x = (float(windowCX) - float(baseCX)*scale) / 2.0f; x = (float(windowCX) - float(baseCX) * scale) / 2.0f;
y = (float(windowCY) - float(baseCY)*scale) / 2.0f; y = (float(windowCY) - float(baseCY) * scale) / 2.0f;
} }
static inline QSize GetPixelSize(QWidget *widget) static inline QSize GetPixelSize(QWidget *widget)
+4 -4
View File
@@ -4,12 +4,12 @@
DoubleSlider::DoubleSlider(QWidget *parent) : SliderIgnoreScroll(parent) DoubleSlider::DoubleSlider(QWidget *parent) : SliderIgnoreScroll(parent)
{ {
connect(this, SIGNAL(valueChanged(int)), connect(this, SIGNAL(valueChanged(int)), this,
this, SLOT(intValChanged(int))); SLOT(intValChanged(int)));
} }
void DoubleSlider::setDoubleConstraints(double newMin, double newMax, void DoubleSlider::setDoubleConstraints(double newMin, double newMax,
double newStep, double val) double newStep, double val)
{ {
minVal = newMin; minVal = newMin;
maxVal = newMax; maxVal = newMax;
@@ -26,7 +26,7 @@ void DoubleSlider::setDoubleConstraints(double newMin, double newMax,
void DoubleSlider::intValChanged(int val) void DoubleSlider::intValChanged(int val)
{ {
emit doubleValChanged((minVal/minStep + val) * minStep); emit doubleValChanged((minVal / minStep + val) * minStep);
} }
void DoubleSlider::setDoubleVal(double val) void DoubleSlider::setDoubleVal(double val)
+2 -2
View File
@@ -11,8 +11,8 @@ class DoubleSlider : public SliderIgnoreScroll {
public: public:
DoubleSlider(QWidget *parent = nullptr); DoubleSlider(QWidget *parent = nullptr);
void setDoubleConstraints(double newMin, double newMax, void setDoubleConstraints(double newMin, double newMax, double newStep,
double newStep, double val); double val);
signals: signals:
void doubleValChanged(double val); void doubleValChanged(double val);
+1 -2
View File
@@ -2,8 +2,7 @@
#include <QListWidget> #include <QListWidget>
class FocusList : public QListWidget class FocusList : public QListWidget {
{
Q_OBJECT Q_OBJECT
public: public:
@@ -5,8 +5,7 @@
#include "decklink-ui-main.h" #include "decklink-ui-main.h"
DecklinkOutputUI::DecklinkOutputUI(QWidget *parent) DecklinkOutputUI::DecklinkOutputUI(QWidget *parent)
: QDialog(parent), : QDialog(parent), ui(new Ui_Output)
ui(new Ui_Output)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -20,8 +19,10 @@ DecklinkOutputUI::DecklinkOutputUI(QWidget *parent)
connect(ui->startOutput, SIGNAL(released()), this, SLOT(StartOutput())); connect(ui->startOutput, SIGNAL(released()), this, SLOT(StartOutput()));
connect(ui->stopOutput, SIGNAL(released()), this, SLOT(StopOutput())); connect(ui->stopOutput, SIGNAL(released()), this, SLOT(StopOutput()));
connect(ui->startPreviewOutput, SIGNAL(released()), this, SLOT(StartPreviewOutput())); connect(ui->startPreviewOutput, SIGNAL(released()), this,
connect(ui->stopPreviewOutput, SIGNAL(released()), this, SLOT(StopPreviewOutput())); SLOT(StartPreviewOutput()));
connect(ui->stopPreviewOutput, SIGNAL(released()), this,
SLOT(StopPreviewOutput()));
} }
void DecklinkOutputUI::ShowHideDialog() void DecklinkOutputUI::ShowHideDialog()
@@ -43,25 +44,26 @@ void DecklinkOutputUI::SetupPropertiesView()
if (data) if (data)
obs_data_apply(settings, data); obs_data_apply(settings, data);
propertiesView = new OBSPropertiesView(settings, propertiesView = new OBSPropertiesView(
"decklink_output", settings, "decklink_output",
(PropertiesReloadCallback) obs_get_output_properties, (PropertiesReloadCallback)obs_get_output_properties, 170);
170);
ui->propertiesLayout->addWidget(propertiesView); ui->propertiesLayout->addWidget(propertiesView);
obs_data_release(settings); obs_data_release(settings);
connect(propertiesView, SIGNAL(Changed()), this, SLOT(PropertiesChanged())); connect(propertiesView, SIGNAL(Changed()), this,
SLOT(PropertiesChanged()));
} }
void DecklinkOutputUI::SaveSettings() void DecklinkOutputUI::SaveSettings()
{ {
BPtr<char> modulePath = obs_module_get_config_path(obs_current_module(), ""); BPtr<char> modulePath =
obs_module_get_config_path(obs_current_module(), "");
os_mkdirs(modulePath); os_mkdirs(modulePath);
BPtr<char> path = obs_module_get_config_path(obs_current_module(), BPtr<char> path = obs_module_get_config_path(
"decklinkOutputProps.json"); obs_current_module(), "decklinkOutputProps.json");
obs_data_t *settings = propertiesView->GetSettings(); obs_data_t *settings = propertiesView->GetSettings();
if (settings) if (settings)
@@ -79,15 +81,15 @@ void DecklinkOutputUI::SetupPreviewPropertiesView()
if (data) if (data)
obs_data_apply(settings, data); obs_data_apply(settings, data);
previewPropertiesView = new OBSPropertiesView(settings, previewPropertiesView = new OBSPropertiesView(
"decklink_output", settings, "decklink_output",
(PropertiesReloadCallback) obs_get_output_properties, (PropertiesReloadCallback)obs_get_output_properties, 170);
170);
ui->previewPropertiesLayout->addWidget(previewPropertiesView); ui->previewPropertiesLayout->addWidget(previewPropertiesView);
obs_data_release(settings); obs_data_release(settings);
connect(previewPropertiesView, SIGNAL(Changed()), this, SLOT(PreviewPropertiesChanged())); connect(previewPropertiesView, SIGNAL(Changed()), this,
SLOT(PreviewPropertiesChanged()));
} }
void DecklinkOutputUI::SavePreviewSettings() void DecklinkOutputUI::SavePreviewSettings()
@@ -96,15 +98,14 @@ void DecklinkOutputUI::SavePreviewSettings()
os_mkdirs(modulePath); os_mkdirs(modulePath);
char *path = obs_module_get_config_path(obs_current_module(), char *path = obs_module_get_config_path(
"decklinkPreviewOutputProps.json"); obs_current_module(), "decklinkPreviewOutputProps.json");
obs_data_t *settings = previewPropertiesView->GetSettings(); obs_data_t *settings = previewPropertiesView->GetSettings();
if (settings) if (settings)
obs_data_save_json_safe(settings, path, "tmp", "bak"); obs_data_save_json_safe(settings, path, "tmp", "bak");
} }
void DecklinkOutputUI::StartOutput() void DecklinkOutputUI::StartOutput()
{ {
SaveSettings(); SaveSettings();
@@ -121,7 +122,6 @@ void DecklinkOutputUI::PropertiesChanged()
SaveSettings(); SaveSettings();
} }
void DecklinkOutputUI::StartPreviewOutput() void DecklinkOutputUI::StartPreviewOutput()
{ {
SavePreviewSettings(); SavePreviewSettings();
@@ -6,7 +6,7 @@
#include "../../UI/properties-view.hpp" #include "../../UI/properties-view.hpp"
class DecklinkOutputUI : public QDialog { class DecklinkOutputUI : public QDialog {
Q_OBJECT Q_OBJECT
private: private:
OBSPropertiesView *propertiesView; OBSPropertiesView *propertiesView;
OBSPropertiesView *previewPropertiesView; OBSPropertiesView *previewPropertiesView;
@@ -37,8 +37,8 @@ static struct preview_output context = {0};
OBSData load_settings() OBSData load_settings()
{ {
BPtr<char> path = obs_module_get_config_path(obs_current_module(), BPtr<char> path = obs_module_get_config_path(
"decklinkOutputProps.json"); obs_current_module(), "decklinkOutputProps.json");
BPtr<char> jsonData = os_quick_read_utf8_file(path); BPtr<char> jsonData = os_quick_read_utf8_file(path);
if (!!jsonData) { if (!!jsonData) {
obs_data_t *data = obs_data_create_from_json(jsonData); obs_data_t *data = obs_data_create_from_json(jsonData);
@@ -58,7 +58,8 @@ void output_start()
if (settings != nullptr) { if (settings != nullptr) {
output = obs_output_create("decklink_output", output = obs_output_create("decklink_output",
"decklink_output", settings, NULL); "decklink_output", settings,
NULL);
obs_output_start(output); obs_output_start(output);
obs_data_release(settings); obs_data_release(settings);
@@ -77,11 +78,10 @@ void output_stop()
} }
} }
OBSData load_preview_settings() OBSData load_preview_settings()
{ {
BPtr<char> path = obs_module_get_config_path(obs_current_module(), BPtr<char> path = obs_module_get_config_path(
"decklinkPreviewOutputProps.json"); obs_current_module(), "decklinkPreviewOutputProps.json");
BPtr<char> jsonData = os_quick_read_utf8_file(path); BPtr<char> jsonData = os_quick_read_utf8_file(path);
if (!!jsonData) { if (!!jsonData) {
obs_data_t *data = obs_data_create_from_json(jsonData); obs_data_t *data = obs_data_create_from_json(jsonData);
@@ -103,8 +103,9 @@ void preview_output_start()
OBSData settings = load_preview_settings(); OBSData settings = load_preview_settings();
if (settings != nullptr) { if (settings != nullptr) {
context.output = obs_output_create("decklink_output", context.output = obs_output_create(
"decklink_preview_output", settings, NULL); "decklink_output", "decklink_preview_output",
settings, NULL);
obs_get_video_info(&context.ovi); obs_get_video_info(&context.ovi);
@@ -112,11 +113,14 @@ void preview_output_start()
uint32_t height = context.ovi.base_height; uint32_t height = context.ovi.base_height;
obs_enter_graphics(); obs_enter_graphics();
context.texrender = gs_texrender_create(GS_BGRA, GS_ZS_NONE); context.texrender =
context.stagesurface = gs_stagesurface_create(width, height, GS_BGRA); gs_texrender_create(GS_BGRA, GS_ZS_NONE);
context.stagesurface =
gs_stagesurface_create(width, height, GS_BGRA);
obs_leave_graphics(); obs_leave_graphics();
const video_output_info *mainVOI = video_output_get_info(obs_get_video()); const video_output_info *mainVOI =
video_output_get_info(obs_get_video());
video_output_info vi = {0}; video_output_info vi = {0};
vi.format = VIDEO_FORMAT_BGRA; vi.format = VIDEO_FORMAT_BGRA;
@@ -131,15 +135,21 @@ void preview_output_start()
video_output_open(&context.video_queue, &vi); video_output_open(&context.video_queue, &vi);
obs_frontend_add_event_callback(on_preview_scene_changed, &context); obs_frontend_add_event_callback(
on_preview_scene_changed, &context);
if (obs_frontend_preview_program_mode_active()) { if (obs_frontend_preview_program_mode_active()) {
context.current_source = obs_frontend_get_current_preview_scene(); context.current_source =
obs_frontend_get_current_preview_scene();
} else { } else {
context.current_source = obs_frontend_get_current_scene(); context.current_source =
obs_frontend_get_current_scene();
} }
obs_add_main_render_callback(render_preview_source, &context); obs_add_main_render_callback(render_preview_source,
&context);
obs_output_set_media(context.output, context.video_queue, obs_get_audio()); obs_output_set_media(context.output,
context.video_queue,
obs_get_audio());
obs_output_start(context.output); obs_output_start(context.output);
preview_output_running = true; preview_output_running = true;
@@ -153,8 +163,10 @@ void preview_output_stop()
obs_output_stop(context.output); obs_output_stop(context.output);
video_output_stop(context.video_queue); video_output_stop(context.video_queue);
obs_remove_main_render_callback(render_preview_source, &context); obs_remove_main_render_callback(render_preview_source,
obs_frontend_remove_event_callback(on_preview_scene_changed, &context); &context);
obs_frontend_remove_event_callback(on_preview_scene_changed,
&context);
obs_source_release(context.current_source); obs_source_release(context.current_source);
@@ -171,33 +183,34 @@ void preview_output_stop()
void on_preview_scene_changed(enum obs_frontend_event event, void *param) void on_preview_scene_changed(enum obs_frontend_event event, void *param)
{ {
auto ctx = (struct preview_output*)param; auto ctx = (struct preview_output *)param;
switch (event) { switch (event) {
case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED: case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED:
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED: case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
obs_source_release(ctx->current_source); obs_source_release(ctx->current_source);
ctx->current_source = obs_frontend_get_current_preview_scene(); ctx->current_source = obs_frontend_get_current_preview_scene();
break; break;
case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED: case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED:
obs_source_release(ctx->current_source);
ctx->current_source = obs_frontend_get_current_scene();
break;
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
if (!obs_frontend_preview_program_mode_active()) {
obs_source_release(ctx->current_source); obs_source_release(ctx->current_source);
ctx->current_source = obs_frontend_get_current_scene(); ctx->current_source = obs_frontend_get_current_scene();
break; }
case OBS_FRONTEND_EVENT_SCENE_CHANGED: break;
if (!obs_frontend_preview_program_mode_active()) { default:
obs_source_release(ctx->current_source); break;
ctx->current_source = obs_frontend_get_current_scene();
}
break;
default:
break;
} }
} }
void render_preview_source(void *param, uint32_t cx, uint32_t cy) void render_preview_source(void *param, uint32_t cx, uint32_t cy)
{ {
auto ctx = (struct preview_output*)param; auto ctx = (struct preview_output *)param;
if (!ctx->current_source) return; if (!ctx->current_source)
return;
uint32_t width = obs_source_get_base_width(ctx->current_source); uint32_t width = obs_source_get_base_width(ctx->current_source);
uint32_t height = obs_source_get_base_height(ctx->current_source); uint32_t height = obs_source_get_base_height(ctx->current_source);
@@ -209,7 +222,8 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
vec4_zero(&background); vec4_zero(&background);
gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0); gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0);
gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f); gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f,
100.0f);
gs_blend_state_push(); gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO); gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
@@ -220,18 +234,25 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
gs_texrender_end(ctx->texrender); gs_texrender_end(ctx->texrender);
struct video_frame output_frame; struct video_frame output_frame;
if (video_output_lock_frame(ctx->video_queue, &output_frame, 1, os_gettime_ns())) if (video_output_lock_frame(ctx->video_queue, &output_frame, 1,
{ os_gettime_ns())) {
gs_stage_texture(ctx->stagesurface, gs_texrender_get_texture(ctx->texrender)); gs_stage_texture(
ctx->stagesurface,
gs_texrender_get_texture(ctx->texrender));
if (gs_stagesurface_map(ctx->stagesurface, &ctx->video_data, &ctx->video_linesize)) { if (gs_stagesurface_map(ctx->stagesurface,
&ctx->video_data,
&ctx->video_linesize)) {
uint32_t linesize = output_frame.linesize[0]; uint32_t linesize = output_frame.linesize[0];
for (uint32_t i = 0; i < ctx->ovi.base_height; i++) { for (uint32_t i = 0; i < ctx->ovi.base_height;
i++) {
uint32_t dst_offset = linesize * i; uint32_t dst_offset = linesize * i;
uint32_t src_offset = ctx->video_linesize * i; uint32_t src_offset =
memcpy(output_frame.data[0] + dst_offset, ctx->video_linesize * i;
ctx->video_data + src_offset, memcpy(output_frame.data[0] +
linesize); dst_offset,
ctx->video_data + src_offset,
linesize);
} }
gs_stagesurface_unmap(ctx->stagesurface); gs_stagesurface_unmap(ctx->stagesurface);
@@ -245,18 +266,16 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
void addOutputUI(void) void addOutputUI(void)
{ {
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("Decklink Output")); obs_module_text("Decklink Output"));
QMainWindow *window = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow *window = (QMainWindow *)obs_frontend_get_main_window();
obs_frontend_push_ui_translation(obs_module_get_string); obs_frontend_push_ui_translation(obs_module_get_string);
doUI = new DecklinkOutputUI(window); doUI = new DecklinkOutputUI(window);
obs_frontend_pop_ui_translation(); obs_frontend_pop_ui_translation();
auto cb = []() { auto cb = []() { doUI->ShowHideDialog(); };
doUI->ShowHideDialog();
};
action->connect(action, &QAction::triggered, cb); action->connect(action, &QAction::triggered, cb);
} }
@@ -271,7 +290,8 @@ static void OBSEvent(enum obs_frontend_event event, void *)
OBSData previewSettings = load_preview_settings(); OBSData previewSettings = load_preview_settings();
if (previewSettings && obs_data_get_bool(previewSettings, "auto_start")) if (previewSettings &&
obs_data_get_bool(previewSettings, "auto_start"))
preview_output_start(); preview_output_start();
} }
} }
@@ -17,7 +17,7 @@
using namespace std; using namespace std;
static Display* xdisplay = 0; static Display *xdisplay = 0;
Display *disp() Display *disp()
{ {
@@ -39,31 +39,22 @@ void cleanupDisplay()
static bool ewmhIsSupported() static bool ewmhIsSupported()
{ {
Display *display = disp(); Display *display = disp();
Atom netSupportingWmCheck = XInternAtom(display, Atom netSupportingWmCheck =
"_NET_SUPPORTING_WM_CHECK", true); XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", true);
Atom actualType; Atom actualType;
int format = 0; int format = 0;
unsigned long num = 0, bytes = 0; unsigned long num = 0, bytes = 0;
unsigned char *data = NULL; unsigned char *data = NULL;
Window ewmh_window = 0; Window ewmh_window = 0;
int status = XGetWindowProperty( int status = XGetWindowProperty(display, DefaultRootWindow(display),
display, netSupportingWmCheck, 0L, 1L, false,
DefaultRootWindow(display), XA_WINDOW, &actualType, &format, &num,
netSupportingWmCheck, &bytes, &data);
0L,
1L,
false,
XA_WINDOW,
&actualType,
&format,
&num,
&bytes,
&data);
if (status == Success) { if (status == Success) {
if (num > 0) { if (num > 0) {
ewmh_window = ((Window*)data)[0]; ewmh_window = ((Window *)data)[0];
} }
if (data) { if (data) {
XFree(data); XFree(data);
@@ -72,21 +63,12 @@ static bool ewmhIsSupported()
} }
if (ewmh_window) { if (ewmh_window) {
status = XGetWindowProperty( status = XGetWindowProperty(display, ewmh_window,
display, netSupportingWmCheck, 0L, 1L, false,
ewmh_window, XA_WINDOW, &actualType, &format,
netSupportingWmCheck, &num, &bytes, &data);
0L,
1L,
false,
XA_WINDOW,
&actualType,
&format,
&num,
&bytes,
&data);
if (status != Success || num == 0 || if (status != Success || num == 0 ||
ewmh_window != ((Window*)data)[0]) { ewmh_window != ((Window *)data)[0]) {
ewmh_window = 0; ewmh_window = 0;
} }
if (status == Success && data) { if (status == Success && data) {
@@ -111,24 +93,15 @@ static std::vector<Window> getTopLevelWindows()
Atom actualType; Atom actualType;
int format; int format;
unsigned long num, bytes; unsigned long num, bytes;
Window* data = 0; Window *data = 0;
for (int i = 0; i < ScreenCount(disp()); ++i) { for (int i = 0; i < ScreenCount(disp()); ++i) {
Window rootWin = RootWindow(disp(), i); Window rootWin = RootWindow(disp(), i);
int status = XGetWindowProperty( int status = XGetWindowProperty(disp(), rootWin, netClList, 0L,
disp(), ~0L, false, AnyPropertyType,
rootWin, &actualType, &format, &num,
netClList, &bytes, (uint8_t **)&data);
0L,
~0L,
false,
AnyPropertyType,
&actualType,
&format,
&num,
&bytes,
(uint8_t**)&data);
if (status != Success) { if (status != Success) {
continue; continue;
@@ -147,11 +120,10 @@ static std::string GetWindowTitle(size_t i)
{ {
Window w = getTopLevelWindows().at(i); Window w = getTopLevelWindows().at(i);
std::string windowTitle; std::string windowTitle;
char* name; char *name;
int status = XFetchName(disp(), w, &name); int status = XFetchName(disp(), w, &name);
if (status >= Success && name != nullptr) if (status >= Success && name != nullptr) {
{
std::string str(name); std::string str(name);
windowTitle = str; windowTitle = str;
} }
@@ -165,7 +137,7 @@ void GetWindowList(vector<string> &windows)
{ {
windows.resize(0); windows.resize(0);
for (size_t i = 0; i < getTopLevelWindows().size(); ++i){ for (size_t i = 0; i < getTopLevelWindows().size(); ++i) {
if (GetWindowTitle(i) != "") if (GetWindowTitle(i) != "")
windows.emplace_back(GetWindowTitle(i)); windows.emplace_back(GetWindowTitle(i));
} }
@@ -181,24 +153,14 @@ void GetCurrentWindowTitle(string &title)
Atom actualType; Atom actualType;
int format; int format;
unsigned long num, bytes; unsigned long num, bytes;
Window* data = 0; Window *data = 0;
char* name; char *name;
Window rootWin = RootWindow(disp(), 0); Window rootWin = RootWindow(disp(), 0);
XGetWindowProperty( XGetWindowProperty(disp(), rootWin, active, 0L, ~0L, false,
disp(), AnyPropertyType, &actualType, &format, &num, &bytes,
rootWin, (uint8_t **)&data);
active,
0L,
~0L,
false,
AnyPropertyType,
&actualType,
&format,
&num,
&bytes,
(uint8_t**)&data);
int status = XFetchName(disp(), data[0], &name); int status = XFetchName(disp(), data[0], &name);
@@ -32,7 +32,7 @@ static bool WindowValid(HWND window)
return false; return false;
GetClientRect(window, &rect); GetClientRect(window, &rect);
styles = GetWindowLongPtr(window, GWL_STYLE); styles = GetWindowLongPtr(window, GWL_STYLE);
ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE); ex_styles = GetWindowLongPtr(window, GWL_EXSTYLE);
if (ex_styles & WS_EX_TOOLWINDOW) if (ex_styles & WS_EX_TOOLWINDOW)
@@ -69,23 +69,19 @@ struct SwitcherData {
} }
} }
inline ~SwitcherData() inline ~SwitcherData() { Stop(); }
{
Stop();
}
}; };
static SwitcherData *switcher = nullptr; static SwitcherData *switcher = nullptr;
static inline QString MakeSwitchName(const QString &scene, static inline QString MakeSwitchName(const QString &scene,
const QString &window) const QString &window)
{ {
return QStringLiteral("[") + scene + QStringLiteral("]: ") + window; return QStringLiteral("[") + scene + QStringLiteral("]: ") + window;
} }
SceneSwitcher::SceneSwitcher(QWidget *parent) SceneSwitcher::SceneSwitcher(QWidget *parent)
: QDialog(parent), : QDialog(parent), ui(new Ui_SceneSwitcher)
ui(new Ui_SceneSwitcher)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -95,7 +91,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
switcher->Prune(); switcher->Prune();
BPtr<char*> scenes = obs_frontend_get_scene_names(); BPtr<char *> scenes = obs_frontend_get_scene_names();
char **temp = scenes; char **temp = scenes;
while (*temp) { while (*temp) {
const char *name = *temp; const char *name = *temp;
@@ -110,7 +106,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->noMatchDontSwitch->setChecked(true); ui->noMatchDontSwitch->setChecked(true);
ui->noMatchSwitchScene->setCurrentText( ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str()); GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->checkInterval->setValue(switcher->interval); ui->checkInterval->setValue(switcher->interval);
vector<string> windows; vector<string> windows;
@@ -121,11 +117,10 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
for (auto &s : switcher->switches) { for (auto &s : switcher->switches) {
string sceneName = GetWeakSourceName(s.scene); string sceneName = GetWeakSourceName(s.scene);
QString text = MakeSwitchName(sceneName.c_str(), QString text =
s.window.c_str()); MakeSwitchName(sceneName.c_str(), s.window.c_str());
QListWidgetItem *item = new QListWidgetItem(text, QListWidgetItem *item = new QListWidgetItem(text, ui->switches);
ui->switches);
item->setData(Qt::UserRole, s.window.c_str()); item->setData(Qt::UserRole, s.window.c_str());
} }
@@ -137,7 +132,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
loading = false; loading = false;
} }
void SceneSwitcher::closeEvent(QCloseEvent*) void SceneSwitcher::closeEvent(QCloseEvent *)
{ {
obs_frontend_save(); obs_frontend_save();
} }
@@ -149,8 +144,7 @@ int SceneSwitcher::FindByData(const QString &window)
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
QListWidgetItem *item = ui->switches->item(i); QListWidgetItem *item = ui->switches->item(i);
QString itemWindow = QString itemWindow = item->data(Qt::UserRole).toString();
item->data(Qt::UserRole).toString();
if (itemWindow == window) { if (itemWindow == window) {
idx = i; idx = i;
@@ -206,16 +200,16 @@ void SceneSwitcher::on_add_clicked()
if (idx == -1) { if (idx == -1) {
try { try {
lock_guard<mutex> lock(switcher->m); lock_guard<mutex> lock(switcher->m);
switcher->switches.emplace_back(source, switcher->switches.emplace_back(
windowName.toUtf8().constData()); source, windowName.toUtf8().constData());
QListWidgetItem *item = new QListWidgetItem(text, QListWidgetItem *item =
ui->switches); new QListWidgetItem(text, ui->switches);
item->setData(Qt::UserRole, v); item->setData(Qt::UserRole, v);
} catch (const regex_error &) { } catch (const regex_error &) {
QMessageBox::warning(this, QMessageBox::warning(
obs_module_text("InvalidRegex.Title"), this, obs_module_text("InvalidRegex.Title"),
obs_module_text("InvalidRegex.Text")); obs_module_text("InvalidRegex.Text"));
} }
} else { } else {
QListWidgetItem *item = ui->switches->item(idx); QListWidgetItem *item = ui->switches->item(idx);
@@ -274,8 +268,7 @@ void SceneSwitcher::on_startAtLaunch_toggled(bool value)
void SceneSwitcher::UpdateNonMatchingScene(const QString &name) void SceneSwitcher::UpdateNonMatchingScene(const QString &name)
{ {
obs_source_t *scene = obs_get_source_by_name( obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene); obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws; switcher->nonMatchingScene = ws;
@@ -303,8 +296,7 @@ void SceneSwitcher::on_noMatchSwitch_clicked()
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText()); UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
} }
void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged( void SceneSwitcher::on_noMatchSwitchScene_currentTextChanged(const QString &text)
const QString &text)
{ {
if (loading) if (loading)
return; return;
@@ -357,13 +349,13 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
for (SceneSwitch &s : switcher->switches) { for (SceneSwitch &s : switcher->switches) {
obs_data_t *array_obj = obs_data_create(); obs_data_t *array_obj = obs_data_create();
obs_source_t *source = obs_weak_source_get_source( obs_source_t *source =
s.scene); obs_weak_source_get_source(s.scene);
if (source) { if (source) {
const char *n = obs_source_get_name(source); const char *n = obs_source_get_name(source);
obs_data_set_string(array_obj, "scene", n); obs_data_set_string(array_obj, "scene", n);
obs_data_set_string(array_obj, "window_title", obs_data_set_string(array_obj, "window_title",
s.window.c_str()); s.window.c_str());
obs_data_array_push_back(array, array_obj); obs_data_array_push_back(array, array_obj);
obs_source_release(source); obs_source_release(source);
} }
@@ -376,9 +368,9 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_int(obj, "interval", switcher->interval); obs_data_set_int(obj, "interval", switcher->interval);
obs_data_set_string(obj, "non_matching_scene", obs_data_set_string(obj, "non_matching_scene",
nonMatchingSceneName.c_str()); nonMatchingSceneName.c_str());
obs_data_set_bool(obj, "switch_if_not_matching", obs_data_set_bool(obj, "switch_if_not_matching",
switcher->switchIfNotMatching); switcher->switchIfNotMatching);
obs_data_set_bool(obj, "active", switcher->th.joinable()); obs_data_set_bool(obj, "active", switcher->th.joinable());
obs_data_set_array(obj, "switches", array); obs_data_set_array(obj, "switches", array);
@@ -389,8 +381,8 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
} else { } else {
switcher->m.lock(); switcher->m.lock();
obs_data_t *obj = obs_data_get_obj(save_data, obs_data_t *obj =
"auto-scene-switcher"); obs_data_get_obj(save_data, "auto-scene-switcher");
obs_data_array_t *array = obs_data_get_array(obj, "switches"); obs_data_array_t *array = obs_data_get_array(obj, "switches");
size_t count = obs_data_array_count(array); size_t count = obs_data_array_count(array);
@@ -420,8 +412,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_get_string(array_obj, "window_title"); obs_data_get_string(array_obj, "window_title");
switcher->switches.emplace_back( switcher->switches.emplace_back(
GetWeakSourceByName(scene), GetWeakSourceByName(scene), window);
window);
obs_data_release(array_obj); obs_data_release(array_obj);
} }
@@ -476,18 +467,18 @@ void SwitcherData::Thread()
for (SceneSwitch &s : switches) { for (SceneSwitch &s : switches) {
try { try {
bool matches = regex_match( bool matches = regex_match(
title, s.re); title, s.re);
if (matches) { if (matches) {
match = true; match = true;
scene = s.scene; scene = s.scene;
break; break;
} }
} catch (const regex_error &) {} } catch (const regex_error &) {
}
} }
} }
if (!match && switchIfNotMatching && if (!match && switchIfNotMatching && nonMatchingScene) {
nonMatchingScene) {
match = true; match = true;
scene = nonMatchingScene; scene = nonMatchingScene;
} }
@@ -513,7 +504,7 @@ void SwitcherData::Thread()
void SwitcherData::Start() void SwitcherData::Start()
{ {
if (!switcher->th.joinable()) if (!switcher->th.joinable())
switcher->th = thread([] () {switcher->Thread();}); switcher->th = thread([]() { switcher->Thread(); });
} }
void SwitcherData::Stop() void SwitcherData::Stop()
@@ -542,17 +533,16 @@ static void OBSEvent(enum obs_frontend_event event, void *)
extern "C" void InitSceneSwitcher() extern "C" void InitSceneSwitcher()
{ {
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("SceneSwitcher")); obs_module_text("SceneSwitcher"));
switcher = new SwitcherData; switcher = new SwitcherData;
auto cb = [] () auto cb = []() {
{
obs_frontend_push_ui_translation(obs_module_get_string); obs_frontend_push_ui_translation(obs_module_get_string);
QMainWindow *window = QMainWindow *window =
(QMainWindow*)obs_frontend_get_main_window(); (QMainWindow *)obs_frontend_get_main_window();
SceneSwitcher ss(window); SceneSwitcher ss(window);
ss.exec(); ss.exec();
@@ -1,33 +1,24 @@
#include "captions-handler.hpp" #include "captions-handler.hpp"
captions_handler::captions_handler( captions_handler::captions_handler(captions_cb callback,
captions_cb callback, enum audio_format format,
enum audio_format format, uint32_t sample_rate)
uint32_t sample_rate)
: cb(callback) : cb(callback)
{ {
if (!reset_resampler(format, sample_rate)) if (!reset_resampler(format, sample_rate))
throw CAPTIONS_ERROR_GENERIC_FAIL; throw CAPTIONS_ERROR_GENERIC_FAIL;
} }
bool captions_handler::reset_resampler( bool captions_handler::reset_resampler(enum audio_format format,
enum audio_format format, uint32_t sample_rate)
uint32_t sample_rate)
try { try {
obs_audio_info ai; obs_audio_info ai;
if (!obs_get_audio_info(&ai)) if (!obs_get_audio_info(&ai))
throw std::string("Failed to get OBS audio info"); throw std::string("Failed to get OBS audio info");
resample_info src = { resample_info src = {ai.samples_per_sec, AUDIO_FORMAT_FLOAT_PLANAR,
ai.samples_per_sec, ai.speakers};
AUDIO_FORMAT_FLOAT_PLANAR, resample_info dst = {sample_rate, format, SPEAKERS_MONO};
ai.speakers
};
resample_info dst = {
sample_rate,
format,
SPEAKERS_MONO
};
if (!resampler.reset(dst, src)) if (!resampler.reset(dst, src))
throw std::string("Failed to create audio resampler"); throw std::string("Failed to create audio resampler");
@@ -46,9 +37,9 @@ void captions_handler::push_audio(const audio_data *audio)
uint64_t ts_offset; uint64_t ts_offset;
bool success; bool success;
success = audio_resampler_resample(resampler, success = audio_resampler_resample(resampler, out, &frames, &ts_offset,
out, &frames, &ts_offset, (const uint8_t *const *)audio->data,
(const uint8_t *const *)audio->data, audio->frames); audio->frames);
if (success) if (success)
pcm_data(out[0], frames); pcm_data(out[0], frames);
} }
@@ -9,10 +9,7 @@ class resampler_obj {
audio_resampler_t *resampler = nullptr; audio_resampler_t *resampler = nullptr;
public: public:
inline ~resampler_obj() inline ~resampler_obj() { audio_resampler_destroy(resampler); }
{
audio_resampler_destroy(resampler);
}
inline bool reset(const resample_info &dst, const resample_info &src) inline bool reset(const resample_info &dst, const resample_info &src)
{ {
@@ -21,15 +18,15 @@ public:
return !!resampler; return !!resampler;
} }
inline operator audio_resampler_t*() {return resampler;} inline operator audio_resampler_t *() { return resampler; }
}; };
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
typedef std::function<void (const std::string &)> captions_cb; typedef std::function<void(const std::string &)> captions_cb;
#define captions_error(s) std::string(obs_module_text("Captions.Error." ## s)) #define captions_error(s) std::string(obs_module_text("Captions.Error."##s))
#define CAPTIONS_ERROR_GENERIC_FAIL captions_error("GenericFail") #define CAPTIONS_ERROR_GENERIC_FAIL captions_error("GenericFail")
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -38,22 +35,17 @@ class captions_handler {
resampler_obj resampler; resampler_obj resampler;
protected: protected:
inline void callback(const std::string &text) inline void callback(const std::string &text) { cb(text); }
{
cb(text);
}
virtual void pcm_data(const void *data, size_t frames)=0; virtual void pcm_data(const void *data, size_t frames) = 0;
/* always resamples to 1 channel */ /* always resamples to 1 channel */
bool reset_resampler(enum audio_format format, uint32_t sample_rate); bool reset_resampler(enum audio_format format, uint32_t sample_rate);
public: public:
/* throw std::string for errors shown to users */ /* throw std::string for errors shown to users */
captions_handler( captions_handler(captions_cb callback, enum audio_format format,
captions_cb callback, uint32_t sample_rate);
enum audio_format format,
uint32_t sample_rate);
virtual ~captions_handler() {} virtual ~captions_handler() {}
void push_audio(const audio_data *audio); void push_audio(const audio_data *audio);
@@ -62,6 +54,6 @@ public:
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
struct captions_handler_info { struct captions_handler_info {
std::string (*name)(void); std::string (*name)(void);
captions_handler *(*create)(captions_cb cb, const std::string &lang); captions_handler *(*create)(captions_cb cb, const std::string &lang);
}; };
@@ -8,16 +8,17 @@
using namespace std; using namespace std;
#if 0 #if 0
#define debugfunc(format, ...) blog(LOG_DEBUG, "[Captions] %s(" format ")", \ #define debugfunc(format, ...) \
__FUNCTION__, ##__VA_ARGS__) blog(LOG_DEBUG, "[Captions] %s(" format ")", __FUNCTION__, \
##__VA_ARGS__)
#else #else
#define debugfunc(format, ...) #define debugfunc(format, ...)
#endif #endif
CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_) : CaptionStream::CaptionStream(DWORD samplerate_, mssapi_captions *handler_)
handler(handler_), : handler(handler_),
samplerate(samplerate_), samplerate(samplerate_),
event(CreateEvent(nullptr, false, false, nullptr)) event(CreateEvent(nullptr, false, false, nullptr))
{ {
buf_info.ulMsMinNotification = 50; buf_info.ulMsMinNotification = 50;
buf_info.ulMsBufferSize = 500; buf_info.ulMsBufferSize = 500;
@@ -66,15 +67,15 @@ STDMETHODIMP CaptionStream::QueryInterface(REFIID riid, void **ppv)
} else if (riid == IID_IStream) { } else if (riid == IID_IStream) {
AddRef(); AddRef();
*ppv = (IStream*)this; *ppv = (IStream *)this;
} else if (riid == IID_ISpStreamFormat) { } else if (riid == IID_ISpStreamFormat) {
AddRef(); AddRef();
*ppv = (ISpStreamFormat*)this; *ppv = (ISpStreamFormat *)this;
} else if (riid == IID_ISpAudio) { } else if (riid == IID_ISpAudio) {
AddRef(); AddRef();
*ppv = (ISpAudio*)this; *ppv = (ISpAudio *)this;
} else { } else {
*ppv = nullptr; *ppv = nullptr;
@@ -134,8 +135,7 @@ STDMETHODIMP CaptionStream::Read(void *data, ULONG bytes, ULONG *read_bytes)
return hr; return hr;
} }
STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes, STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes, ULONG *)
ULONG*)
{ {
debugfunc("data, %lu, written_bytes", bytes); debugfunc("data, %lu, written_bytes", bytes);
UNUSED_PARAMETER(bytes); UNUSED_PARAMETER(bytes);
@@ -146,7 +146,7 @@ STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes,
// IStream methods // IStream methods
STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin, STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin,
ULARGE_INTEGER *new_pos) ULARGE_INTEGER *new_pos)
{ {
debugfunc("%lld, %lx, new_pos", move, origin); debugfunc("%lld, %lx, new_pos", move, origin);
UNUSED_PARAMETER(move); UNUSED_PARAMETER(move);
@@ -170,8 +170,8 @@ STDMETHODIMP CaptionStream::SetSize(ULARGE_INTEGER new_size)
} }
STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes, STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes,
ULARGE_INTEGER *read_bytes, ULARGE_INTEGER *read_bytes,
ULARGE_INTEGER *written_bytes) ULARGE_INTEGER *written_bytes)
{ {
HRESULT hr; HRESULT hr;
@@ -213,7 +213,7 @@ STDMETHODIMP CaptionStream::Revert(void)
} }
STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset, STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
ULARGE_INTEGER size, DWORD type) ULARGE_INTEGER size, DWORD type)
{ {
debugfunc("%llu, %llu, %ld", offset, size, type); debugfunc("%llu, %llu, %ld", offset, size, type);
UNUSED_PARAMETER(offset); UNUSED_PARAMETER(offset);
@@ -224,7 +224,7 @@ STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
} }
STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset, STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset,
ULARGE_INTEGER size, DWORD type) ULARGE_INTEGER size, DWORD type)
{ {
debugfunc("%llu, %llu, %ld", offset, size, type); debugfunc("%llu, %llu, %ld", offset, size, type);
UNUSED_PARAMETER(offset); UNUSED_PARAMETER(offset);
@@ -250,7 +250,7 @@ STDMETHODIMP CaptionStream::Stat(STATSTG *stg, DWORD flag)
if (flag == STATFLAG_DEFAULT) { if (flag == STATFLAG_DEFAULT) {
size_t byte_size = (wcslen(stat_name) + 1) * sizeof(wchar_t); size_t byte_size = (wcslen(stat_name) + 1) * sizeof(wchar_t);
stg->pwcsName = (wchar_t*)CoTaskMemAlloc(byte_size); stg->pwcsName = (wchar_t *)CoTaskMemAlloc(byte_size);
memcpy(stg->pwcsName, stat_name, byte_size); memcpy(stg->pwcsName, stat_name, byte_size);
} }
@@ -267,7 +267,7 @@ STDMETHODIMP CaptionStream::Clone(IStream **stream)
// ISpStreamFormat methods // ISpStreamFormat methods
STDMETHODIMP CaptionStream::GetFormat(GUID *guid, STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
WAVEFORMATEX **co_mem_wfex_out) WAVEFORMATEX **co_mem_wfex_out)
{ {
debugfunc("guid, co_mem_wfex_out"); debugfunc("guid, co_mem_wfex_out");
@@ -282,7 +282,7 @@ STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
void *wfex = CoTaskMemAlloc(sizeof(format)); void *wfex = CoTaskMemAlloc(sizeof(format));
memcpy(wfex, &format, sizeof(format)); memcpy(wfex, &format, sizeof(format));
*co_mem_wfex_out = (WAVEFORMATEX*)wfex; *co_mem_wfex_out = (WAVEFORMATEX *)wfex;
return S_OK; return S_OK;
} }
@@ -296,7 +296,7 @@ STDMETHODIMP CaptionStream::SetState(SPAUDIOSTATE state_, ULONGLONG)
} }
STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref, STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
const WAVEFORMATEX *wfex) const WAVEFORMATEX *wfex)
{ {
debugfunc("guid, wfex"); debugfunc("guid, wfex");
if (!wfex) if (!wfex)
@@ -306,7 +306,7 @@ STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
lock_guard<mutex> lock(m); lock_guard<mutex> lock(m);
memcpy(&format, wfex, sizeof(format)); memcpy(&format, wfex, sizeof(format));
if (!handler->reset_resampler(AUDIO_FORMAT_16BIT, if (!handler->reset_resampler(AUDIO_FORMAT_16BIT,
wfex->nSamplesPerSec)) wfex->nSamplesPerSec))
return E_FAIL; return E_FAIL;
/* 50 msec */ /* 50 msec */
@@ -354,7 +354,7 @@ STDMETHODIMP CaptionStream::GetBufferInfo(SPAUDIOBUFFERINFO *buf_info_)
} }
STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format, STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
WAVEFORMATEX **co_mem_wfex_out) WAVEFORMATEX **co_mem_wfex_out)
{ {
debugfunc("format, co_mem_wfex_out"); debugfunc("format, co_mem_wfex_out");
@@ -365,7 +365,7 @@ STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
memcpy(wfex, &format, sizeof(format)); memcpy(wfex, &format, sizeof(format));
*format = SPDFID_WaveFormatEx; *format = SPDFID_WaveFormatEx;
*co_mem_wfex_out = (WAVEFORMATEX*)wfex; *co_mem_wfex_out = (WAVEFORMATEX *)wfex;
return S_OK; return S_OK;
} }
@@ -13,10 +13,11 @@
class CircleBuf { class CircleBuf {
circlebuf buf = {}; circlebuf buf = {};
public: public:
inline ~CircleBuf() {circlebuf_free(&buf);} inline ~CircleBuf() { circlebuf_free(&buf); }
inline operator circlebuf*() {return &buf;} inline operator circlebuf *() { return &buf; }
inline circlebuf *operator->() {return &buf;} inline circlebuf *operator->() { return &buf; }
}; };
class mssapi_captions; class mssapi_captions;
@@ -54,38 +55,38 @@ public:
// ISequentialStream methods // ISequentialStream methods
STDMETHODIMP Read(void *data, ULONG bytes, ULONG *read_bytes) override; STDMETHODIMP Read(void *data, ULONG bytes, ULONG *read_bytes) override;
STDMETHODIMP Write(const void *data, ULONG bytes, ULONG *written_bytes) STDMETHODIMP Write(const void *data, ULONG bytes,
override; ULONG *written_bytes) override;
// IStream methods // IStream methods
STDMETHODIMP Seek(LARGE_INTEGER move, DWORD origin, STDMETHODIMP Seek(LARGE_INTEGER move, DWORD origin,
ULARGE_INTEGER *new_pos) override; ULARGE_INTEGER *new_pos) override;
STDMETHODIMP SetSize(ULARGE_INTEGER new_size) override; STDMETHODIMP SetSize(ULARGE_INTEGER new_size) override;
STDMETHODIMP CopyTo(IStream *stream, ULARGE_INTEGER bytes, STDMETHODIMP CopyTo(IStream *stream, ULARGE_INTEGER bytes,
ULARGE_INTEGER *read_bytes, ULARGE_INTEGER *read_bytes,
ULARGE_INTEGER *written_bytes) override; ULARGE_INTEGER *written_bytes) override;
STDMETHODIMP Commit(DWORD commit_flags) override; STDMETHODIMP Commit(DWORD commit_flags) override;
STDMETHODIMP Revert(void) override; STDMETHODIMP Revert(void) override;
STDMETHODIMP LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size, STDMETHODIMP LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
DWORD type) override; DWORD type) override;
STDMETHODIMP UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size, STDMETHODIMP UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
DWORD type) override; DWORD type) override;
STDMETHODIMP Stat(STATSTG *stg, DWORD flags) override; STDMETHODIMP Stat(STATSTG *stg, DWORD flags) override;
STDMETHODIMP Clone(IStream **stream) override; STDMETHODIMP Clone(IStream **stream) override;
// ISpStreamFormat methods // ISpStreamFormat methods
STDMETHODIMP GetFormat(GUID *guid, WAVEFORMATEX **co_mem_wfex_out) STDMETHODIMP GetFormat(GUID *guid,
override; WAVEFORMATEX **co_mem_wfex_out) override;
// ISpAudio methods // ISpAudio methods
STDMETHODIMP SetState(SPAUDIOSTATE state, ULONGLONG reserved) override; STDMETHODIMP SetState(SPAUDIOSTATE state, ULONGLONG reserved) override;
STDMETHODIMP SetFormat(REFGUID guid_ref, const WAVEFORMATEX *wfex) STDMETHODIMP SetFormat(REFGUID guid_ref,
override; const WAVEFORMATEX *wfex) override;
STDMETHODIMP GetStatus(SPAUDIOSTATUS *status) override; STDMETHODIMP GetStatus(SPAUDIOSTATUS *status) override;
STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info) override; STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info) override;
STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO *buf_info) override; STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO *buf_info) override;
STDMETHODIMP GetDefaultFormat(GUID *format, STDMETHODIMP GetDefaultFormat(GUID *format,
WAVEFORMATEX **co_mem_wfex_out) override; WAVEFORMATEX **co_mem_wfex_out) override;
STDMETHODIMP_(HANDLE) EventHandle(void) override; STDMETHODIMP_(HANDLE) EventHandle(void) override;
STDMETHODIMP GetVolumeLevel(ULONG *level) override; STDMETHODIMP GetVolumeLevel(ULONG *level) override;
STDMETHODIMP SetVolumeLevel(ULONG level) override; STDMETHODIMP SetVolumeLevel(ULONG level) override;
@@ -1,16 +1,13 @@
#include "captions-mssapi.hpp" #include "captions-mssapi.hpp"
#define do_log(type, format, ...) blog(type, "[Captions] " format, \ #define do_log(type, format, ...) \
##__VA_ARGS__) blog(type, "[Captions] " format, ##__VA_ARGS__)
#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__) #define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
mssapi_captions::mssapi_captions( mssapi_captions::mssapi_captions(captions_cb callback, const std::string &lang)
captions_cb callback, try : captions_handler(callback, AUDIO_FORMAT_16BIT, 16000) {
const std::string &lang) try
: captions_handler(callback, AUDIO_FORMAT_16BIT, 16000)
{
HRESULT hr; HRESULT hr;
std::wstring wlang; std::wstring wlang;
@@ -33,7 +30,7 @@ mssapi_captions::mssapi_captions(
throw HRError("SpFindBestToken failed", hr); throw HRError("SpFindBestToken failed", hr);
hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_ALL, hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_ALL,
__uuidof(ISpRecognizer), (void**)&recognizer); __uuidof(ISpRecognizer), (void **)&recognizer);
if (FAILED(hr)) if (FAILED(hr))
throw HRError("CoCreateInstance for recognizer failed", hr); throw HRError("CoCreateInstance for recognizer failed", hr);
@@ -50,7 +47,7 @@ mssapi_captions::mssapi_captions(
throw HRError("CreateRecoContext failed", hr); throw HRError("CreateRecoContext failed", hr);
ULONGLONG interest = SPFEI(SPEI_RECOGNITION) | ULONGLONG interest = SPFEI(SPEI_RECOGNITION) |
SPFEI(SPEI_END_SR_STREAM); SPFEI(SPEI_END_SR_STREAM);
hr = context->SetInterest(interest, interest); hr = context->SetInterest(interest, interest);
if (FAILED(hr)) if (FAILED(hr))
throw HRError("SetInterest failed", hr); throw HRError("SetInterest failed", hr);
@@ -80,7 +77,7 @@ mssapi_captions::mssapi_captions(
throw HRError("LoadDictation failed", hr); throw HRError("LoadDictation failed", hr);
try { try {
t = std::thread([this] () {main_thread();}); t = std::thread([this]() { main_thread(); });
} catch (...) { } catch (...) {
throw "Failed to create thread"; throw "Failed to create thread";
} }
@@ -133,8 +130,8 @@ try {
ISpRecoResult *result = event.RecoResult(); ISpRecoResult *result = event.RecoResult();
CoTaskMemPtr<wchar_t> text; CoTaskMemPtr<wchar_t> text;
hr = result->GetText((ULONG)-1, (ULONG)-1, hr = result->GetText((ULONG)-1, (ULONG)-1, true,
true, &text, nullptr); &text, nullptr);
if (FAILED(hr)) if (FAILED(hr))
continue; continue;
@@ -168,12 +165,7 @@ void mssapi_captions::pcm_data(const void *data, size_t frames)
} }
captions_handler_info mssapi_info = { captions_handler_info mssapi_info = {
[] () -> std::string []() -> std::string { return "Microsoft Speech-to-Text"; },
{ [](captions_cb cb, const std::string &lang) -> captions_handler * {
return "Microsoft Speech-to-Text";
},
[] (captions_cb cb, const std::string &lang) -> captions_handler *
{
return new mssapi_captions(cb, lang); return new mssapi_captions(cb, lang);
} }};
};
@@ -27,16 +27,16 @@
class mssapi_captions : public captions_handler { class mssapi_captions : public captions_handler {
friend class CaptionStream; friend class CaptionStream;
ComPtr<CaptionStream> audio; ComPtr<CaptionStream> audio;
ComPtr<ISpObjectToken> token; ComPtr<ISpObjectToken> token;
ComPtr<ISpRecoGrammar> grammar; ComPtr<ISpRecoGrammar> grammar;
ComPtr<ISpRecognizer> recognizer; ComPtr<ISpRecognizer> recognizer;
ComPtr<ISpRecoContext> context; ComPtr<ISpRecoContext> context;
HANDLE notify; HANDLE notify;
WinHandle stop; WinHandle stop;
std::thread t; std::thread t;
bool started = false; bool started = false;
void main_thread(); void main_thread();
+46 -73
View File
@@ -31,8 +31,8 @@
#include "captions-mssapi.hpp" #include "captions-mssapi.hpp"
#define do_log(type, format, ...) blog(type, "[Captions] " format, \ #define do_log(type, format, ...) \
##__VA_ARGS__) blog(type, "[Captions] " format, ##__VA_ARGS__)
#define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__) #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
@@ -48,10 +48,10 @@ struct obs_captions {
unique_ptr<captions_handler> handler; unique_ptr<captions_handler> handler;
LANGID lang_id = GetUserDefaultUILanguage(); LANGID lang_id = GetUserDefaultUILanguage();
std::unordered_map<std::string, captions_handler_info&> handler_types; std::unordered_map<std::string, captions_handler_info &> handler_types;
inline void register_handler(const char *id, inline void register_handler(const char *id,
captions_handler_info &info) captions_handler_info &info)
{ {
handler_types.emplace(id, info); handler_types.emplace(id, info);
} }
@@ -60,7 +60,7 @@ struct obs_captions {
void stop(); void stop();
obs_captions(); obs_captions();
inline ~obs_captions() {stop();} inline ~obs_captions() { stop(); }
}; };
static obs_captions *captions = nullptr; static obs_captions *captions = nullptr;
@@ -74,9 +74,9 @@ struct locale_info {
inline locale_info() {} inline locale_info() {}
inline locale_info(const locale_info &) = delete; inline locale_info(const locale_info &) = delete;
inline locale_info(locale_info &&li) inline locale_info(locale_info &&li)
: name(std::move(li.name)), : name(std::move(li.name)), id(li.id)
id(li.id) {
{} }
}; };
static void get_valid_locale_names(vector<locale_info> &names); static void get_valid_locale_names(vector<locale_info> &names);
@@ -84,16 +84,14 @@ static bool valid_lang(LANGID id);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
CaptionsDialog::CaptionsDialog(QWidget *parent) : CaptionsDialog::CaptionsDialog(QWidget *parent)
QDialog(parent), : QDialog(parent), ui(new Ui_CaptionsDialog)
ui(new Ui_CaptionsDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
auto cb = [this] (obs_source_t *source) auto cb = [this](obs_source_t *source) {
{
uint32_t caps = obs_source_get_output_flags(source); uint32_t caps = obs_source_get_output_flags(source);
QString name = obs_source_get_name(source); QString name = obs_source_get_name(source);
@@ -111,8 +109,11 @@ CaptionsDialog::CaptionsDialog(QWidget *parent) :
ui->source->blockSignals(true); ui->source->blockSignals(true);
ui->source->addItem(QStringLiteral("")); ui->source->addItem(QStringLiteral(""));
ui->source->setCurrentIndex(0); ui->source->setCurrentIndex(0);
obs_enum_sources([] (void *data, obs_source_t *source) { obs_enum_sources(
return (*static_cast<cb_t*>(data))(source);}, &cb); [](void *data, obs_source_t *source) {
return (*static_cast<cb_t *>(data))(source);
},
&cb);
ui->source->blockSignals(false); ui->source->blockSignals(false);
for (auto &ht : captions->handler_types) { for (auto &ht : captions->handler_types) {
@@ -232,8 +233,8 @@ static void caption_text(const std::string &text)
} }
} }
static void audio_capture(void*, obs_source_t*, static void audio_capture(void *, obs_source_t *,
const struct audio_data *audio, bool) const struct audio_data *audio, bool)
{ {
captions->handler->push_audio(audio); captions->handler->push_audio(audio);
} }
@@ -245,14 +246,13 @@ void obs_captions::start()
auto pair = handler_types.find(handler_id); auto pair = handler_types.find(handler_id);
if (pair == handler_types.end()) { if (pair == handler_types.end()) {
warn("Failed to find handler '%s'", warn("Failed to find handler '%s'", handler_id.c_str());
handler_id.c_str());
return; return;
} }
if (!LCIDToLocaleName(lang_id, wname, 256, 0)) { if (!LCIDToLocaleName(lang_id, wname, 256, 0)) {
warn("Failed to get locale name: %d", warn("Failed to get locale name: %d",
(int)GetLastError()); (int)GetLastError());
return; return;
} }
@@ -271,24 +271,24 @@ void obs_captions::start()
} }
try { try {
captions_handler *h = pair->second.create(caption_text, captions_handler *h =
lang_name); pair->second.create(caption_text, lang_name);
handler.reset(h); handler.reset(h);
OBSSource s = OBSGetStrongRef(source); OBSSource s = OBSGetStrongRef(source);
obs_source_add_audio_capture_callback(s, obs_source_add_audio_capture_callback(s, audio_capture,
audio_capture, nullptr); nullptr);
} catch (std::string text) { } catch (std::string text) {
QWidget *window = QWidget *window =
(QWidget*)obs_frontend_get_main_window(); (QWidget *)obs_frontend_get_main_window();
warn("Failed to create handler: %s", text.c_str()); warn("Failed to create handler: %s", text.c_str());
QMessageBox::warning(window, QMessageBox::warning(
window,
obs_module_text("Captions.Error.GenericFail"), obs_module_text("Captions.Error.GenericFail"),
text.c_str()); text.c_str());
} }
} }
} }
@@ -297,8 +297,8 @@ void obs_captions::stop()
{ {
OBSSource s = OBSGetStrongRef(source); OBSSource s = OBSGetStrongRef(source);
if (s) if (s)
obs_source_remove_audio_capture_callback(s, obs_source_remove_audio_capture_callback(s, audio_capture,
audio_capture, nullptr); nullptr);
handler.reset(); handler.reset();
} }
@@ -332,42 +332,18 @@ static void get_valid_locale_names(vector<locale_info> &locales)
char locale_name[256]; char locale_name[256];
static const LANGID default_locales[] = { static const LANGID default_locales[] = {
0x0409, 0x0409, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406,
0x0401, 0x0407, 0x0408, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e,
0x0402, 0x040f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415,
0x0403, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0};
0x0404,
0x0405,
0x0406,
0x0407,
0x0408,
0x040a,
0x040b,
0x040c,
0x040d,
0x040e,
0x040f,
0x0410,
0x0411,
0x0412,
0x0413,
0x0414,
0x0415,
0x0416,
0x0417,
0x0418,
0x0419,
0x041a,
0
};
/* ---------------------------------- */ /* ---------------------------------- */
LANGID def_id = GetUserDefaultUILanguage(); LANGID def_id = GetUserDefaultUILanguage();
LANGID id = def_id; LANGID id = def_id;
if (valid_lang(id) && get_locale_name(id, locale_name)) { if (valid_lang(id) && get_locale_name(id, locale_name)) {
dstr_copy(cur.name, obs_module_text( dstr_copy(cur.name,
"Captions.CurrentSystemLanguage")); obs_module_text("Captions.CurrentSystemLanguage"));
dstr_replace(cur.name, "%1", locale_name); dstr_replace(cur.name, "%1", locale_name);
cur.id = id; cur.id = id;
@@ -381,8 +357,7 @@ static void get_valid_locale_names(vector<locale_info> &locales)
while (*locale) { while (*locale) {
id = *locale; id = *locale;
if (id != def_id && if (id != def_id && valid_lang(id) &&
valid_lang(id) &&
get_locale_name(id, locale_name)) { get_locale_name(id, locale_name)) {
dstr_copy(cur.name, locale_name); dstr_copy(cur.name, locale_name);
@@ -418,17 +393,17 @@ static void obs_event(enum obs_frontend_event event, void *)
FreeCaptions(); FreeCaptions();
} }
static void save_caption_data(obs_data_t *save_data, bool saving, void*) static void save_caption_data(obs_data_t *save_data, bool saving, void *)
{ {
if (saving) { if (saving) {
obs_data_t *obj = obs_data_create(); obs_data_t *obj = obs_data_create();
obs_data_set_string(obj, "source", obs_data_set_string(obj, "source",
captions->source_name.c_str()); captions->source_name.c_str());
obs_data_set_bool(obj, "enabled", !!captions->handler); obs_data_set_bool(obj, "enabled", !!captions->handler);
obs_data_set_int(obj, "lang_id", captions->lang_id); obs_data_set_int(obj, "lang_id", captions->lang_id);
obs_data_set_string(obj, "provider", obs_data_set_string(obj, "provider",
captions->handler_id.c_str()); captions->handler_id.c_str());
obs_data_set_obj(save_data, "captions", obj); obs_data_set_obj(save_data, "captions", obj);
obs_data_release(obj); obs_data_release(obj);
@@ -440,15 +415,15 @@ static void save_caption_data(obs_data_t *save_data, bool saving, void*)
obj = obs_data_create(); obj = obs_data_create();
obs_data_set_default_int(obj, "lang_id", obs_data_set_default_int(obj, "lang_id",
GetUserDefaultUILanguage()); GetUserDefaultUILanguage());
obs_data_set_default_string(obj, "provider", DEFAULT_HANDLER); obs_data_set_default_string(obj, "provider", DEFAULT_HANDLER);
bool enabled = obs_data_get_bool(obj, "enabled"); bool enabled = obs_data_get_bool(obj, "enabled");
captions->source_name = obs_data_get_string(obj, "source"); captions->source_name = obs_data_get_string(obj, "source");
captions->lang_id = (int)obs_data_get_int(obj, "lang_id"); captions->lang_id = (int)obs_data_get_int(obj, "lang_id");
captions->handler_id = obs_data_get_string(obj, "provider"); captions->handler_id = obs_data_get_string(obj, "provider");
captions->source = GetWeakSourceByName( captions->source =
captions->source_name.c_str()); GetWeakSourceByName(captions->source_name.c_str());
obs_data_release(obj); obs_data_release(obj);
if (enabled) if (enabled)
@@ -458,17 +433,15 @@ static void save_caption_data(obs_data_t *save_data, bool saving, void*)
extern "C" void InitCaptions() extern "C" void InitCaptions()
{ {
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("Captions")); obs_module_text("Captions"));
captions = new obs_captions; captions = new obs_captions;
auto cb = [] () auto cb = []() {
{
obs_frontend_push_ui_translation(obs_module_get_string); obs_frontend_push_ui_translation(obs_module_get_string);
QWidget *window = QWidget *window = (QWidget *)obs_frontend_get_main_window();
(QWidget*)obs_frontend_get_main_window();
CaptionsDialog dialog(window); CaptionsDialog dialog(window);
dialog.exec(); dialog.exec();
@@ -13,19 +13,18 @@ using namespace std;
OutputTimer *ot; OutputTimer *ot;
OutputTimer::OutputTimer(QWidget *parent) OutputTimer::OutputTimer(QWidget *parent)
: QDialog(parent), : QDialog(parent), ui(new Ui_OutputTimer)
ui(new Ui_OutputTimer)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QObject::connect(ui->outputTimerStream, SIGNAL(clicked()), this, QObject::connect(ui->outputTimerStream, SIGNAL(clicked()), this,
SLOT(StreamingTimerButton())); SLOT(StreamingTimerButton()));
QObject::connect(ui->outputTimerRecord, SIGNAL(clicked()), this, QObject::connect(ui->outputTimerRecord, SIGNAL(clicked()), this,
SLOT(RecordingTimerButton())); SLOT(RecordingTimerButton()));
QObject::connect(ui->buttonBox->button(QDialogButtonBox::Close), QObject::connect(ui->buttonBox->button(QDialogButtonBox::Close),
SIGNAL(clicked()), this, SLOT(hide())); SIGNAL(clicked()), this, SLOT(hide()));
streamingTimer = new QTimer(this); streamingTimer = new QTimer(this);
streamingTimerDisplay = new QTimer(this); streamingTimerDisplay = new QTimer(this);
@@ -34,7 +33,7 @@ OutputTimer::OutputTimer(QWidget *parent)
recordingTimerDisplay = new QTimer(this); recordingTimerDisplay = new QTimer(this);
} }
void OutputTimer::closeEvent(QCloseEvent*) void OutputTimer::closeEvent(QCloseEvent *)
{ {
obs_frontend_save(); obs_frontend_save();
} }
@@ -78,9 +77,7 @@ void OutputTimer::StreamTimerStart()
int minutes = ui->streamingTimerMinutes->value(); int minutes = ui->streamingTimerMinutes->value();
int seconds = ui->streamingTimerSeconds->value(); int seconds = ui->streamingTimerSeconds->value();
int total = (((hours * 3600) + int total = (((hours * 3600) + (minutes * 60)) + seconds) * 1000;
(minutes * 60)) +
seconds) * 1000;
if (total == 0) if (total == 0)
total = 1000; total = 1000;
@@ -89,10 +86,10 @@ void OutputTimer::StreamTimerStart()
streamingTimer->setSingleShot(true); streamingTimer->setSingleShot(true);
QObject::connect(streamingTimer, SIGNAL(timeout()), QObject::connect(streamingTimer, SIGNAL(timeout()),
SLOT(EventStopStreaming())); SLOT(EventStopStreaming()));
QObject::connect(streamingTimerDisplay, SIGNAL(timeout()), this, QObject::connect(streamingTimerDisplay, SIGNAL(timeout()), this,
SLOT(UpdateStreamTimerDisplay())); SLOT(UpdateStreamTimerDisplay()));
streamingTimer->start(); streamingTimer->start();
streamingTimerDisplay->start(1000); streamingTimerDisplay->start(1000);
@@ -112,9 +109,7 @@ void OutputTimer::RecordTimerStart()
int minutes = ui->recordingTimerMinutes->value(); int minutes = ui->recordingTimerMinutes->value();
int seconds = ui->recordingTimerSeconds->value(); int seconds = ui->recordingTimerSeconds->value();
int total = (((hours * 3600) + int total = (((hours * 3600) + (minutes * 60)) + seconds) * 1000;
(minutes * 60)) +
seconds) * 1000;
if (total == 0) if (total == 0)
total = 1000; total = 1000;
@@ -123,10 +118,10 @@ void OutputTimer::RecordTimerStart()
recordingTimer->setSingleShot(true); recordingTimer->setSingleShot(true);
QObject::connect(recordingTimer, SIGNAL(timeout()), QObject::connect(recordingTimer, SIGNAL(timeout()),
SLOT(EventStopRecording())); SLOT(EventStopRecording()));
QObject::connect(recordingTimerDisplay, SIGNAL(timeout()), this, QObject::connect(recordingTimerDisplay, SIGNAL(timeout()), this,
SLOT(UpdateRecordTimerDisplay())); SLOT(UpdateRecordTimerDisplay()));
recordingTimer->start(); recordingTimer->start();
recordingTimerDisplay->start(1000); recordingTimerDisplay->start(1000);
@@ -226,60 +221,57 @@ static void SaveOutputTimer(obs_data_t *save_data, bool saving, void *)
obs_data_t *obj = obs_data_create(); obs_data_t *obj = obs_data_create();
obs_data_set_int(obj, "streamTimerHours", obs_data_set_int(obj, "streamTimerHours",
ot->ui->streamingTimerHours->value()); ot->ui->streamingTimerHours->value());
obs_data_set_int(obj, "streamTimerMinutes", obs_data_set_int(obj, "streamTimerMinutes",
ot->ui->streamingTimerMinutes->value()); ot->ui->streamingTimerMinutes->value());
obs_data_set_int(obj, "streamTimerSeconds", obs_data_set_int(obj, "streamTimerSeconds",
ot->ui->streamingTimerSeconds->value()); ot->ui->streamingTimerSeconds->value());
obs_data_set_int(obj, "recordTimerHours", obs_data_set_int(obj, "recordTimerHours",
ot->ui->recordingTimerHours->value()); ot->ui->recordingTimerHours->value());
obs_data_set_int(obj, "recordTimerMinutes", obs_data_set_int(obj, "recordTimerMinutes",
ot->ui->recordingTimerMinutes->value()); ot->ui->recordingTimerMinutes->value());
obs_data_set_int(obj, "recordTimerSeconds", obs_data_set_int(obj, "recordTimerSeconds",
ot->ui->recordingTimerSeconds->value()); ot->ui->recordingTimerSeconds->value());
obs_data_set_bool(obj, "autoStartStreamTimer", obs_data_set_bool(obj, "autoStartStreamTimer",
ot->ui->autoStartStreamTimer->isChecked()); ot->ui->autoStartStreamTimer->isChecked());
obs_data_set_bool(obj, "autoStartRecordTimer", obs_data_set_bool(obj, "autoStartRecordTimer",
ot->ui->autoStartRecordTimer->isChecked()); ot->ui->autoStartRecordTimer->isChecked());
obs_data_set_obj(save_data, "output-timer", obj); obs_data_set_obj(save_data, "output-timer", obj);
obs_data_release(obj); obs_data_release(obj);
} else { } else {
obs_data_t *obj = obs_data_get_obj(save_data, obs_data_t *obj = obs_data_get_obj(save_data, "output-timer");
"output-timer");
if (!obj) if (!obj)
obj = obs_data_create(); obj = obs_data_create();
ot->ui->streamingTimerHours->setValue( ot->ui->streamingTimerHours->setValue(
obs_data_get_int(obj, "streamTimerHours")); obs_data_get_int(obj, "streamTimerHours"));
ot->ui->streamingTimerMinutes->setValue( ot->ui->streamingTimerMinutes->setValue(
obs_data_get_int(obj, "streamTimerMinutes")); obs_data_get_int(obj, "streamTimerMinutes"));
ot->ui->streamingTimerSeconds->setValue( ot->ui->streamingTimerSeconds->setValue(
obs_data_get_int(obj, "streamTimerSeconds")); obs_data_get_int(obj, "streamTimerSeconds"));
ot->ui->recordingTimerHours->setValue( ot->ui->recordingTimerHours->setValue(
obs_data_get_int(obj, "recordTimerHours")); obs_data_get_int(obj, "recordTimerHours"));
ot->ui->recordingTimerMinutes->setValue( ot->ui->recordingTimerMinutes->setValue(
obs_data_get_int(obj, "recordTimerMinutes")); obs_data_get_int(obj, "recordTimerMinutes"));
ot->ui->recordingTimerSeconds->setValue( ot->ui->recordingTimerSeconds->setValue(
obs_data_get_int(obj, "recordTimerSeconds")); obs_data_get_int(obj, "recordTimerSeconds"));
ot->ui->autoStartStreamTimer->setChecked( ot->ui->autoStartStreamTimer->setChecked(
obs_data_get_bool(obj, "autoStartStreamTimer")); obs_data_get_bool(obj, "autoStartStreamTimer"));
ot->ui->autoStartRecordTimer->setChecked( ot->ui->autoStartRecordTimer->setChecked(
obs_data_get_bool(obj, "autoStartRecordTimer")); obs_data_get_bool(obj, "autoStartRecordTimer"));
obs_data_release(obj); obs_data_release(obj);
} }
} }
extern "C" void FreeOutputTimer() extern "C" void FreeOutputTimer() {}
{
}
static void OBSEvent(enum obs_frontend_event event, void *) static void OBSEvent(enum obs_frontend_event event, void *)
{ {
@@ -299,19 +291,16 @@ static void OBSEvent(enum obs_frontend_event event, void *)
extern "C" void InitOutputTimer() extern "C" void InitOutputTimer()
{ {
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("OutputTimer")); obs_module_text("OutputTimer"));
obs_frontend_push_ui_translation(obs_module_get_string); obs_frontend_push_ui_translation(obs_module_get_string);
QMainWindow *window = (QMainWindow*)obs_frontend_get_main_window(); QMainWindow *window = (QMainWindow *)obs_frontend_get_main_window();
ot = new OutputTimer(window); ot = new OutputTimer(window);
auto cb = [] () auto cb = []() { ot->ShowHideDialog(); };
{
ot->ShowHideDialog();
};
obs_frontend_pop_ui_translation(); obs_frontend_pop_ui_translation();
+43 -47
View File
@@ -43,7 +43,7 @@
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
using OBSScript = OBSObj<obs_script_t*, obs_script_destroy>; using OBSScript = OBSObj<obs_script_t *, obs_script_destroy>;
struct ScriptData { struct ScriptData {
std::vector<OBSScript> scripts; std::vector<OBSScript> scripts;
@@ -92,11 +92,10 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
QHBoxLayout *buttonLayout = new QHBoxLayout(); QHBoxLayout *buttonLayout = new QHBoxLayout();
QPushButton *clearButton = new QPushButton(tr("Clear")); QPushButton *clearButton = new QPushButton(tr("Clear"));
connect(clearButton, &QPushButton::clicked, connect(clearButton, &QPushButton::clicked, this,
this, &ScriptLogWindow::ClearWindow); &ScriptLogWindow::ClearWindow);
QPushButton *closeButton = new QPushButton(tr("Close")); QPushButton *closeButton = new QPushButton(tr("Close"));
connect(closeButton, &QPushButton::clicked, connect(closeButton, &QPushButton::clicked, this, &QDialog::hide);
this, &QDialog::hide);
buttonLayout->addStretch(); buttonLayout->addStretch();
buttonLayout->addWidget(clearButton); buttonLayout->addWidget(clearButton);
@@ -112,8 +111,8 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
resize(600, 400); resize(600, 400);
config_t *global_config = obs_frontend_get_global_config(); config_t *global_config = obs_frontend_get_global_config();
const char *geom = config_get_string(global_config, const char *geom =
"ScriptLogWindow", "geometry"); config_get_string(global_config, "ScriptLogWindow", "geometry");
if (geom != nullptr) { if (geom != nullptr) {
QByteArray ba = QByteArray::fromBase64(QByteArray(geom)); QByteArray ba = QByteArray::fromBase64(QByteArray(geom));
restoreGeometry(ba); restoreGeometry(ba);
@@ -121,16 +120,15 @@ ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
setWindowTitle(obs_module_text("ScriptLogWindow")); setWindowTitle(obs_module_text("ScriptLogWindow"));
connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved, connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved, this,
this, &ScriptLogWindow::ScrollChanged); &ScriptLogWindow::ScrollChanged);
} }
ScriptLogWindow::~ScriptLogWindow() ScriptLogWindow::~ScriptLogWindow()
{ {
config_t *global_config = obs_frontend_get_global_config(); config_t *global_config = obs_frontend_get_global_config();
config_set_string(global_config, config_set_string(global_config, "ScriptLogWindow", "geometry",
"ScriptLogWindow", "geometry", saveGeometry().toBase64().constData());
saveGeometry().toBase64().constData());
} }
void ScriptLogWindow::ScrollChanged(int val) void ScriptLogWindow::ScrollChanged(int val)
@@ -180,17 +178,15 @@ void ScriptLogWindow::Clear()
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
ScriptsTool::ScriptsTool() ScriptsTool::ScriptsTool() : QWidget(nullptr), ui(new Ui_ScriptsTool)
: QWidget (nullptr),
ui (new Ui_ScriptsTool)
{ {
ui->setupUi(this); ui->setupUi(this);
RefreshLists(); RefreshLists();
#if PYTHON_UI #if PYTHON_UI
config_t *config = obs_frontend_get_global_config(); config_t *config = obs_frontend_get_global_config();
const char *path = config_get_string(config, "Python", const char *path =
"Path" ARCH_NAME); config_get_string(config, "Python", "Path" ARCH_NAME);
ui->pythonPath->setText(path); ui->pythonPath->setText(path);
ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT)); ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT));
#else #else
@@ -201,7 +197,7 @@ ScriptsTool::ScriptsTool()
delete propertiesView; delete propertiesView;
propertiesView = new QWidget(); propertiesView = new QWidget();
propertiesView->setSizePolicy(QSizePolicy::Expanding, propertiesView->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding); QSizePolicy::Expanding);
ui->propertiesLayout->addWidget(propertiesView); ui->propertiesLayout->addWidget(propertiesView);
} }
@@ -217,8 +213,8 @@ void ScriptsTool::RemoveScript(const char *path)
const char *script_path = obs_script_get_path(script); const char *script_path = obs_script_get_path(script);
if (strcmp(script_path, path) == 0) { if (strcmp(script_path, path) == 0) {
scriptData->scripts.erase( scriptData->scripts.erase(scriptData->scripts.begin() +
scriptData->scripts.begin() + i); i);
break; break;
} }
} }
@@ -323,7 +319,8 @@ void ScriptsTool::on_addScripts_clicked()
scriptData->scripts.emplace_back(script); scriptData->scripts.emplace_back(script);
QListWidgetItem *item = new QListWidgetItem(script_file); QListWidgetItem *item =
new QListWidgetItem(script_file);
item->setData(Qt::UserRole, QString(file)); item->setData(Qt::UserRole, QString(file));
ui->scripts->addItem(item); ui->scripts->addItem(item);
@@ -343,8 +340,10 @@ void ScriptsTool::on_removeScripts_clicked()
QList<QListWidgetItem *> items = ui->scripts->selectedItems(); QList<QListWidgetItem *> items = ui->scripts->selectedItems();
for (QListWidgetItem *item : items) for (QListWidgetItem *item : items)
RemoveScript(item->data(Qt::UserRole).toString() RemoveScript(item->data(Qt::UserRole)
.toUtf8().constData()); .toString()
.toUtf8()
.constData());
RefreshLists(); RefreshLists();
} }
@@ -352,8 +351,10 @@ void ScriptsTool::on_reloadScripts_clicked()
{ {
QList<QListWidgetItem *> items = ui->scripts->selectedItems(); QList<QListWidgetItem *> items = ui->scripts->selectedItems();
for (QListWidgetItem *item : items) for (QListWidgetItem *item : items)
ReloadScript(item->data(Qt::UserRole).toString() ReloadScript(item->data(Qt::UserRole)
.toUtf8().constData()); .toString()
.toUtf8()
.constData());
on_scripts_currentRowChanged(ui->scripts->currentRow()); on_scripts_currentRowChanged(ui->scripts->currentRow());
} }
@@ -368,9 +369,7 @@ void ScriptsTool::on_pythonPathBrowse_clicked()
{ {
QString curPath = ui->pythonPath->text(); QString curPath = ui->pythonPath->text();
QString newPath = QFileDialog::getExistingDirectory( QString newPath = QFileDialog::getExistingDirectory(
this, this, ui->pythonPathLabel->text(), curPath);
ui->pythonPathLabel->text(),
curPath);
if (newPath.isEmpty()) if (newPath.isEmpty())
return; return;
@@ -406,14 +405,14 @@ void ScriptsTool::on_scripts_currentRowChanged(int row)
if (row == -1) { if (row == -1) {
propertiesView = new QWidget(); propertiesView = new QWidget();
propertiesView->setSizePolicy(QSizePolicy::Expanding, propertiesView->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding); QSizePolicy::Expanding);
ui->propertiesLayout->addWidget(propertiesView); ui->propertiesLayout->addWidget(propertiesView);
ui->description->setText(QString()); ui->description->setText(QString());
return; return;
} }
QByteArray array = ui->scripts->item(row)->data(Qt::UserRole) QByteArray array =
.toString().toUtf8(); ui->scripts->item(row)->data(Qt::UserRole).toString().toUtf8();
const char *path = array.constData(); const char *path = array.constData();
obs_script_t *script = scriptData->FindScript(path); obs_script_t *script = scriptData->FindScript(path);
@@ -425,9 +424,10 @@ void ScriptsTool::on_scripts_currentRowChanged(int row)
OBSData settings = obs_script_get_settings(script); OBSData settings = obs_script_get_settings(script);
obs_data_release(settings); obs_data_release(settings);
propertiesView = new OBSPropertiesView(settings, script, propertiesView = new OBSPropertiesView(
(PropertiesReloadCallback)obs_script_get_properties, settings, script,
(PropertiesUpdateCallback)obs_script_update); (PropertiesReloadCallback)obs_script_get_properties,
(PropertiesUpdateCallback)obs_script_update);
ui->propertiesLayout->addWidget(propertiesView); ui->propertiesLayout->addWidget(propertiesView);
ui->description->setText(obs_script_get_description(script)); ui->description->setText(obs_script_get_description(script));
} }
@@ -457,8 +457,7 @@ static void obs_event(enum obs_frontend_event event, void *)
static void load_script_data(obs_data_t *load_data, bool, void *) static void load_script_data(obs_data_t *load_data, bool, void *)
{ {
obs_data_array_t *array = obs_data_get_array(load_data, obs_data_array_t *array = obs_data_get_array(load_data, "scripts-tool");
"scripts-tool");
delete scriptData; delete scriptData;
scriptData = new ScriptData; scriptData = new ScriptData;
@@ -509,21 +508,19 @@ static void save_script_data(obs_data_t *save_data, bool saving, void *)
} }
static void script_log(void *, obs_script_t *script, int log_level, static void script_log(void *, obs_script_t *script, int log_level,
const char *message) const char *message)
{ {
QString qmsg; QString qmsg;
if (script) { if (script) {
qmsg = QStringLiteral("[%1] %2").arg( qmsg = QStringLiteral("[%1] %2").arg(
obs_script_get_file(script), obs_script_get_file(script), message);
message);
} else { } else {
qmsg = QStringLiteral("[Unknown Script] %1").arg(message); qmsg = QStringLiteral("[Unknown Script] %1").arg(message);
} }
QMetaObject::invokeMethod(scriptLogWindow, "AddLogMsg", QMetaObject::invokeMethod(scriptLogWindow, "AddLogMsg",
Q_ARG(int, log_level), Q_ARG(int, log_level), Q_ARG(QString, qmsg));
Q_ARG(QString, qmsg));
} }
extern "C" void InitScripts() extern "C" void InitScripts()
@@ -533,13 +530,13 @@ extern "C" void InitScripts()
obs_scripting_load(); obs_scripting_load();
obs_scripting_set_log_callback(script_log, nullptr); obs_scripting_set_log_callback(script_log, nullptr);
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("Scripts")); obs_module_text("Scripts"));
#if PYTHON_UI #if PYTHON_UI
config_t *config = obs_frontend_get_global_config(); config_t *config = obs_frontend_get_global_config();
const char *python_path = config_get_string(config, "Python", const char *python_path =
"Path" ARCH_NAME); config_get_string(config, "Python", "Path" ARCH_NAME);
if (!obs_scripting_python_loaded() && python_path && *python_path) if (!obs_scripting_python_loaded() && python_path && *python_path)
obs_scripting_load_python(python_path); obs_scripting_load_python(python_path);
@@ -547,8 +544,7 @@ extern "C" void InitScripts()
scriptData = new ScriptData; scriptData = new ScriptData;
auto cb = [] () auto cb = []() {
{
obs_frontend_push_ui_translation(obs_module_get_string); obs_frontend_push_ui_translation(obs_module_get_string);
if (!scriptsWindow) { if (!scriptsWindow) {
+1 -2
View File
@@ -8,8 +8,7 @@ class HScrollArea : public QScrollArea {
Q_OBJECT Q_OBJECT
public: public:
inline HScrollArea(QWidget *parent = nullptr) inline HScrollArea(QWidget *parent = nullptr) : QScrollArea(parent)
: QScrollArea(parent)
{ {
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
} }
+79 -89
View File
@@ -25,13 +25,13 @@
#include "qt-wrappers.hpp" #include "qt-wrappers.hpp"
static inline bool operator!=(const obs_key_combination_t &c1, static inline bool operator!=(const obs_key_combination_t &c1,
const obs_key_combination_t &c2) const obs_key_combination_t &c2)
{ {
return c1.modifiers != c2.modifiers || c1.key != c2.key; return c1.modifiers != c2.modifiers || c1.key != c2.key;
} }
static inline bool operator==(const obs_key_combination_t &c1, static inline bool operator==(const obs_key_combination_t &c1,
const obs_key_combination_t &c2) const obs_key_combination_t &c2)
{ {
return !(c1 != c2); return !(c1 != c2);
} }
@@ -105,32 +105,34 @@ void OBSHotkeyEdit::mousePressEvent(QMouseEvent *event)
new_key.key = OBS_KEY_MOUSE3; new_key.key = OBS_KEY_MOUSE3;
break; break;
#define MAP_BUTTON(i, j) case Qt::ExtraButton ## i: \ #define MAP_BUTTON(i, j) \
new_key.key = OBS_KEY_MOUSE ## j; break; case Qt::ExtraButton##i: \
MAP_BUTTON( 1, 4); new_key.key = OBS_KEY_MOUSE##j; \
MAP_BUTTON( 2, 5); break;
MAP_BUTTON( 3, 6); MAP_BUTTON(1, 4)
MAP_BUTTON( 4, 7); MAP_BUTTON(2, 5)
MAP_BUTTON( 5, 8); MAP_BUTTON(3, 6)
MAP_BUTTON( 6, 9); MAP_BUTTON(4, 7)
MAP_BUTTON( 7, 10); MAP_BUTTON(5, 8)
MAP_BUTTON( 8, 11); MAP_BUTTON(6, 9)
MAP_BUTTON( 9, 12); MAP_BUTTON(7, 10)
MAP_BUTTON(10, 13); MAP_BUTTON(8, 11)
MAP_BUTTON(11, 14); MAP_BUTTON(9, 12)
MAP_BUTTON(12, 15); MAP_BUTTON(10, 13)
MAP_BUTTON(13, 16); MAP_BUTTON(11, 14)
MAP_BUTTON(14, 17); MAP_BUTTON(12, 15)
MAP_BUTTON(15, 18); MAP_BUTTON(13, 16)
MAP_BUTTON(16, 19); MAP_BUTTON(14, 17)
MAP_BUTTON(17, 20); MAP_BUTTON(15, 18)
MAP_BUTTON(18, 21); MAP_BUTTON(16, 19)
MAP_BUTTON(19, 22); MAP_BUTTON(17, 20)
MAP_BUTTON(20, 23); MAP_BUTTON(18, 21)
MAP_BUTTON(21, 24); MAP_BUTTON(19, 22)
MAP_BUTTON(22, 25); MAP_BUTTON(20, 23)
MAP_BUTTON(23, 26); MAP_BUTTON(21, 24)
MAP_BUTTON(24, 27); MAP_BUTTON(22, 25)
MAP_BUTTON(23, 26)
MAP_BUTTON(24, 27)
#undef MAP_BUTTON #undef MAP_BUTTON
} }
@@ -183,13 +185,13 @@ void OBSHotkeyEdit::ClearKey()
void OBSHotkeyEdit::InitSignalHandler() void OBSHotkeyEdit::InitSignalHandler()
{ {
layoutChanged = {obs_get_signal_handler(), layoutChanged = {
"hotkey_layout_change", obs_get_signal_handler(), "hotkey_layout_change",
[](void *this_, calldata_t*) [](void *this_, calldata_t *) {
{ auto edit = static_cast<OBSHotkeyEdit *>(this_);
auto edit = static_cast<OBSHotkeyEdit*>(this_); QMetaObject::invokeMethod(edit, "ReloadKeyLayout");
QMetaObject::invokeMethod(edit, "ReloadKeyLayout"); },
}, this}; this};
} }
void OBSHotkeyEdit::ReloadKeyLayout() void OBSHotkeyEdit::ReloadKeyLayout()
@@ -198,7 +200,7 @@ void OBSHotkeyEdit::ReloadKeyLayout()
} }
void OBSHotkeyWidget::SetKeyCombinations( void OBSHotkeyWidget::SetKeyCombinations(
const std::vector<obs_key_combination_t> &combos) const std::vector<obs_key_combination_t> &combos)
{ {
if (combos.empty()) if (combos.empty())
AddEdit({0, OBS_KEY_NONE}); AddEdit({0, OBS_KEY_NONE});
@@ -210,10 +212,8 @@ void OBSHotkeyWidget::SetKeyCombinations(
bool OBSHotkeyWidget::Changed() const bool OBSHotkeyWidget::Changed() const
{ {
return changed || return changed ||
std::any_of(begin(edits), end(edits), [](OBSHotkeyEdit *edit) std::any_of(begin(edits), end(edits),
{ [](OBSHotkeyEdit *edit) { return edit->changed; });
return edit->changed;
});
} }
void OBSHotkeyWidget::Apply() void OBSHotkeyWidget::Apply()
@@ -230,7 +230,7 @@ void OBSHotkeyWidget::Apply()
} }
void OBSHotkeyWidget::GetCombinations( void OBSHotkeyWidget::GetCombinations(
std::vector<obs_key_combination_t> &combinations) const std::vector<obs_key_combination_t> &combinations) const
{ {
combinations.clear(); combinations.clear();
for (auto &edit : edits) for (auto &edit : edits)
@@ -249,21 +249,19 @@ void OBSHotkeyWidget::Save(std::vector<obs_key_combination_t> &combinations)
GetCombinations(combinations); GetCombinations(combinations);
Apply(); Apply();
auto AtomicUpdate = [&]() auto AtomicUpdate = [&]() {
{
ignoreChangedBindings = true; ignoreChangedBindings = true;
obs_hotkey_load_bindings(id, obs_hotkey_load_bindings(id, combinations.data(),
combinations.data(), combinations.size()); combinations.size());
ignoreChangedBindings = false; ignoreChangedBindings = false;
}; };
using AtomicUpdate_t = decltype(&AtomicUpdate); using AtomicUpdate_t = decltype(&AtomicUpdate);
obs_hotkey_update_atomic([](void *d) obs_hotkey_update_atomic(
{ [](void *d) { (*static_cast<AtomicUpdate_t>(d))(); },
(*static_cast<AtomicUpdate_t>(d))(); static_cast<void *>(&AtomicUpdate));
}, static_cast<void*>(&AtomicUpdate));
} }
void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx) void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
@@ -285,12 +283,13 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
clear->setFlat(true); clear->setFlat(true);
clear->setEnabled(!obs_key_combination_is_empty(combo)); clear->setEnabled(!obs_key_combination_is_empty(combo));
QObject::connect(edit, &OBSHotkeyEdit::KeyChanged, QObject::connect(
[=](obs_key_combination_t new_combo) edit, &OBSHotkeyEdit::KeyChanged,
{ [=](obs_key_combination_t new_combo) {
clear->setEnabled(!obs_key_combination_is_empty(new_combo)); clear->setEnabled(
revert->setEnabled(edit->original != new_combo); !obs_key_combination_is_empty(new_combo));
}); revert->setEnabled(edit->original != new_combo);
});
auto add = new QPushButton; auto add = new QPushButton;
add->setProperty("themeID", "addIconSmall"); add->setProperty("themeID", "addIconSmall");
@@ -303,25 +302,18 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
remove->setFixedSize(24, 24); remove->setFixedSize(24, 24);
remove->setFlat(true); remove->setFlat(true);
auto CurrentIndex = [&, remove] auto CurrentIndex = [&, remove] {
{ auto res = std::find(begin(removeButtons), end(removeButtons),
auto res = std::find(begin(removeButtons), remove);
end(removeButtons),
remove);
return std::distance(begin(removeButtons), res); return std::distance(begin(removeButtons), res);
}; };
QObject::connect(add, &QPushButton::clicked, QObject::connect(add, &QPushButton::clicked, [&, CurrentIndex] {
[&, CurrentIndex]
{
AddEdit({0, OBS_KEY_NONE}, CurrentIndex() + 1); AddEdit({0, OBS_KEY_NONE}, CurrentIndex() + 1);
}); });
QObject::connect(remove, &QPushButton::clicked, QObject::connect(remove, &QPushButton::clicked,
[&, CurrentIndex] [&, CurrentIndex] { RemoveEdit(CurrentIndex()); });
{
RemoveEdit(CurrentIndex());
});
QHBoxLayout *subLayout = new QHBoxLayout; QHBoxLayout *subLayout = new QHBoxLayout;
subLayout->setContentsMargins(0, 4, 0, 0); subLayout->setContentsMargins(0, 4, 0, 0);
@@ -346,16 +338,13 @@ void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
layout()->insertLayout(idx, subLayout); layout()->insertLayout(idx, subLayout);
QObject::connect(revert, &QPushButton::clicked, QObject::connect(revert, &QPushButton::clicked, edit,
edit, &OBSHotkeyEdit::ResetKey); &OBSHotkeyEdit::ResetKey);
QObject::connect(clear, &QPushButton::clicked, QObject::connect(clear, &QPushButton::clicked, edit,
edit, &OBSHotkeyEdit::ClearKey); &OBSHotkeyEdit::ClearKey);
QObject::connect(edit, &OBSHotkeyEdit::KeyChanged, QObject::connect(edit, &OBSHotkeyEdit::KeyChanged,
[&](obs_key_combination) [&](obs_key_combination) { emit KeyChanged(); });
{
emit KeyChanged();
});
} }
void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal) void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal)
@@ -384,34 +373,35 @@ void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal)
void OBSHotkeyWidget::BindingsChanged(void *data, calldata_t *param) void OBSHotkeyWidget::BindingsChanged(void *data, calldata_t *param)
{ {
auto widget = static_cast<OBSHotkeyWidget*>(data); auto widget = static_cast<OBSHotkeyWidget *>(data);
auto key = static_cast<obs_hotkey_t*>(calldata_ptr(param, "key")); auto key = static_cast<obs_hotkey_t *>(calldata_ptr(param, "key"));
QMetaObject::invokeMethod(widget, "HandleChangedBindings", QMetaObject::invokeMethod(widget, "HandleChangedBindings",
Q_ARG(obs_hotkey_id, obs_hotkey_get_id(key))); Q_ARG(obs_hotkey_id, obs_hotkey_get_id(key)));
} }
void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_) void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_)
{ {
if (ignoreChangedBindings || id != id_) return; if (ignoreChangedBindings || id != id_)
return;
std::vector<obs_key_combination_t> bindings; std::vector<obs_key_combination_t> bindings;
auto LoadBindings = [&](obs_hotkey_binding_t *binding) auto LoadBindings = [&](obs_hotkey_binding_t *binding) {
{ if (obs_hotkey_binding_get_hotkey_id(binding) != id)
if (obs_hotkey_binding_get_hotkey_id(binding) != id) return; return;
auto get_combo = obs_hotkey_binding_get_key_combination; auto get_combo = obs_hotkey_binding_get_key_combination;
bindings.push_back(get_combo(binding)); bindings.push_back(get_combo(binding));
}; };
using LoadBindings_t = decltype(&LoadBindings); using LoadBindings_t = decltype(&LoadBindings);
obs_enum_hotkey_bindings([](void *data, obs_enum_hotkey_bindings(
size_t, obs_hotkey_binding_t *binding) [](void *data, size_t, obs_hotkey_binding_t *binding) {
{ auto LoadBindings = *static_cast<LoadBindings_t>(data);
auto LoadBindings = *static_cast<LoadBindings_t>(data); LoadBindings(binding);
LoadBindings(binding); return true;
return true; },
}, static_cast<void*>(&LoadBindings)); static_cast<void *>(&LoadBindings));
while (edits.size() > 0) while (edits.size() > 0)
RemoveEdit(edits.size() - 1, false); RemoveEdit(edits.size() - 1, false);
+13 -15
View File
@@ -45,10 +45,8 @@ class OBSHotkeyEdit : public QLineEdit {
Q_OBJECT; Q_OBJECT;
public: public:
OBSHotkeyEdit(obs_key_combination_t original, OBSHotkeyEdit(obs_key_combination_t original, QWidget *parent = nullptr)
QWidget *parent=nullptr) : QLineEdit(parent), original(original)
: QLineEdit(parent),
original(original)
{ {
#ifdef __APPLE__ #ifdef __APPLE__
// disable the input cursor on OSX, focus should be clear // disable the input cursor on OSX, focus should be clear
@@ -63,9 +61,10 @@ public:
obs_key_combination_t original; obs_key_combination_t original;
obs_key_combination_t key; obs_key_combination_t key;
bool changed = false; bool changed = false;
protected: protected:
OBSSignal layoutChanged; OBSSignal layoutChanged;
void InitSignalHandler(); void InitSignalHandler();
@@ -92,15 +91,14 @@ class OBSHotkeyWidget : public QWidget {
public: public:
OBSHotkeyWidget(obs_hotkey_id id, std::string name, OBSHotkeyWidget(obs_hotkey_id id, std::string name,
const std::vector<obs_key_combination_t> &combos={}, const std::vector<obs_key_combination_t> &combos = {},
QWidget *parent=nullptr) QWidget *parent = nullptr)
: QWidget(parent), : QWidget(parent),
id(id), id(id),
name(name), name(name),
bindingsChanged(obs_get_signal_handler(), bindingsChanged(obs_get_signal_handler(),
"hotkey_bindings_changed", "hotkey_bindings_changed",
&OBSHotkeyWidget::BindingsChanged, &OBSHotkeyWidget::BindingsChanged, this)
this)
{ {
auto layout = new QVBoxLayout; auto layout = new QVBoxLayout;
layout->setSpacing(0); layout->setSpacing(0);
@@ -110,7 +108,7 @@ public:
SetKeyCombinations(combos); SetKeyCombinations(combos);
} }
void SetKeyCombinations(const std::vector<obs_key_combination_t>&); void SetKeyCombinations(const std::vector<obs_key_combination_t> &);
obs_hotkey_id id; obs_hotkey_id id;
std::string name; std::string name;
@@ -129,7 +127,7 @@ public:
} }
void Apply(); void Apply();
void GetCombinations(std::vector<obs_key_combination_t>&) const; void GetCombinations(std::vector<obs_key_combination_t> &) const;
void Save(); void Save();
void Save(std::vector<obs_key_combination_t> &combinations); void Save(std::vector<obs_key_combination_t> &combinations);
@@ -137,8 +135,8 @@ public:
void leaveEvent(QEvent *event) override; void leaveEvent(QEvent *event) override;
private: private:
void AddEdit(obs_key_combination combo, int idx=-1); void AddEdit(obs_key_combination combo, int idx = -1);
void RemoveEdit(size_t idx, bool signal=true); void RemoveEdit(size_t idx, bool signal = true);
static void BindingsChanged(void *data, calldata_t *param); static void BindingsChanged(void *data, calldata_t *param);
@@ -150,7 +148,7 @@ private:
QVBoxLayout *layout() const QVBoxLayout *layout() const
{ {
return dynamic_cast<QVBoxLayout*>(QWidget::layout()); return dynamic_cast<QVBoxLayout *>(QWidget::layout());
} }
private slots: private slots:
+1 -1
View File
@@ -16,7 +16,7 @@ public:
} }
explicit inline MenuButton(const QString &text, explicit inline MenuButton(const QString &text,
QWidget *parent = nullptr) QWidget *parent = nullptr)
: QPushButton(text, parent) : QPushButton(text, parent)
{ {
} }
+5 -6
View File
@@ -1,21 +1,20 @@
#include "obf.h" #include "obf.h"
#include <stdbool.h> #include <stdbool.h>
#define LOWER_HALFBYTE(x) ((x) & 0xF) #define LOWER_HALFBYTE(x) ((x)&0xF)
#define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF) #define UPPER_HALFBYTE(x) (((x) >> 4) & 0xF)
void deobfuscate_str(char *str, uint64_t val) void deobfuscate_str(char *str, uint64_t val)
{ {
uint8_t *dec_val = (uint8_t*)&val; uint8_t *dec_val = (uint8_t *)&val;
int i = 0; int i = 0;
while (*str != 0) { while (*str != 0) {
int pos = i / 2; int pos = i / 2;
bool bottom = (i % 2) == 0; bool bottom = (i % 2) == 0;
uint8_t *ch = (uint8_t*)str; uint8_t *ch = (uint8_t *)str;
uint8_t xor = bottom ? uint8_t xor = bottom ? LOWER_HALFBYTE(dec_val[pos])
LOWER_HALFBYTE(dec_val[pos]) : : UPPER_HALFBYTE(dec_val[pos]);
UPPER_HALFBYTE(dec_val[pos]);
*ch ^= xor; *ch ^= xor;
+348 -338
View File
File diff suppressed because it is too large. Load diff
+49 -41
View File
@@ -36,48 +36,50 @@
std::string CurrentTimeString(); std::string CurrentTimeString();
std::string CurrentDateTimeString(); std::string CurrentDateTimeString();
std::string GenerateTimeDateFilename(const char *extension, bool noSpace=false); std::string GenerateTimeDateFilename(const char *extension,
bool noSpace = false);
std::string GenerateSpecifiedFilename(const char *extension, bool noSpace, std::string GenerateSpecifiedFilename(const char *extension, bool noSpace,
const char *format); const char *format);
QObject *CreateShortcutFilter(); QObject *CreateShortcutFilter();
struct BaseLexer { struct BaseLexer {
lexer lex; lexer lex;
public: public:
inline BaseLexer() {lexer_init(&lex);} inline BaseLexer() { lexer_init(&lex); }
inline ~BaseLexer() {lexer_free(&lex);} inline ~BaseLexer() { lexer_free(&lex); }
operator lexer*() {return &lex;} operator lexer *() { return &lex; }
}; };
class OBSTranslator : public QTranslator { class OBSTranslator : public QTranslator {
Q_OBJECT Q_OBJECT
public: public:
virtual bool isEmpty() const override {return false;} virtual bool isEmpty() const override { return false; }
virtual QString translate(const char *context, const char *sourceText, virtual QString translate(const char *context, const char *sourceText,
const char *disambiguation, int n) const override; const char *disambiguation,
int n) const override;
}; };
typedef std::function<void ()> VoidFunc; typedef std::function<void()> VoidFunc;
class OBSApp : public QApplication { class OBSApp : public QApplication {
Q_OBJECT Q_OBJECT
private: private:
std::string locale; std::string locale;
std::string theme; std::string theme;
ConfigFile globalConfig; ConfigFile globalConfig;
TextLookup textLookup; TextLookup textLookup;
OBSContext obsContext; OBSContext obsContext;
QPointer<OBSMainWindow> mainWindow; QPointer<OBSMainWindow> mainWindow;
profiler_name_store_t *profilerNameStore = nullptr; profiler_name_store_t *profilerNameStore = nullptr;
os_inhibit_t *sleepInhibitor = nullptr; os_inhibit_t *sleepInhibitor = nullptr;
int sleepInhibitRefs = 0; int sleepInhibitRefs = 0;
bool enableHotkeysInFocus = true;
bool enableHotkeysInFocus = true;
std::deque<obs_frontend_translate_ui_cb> translatorHooks; std::deque<obs_frontend_translate_ui_cb> translatorHooks;
@@ -93,8 +95,8 @@ private:
QPalette defaultPalette; QPalette defaultPalette;
void ParseExtraThemeData(const char *path); void ParseExtraThemeData(const char *path);
void AddExtraThemeColor(QPalette &pal, int group, void AddExtraThemeColor(QPalette &pal, int group, const char *name,
const char *name, uint32_t color); uint32_t color);
public: public:
OBSApp(int &argc, char **argv, profiler_name_store_t *store); OBSApp(int &argc, char **argv, profiler_name_store_t *store);
@@ -105,19 +107,16 @@ public:
void EnableInFocusHotkeys(bool enable); void EnableInFocusHotkeys(bool enable);
inline QMainWindow *GetMainWindow() const {return mainWindow.data();} inline QMainWindow *GetMainWindow() const { return mainWindow.data(); }
inline config_t *GlobalConfig() const {return globalConfig;} inline config_t *GlobalConfig() const { return globalConfig; }
inline const char *GetLocale() const inline const char *GetLocale() const { return locale.c_str(); }
{
return locale.c_str();
}
inline const char *GetTheme() const {return theme.c_str();} inline const char *GetTheme() const { return theme.c_str(); }
bool SetTheme(std::string name, std::string path = ""); bool SetTheme(std::string name, std::string path = "");
inline lookup_t *GetTextLookup() const {return textLookup;} inline lookup_t *GetTextLookup() const { return textLookup; }
inline const char *GetString(const char *lookupVal) const inline const char *GetString(const char *lookupVal) const
{ {
@@ -146,15 +145,18 @@ public:
inline void IncrementSleepInhibition() inline void IncrementSleepInhibition()
{ {
if (!sleepInhibitor) return; if (!sleepInhibitor)
return;
if (sleepInhibitRefs++ == 0) if (sleepInhibitRefs++ == 0)
os_inhibit_sleep_set_active(sleepInhibitor, true); os_inhibit_sleep_set_active(sleepInhibitor, true);
} }
inline void DecrementSleepInhibition() inline void DecrementSleepInhibition()
{ {
if (!sleepInhibitor) return; if (!sleepInhibitor)
if (sleepInhibitRefs == 0) return; return;
if (sleepInhibitRefs == 0)
return;
if (--sleepInhibitRefs == 0) if (--sleepInhibitRefs == 0)
os_inhibit_sleep_set_active(sleepInhibitor, false); os_inhibit_sleep_set_active(sleepInhibitor, false);
} }
@@ -164,10 +166,7 @@ public:
translatorHooks.emplace_front(cb); translatorHooks.emplace_front(cb);
} }
inline void PopUITranslation() inline void PopUITranslation() { translatorHooks.pop_front(); }
{
translatorHooks.pop_front();
}
public slots: public slots:
void Exec(VoidFunc func); void Exec(VoidFunc func);
@@ -182,12 +181,21 @@ char *GetConfigPathPtr(const char *name);
int GetProgramDataPath(char *path, size_t size, const char *name); int GetProgramDataPath(char *path, size_t size, const char *name);
char *GetProgramDataPathPtr(const char *name); char *GetProgramDataPathPtr(const char *name);
inline OBSApp *App() {return static_cast<OBSApp*>(qApp);} inline OBSApp *App()
{
return static_cast<OBSApp *>(qApp);
}
inline config_t *GetGlobalConfig() {return App()->GlobalConfig();} inline config_t *GetGlobalConfig()
{
return App()->GlobalConfig();
}
std::vector<std::pair<std::string, std::string>> GetLocaleNames(); std::vector<std::pair<std::string, std::string>> GetLocaleNames();
inline const char *Str(const char *lookup) {return App()->GetString(lookup);} inline const char *Str(const char *lookup)
{
return App()->GetString(lookup);
}
#define QTStr(lookupVal) QString::fromUtf8(Str(lookupVal)) #define QTStr(lookupVal) QString::fromUtf8(Str(lookupVal))
bool GetFileSafeName(const char *name, std::string &file); bool GetFileSafeName(const char *name, std::string &file);
@@ -197,8 +205,8 @@ bool WindowPositionValid(QRect rect);
static inline int GetProfilePath(char *path, size_t size, const char *file) static inline int GetProfilePath(char *path, size_t size, const char *file)
{ {
OBSMainWindow *window = reinterpret_cast<OBSMainWindow*>( OBSMainWindow *window =
App()->GetMainWindow()); reinterpret_cast<OBSMainWindow *>(App()->GetMainWindow());
return window->GetProfilePath(path, size, file); return window->GetProfilePath(path, size, file);
} }
+78 -91
View File
@@ -14,7 +14,7 @@ static inline bool callbacks_valid_(const char *func_name)
{ {
if (!c) { if (!c) {
blog(LOG_WARNING, "Tried to call %s with no callbacks!", blog(LOG_WARNING, "Tried to call %s with no callbacks!",
func_name); func_name);
return false; return false;
} }
@@ -26,7 +26,7 @@ static inline bool callbacks_valid_(const char *func_name)
static char **convert_string_list(vector<string> &strings) static char **convert_string_list(vector<string> &strings)
{ {
size_t size = 0; size_t size = 0;
size_t string_data_offset = (strings.size() + 1) * sizeof(char*); size_t string_data_offset = (strings.size() + 1) * sizeof(char *);
uint8_t *out; uint8_t *out;
char **ptr_list; char **ptr_list;
char *string_data; char *string_data;
@@ -39,9 +39,9 @@ static char **convert_string_list(vector<string> &strings)
if (!size) if (!size)
return 0; return 0;
out = (uint8_t*)bmalloc(size); out = (uint8_t *)bmalloc(size);
ptr_list = (char**)out; ptr_list = (char **)out;
string_data = (char*)(out + string_data_offset); string_data = (char *)(out + string_data_offset);
for (auto &str : strings) { for (auto &str : strings) {
*ptr_list = string_data; *ptr_list = string_data;
@@ -52,30 +52,27 @@ static char **convert_string_list(vector<string> &strings)
} }
*ptr_list = nullptr; *ptr_list = nullptr;
return (char**)out; return (char **)out;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
void *obs_frontend_get_main_window(void) void *obs_frontend_get_main_window(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_main_window()
? c->obs_frontend_get_main_window() : nullptr;
: nullptr;
} }
void *obs_frontend_get_main_window_handle(void) void *obs_frontend_get_main_window_handle(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_main_window_handle()
? c->obs_frontend_get_main_window_handle() : nullptr;
: nullptr;
} }
void *obs_frontend_get_system_tray(void) void *obs_frontend_get_system_tray(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_system_tray()
? c->obs_frontend_get_system_tray() : nullptr;
: nullptr;
} }
char **obs_frontend_get_scene_names(void) char **obs_frontend_get_scene_names(void)
@@ -99,31 +96,32 @@ char **obs_frontend_get_scene_names(void)
void obs_frontend_get_scenes(struct obs_frontend_source_list *sources) void obs_frontend_get_scenes(struct obs_frontend_source_list *sources)
{ {
if (callbacks_valid()) c->obs_frontend_get_scenes(sources); if (callbacks_valid())
c->obs_frontend_get_scenes(sources);
} }
obs_source_t *obs_frontend_get_current_scene(void) obs_source_t *obs_frontend_get_current_scene(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_current_scene()
? c->obs_frontend_get_current_scene() : nullptr;
: nullptr;
} }
void obs_frontend_set_current_scene(obs_source_t *scene) void obs_frontend_set_current_scene(obs_source_t *scene)
{ {
if (callbacks_valid()) c->obs_frontend_set_current_scene(scene); if (callbacks_valid())
c->obs_frontend_set_current_scene(scene);
} }
void obs_frontend_get_transitions(struct obs_frontend_source_list *sources) void obs_frontend_get_transitions(struct obs_frontend_source_list *sources)
{ {
if (callbacks_valid()) c->obs_frontend_get_transitions(sources); if (callbacks_valid())
c->obs_frontend_get_transitions(sources);
} }
obs_source_t *obs_frontend_get_current_transition(void) obs_source_t *obs_frontend_get_current_transition(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_current_transition()
? c->obs_frontend_get_current_transition() : nullptr;
: nullptr;
} }
void obs_frontend_set_current_transition(obs_source_t *transition) void obs_frontend_set_current_transition(obs_source_t *transition)
@@ -134,9 +132,8 @@ void obs_frontend_set_current_transition(obs_source_t *transition)
int obs_frontend_get_transition_duration(void) int obs_frontend_get_transition_duration(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_transition_duration()
? c->obs_frontend_get_transition_duration() : 0;
: 0;
} }
void obs_frontend_set_transition_duration(int duration) void obs_frontend_set_transition_duration(int duration)
@@ -158,8 +155,8 @@ char **obs_frontend_get_scene_collections(void)
char *obs_frontend_get_current_scene_collection(void) char *obs_frontend_get_current_scene_collection(void)
{ {
return !!callbacks_valid() return !!callbacks_valid()
? c->obs_frontend_get_current_scene_collection() ? c->obs_frontend_get_current_scene_collection()
: nullptr; : nullptr;
} }
void obs_frontend_set_current_scene_collection(const char *collection) void obs_frontend_set_current_scene_collection(const char *collection)
@@ -170,9 +167,8 @@ void obs_frontend_set_current_scene_collection(const char *collection)
bool obs_frontend_add_scene_collection(const char *name) bool obs_frontend_add_scene_collection(const char *name)
{ {
return callbacks_valid() return callbacks_valid() ? c->obs_frontend_add_scene_collection(name)
? c->obs_frontend_add_scene_collection(name) : false;
: false;
} }
char **obs_frontend_get_profiles(void) char **obs_frontend_get_profiles(void)
@@ -187,9 +183,8 @@ char **obs_frontend_get_profiles(void)
char *obs_frontend_get_current_profile(void) char *obs_frontend_get_current_profile(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_current_profile()
? c->obs_frontend_get_current_profile() : nullptr;
: nullptr;
} }
void obs_frontend_set_current_profile(const char *profile) void obs_frontend_set_current_profile(const char *profile)
@@ -200,91 +195,92 @@ void obs_frontend_set_current_profile(const char *profile)
void obs_frontend_streaming_start(void) void obs_frontend_streaming_start(void)
{ {
if (callbacks_valid()) c->obs_frontend_streaming_start(); if (callbacks_valid())
c->obs_frontend_streaming_start();
} }
void obs_frontend_streaming_stop(void) void obs_frontend_streaming_stop(void)
{ {
if (callbacks_valid()) c->obs_frontend_streaming_stop(); if (callbacks_valid())
c->obs_frontend_streaming_stop();
} }
bool obs_frontend_streaming_active(void) bool obs_frontend_streaming_active(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_streaming_active() : false;
? c->obs_frontend_streaming_active()
: false;
} }
void obs_frontend_recording_start(void) void obs_frontend_recording_start(void)
{ {
if (callbacks_valid()) c->obs_frontend_recording_start(); if (callbacks_valid())
c->obs_frontend_recording_start();
} }
void obs_frontend_recording_stop(void) void obs_frontend_recording_stop(void)
{ {
if (callbacks_valid()) c->obs_frontend_recording_stop(); if (callbacks_valid())
c->obs_frontend_recording_stop();
} }
bool obs_frontend_recording_active(void) bool obs_frontend_recording_active(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_recording_active() : false;
? c->obs_frontend_recording_active()
: false;
} }
void obs_frontend_replay_buffer_start(void) void obs_frontend_replay_buffer_start(void)
{ {
if (callbacks_valid()) c->obs_frontend_replay_buffer_start(); if (callbacks_valid())
c->obs_frontend_replay_buffer_start();
} }
void obs_frontend_replay_buffer_save(void) void obs_frontend_replay_buffer_save(void)
{ {
if (callbacks_valid()) c->obs_frontend_replay_buffer_save(); if (callbacks_valid())
c->obs_frontend_replay_buffer_save();
} }
void obs_frontend_replay_buffer_stop(void) void obs_frontend_replay_buffer_stop(void)
{ {
if (callbacks_valid()) c->obs_frontend_replay_buffer_stop(); if (callbacks_valid())
c->obs_frontend_replay_buffer_stop();
} }
bool obs_frontend_replay_buffer_active(void) bool obs_frontend_replay_buffer_active(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_replay_buffer_active()
? c->obs_frontend_replay_buffer_active() : false;
: false;
} }
void *obs_frontend_add_tools_menu_qaction(const char *name) void *obs_frontend_add_tools_menu_qaction(const char *name)
{ {
return !!callbacks_valid() return !!callbacks_valid()
? c->obs_frontend_add_tools_menu_qaction(name) ? c->obs_frontend_add_tools_menu_qaction(name)
: nullptr; : nullptr;
} }
void obs_frontend_add_tools_menu_item(const char *name, void obs_frontend_add_tools_menu_item(const char *name,
obs_frontend_cb callback, void *private_data) obs_frontend_cb callback,
void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_add_tools_menu_item(name, callback, c->obs_frontend_add_tools_menu_item(name, callback,
private_data); private_data);
} }
void *obs_frontend_add_dock(void *dock) void *obs_frontend_add_dock(void *dock)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_add_dock(dock) : nullptr;
? c->obs_frontend_add_dock(dock)
: nullptr;
} }
void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
void *private_data) void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_add_event_callback(callback, private_data); c->obs_frontend_add_event_callback(callback, private_data);
} }
void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
void *private_data) void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_remove_event_callback(callback, private_data); c->obs_frontend_remove_event_callback(callback, private_data);
@@ -292,37 +288,32 @@ void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
obs_output_t *obs_frontend_get_streaming_output(void) obs_output_t *obs_frontend_get_streaming_output(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_streaming_output()
? c->obs_frontend_get_streaming_output() : nullptr;
: nullptr;
} }
obs_output_t *obs_frontend_get_recording_output(void) obs_output_t *obs_frontend_get_recording_output(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_recording_output()
? c->obs_frontend_get_recording_output() : nullptr;
: nullptr;
} }
obs_output_t *obs_frontend_get_replay_buffer_output(void) obs_output_t *obs_frontend_get_replay_buffer_output(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_replay_buffer_output()
? c->obs_frontend_get_replay_buffer_output() : nullptr;
: nullptr;
} }
config_t *obs_frontend_get_profile_config(void) config_t *obs_frontend_get_profile_config(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_profile_config()
? c->obs_frontend_get_profile_config() : nullptr;
: nullptr;
} }
config_t *obs_frontend_get_global_config(void) config_t *obs_frontend_get_global_config(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_global_config()
? c->obs_frontend_get_global_config() : nullptr;
: nullptr;
} }
void obs_frontend_save(void) void obs_frontend_save(void)
@@ -344,28 +335,28 @@ void obs_frontend_defer_save_end(void)
} }
void obs_frontend_add_save_callback(obs_frontend_save_cb callback, void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
void *private_data) void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_add_save_callback(callback, private_data); c->obs_frontend_add_save_callback(callback, private_data);
} }
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
void *private_data) void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_remove_save_callback(callback, private_data); c->obs_frontend_remove_save_callback(callback, private_data);
} }
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback, void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
void *private_data) void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_add_preload_callback(callback, private_data); c->obs_frontend_add_preload_callback(callback, private_data);
} }
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
void *private_data) void *private_data)
{ {
if (callbacks_valid()) if (callbacks_valid())
c->obs_frontend_remove_preload_callback(callback, private_data); c->obs_frontend_remove_preload_callback(callback, private_data);
@@ -389,11 +380,10 @@ void obs_frontend_set_streaming_service(obs_service_t *service)
c->obs_frontend_set_streaming_service(service); c->obs_frontend_set_streaming_service(service);
} }
obs_service_t* obs_frontend_get_streaming_service(void) obs_service_t *obs_frontend_get_streaming_service(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_streaming_service()
? c->obs_frontend_get_streaming_service() : nullptr;
: nullptr;
} }
void obs_frontend_save_streaming_service(void) void obs_frontend_save_streaming_service(void)
@@ -405,8 +395,8 @@ void obs_frontend_save_streaming_service(void)
bool obs_frontend_preview_program_mode_active(void) bool obs_frontend_preview_program_mode_active(void)
{ {
return !!callbacks_valid() return !!callbacks_valid()
? c->obs_frontend_preview_program_mode_active() ? c->obs_frontend_preview_program_mode_active()
: false; : false;
} }
void obs_frontend_set_preview_program_mode(bool enable) void obs_frontend_set_preview_program_mode(bool enable)
@@ -429,16 +419,13 @@ void obs_frontend_set_preview_enabled(bool enable)
bool obs_frontend_preview_enabled(void) bool obs_frontend_preview_enabled(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_preview_enabled() : false;
? c->obs_frontend_preview_enabled()
: false;
} }
obs_source_t *obs_frontend_get_current_preview_scene(void) obs_source_t *obs_frontend_get_current_preview_scene(void)
{ {
return !!callbacks_valid() return !!callbacks_valid() ? c->obs_frontend_get_current_preview_scene()
? c->obs_frontend_get_current_preview_scene() : nullptr;
: nullptr;
} }
void obs_frontend_set_current_preview_scene(obs_source_t *scene) void obs_frontend_set_current_preview_scene(obs_source_t *scene)
+20 -19
View File
@@ -43,7 +43,7 @@ enum obs_frontend_event {
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED, OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED,
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP, OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP,
OBS_FRONTEND_EVENT_FINISHED_LOADING OBS_FRONTEND_EVENT_FINISHED_LOADING,
}; };
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -51,11 +51,11 @@ enum obs_frontend_event {
#ifndef SWIG #ifndef SWIG
struct obs_frontend_source_list { struct obs_frontend_source_list {
DARRAY(obs_source_t*) sources; DARRAY(obs_source_t *) sources;
}; };
static inline void obs_frontend_source_list_free( static inline void
struct obs_frontend_source_list *source_list) obs_frontend_source_list_free(struct obs_frontend_source_list *source_list)
{ {
size_t num = source_list->sources.num; size_t num = source_list->sources.num;
for (size_t i = 0; i < num; i++) for (size_t i = 0; i < num; i++)
@@ -89,8 +89,8 @@ EXPORT void obs_frontend_get_scenes(struct obs_frontend_source_list *sources);
EXPORT obs_source_t *obs_frontend_get_current_scene(void); 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_set_current_scene(obs_source_t *scene);
EXPORT void obs_frontend_get_transitions( EXPORT void
struct obs_frontend_source_list *sources); obs_frontend_get_transitions(struct obs_frontend_source_list *sources);
EXPORT obs_source_t *obs_frontend_get_current_transition(void); EXPORT obs_source_t *obs_frontend_get_current_transition(void);
EXPORT void obs_frontend_set_current_transition(obs_source_t *transition); EXPORT void obs_frontend_set_current_transition(obs_source_t *transition);
EXPORT int obs_frontend_get_transition_duration(void); EXPORT int obs_frontend_get_transition_duration(void);
@@ -109,37 +109,38 @@ 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_qaction(const char *name);
EXPORT void obs_frontend_add_tools_menu_item(const char *name, EXPORT void obs_frontend_add_tools_menu_item(const char *name,
obs_frontend_cb callback, void *private_data); obs_frontend_cb callback,
void *private_data);
/* takes QDockWidget and returns QAction */ /* takes QDockWidget and returns QAction */
EXPORT void *obs_frontend_add_dock(void *dock); EXPORT void *obs_frontend_add_dock(void *dock);
typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event, typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event,
void *private_data); void *private_data);
EXPORT void obs_frontend_add_event_callback(obs_frontend_event_cb callback, EXPORT void obs_frontend_add_event_callback(obs_frontend_event_cb callback,
void *private_data); void *private_data);
EXPORT void obs_frontend_remove_event_callback(obs_frontend_event_cb callback, EXPORT void obs_frontend_remove_event_callback(obs_frontend_event_cb callback,
void *private_data); void *private_data);
typedef void (*obs_frontend_save_cb)(obs_data_t *save_data, bool saving, typedef void (*obs_frontend_save_cb)(obs_data_t *save_data, bool saving,
void *private_data); void *private_data);
EXPORT void obs_frontend_add_save_callback(obs_frontend_save_cb callback, EXPORT void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
void *private_data); void *private_data);
EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback, EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
void *private_data); void *private_data);
EXPORT void obs_frontend_add_preload_callback(obs_frontend_save_cb callback, EXPORT void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
void *private_data); void *private_data);
EXPORT void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback, EXPORT void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
void *private_data); void *private_data);
typedef bool (*obs_frontend_translate_ui_cb)(const char *text, typedef bool (*obs_frontend_translate_ui_cb)(const char *text,
const char **out); const char **out);
EXPORT void obs_frontend_push_ui_translation( EXPORT void
obs_frontend_translate_ui_cb translate); obs_frontend_push_ui_translation(obs_frontend_translate_ui_cb translate);
EXPORT void obs_frontend_pop_ui_translation(void); EXPORT void obs_frontend_pop_ui_translation(void);
#endif //!SWIG #endif //!SWIG
@@ -169,7 +170,7 @@ EXPORT config_t *obs_frontend_get_profile_config(void);
EXPORT config_t *obs_frontend_get_global_config(void); EXPORT config_t *obs_frontend_get_global_config(void);
EXPORT void obs_frontend_set_streaming_service(obs_service_t *service); EXPORT void obs_frontend_set_streaming_service(obs_service_t *service);
EXPORT obs_service_t* obs_frontend_get_streaming_service(void); EXPORT obs_service_t *obs_frontend_get_streaming_service(void);
EXPORT void obs_frontend_save_streaming_service(void); EXPORT void obs_frontend_save_streaming_service(void);
EXPORT bool obs_frontend_preview_program_mode_active(void); EXPORT bool obs_frontend_preview_program_mode_active(void);
+78 -70
View File
@@ -7,103 +7,111 @@
struct obs_frontend_callbacks { struct obs_frontend_callbacks {
virtual ~obs_frontend_callbacks() {} virtual ~obs_frontend_callbacks() {}
virtual void *obs_frontend_get_main_window(void)=0; virtual void *obs_frontend_get_main_window(void) = 0;
virtual void *obs_frontend_get_main_window_handle(void)=0; virtual void *obs_frontend_get_main_window_handle(void) = 0;
virtual void *obs_frontend_get_system_tray(void)=0; virtual void *obs_frontend_get_system_tray(void) = 0;
virtual void obs_frontend_get_scenes( virtual void
struct obs_frontend_source_list *sources)=0; obs_frontend_get_scenes(struct obs_frontend_source_list *sources) = 0;
virtual obs_source_t *obs_frontend_get_current_scene(void)=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_set_current_scene(obs_source_t *scene) = 0;
virtual void obs_frontend_get_transitions( virtual void obs_frontend_get_transitions(
struct obs_frontend_source_list *sources)=0; struct obs_frontend_source_list *sources) = 0;
virtual obs_source_t *obs_frontend_get_current_transition(void)=0; virtual obs_source_t *obs_frontend_get_current_transition(void) = 0;
virtual void obs_frontend_set_current_transition( virtual void
obs_source_t *transition)=0; obs_frontend_set_current_transition(obs_source_t *transition) = 0;
virtual int obs_frontend_get_transition_duration(void)=0; virtual int obs_frontend_get_transition_duration(void) = 0;
virtual void obs_frontend_set_transition_duration(int duration)=0; virtual void obs_frontend_set_transition_duration(int duration) = 0;
virtual void obs_frontend_get_scene_collections( virtual void obs_frontend_get_scene_collections(
std::vector<std::string> &strings)=0; std::vector<std::string> &strings) = 0;
virtual char *obs_frontend_get_current_scene_collection(void)=0; virtual char *obs_frontend_get_current_scene_collection(void) = 0;
virtual void obs_frontend_set_current_scene_collection( virtual void
const char *collection)=0; obs_frontend_set_current_scene_collection(const char *collection) = 0;
virtual bool obs_frontend_add_scene_collection(const char *name)=0; virtual bool obs_frontend_add_scene_collection(const char *name) = 0;
virtual void obs_frontend_get_profiles( virtual void
std::vector<std::string> &strings)=0; obs_frontend_get_profiles(std::vector<std::string> &strings) = 0;
virtual char *obs_frontend_get_current_profile(void)=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_set_current_profile(const char *profile) = 0;
virtual void obs_frontend_streaming_start(void)=0; virtual void obs_frontend_streaming_start(void) = 0;
virtual void obs_frontend_streaming_stop(void)=0; virtual void obs_frontend_streaming_stop(void) = 0;
virtual bool obs_frontend_streaming_active(void)=0; virtual bool obs_frontend_streaming_active(void) = 0;
virtual void obs_frontend_recording_start(void)=0; virtual void obs_frontend_recording_start(void) = 0;
virtual void obs_frontend_recording_stop(void)=0; virtual void obs_frontend_recording_stop(void) = 0;
virtual bool obs_frontend_recording_active(void)=0; virtual bool obs_frontend_recording_active(void) = 0;
virtual void obs_frontend_replay_buffer_start(void)=0; virtual void obs_frontend_replay_buffer_start(void) = 0;
virtual void obs_frontend_replay_buffer_save(void) = 0; virtual void obs_frontend_replay_buffer_save(void) = 0;
virtual void obs_frontend_replay_buffer_stop(void)=0; virtual void obs_frontend_replay_buffer_stop(void) = 0;
virtual bool obs_frontend_replay_buffer_active(void)=0; virtual bool obs_frontend_replay_buffer_active(void) = 0;
virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0; virtual void *obs_frontend_add_tools_menu_qaction(const char *name) = 0;
virtual void obs_frontend_add_tools_menu_item(const char *name, virtual void obs_frontend_add_tools_menu_item(const char *name,
obs_frontend_cb callback, void *private_data)=0; obs_frontend_cb callback,
void *private_data) = 0;
virtual void *obs_frontend_add_dock(void *dock)=0; virtual void *obs_frontend_add_dock(void *dock) = 0;
virtual void obs_frontend_add_event_callback( virtual void
obs_frontend_event_cb callback, void *private_data)=0; obs_frontend_add_event_callback(obs_frontend_event_cb callback,
virtual void obs_frontend_remove_event_callback( void *private_data) = 0;
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_streaming_output(void) = 0;
virtual obs_output_t *obs_frontend_get_recording_output(void)=0; virtual obs_output_t *obs_frontend_get_recording_output(void) = 0;
virtual obs_output_t *obs_frontend_get_replay_buffer_output(void)=0; virtual obs_output_t *obs_frontend_get_replay_buffer_output(void) = 0;
virtual config_t *obs_frontend_get_profile_config(void)=0; virtual config_t *obs_frontend_get_profile_config(void) = 0;
virtual config_t *obs_frontend_get_global_config(void)=0; virtual config_t *obs_frontend_get_global_config(void) = 0;
virtual void obs_frontend_save(void) = 0; virtual void obs_frontend_save(void) = 0;
virtual void obs_frontend_defer_save_begin(void) = 0; virtual void obs_frontend_defer_save_begin(void) = 0;
virtual void obs_frontend_defer_save_end(void) = 0; virtual void obs_frontend_defer_save_end(void) = 0;
virtual void obs_frontend_add_save_callback( virtual void
obs_frontend_save_cb callback, void *private_data)=0; obs_frontend_add_save_callback(obs_frontend_save_cb callback,
virtual void obs_frontend_remove_save_callback( void *private_data) = 0;
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_add_preload_callback( virtual void
obs_frontend_save_cb callback, void *private_data)=0; obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
virtual void obs_frontend_remove_preload_callback( void *private_data) = 0;
obs_frontend_save_cb callback, void *private_data)=0; virtual void
obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
void *private_data) = 0;
virtual void obs_frontend_push_ui_translation( virtual void obs_frontend_push_ui_translation(
obs_frontend_translate_ui_cb translate)=0; obs_frontend_translate_ui_cb translate) = 0;
virtual void obs_frontend_pop_ui_translation(void)=0; virtual void obs_frontend_pop_ui_translation(void) = 0;
virtual void obs_frontend_set_streaming_service( virtual void
obs_service_t *service)=0; obs_frontend_set_streaming_service(obs_service_t *service) = 0;
virtual obs_service_t *obs_frontend_get_streaming_service(void)=0; virtual obs_service_t *obs_frontend_get_streaming_service(void) = 0;
virtual void obs_frontend_save_streaming_service()=0; virtual void obs_frontend_save_streaming_service() = 0;
virtual bool obs_frontend_preview_program_mode_active(void)=0; virtual bool obs_frontend_preview_program_mode_active(void) = 0;
virtual void obs_frontend_set_preview_program_mode(bool enable)=0; virtual void obs_frontend_set_preview_program_mode(bool enable) = 0;
virtual void obs_frontend_preview_program_trigger_transition(void)=0; virtual void obs_frontend_preview_program_trigger_transition(void) = 0;
virtual bool obs_frontend_preview_enabled(void)=0; virtual bool obs_frontend_preview_enabled(void) = 0;
virtual void obs_frontend_set_preview_enabled(bool enable)=0; virtual void obs_frontend_set_preview_enabled(bool enable) = 0;
virtual obs_source_t *obs_frontend_get_current_preview_scene(void)=0; virtual obs_source_t *obs_frontend_get_current_preview_scene(void) = 0;
virtual void obs_frontend_set_current_preview_scene(obs_source_t *scene)=0; virtual void
obs_frontend_set_current_preview_scene(obs_source_t *scene) = 0;
virtual void on_load(obs_data_t *settings)=0; virtual void on_load(obs_data_t *settings) = 0;
virtual void on_preload(obs_data_t *settings)=0; virtual void on_preload(obs_data_t *settings) = 0;
virtual void on_save(obs_data_t *settings)=0; virtual void on_save(obs_data_t *settings) = 0;
virtual void on_event(enum obs_frontend_event event)=0; virtual void on_event(enum obs_frontend_event event) = 0;
}; };
EXPORT void obs_frontend_set_callbacks_internal( EXPORT void
obs_frontend_callbacks *callbacks); obs_frontend_set_callbacks_internal(obs_frontend_callbacks *callbacks);
+26 -24
View File
@@ -37,8 +37,8 @@ using namespace std;
#include <util/windows/HRError.hpp> #include <util/windows/HRError.hpp>
#include <util/windows/ComPtr.hpp> #include <util/windows/ComPtr.hpp>
static inline bool check_path(const char* data, const char *path, static inline bool check_path(const char *data, const char *path,
string &output) string &output)
{ {
ostringstream str; ostringstream str;
str << path << data; str << path << data;
@@ -65,10 +65,10 @@ bool InitApplicationBundle()
string GetDefaultVideoSavePath() string GetDefaultVideoSavePath()
{ {
wchar_t path_utf16[MAX_PATH]; wchar_t path_utf16[MAX_PATH];
char path_utf8[MAX_PATH] = {}; char path_utf8[MAX_PATH] = {};
SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT, SHGetFolderPathW(NULL, CSIDL_MYVIDEO, NULL, SHGFP_TYPE_CURRENT,
path_utf16); path_utf16);
os_wcs_to_utf8(path_utf16, wcslen(path_utf16), path_utf8, MAX_PATH); os_wcs_to_utf8(path_utf16, wcslen(path_utf16), path_utf8, MAX_PATH);
return string(path_utf8); return string(path_utf8);
@@ -79,18 +79,18 @@ static vector<string> GetUserPreferredLocales()
vector<string> result; vector<string> result;
ULONG num, length = 0; ULONG num, length = 0;
if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num, if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num, nullptr,
nullptr, &length)) &length))
return result; return result;
vector<wchar_t> buffer(length); vector<wchar_t> buffer(length);
if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num, if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num,
&buffer.front(), &length)) &buffer.front(), &length))
return result; return result;
result.reserve(num); result.reserve(num);
auto start = begin(buffer); auto start = begin(buffer);
auto end_ = end(buffer); auto end_ = end(buffer);
decltype(start) separator; decltype(start) separator;
while ((separator = find(start, end_, 0)) != end_) { while ((separator = find(start, end_, 0)) != end_) {
if (result.size() == num) if (result.size() == num)
@@ -162,7 +162,7 @@ uint32_t GetWindowsVersion()
void SetAeroEnabled(bool enable) void SetAeroEnabled(bool enable)
{ {
static HRESULT (WINAPI *func)(UINT) = nullptr; static HRESULT(WINAPI * func)(UINT) = nullptr;
static bool failed = false; static bool failed = false;
if (!func) { if (!func) {
@@ -176,8 +176,8 @@ void SetAeroEnabled(bool enable)
return; return;
} }
func = reinterpret_cast<decltype(func)>(GetProcAddress(dwm, func = reinterpret_cast<decltype(func)>(
"DwmEnableComposition")); GetProcAddress(dwm, "DwmEnableComposition"));
if (!func) { if (!func) {
failed = true; failed = true;
return; return;
@@ -197,7 +197,7 @@ void SetAlwaysOnTop(QWidget *window, bool enable)
{ {
HWND hwnd = (HWND)window->winId(); HWND hwnd = (HWND)window->winId();
SetWindowPos(hwnd, enable ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SetWindowPos(hwnd, enable ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
} }
void SetProcessPriority(const char *priority) void SetProcessPriority(const char *priority)
@@ -208,11 +208,13 @@ void SetProcessPriority(const char *priority)
if (strcmp(priority, "High") == 0) if (strcmp(priority, "High") == 0)
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
else if (strcmp(priority, "AboveNormal") == 0) else if (strcmp(priority, "AboveNormal") == 0)
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(),
ABOVE_NORMAL_PRIORITY_CLASS);
else if (strcmp(priority, "Normal") == 0) else if (strcmp(priority, "Normal") == 0)
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
else if (strcmp(priority, "BelowNormal") == 0) else if (strcmp(priority, "BelowNormal") == 0)
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(),
BELOW_NORMAL_PRIORITY_CLASS);
else if (strcmp(priority, "Idle") == 0) else if (strcmp(priority, "Idle") == 0)
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
} }
@@ -227,16 +229,16 @@ void SetWin32DropStyle(QWidget *window)
bool DisableAudioDucking(bool disable) bool DisableAudioDucking(bool disable)
{ {
ComPtr<IMMDeviceEnumerator> devEmum; ComPtr<IMMDeviceEnumerator> devEmum;
ComPtr<IMMDevice> device; ComPtr<IMMDevice> device;
ComPtr<IAudioSessionManager2> sessionManager2; ComPtr<IAudioSessionManager2> sessionManager2;
ComPtr<IAudioSessionControl> sessionControl; ComPtr<IAudioSessionControl> sessionControl;
ComPtr<IAudioSessionControl2> sessionControl2; ComPtr<IAudioSessionControl2> sessionControl2;
HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator), HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
nullptr, CLSCTX_INPROC_SERVER, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), __uuidof(IMMDeviceEnumerator),
(void **)&devEmum); (void **)&devEmum);
if (FAILED(result)) if (FAILED(result))
return false; return false;
@@ -245,13 +247,13 @@ bool DisableAudioDucking(bool disable)
return false; return false;
result = device->Activate(__uuidof(IAudioSessionManager2), result = device->Activate(__uuidof(IAudioSessionManager2),
CLSCTX_INPROC_SERVER, nullptr, CLSCTX_INPROC_SERVER, nullptr,
(void **)&sessionManager2); (void **)&sessionManager2);
if (FAILED(result)) if (FAILED(result))
return false; return false;
result = sessionManager2->GetAudioSessionControl(nullptr, 0, result = sessionManager2->GetAudioSessionControl(nullptr, 0,
&sessionControl); &sessionControl);
if (FAILED(result)) if (FAILED(result))
return false; return false;
+2 -2
View File
@@ -29,8 +29,8 @@
#include "platform.hpp" #include "platform.hpp"
using namespace std; using namespace std;
static inline bool check_path(const char* data, const char *path, static inline bool check_path(const char *data, const char *path,
string &output) string &output)
{ {
ostringstream str; ostringstream str;
str << path << data; str << path << data;
+1
View File
@@ -48,6 +48,7 @@ struct RunOnceMutexData;
class RunOnceMutex { class RunOnceMutex {
RunOnceMutexData *data = nullptr; RunOnceMutexData *data = nullptr;
public: public:
RunOnceMutex(RunOnceMutexData *data_) : data(data_) {} RunOnceMutex(RunOnceMutexData *data_) : data(data_) {}
RunOnceMutex(const RunOnceMutex &rom) = delete; RunOnceMutex(const RunOnceMutex &rom) = delete;
+347 -359
View File
File diff suppressed because it is too large. Load diff
+31 -31
View File
@@ -10,8 +10,7 @@ class OBSPropertiesView;
class QLabel; class QLabel;
typedef obs_properties_t *(*PropertiesReloadCallback)(void *obj); typedef obs_properties_t *(*PropertiesReloadCallback)(void *obj);
typedef void (*PropertiesUpdateCallback)(void *obj, typedef void (*PropertiesUpdateCallback)(void *obj, obs_data_t *settings);
obs_data_t *settings);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -22,8 +21,8 @@ class WidgetInfo : public QObject {
private: private:
OBSPropertiesView *view; OBSPropertiesView *view;
obs_property_t *property; obs_property_t *property;
QWidget *widget; QWidget *widget;
void BoolChanged(const char *setting); void BoolChanged(const char *setting);
void IntChanged(const char *setting); void IntChanged(const char *setting);
@@ -41,9 +40,10 @@ private:
public: public:
inline WidgetInfo(OBSPropertiesView *view_, obs_property_t *prop, inline WidgetInfo(OBSPropertiesView *view_, obs_property_t *prop,
QWidget *widget_) QWidget *widget_)
: view(view_), property(prop), widget(widget_) : view(view_), property(prop), widget(widget_)
{} {
}
public slots: public slots:
@@ -72,37 +72,38 @@ class OBSPropertiesView : public VScrollArea {
std::unique_ptr<obs_properties_t, properties_delete_t>; std::unique_ptr<obs_properties_t, properties_delete_t>;
private: private:
QWidget *widget = nullptr; QWidget *widget = nullptr;
properties_t properties; properties_t properties;
OBSData settings; OBSData settings;
void *obj = nullptr; void *obj = nullptr;
std::string type; std::string type;
PropertiesReloadCallback reloadCallback; PropertiesReloadCallback reloadCallback;
PropertiesUpdateCallback callback = nullptr; PropertiesUpdateCallback callback = nullptr;
int minSize; int minSize;
std::vector<std::unique_ptr<WidgetInfo>> children; std::vector<std::unique_ptr<WidgetInfo>> children;
std::string lastFocused; std::string lastFocused;
QWidget *lastWidget = nullptr; QWidget *lastWidget = nullptr;
bool deferUpdate; bool deferUpdate;
QWidget *NewWidget(obs_property_t *prop, QWidget *widget, QWidget *NewWidget(obs_property_t *prop, QWidget *widget,
const char *signal); const char *signal);
QWidget *AddCheckbox(obs_property_t *prop); QWidget *AddCheckbox(obs_property_t *prop);
QWidget *AddText(obs_property_t *prop, QFormLayout *layout, QWidget *AddText(obs_property_t *prop, QFormLayout *layout,
QLabel *&label); QLabel *&label);
void AddPath(obs_property_t *prop, QFormLayout *layout, QLabel **label); void AddPath(obs_property_t *prop, QFormLayout *layout, QLabel **label);
void AddInt(obs_property_t *prop, QFormLayout *layout, QLabel **label); void AddInt(obs_property_t *prop, QFormLayout *layout, QLabel **label);
void AddFloat(obs_property_t *prop, QFormLayout *layout, void AddFloat(obs_property_t *prop, QFormLayout *layout,
QLabel**label); QLabel **label);
QWidget *AddList(obs_property_t *prop, bool &warning); QWidget *AddList(obs_property_t *prop, bool &warning);
void AddEditableList(obs_property_t *prop, QFormLayout *layout, void AddEditableList(obs_property_t *prop, QFormLayout *layout,
QLabel *&label); QLabel *&label);
QWidget *AddButton(obs_property_t *prop); QWidget *AddButton(obs_property_t *prop);
void AddColor(obs_property_t *prop, QFormLayout *layout, QLabel *&label); void AddColor(obs_property_t *prop, QFormLayout *layout,
QLabel *&label);
void AddFont(obs_property_t *prop, QFormLayout *layout, QLabel *&label); void AddFont(obs_property_t *prop, QFormLayout *layout, QLabel *&label);
void AddFrameRate(obs_property_t *prop, bool &warning, void AddFrameRate(obs_property_t *prop, bool &warning,
QFormLayout *layout, QLabel *&label); QFormLayout *layout, QLabel *&label);
void AddGroup(obs_property_t *prop, QFormLayout *layout); void AddGroup(obs_property_t *prop, QFormLayout *layout);
@@ -125,15 +126,14 @@ signals:
public: public:
OBSPropertiesView(OBSData settings, void *obj, OBSPropertiesView(OBSData settings, void *obj,
PropertiesReloadCallback reloadCallback, PropertiesReloadCallback reloadCallback,
PropertiesUpdateCallback callback, PropertiesUpdateCallback callback, int minSize = 0);
int minSize = 0);
OBSPropertiesView(OBSData settings, const char *type, OBSPropertiesView(OBSData settings, const char *type,
PropertiesReloadCallback reloadCallback, PropertiesReloadCallback reloadCallback,
int minSize = 0); int minSize = 0);
inline obs_data_t *GetSettings() const {return settings;} inline obs_data_t *GetSettings() const { return settings; }
inline void UpdateSettings() {callback(obj, settings);} inline void UpdateSettings() { callback(obj, settings); }
inline bool DeferUpdate() const {return deferUpdate;} inline bool DeferUpdate() const { return deferUpdate; }
}; };
+17 -17
View File
@@ -15,13 +15,13 @@
#endif #endif
static bool operator!=(const media_frames_per_second &a, static bool operator!=(const media_frames_per_second &a,
const media_frames_per_second &b) const media_frames_per_second &b)
{ {
return a.numerator != b.numerator || a.denominator != b.denominator; return a.numerator != b.numerator || a.denominator != b.denominator;
} }
static bool operator==(const media_frames_per_second &a, static bool operator==(const media_frames_per_second &a,
const media_frames_per_second &b) const media_frames_per_second &b)
{ {
return !(a != b); return !(a != b);
} }
@@ -36,27 +36,27 @@ class OBSFrameRatePropertyWidget : public QWidget {
public: public:
frame_rate_ranges_t fps_ranges; frame_rate_ranges_t fps_ranges;
QComboBox *modeSelect = nullptr; QComboBox *modeSelect = nullptr;
QStackedWidget *modeDisplay = nullptr; QStackedWidget *modeDisplay = nullptr;
QWidget *labels = nullptr; QWidget *labels = nullptr;
QLabel *currentFPS = nullptr; QLabel *currentFPS = nullptr;
QLabel *timePerFrame = nullptr; QLabel *timePerFrame = nullptr;
QLabel *minLabel = nullptr; QLabel *minLabel = nullptr;
QLabel *maxLabel = nullptr; QLabel *maxLabel = nullptr;
QComboBox *simpleFPS = nullptr; QComboBox *simpleFPS = nullptr;
QComboBox *fpsRange = nullptr; QComboBox *fpsRange = nullptr;
QSpinBox *numEdit = nullptr; QSpinBox *numEdit = nullptr;
QSpinBox *denEdit = nullptr; QSpinBox *denEdit = nullptr;
bool updating = false; bool updating = false;
const char *name = nullptr; const char *name = nullptr;
obs_data_t *settings = nullptr; obs_data_t *settings = nullptr;
QLabel *warningLabel = nullptr; QLabel *warningLabel = nullptr;
OBSFrameRatePropertyWidget() = default; OBSFrameRatePropertyWidget() = default;
}; };
+14 -20
View File
@@ -8,23 +8,18 @@
static inline long long color_to_int(QColor color) static inline long long color_to_int(QColor color)
{ {
auto shift = [&](unsigned val, int shift) auto shift = [&](unsigned val, int shift) {
{
return ((val & 0xff) << shift); return ((val & 0xff) << shift);
}; };
return shift(color.red(), 0) | return shift(color.red(), 0) | shift(color.green(), 8) |
shift(color.green(), 8) | shift(color.blue(), 16) | shift(color.alpha(), 24);
shift(color.blue(), 16) |
shift(color.alpha(), 24);
} }
static inline QColor rgba_to_color(uint32_t rgba) static inline QColor rgba_to_color(uint32_t rgba)
{ {
return QColor::fromRgb(rgba & 0xFF, return QColor::fromRgb(rgba & 0xFF, (rgba >> 8) & 0xFF,
(rgba >> 8) & 0xFF, (rgba >> 16) & 0xFF, (rgba >> 24) & 0xFF);
(rgba >> 16) & 0xFF,
(rgba >> 24) & 0xFF);
} }
OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags) OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
@@ -37,8 +32,7 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
setAttribute(Qt::WA_DontCreateNativeAncestors); setAttribute(Qt::WA_DontCreateNativeAncestors);
setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_NativeWindow);
auto windowVisible = [this] (bool visible) auto windowVisible = [this](bool visible) {
{
if (!visible) if (!visible)
return; return;
@@ -46,12 +40,12 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
CreateDisplay(); CreateDisplay();
} else { } else {
QSize size = GetPixelSize(this); QSize size = GetPixelSize(this);
obs_display_resize(display, size.width(), size.height()); obs_display_resize(display, size.width(),
size.height());
} }
}; };
auto sizeChanged = [this] (QScreen*) auto sizeChanged = [this](QScreen *) {
{
CreateDisplay(); CreateDisplay();
QSize size = GetPixelSize(this); QSize size = GetPixelSize(this);
@@ -89,11 +83,11 @@ void OBSQTDisplay::CreateDisplay()
QSize size = GetPixelSize(this); QSize size = GetPixelSize(this);
gs_init_data info = {}; gs_init_data info = {};
info.cx = size.width(); info.cx = size.width();
info.cy = size.height(); info.cy = size.height();
info.format = GS_RGBA; info.format = GS_RGBA;
info.zsformat = GS_ZS_NONE; info.zsformat = GS_ZS_NONE;
QTToGSWindow(winId(), info.window); QTToGSWindow(winId(), info.window);
+5 -5
View File
@@ -7,9 +7,9 @@
class OBSQTDisplay : public QWidget { class OBSQTDisplay : public QWidget {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor displayBackgroundColor MEMBER backgroundColor Q_PROPERTY(QColor displayBackgroundColor MEMBER backgroundColor READ
READ GetDisplayBackgroundColor GetDisplayBackgroundColor WRITE
WRITE SetDisplayBackgroundColor) SetDisplayBackgroundColor)
OBSDisplay display; OBSDisplay display;
@@ -24,11 +24,11 @@ signals:
public: public:
OBSQTDisplay(QWidget *parent = nullptr, OBSQTDisplay(QWidget *parent = nullptr,
Qt::WindowFlags flags = nullptr); Qt::WindowFlags flags = nullptr);
virtual QPaintEngine *paintEngine() const override; virtual QPaintEngine *paintEngine() const override;
inline obs_display_t *GetDisplay() const {return display;} inline obs_display_t *GetDisplay() const { return display; }
uint32_t backgroundColor = GREY_COLOR_BACKGROUND; uint32_t backgroundColor = GREY_COLOR_BACKGROUND;
+34 -56
View File
@@ -45,20 +45,17 @@ void OBSErrorBox(QWidget *parent, const char *msg, ...)
va_end(args); va_end(args);
} }
QMessageBox::StandardButton OBSMessageBox::question( QMessageBox::StandardButton
QWidget *parent, OBSMessageBox::question(QWidget *parent, const QString &title,
const QString &title, const QString &text,
const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QMessageBox::StandardButton defaultButton)
{ {
QMessageBox mb(QMessageBox::Question, QMessageBox mb(QMessageBox::Question, title, text, buttons, parent);
title, text, buttons,
parent);
mb.setDefaultButton(defaultButton); mb.setDefaultButton(defaultButton);
if (buttons & QMessageBox::Ok) \ if (buttons & QMessageBox::Ok)
mb.setButtonText(QMessageBox::Ok, QTStr("OK")); mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
#define translate_button(x) \ #define translate_button(x) \
if (buttons & QMessageBox::x) \ if (buttons & QMessageBox::x) \
mb.setButtonText(QMessageBox::x, QTStr(#x)); mb.setButtonText(QMessageBox::x, QTStr(#x));
translate_button(Open); translate_button(Open);
@@ -78,41 +75,31 @@ QMessageBox::StandardButton OBSMessageBox::question(
return (QMessageBox::StandardButton)mb.exec(); return (QMessageBox::StandardButton)mb.exec();
} }
void OBSMessageBox::information( void OBSMessageBox::information(QWidget *parent, const QString &title,
QWidget *parent, const QString &text)
const QString &title,
const QString &text)
{ {
QMessageBox mb(QMessageBox::Information, QMessageBox mb(QMessageBox::Information, title, text, QMessageBox::Ok,
title, text, QMessageBox::Ok, parent);
parent);
mb.setButtonText(QMessageBox::Ok, QTStr("OK")); mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
mb.exec(); mb.exec();
} }
void OBSMessageBox::warning( void OBSMessageBox::warning(QWidget *parent, const QString &title,
QWidget *parent, const QString &text, bool enableRichText)
const QString &title,
const QString &text,
bool enableRichText)
{ {
QMessageBox mb(QMessageBox::Warning, QMessageBox mb(QMessageBox::Warning, title, text, QMessageBox::Ok,
title, text, QMessageBox::Ok, parent);
parent);
if (enableRichText) if (enableRichText)
mb.setTextFormat(Qt::RichText); mb.setTextFormat(Qt::RichText);
mb.setButtonText(QMessageBox::Ok, QTStr("OK")); mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
mb.exec(); mb.exec();
} }
void OBSMessageBox::critical( void OBSMessageBox::critical(QWidget *parent, const QString &title,
QWidget *parent, const QString &text)
const QString &title,
const QString &text)
{ {
QMessageBox mb(QMessageBox::Critical, QMessageBox mb(QMessageBox::Critical, title, text, QMessageBox::Ok,
title, text, QMessageBox::Ok, parent);
parent);
mb.setButtonText(QMessageBox::Ok, QTStr("OK")); mb.setButtonText(QMessageBox::Ok, QTStr("OK"));
mb.exec(); mb.exec();
} }
@@ -156,13 +143,13 @@ uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods)
} }
QDataStream &operator<<(QDataStream &out, QDataStream &operator<<(QDataStream &out,
const std::vector<std::shared_ptr<OBSSignal>> &) const std::vector<std::shared_ptr<OBSSignal>> &)
{ {
return out; return out;
} }
QDataStream &operator>>(QDataStream &in, QDataStream &operator>>(QDataStream &in,
std::vector<std::shared_ptr<OBSSignal>> &) std::vector<std::shared_ptr<OBSSignal>> &)
{ {
return in; return in;
} }
@@ -186,7 +173,7 @@ QDataStream &operator>>(QDataStream &in, OBSScene &scene)
QDataStream &operator<<(QDataStream &out, const OBSSceneItem &si) QDataStream &operator<<(QDataStream &out, const OBSSceneItem &si)
{ {
obs_scene_t *scene = obs_sceneitem_get_scene(si); obs_scene_t *scene = obs_sceneitem_get_scene(si);
obs_source_t *source = obs_sceneitem_get_source(si); obs_source_t *source = obs_sceneitem_get_source(si);
return out << QString(obs_source_get_name(obs_scene_get_source(scene))) return out << QString(obs_source_get_name(obs_scene_get_source(scene)))
<< QString(obs_source_get_name(source)); << QString(obs_source_get_name(source));
@@ -234,15 +221,12 @@ void DeleteLayout(QLayout *layout)
class QuickThread : public QThread { class QuickThread : public QThread {
public: public:
explicit inline QuickThread(std::function<void()> func_) explicit inline QuickThread(std::function<void()> func_) : func(func_)
: func(func_) {
{} }
private: private:
virtual void run() override virtual void run() override { func(); }
{
func();
}
std::function<void()> func; std::function<void()> func;
}; };
@@ -258,11 +242,10 @@ void ExecuteFuncSafeBlock(std::function<void()> func)
{ {
QEventLoop eventLoop; QEventLoop eventLoop;
auto wait = [&] () auto wait = [&]() {
{
func(); func();
QMetaObject::invokeMethod(&eventLoop, "quit", QMetaObject::invokeMethod(&eventLoop, "quit",
Qt::QueuedConnection); Qt::QueuedConnection);
}; };
os_atomic_inc_long(&insideEventLoop); os_atomic_inc_long(&insideEventLoop);
@@ -273,10 +256,8 @@ void ExecuteFuncSafeBlock(std::function<void()> func)
os_atomic_dec_long(&insideEventLoop); os_atomic_dec_long(&insideEventLoop);
} }
void ExecuteFuncSafeBlockMsgBox( void ExecuteFuncSafeBlockMsgBox(std::function<void()> func,
std::function<void()> func, const QString &title, const QString &text)
const QString &title,
const QString &text)
{ {
QMessageBox dlg; QMessageBox dlg;
dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowCloseButtonHint); dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowCloseButtonHint);
@@ -284,8 +265,7 @@ void ExecuteFuncSafeBlockMsgBox(
dlg.setText(text); dlg.setText(text);
dlg.setStandardButtons(0); dlg.setStandardButtons(0);
auto wait = [&] () auto wait = [&]() {
{
func(); func();
QMetaObject::invokeMethod(&dlg, "accept", Qt::QueuedConnection); QMetaObject::invokeMethod(&dlg, "accept", Qt::QueuedConnection);
}; };
@@ -305,10 +285,8 @@ void EnableThreadedMessageBoxes(bool enable)
enable_message_boxes = enable; enable_message_boxes = enable;
} }
void ExecThreadedWithoutBlocking( void ExecThreadedWithoutBlocking(std::function<void()> func,
std::function<void()> func, const QString &title, const QString &text)
const QString &title,
const QString &text)
{ {
if (!enable_message_boxes) if (!enable_message_boxes)
ExecuteFuncSafeBlock(func); ExecuteFuncSafeBlock(func);
+24 -36
View File
@@ -38,25 +38,19 @@ struct gs_window;
class OBSMessageBox { class OBSMessageBox {
public: public:
static QMessageBox::StandardButton question( static QMessageBox::StandardButton
QWidget *parent, question(QWidget *parent, const QString &title, const QString &text,
const QString &title, QMessageBox::StandardButtons buttons =
const QString &text, QMessageBox::StandardButtons(QMessageBox::Yes |
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons( QMessageBox::Yes | QMessageBox::No ), QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); QMessageBox::StandardButton defaultButton =
static void information( QMessageBox::NoButton);
QWidget *parent, static void information(QWidget *parent, const QString &title,
const QString &title, const QString &text);
const QString &text); static void warning(QWidget *parent, const QString &title,
static void warning( const QString &text, bool enableRichText = false);
QWidget *parent, static void critical(QWidget *parent, const QString &title,
const QString &title, const QString &text);
const QString &text,
bool enableRichText = false);
static void critical(
QWidget *parent,
const QString &title,
const QString &text);
}; };
void OBSErrorBox(QWidget *parent, const char *msg, ...); void OBSErrorBox(QWidget *parent, const char *msg, ...);
@@ -65,10 +59,11 @@ void QTToGSWindow(WId windowId, gs_window &gswindow);
uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods); uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods);
QDataStream &operator<<(QDataStream &out, QDataStream &
const std::vector<std::shared_ptr<OBSSignal>> &signal_vec); operator<<(QDataStream &out,
const std::vector<std::shared_ptr<OBSSignal>> &signal_vec);
QDataStream &operator>>(QDataStream &in, QDataStream &operator>>(QDataStream &in,
std::vector<std::shared_ptr<OBSSignal>> &signal_vec); std::vector<std::shared_ptr<OBSSignal>> &signal_vec);
QDataStream &operator<<(QDataStream &out, const OBSScene &scene); QDataStream &operator<<(QDataStream &out, const OBSScene &scene);
QDataStream &operator>>(QDataStream &in, OBSScene &scene); QDataStream &operator>>(QDataStream &in, OBSScene &scene);
QDataStream &operator<<(QDataStream &out, const OBSSceneItem &si); QDataStream &operator<<(QDataStream &out, const OBSSceneItem &si);
@@ -77,18 +72,14 @@ QDataStream &operator>>(QDataStream &in, OBSSceneItem &si);
QThread *CreateQThread(std::function<void()> func); QThread *CreateQThread(std::function<void()> func);
void ExecuteFuncSafeBlock(std::function<void()> func); void ExecuteFuncSafeBlock(std::function<void()> func);
void ExecuteFuncSafeBlockMsgBox( void ExecuteFuncSafeBlockMsgBox(std::function<void()> func,
std::function<void()> func, const QString &title, const QString &text);
const QString &title,
const QString &text);
/* allows executing without message boxes if starting up, otherwise with a /* allows executing without message boxes if starting up, otherwise with a
* message box */ * message box */
void EnableThreadedMessageBoxes(bool enable); void EnableThreadedMessageBoxes(bool enable);
void ExecThreadedWithoutBlocking( void ExecThreadedWithoutBlocking(std::function<void()> func,
std::function<void()> func, const QString &title, const QString &text);
const QString &title,
const QString &text);
class SignalBlocker { class SignalBlocker {
QWidget *widget; QWidget *widget;
@@ -100,10 +91,7 @@ public:
blocked = widget->blockSignals(true); blocked = widget->blockSignals(true);
} }
inline ~SignalBlocker() inline ~SignalBlocker() { widget->blockSignals(blocked); }
{
widget->blockSignals(blocked);
}
}; };
void DeleteLayout(QLayout *layout); void DeleteLayout(QLayout *layout);
@@ -111,6 +99,6 @@ void DeleteLayout(QLayout *layout);
static inline Qt::ConnectionType WaitConnection() static inline Qt::ConnectionType WaitConnection()
{ {
return QThread::currentThread() == qApp->thread() return QThread::currentThread() == qApp->thread()
? Qt::DirectConnection ? Qt::DirectConnection
: Qt::BlockingQueuedConnection; : Qt::BlockingQueuedConnection;
} }
+25 -39
View File
@@ -22,7 +22,7 @@
using namespace std; using namespace std;
static auto curl_deleter = [] (CURL *curl) {curl_easy_cleanup(curl);}; static auto curl_deleter = [](CURL *curl) { curl_easy_cleanup(curl); };
using Curl = unique_ptr<CURL, decltype(curl_deleter)>; using Curl = unique_ptr<CURL, decltype(curl_deleter)>;
static size_t string_write(char *ptr, size_t size, size_t nmemb, string &str) static size_t string_write(char *ptr, size_t size, size_t nmemb, string &str)
@@ -53,12 +53,11 @@ void RemoteTextThread::run()
struct curl_slist *header = nullptr; struct curl_slist *header = nullptr;
string str; string str;
header = curl_slist_append(header, header = curl_slist_append(header, versionString.c_str());
versionString.c_str());
if (!contentTypeString.empty()) { if (!contentTypeString.empty()) {
header = curl_slist_append(header, header = curl_slist_append(header,
contentTypeString.c_str()); contentTypeString.c_str());
} }
for (std::string &h : extraHeaders) for (std::string &h : extraHeaders)
@@ -66,18 +65,15 @@ void RemoteTextThread::run()
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, "");
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, header);
header); curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error);
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER,
error);
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION,
string_write); string_write);
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str);
&str);
if (timeoutSec) if (timeoutSec)
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT,
timeoutSec); timeoutSec);
#if LIBCURL_VERSION_NUM >= 0x072400 #if LIBCURL_VERSION_NUM >= 0x072400
// A lot of servers don't yet support ALPN // A lot of servers don't yet support ALPN
@@ -86,7 +82,7 @@ void RemoteTextThread::run()
if (!postData.empty()) { if (!postData.empty()) {
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS,
postData.c_str()); postData.c_str());
} }
code = curl_easy_perform(curl.get()); code = curl_easy_perform(curl.get());
@@ -101,7 +97,7 @@ void RemoteTextThread::run()
} }
static size_t header_write(char *ptr, size_t size, size_t nmemb, static size_t header_write(char *ptr, size_t size, size_t nmemb,
vector<string> &list) vector<string> &list)
{ {
string str; string str;
@@ -118,16 +114,10 @@ static size_t header_write(char *ptr, size_t size, size_t nmemb,
return total; return total;
} }
bool GetRemoteFile( bool GetRemoteFile(const char *url, std::string &str, std::string &error,
const char *url, long *responseCode, const char *contentType,
std::string &str, const char *postData, std::vector<std::string> extraHeaders,
std::string &error, std::string *signature, int timeoutSec)
long *responseCode,
const char *contentType,
const char *postData,
std::vector<std::string> extraHeaders,
std::string *signature,
int timeoutSec)
{ {
vector<string> header_in_list; vector<string> header_in_list;
char error_in[CURL_ERROR_SIZE]; char error_in[CURL_ERROR_SIZE];
@@ -148,12 +138,11 @@ bool GetRemoteFile(
if (curl) { if (curl) {
struct curl_slist *header = nullptr; struct curl_slist *header = nullptr;
header = curl_slist_append(header, header = curl_slist_append(header, versionString.c_str());
versionString.c_str());
if (!contentTypeString.empty()) { if (!contentTypeString.empty()) {
header = curl_slist_append(header, header = curl_slist_append(header,
contentTypeString.c_str()); contentTypeString.c_str());
} }
for (std::string &h : extraHeaders) for (std::string &h : extraHeaders)
@@ -161,24 +150,21 @@ bool GetRemoteFile(
curl_easy_setopt(curl.get(), CURLOPT_URL, url); curl_easy_setopt(curl.get(), CURLOPT_URL, url);
curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, ""); curl_easy_setopt(curl.get(), CURLOPT_ACCEPT_ENCODING, "");
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, header);
header); curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error_in);
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER,
error_in);
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION,
string_write); string_write);
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str);
&str);
if (signature) { if (signature) {
curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION, curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION,
header_write); header_write);
curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA, curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA,
&header_in_list); &header_in_list);
} }
if (timeoutSec) if (timeoutSec)
curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT,
timeoutSec); timeoutSec);
#if LIBCURL_VERSION_NUM >= 0x072400 #if LIBCURL_VERSION_NUM >= 0x072400
// A lot of servers don't yet support ALPN // A lot of servers don't yet support ALPN
@@ -187,13 +173,13 @@ bool GetRemoteFile(
if (postData) { if (postData) {
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS,
postData); postData);
} }
code = curl_easy_perform(curl.get()); code = curl_easy_perform(curl.get());
if (responseCode) if (responseCode)
curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE,
responseCode); responseCode);
if (code != CURLE_OK) { if (code != CURLE_OK) {
error = error_in; error = error_in;
+25 -29
View File
@@ -38,38 +38,34 @@ signals:
void Result(const QString &text, const QString &error); void Result(const QString &text, const QString &error);
public: public:
inline RemoteTextThread( inline RemoteTextThread(std::string url_,
std::string url_, std::string contentType_ = std::string(),
std::string contentType_ = std::string(), std::string postData_ = std::string(),
std::string postData_ = std::string(), int timeoutSec_ = 0)
int timeoutSec_ = 0) : url(url_),
: url (url_), contentType(contentType_),
contentType (contentType_), postData(postData_),
postData (postData_), timeoutSec(timeoutSec_)
timeoutSec (timeoutSec_) {
{} }
inline RemoteTextThread( inline RemoteTextThread(std::string url_,
std::string url_, std::vector<std::string> &&extraHeaders_,
std::vector<std::string> &&extraHeaders_, std::string contentType_ = std::string(),
std::string contentType_ = std::string(), std::string postData_ = std::string(),
std::string postData_ = std::string(), int timeoutSec_ = 0)
int timeoutSec_ = 0) : url(url_),
: url (url_), contentType(contentType_),
contentType (contentType_), postData(postData_),
postData (postData_), extraHeaders(std::move(extraHeaders_)),
extraHeaders (std::move(extraHeaders_)), timeoutSec(timeoutSec_)
timeoutSec (timeoutSec_) {
{} }
}; };
bool GetRemoteFile( bool GetRemoteFile(
const char *url, const char *url, std::string &str, std::string &error,
std::string &str, long *responseCode = nullptr, const char *contentType = nullptr,
std::string &error,
long *responseCode = nullptr,
const char *contentType = nullptr,
const char *postData = nullptr, const char *postData = nullptr,
std::vector<std::string> extraHeaders = std::vector<std::string>(), std::vector<std::string> extraHeaders = std::vector<std::string>(),
std::string *signature = nullptr, std::string *signature = nullptr, int timeoutSec = 0);
int timeoutSec = 0);
+8 -7
View File
@@ -1,19 +1,20 @@
#include "slider-absoluteset-style.hpp" #include "slider-absoluteset-style.hpp"
SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(const QString& baseStyle) SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(const QString &baseStyle)
:QProxyStyle(baseStyle) : QProxyStyle(baseStyle)
{ {
} }
SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(QStyle* baseStyle) SliderAbsoluteSetStyle::SliderAbsoluteSetStyle(QStyle *baseStyle)
:QProxyStyle(baseStyle) : QProxyStyle(baseStyle)
{ {
} }
int SliderAbsoluteSetStyle::styleHint(QStyle::StyleHint hint, int SliderAbsoluteSetStyle::styleHint(QStyle::StyleHint hint,
const QStyleOption* option = 0, const QWidget* widget = 0, const QStyleOption *option = 0,
QStyleHintReturn* returnData = 0) const const QWidget *widget = 0,
QStyleHintReturn *returnData = 0) const
{ {
if(hint == QStyle::SH_Slider_AbsoluteSetButtons) if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
return (Qt::LeftButton | Qt::MidButton); return (Qt::LeftButton | Qt::MidButton);
return QProxyStyle::styleHint(hint, option, widget, returnData); return QProxyStyle::styleHint(hint, option, widget, returnData);
} }
+6 -6
View File
@@ -2,11 +2,11 @@
#include <QProxyStyle> #include <QProxyStyle>
class SliderAbsoluteSetStyle : public QProxyStyle class SliderAbsoluteSetStyle : public QProxyStyle {
{
public: public:
SliderAbsoluteSetStyle(const QString& baseStyle); SliderAbsoluteSetStyle(const QString &baseStyle);
SliderAbsoluteSetStyle(QStyle* baseStyle = Q_NULLPTR); SliderAbsoluteSetStyle(QStyle *baseStyle = Q_NULLPTR);
int styleHint(QStyle::StyleHint hint, const QStyleOption* option, int styleHint(QStyle::StyleHint hint, const QStyleOption *option,
const QWidget* widget, QStyleHintReturn* returnData) const; const QWidget *widget,
QStyleHintReturn *returnData) const;
}; };
+1 -1
View File
@@ -6,7 +6,7 @@ SliderIgnoreScroll::SliderIgnoreScroll(QWidget *parent) : QSlider(parent)
} }
SliderIgnoreScroll::SliderIgnoreScroll(Qt::Orientation orientation, SliderIgnoreScroll::SliderIgnoreScroll(Qt::Orientation orientation,
QWidget *parent) QWidget *parent)
: QSlider(parent) : QSlider(parent)
{ {
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
+2 -1
View File
@@ -9,7 +9,8 @@ class SliderIgnoreScroll : public QSlider {
public: public:
SliderIgnoreScroll(QWidget *parent = nullptr); SliderIgnoreScroll(QWidget *parent = nullptr);
SliderIgnoreScroll(Qt::Orientation orientation, QWidget *parent = nullptr); SliderIgnoreScroll(Qt::Orientation orientation,
QWidget *parent = nullptr);
protected: protected:
virtual void wheelEvent(QWheelEvent *event) override; virtual void wheelEvent(QWheelEvent *event) override;
+3 -3
View File
@@ -19,7 +19,7 @@
void OBSSourceLabel::SourceRenamed(void *data, calldata_t *params) void OBSSourceLabel::SourceRenamed(void *data, calldata_t *params)
{ {
auto &label = *static_cast<OBSSourceLabel*>(data); auto &label = *static_cast<OBSSourceLabel *>(data);
const char *name = calldata_string(params, "new_name"); const char *name = calldata_string(params, "new_name");
label.setText(name); label.setText(name);
@@ -29,13 +29,13 @@ void OBSSourceLabel::SourceRenamed(void *data, calldata_t *params)
void OBSSourceLabel::SourceRemoved(void *data, calldata_t *) void OBSSourceLabel::SourceRemoved(void *data, calldata_t *)
{ {
auto &label = *static_cast<OBSSourceLabel*>(data); auto &label = *static_cast<OBSSourceLabel *>(data);
emit label.Removed(); emit label.Removed();
} }
void OBSSourceLabel::SourceDestroyed(void *data, calldata_t *) void OBSSourceLabel::SourceDestroyed(void *data, calldata_t *)
{ {
auto &label = *static_cast<OBSSourceLabel*>(data); auto &label = *static_cast<OBSSourceLabel *>(data);
emit label.Destroyed(); emit label.Destroyed();
label.destroyedSignal.Disconnect(); label.destroyedSignal.Disconnect();
+6 -5
View File
@@ -28,17 +28,18 @@ public:
OBSSignal removedSignal; OBSSignal removedSignal;
OBSSignal destroyedSignal; OBSSignal destroyedSignal;
OBSSourceLabel(const obs_source_t *source, QWidget *parent=nullptr, OBSSourceLabel(const obs_source_t *source, QWidget *parent = nullptr,
Qt::WindowFlags f=0) Qt::WindowFlags f = 0)
: QLabel(obs_source_get_name(source), parent, f), : QLabel(obs_source_get_name(source), parent, f),
renamedSignal(obs_source_get_signal_handler(source), "rename", renamedSignal(obs_source_get_signal_handler(source), "rename",
&OBSSourceLabel::SourceRenamed, this), &OBSSourceLabel::SourceRenamed, this),
removedSignal(obs_source_get_signal_handler(source), "remove", removedSignal(obs_source_get_signal_handler(source), "remove",
&OBSSourceLabel::SourceRemoved, this), &OBSSourceLabel::SourceRemoved, this),
destroyedSignal(obs_source_get_signal_handler(source), destroyedSignal(obs_source_get_signal_handler(source),
"destroy", &OBSSourceLabel::SourceDestroyed, "destroy", &OBSSourceLabel::SourceDestroyed,
this) this)
{} {
}
protected: protected:
static void SourceRenamed(void *data, calldata_t *params); static void SourceRenamed(void *data, calldata_t *params);
+118 -134
View File
@@ -25,15 +25,14 @@
static inline OBSScene GetCurrentScene() static inline OBSScene GetCurrentScene()
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
return main->GetCurrentScene(); return main->GetCurrentScene();
} }
/* ========================================================================= */ /* ========================================================================= */
SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_)
: tree (tree_), : tree(tree_), sceneitem(sceneitem_)
sceneitem (sceneitem_)
{ {
setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TranslucentBackground);
setMouseTracking(true); setMouseTracking(true);
@@ -98,14 +97,12 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_)
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
auto setItemVisible = [this] (bool checked) auto setItemVisible = [this](bool checked) {
{
SignalBlocker sourcesSignalBlocker(this); SignalBlocker sourcesSignalBlocker(this);
obs_sceneitem_set_visible(sceneitem, checked); obs_sceneitem_set_visible(sceneitem, checked);
}; };
auto setItemLocked = [this] (bool checked) auto setItemLocked = [this](bool checked) {
{
SignalBlocker sourcesSignalBlocker(this); SignalBlocker sourcesSignalBlocker(this);
obs_sceneitem_set_locked(sceneitem, checked); obs_sceneitem_set_locked(sceneitem, checked);
}; };
@@ -150,59 +147,58 @@ void SourceTreeItem::ReconnectSignals()
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
auto removeItem = [] (void *data, calldata_t *cd) auto removeItem = [](void *data, calldata_t *cd) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
obs_sceneitem_t *curItem = obs_sceneitem_t *curItem =
(obs_sceneitem_t*)calldata_ptr(cd, "item"); (obs_sceneitem_t *)calldata_ptr(cd, "item");
if (curItem == this_->sceneitem) { if (curItem == this_->sceneitem) {
QMetaObject::invokeMethod(this_->tree, QMetaObject::invokeMethod(this_->tree, "Remove",
"Remove", Q_ARG(OBSSceneItem, curItem));
Q_ARG(OBSSceneItem, curItem));
curItem = nullptr; curItem = nullptr;
} }
if (!curItem) if (!curItem)
QMetaObject::invokeMethod(this_, "Clear"); QMetaObject::invokeMethod(this_, "Clear");
}; };
auto itemVisible = [] (void *data, calldata_t *cd) auto itemVisible = [](void *data, calldata_t *cd) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
obs_sceneitem_t *curItem = obs_sceneitem_t *curItem =
(obs_sceneitem_t*)calldata_ptr(cd, "item"); (obs_sceneitem_t *)calldata_ptr(cd, "item");
bool visible = calldata_bool(cd, "visible"); bool visible = calldata_bool(cd, "visible");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem)
QMetaObject::invokeMethod(this_, "VisibilityChanged", QMetaObject::invokeMethod(this_, "VisibilityChanged",
Q_ARG(bool, visible)); Q_ARG(bool, visible));
}; };
auto itemLocked = [] (void *data, calldata_t *cd) auto itemLocked = [](void *data, calldata_t *cd) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
obs_sceneitem_t *curItem = obs_sceneitem_t *curItem =
(obs_sceneitem_t*)calldata_ptr(cd, "item"); (obs_sceneitem_t *)calldata_ptr(cd, "item");
bool locked = calldata_bool(cd, "locked"); bool locked = calldata_bool(cd, "locked");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem)
QMetaObject::invokeMethod(this_, "LockedChanged", QMetaObject::invokeMethod(this_, "LockedChanged",
Q_ARG(bool, locked)); Q_ARG(bool, locked));
}; };
auto itemDeselect = [] (void *data, calldata_t *cd) auto itemDeselect = [](void *data, calldata_t *cd) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
obs_sceneitem_t *curItem = obs_sceneitem_t *curItem =
(obs_sceneitem_t*)calldata_ptr(cd, "item"); (obs_sceneitem_t *)calldata_ptr(cd, "item");
if (curItem == this_->sceneitem) if (curItem == this_->sceneitem)
QMetaObject::invokeMethod(this_, "Deselect"); QMetaObject::invokeMethod(this_, "Deselect");
}; };
auto reorderGroup = [] (void *data, calldata_t*) auto reorderGroup = [](void *data, calldata_t *) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
QMetaObject::invokeMethod(this_->tree, "ReorderItems"); QMetaObject::invokeMethod(this_->tree, "ReorderItems");
}; };
@@ -220,27 +216,27 @@ void SourceTreeItem::ReconnectSignals()
signal = obs_source_get_signal_handler(source); signal = obs_source_get_signal_handler(source);
groupReorderSignal.Connect(signal, "reorder", reorderGroup, groupReorderSignal.Connect(signal, "reorder", reorderGroup,
this); this);
} }
if (scene != GetCurrentScene()) if (scene != GetCurrentScene())
deselectSignal.Connect(signal, "item_deselect", itemDeselect, deselectSignal.Connect(signal, "item_deselect", itemDeselect,
this); this);
/* --------------------------------------------------------- */ /* --------------------------------------------------------- */
auto renamed = [] (void *data, calldata_t *cd) auto renamed = [](void *data, calldata_t *cd) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
const char *name = calldata_string(cd, "new_name"); const char *name = calldata_string(cd, "new_name");
QMetaObject::invokeMethod(this_, "Renamed", QMetaObject::invokeMethod(this_, "Renamed",
Q_ARG(QString, QT_UTF8(name))); Q_ARG(QString, QT_UTF8(name)));
}; };
auto removeSource = [] (void *data, calldata_t *) auto removeSource = [](void *data, calldata_t *) {
{ SourceTreeItem *this_ =
SourceTreeItem *this_ = reinterpret_cast<SourceTreeItem*>(data); reinterpret_cast<SourceTreeItem *>(data);
this_->DisconnectSignals(); this_->DisconnectSignals();
this_->sceneitem = nullptr; this_->sceneitem = nullptr;
}; };
@@ -260,7 +256,7 @@ void SourceTreeItem::mouseDoubleClickEvent(QMouseEvent *event)
} else { } else {
obs_source_t *source = obs_sceneitem_get_source(sceneitem); obs_source_t *source = obs_sceneitem_get_source(sceneitem);
OBSBasic *main = OBSBasic *main =
reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
if (source) { if (source) {
main->CreatePropertiesWindow(source); main->CreatePropertiesWindow(source);
} }
@@ -289,7 +285,7 @@ void SourceTreeItem::ExitEditMode(bool save)
if (!editor) if (!editor)
return; return;
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
std::string newName = QT_TO_UTF8(editor->text()); std::string newName = QT_TO_UTF8(editor->text());
@@ -308,9 +304,8 @@ void SourceTreeItem::ExitEditMode(bool save)
return; return;
if (newName.empty()) { if (newName.empty()) {
OBSMessageBox::information(main, OBSMessageBox::information(main, QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Text"));
QTStr("NoNameEntered.Text"));
return; return;
} }
@@ -324,15 +319,13 @@ void SourceTreeItem::ExitEditMode(bool save)
/* ----------------------------------------- */ /* ----------------------------------------- */
/* check for existing source */ /* check for existing source */
obs_source_t *existingSource = obs_source_t *existingSource = obs_get_source_by_name(newName.c_str());
obs_get_source_by_name(newName.c_str());
obs_source_release(existingSource); obs_source_release(existingSource);
bool exists = !!existingSource; bool exists = !!existingSource;
if (exists) { if (exists) {
OBSMessageBox::information(main, OBSMessageBox::information(main, QTStr("NameExists.Title"),
QTStr("NameExists.Title"), QTStr("NameExists.Text"));
QTStr("NameExists.Text"));
return; return;
} }
@@ -355,22 +348,22 @@ bool SourceTreeItem::eventFilter(QObject *object, QEvent *event)
switch (keyEvent->key()) { switch (keyEvent->key()) {
case Qt::Key_Escape: case Qt::Key_Escape:
QMetaObject::invokeMethod(this, "ExitEditMode", QMetaObject::invokeMethod(this, "ExitEditMode",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(bool, false)); Q_ARG(bool, false));
return true; return true;
case Qt::Key_Tab: case Qt::Key_Tab:
case Qt::Key_Backtab: case Qt::Key_Backtab:
case Qt::Key_Enter: case Qt::Key_Enter:
case Qt::Key_Return: case Qt::Key_Return:
QMetaObject::invokeMethod(this, "ExitEditMode", QMetaObject::invokeMethod(this, "ExitEditMode",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(bool, true)); Q_ARG(bool, true));
return true; return true;
} }
} else if (event->type() == QEvent::FocusOut) { } else if (event->type() == QEvent::FocusOut) {
QMetaObject::invokeMethod(this, "ExitEditMode", QMetaObject::invokeMethod(this, "ExitEditMode",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(bool, true)); Q_ARG(bool, true));
return true; return true;
} }
@@ -405,14 +398,14 @@ void SourceTreeItem::Update(bool force)
if (obs_sceneitem_is_group(sceneitem)) { if (obs_sceneitem_is_group(sceneitem)) {
newType = Type::Group; newType = Type::Group;
/* ------------------------------------------------- */ /* ------------------------------------------------- */
/* if it's a group sub-item */ /* if it's a group sub-item */
} else if (itemScene != scene) { } else if (itemScene != scene) {
newType = Type::SubItem; newType = Type::SubItem;
/* ------------------------------------------------- */ /* ------------------------------------------------- */
/* if it's a regular item */ /* if it's a regular item */
} else { } else {
newType = Type::Item; newType = Type::Item;
@@ -448,9 +441,8 @@ void SourceTreeItem::Update(bool force)
} else if (type == Type::Group) { } else if (type == Type::Group) {
expand = new SourceTreeSubItemCheckBox(); expand = new SourceTreeSubItemCheckBox();
expand->setSizePolicy( expand->setSizePolicy(QSizePolicy::Maximum,
QSizePolicy::Maximum, QSizePolicy::Maximum);
QSizePolicy::Maximum);
expand->setMaximumSize(10, 16); expand->setMaximumSize(10, 16);
expand->setMinimumSize(10, 0); expand->setMinimumSize(10, 0);
#ifdef __APPLE__ #ifdef __APPLE__
@@ -458,14 +450,15 @@ void SourceTreeItem::Update(bool force)
#endif #endif
boxLayout->insertWidget(0, expand); boxLayout->insertWidget(0, expand);
obs_data_t *data = obs_sceneitem_get_private_settings(sceneitem); obs_data_t *data =
obs_sceneitem_get_private_settings(sceneitem);
expand->blockSignals(true); expand->blockSignals(true);
expand->setChecked(obs_data_get_bool(data, "collapsed")); expand->setChecked(obs_data_get_bool(data, "collapsed"));
expand->blockSignals(false); expand->blockSignals(false);
obs_data_release(data); obs_data_release(data);
connect(expand, &QPushButton::toggled, connect(expand, &QPushButton::toggled, this,
this, &SourceTreeItem::ExpandClicked); &SourceTreeItem::ExpandClicked);
} else { } else {
spacer = new QSpacerItem(3, 1); spacer = new QSpacerItem(3, 1);
@@ -517,10 +510,10 @@ void SourceTreeModel::Clear()
hasGroups = false; hasGroups = false;
} }
static bool enumItem(obs_scene_t*, obs_sceneitem_t *item, void *ptr) static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{ {
QVector<OBSSceneItem> &items = QVector<OBSSceneItem> &items =
*reinterpret_cast<QVector<OBSSceneItem>*>(ptr); *reinterpret_cast<QVector<OBSSceneItem> *>(ptr);
if (obs_sceneitem_is_group(item)) { if (obs_sceneitem_is_group(item)) {
obs_data_t *data = obs_sceneitem_get_private_settings(item); obs_data_t *data = obs_sceneitem_get_private_settings(item);
@@ -556,14 +549,15 @@ void SourceTreeModel::SceneChanged()
bool select = obs_sceneitem_selected(items[i]); bool select = obs_sceneitem_selected(items[i]);
QModelIndex index = createIndex(i, 0); QModelIndex index = createIndex(i, 0);
st->selectionModel()->select(index, select st->selectionModel()->select(
? QItemSelectionModel::Select index, select ? QItemSelectionModel::Select
: QItemSelectionModel::Deselect); : QItemSelectionModel::Deselect);
} }
} }
/* moves a scene item index (blame linux distros for using older Qt builds) */ /* moves a scene item index (blame linux distros for using older Qt builds) */
static inline void MoveItem(QVector<OBSSceneItem> &items, int oldIdx, int newIdx) static inline void MoveItem(QVector<OBSSceneItem> &items, int oldIdx,
int newIdx)
{ {
OBSSceneItem item = items[oldIdx]; OBSSceneItem item = items[oldIdx];
items.remove(oldIdx); items.remove(oldIdx);
@@ -637,7 +631,7 @@ void SourceTreeModel::ReorderItems()
/* move items */ /* move items */
beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1, beginMoveRows(QModelIndex(), idx1Old, idx1Old + count - 1,
QModelIndex(), idx1New + count); QModelIndex(), idx1New + count);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
int to = idx1New + count; int to = idx1New + count;
if (to > idx1Old) if (to > idx1Old)
@@ -709,8 +703,7 @@ OBSSceneItem SourceTreeModel::Get(int idx)
} }
SourceTreeModel::SourceTreeModel(SourceTree *st_) SourceTreeModel::SourceTreeModel(SourceTree *st_)
: QAbstractListModel (st_), : QAbstractListModel(st_), st(st_)
st (st_)
{ {
obs_frontend_add_event_callback(OBSFrontendEvent, this); obs_frontend_add_event_callback(OBSFrontendEvent, this);
} }
@@ -744,8 +737,7 @@ Qt::ItemFlags SourceTreeModel::flags(const QModelIndex &index) const
obs_sceneitem_t *item = items[index.row()]; obs_sceneitem_t *item = items[index.row()];
bool is_group = obs_sceneitem_is_group(item); bool is_group = obs_sceneitem_is_group(item);
return QAbstractListModel::flags(index) | return QAbstractListModel::flags(index) | Qt::ItemIsEditable |
Qt::ItemIsEditable |
Qt::ItemIsDragEnabled | Qt::ItemIsDragEnabled |
(is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags); (is_group ? Qt::ItemIsDropEnabled : Qt::NoItemFlags);
} }
@@ -775,8 +767,8 @@ QString SourceTreeModel::GetNewGroupName()
void SourceTreeModel::AddGroup() void SourceTreeModel::AddGroup()
{ {
QString name = GetNewGroupName(); QString name = GetNewGroupName();
obs_sceneitem_t *group = obs_scene_add_group(GetCurrentScene(), obs_sceneitem_t *group =
QT_TO_UTF8(name)); obs_scene_add_group(GetCurrentScene(), QT_TO_UTF8(name));
if (!group) if (!group)
return; return;
@@ -788,7 +780,7 @@ void SourceTreeModel::AddGroup()
UpdateGroupState(true); UpdateGroupState(true);
QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection, QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection,
Q_ARG(int, 0)); Q_ARG(int, 0));
} }
void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices) void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
@@ -807,8 +799,7 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
} }
obs_sceneitem_t *item = obs_scene_insert_group( obs_sceneitem_t *item = obs_scene_insert_group(
scene, QT_TO_UTF8(name), scene, QT_TO_UTF8(name), item_order.data(), item_order.size());
item_order.data(), item_order.size());
if (!item) { if (!item) {
return; return;
} }
@@ -827,7 +818,7 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
int toIdx = newIdx + i + 1; int toIdx = newIdx + i + 1;
if (fromIdx != toIdx) { if (fromIdx != toIdx) {
beginMoveRows(QModelIndex(), fromIdx, fromIdx, beginMoveRows(QModelIndex(), fromIdx, fromIdx,
QModelIndex(), toIdx); QModelIndex(), toIdx);
MoveItem(items, fromIdx, toIdx); MoveItem(items, fromIdx, toIdx);
endMoveRows(); endMoveRows();
} }
@@ -839,7 +830,7 @@ void SourceTreeModel::GroupSelectedItems(QModelIndexList &indices)
obs_sceneitem_select(item, true); obs_sceneitem_select(item, true);
QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection, QMetaObject::invokeMethod(st, "Edit", Qt::QueuedConnection,
Q_ARG(int, newIdx)); Q_ARG(int, newIdx));
} }
void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices) void SourceTreeModel::UngroupSelectedGroups(QModelIndexList &indices)
@@ -929,20 +920,20 @@ SourceTree::SourceTree(QWidget *parent_) : QListView(parent_)
SourceTreeModel *stm_ = new SourceTreeModel(this); SourceTreeModel *stm_ = new SourceTreeModel(this);
setModel(stm_); setModel(stm_);
setStyleSheet(QString( setStyleSheet(QString(
"*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" \ "*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}"
"*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" \ "*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}"
"*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" \ "*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}"
"*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" \ "*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}"
"*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" \ "*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}"
"*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" \ "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}"
"*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" \ "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}"
"*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}")); "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}"));
setMouseTracking(true); setMouseTracking(true);
UpdateNoSourcesMessage(); UpdateNoSourcesMessage();
connect(App(), &OBSApp::StyleChanged, connect(App(), &OBSApp::StyleChanged, this,
this, &SourceTree::UpdateNoSourcesMessage); &SourceTree::UpdateNoSourcesMessage);
} }
void SourceTree::ResetWidgets() void SourceTree::ResetWidgets()
@@ -994,9 +985,9 @@ void SourceTree::SelectItem(obs_sceneitem_t *sceneitem, bool select)
QModelIndex index = stm->createIndex(i, 0); QModelIndex index = stm->createIndex(i, 0);
if (index.isValid()) if (index.isValid())
selectionModel()->select(index, select selectionModel()->select(
? QItemSelectionModel::Select index, select ? QItemSelectionModel::Select
: QItemSelectionModel::Deselect); : QItemSelectionModel::Deselect);
} }
Q_DECLARE_METATYPE(OBSSceneItem); Q_DECLARE_METATYPE(OBSSceneItem);
@@ -1040,9 +1031,9 @@ void SourceTree::dropEvent(QDropEvent *event)
obs_sceneitem_t *dropItem = items[row]; /* item being dropped on */ obs_sceneitem_t *dropItem = items[row]; /* item being dropped on */
bool itemIsGroup = obs_sceneitem_is_group(dropItem); bool itemIsGroup = obs_sceneitem_is_group(dropItem);
obs_sceneitem_t *dropGroup = itemIsGroup obs_sceneitem_t *dropGroup =
? dropItem itemIsGroup ? dropItem
: obs_sceneitem_get_group(scene, dropItem); : obs_sceneitem_get_group(scene, dropItem);
/* not a group if moving above the group */ /* not a group if moving above the group */
if (indicator == QAbstractItemView::AboveItem && itemIsGroup) if (indicator == QAbstractItemView::AboveItem && itemIsGroup)
@@ -1056,7 +1047,8 @@ void SourceTree::dropEvent(QDropEvent *event)
bool dropOnCollapsed = false; bool dropOnCollapsed = false;
if (dropGroup) { if (dropGroup) {
obs_data_t *data = obs_sceneitem_get_private_settings(dropGroup); obs_data_t *data =
obs_sceneitem_get_private_settings(dropGroup);
dropOnCollapsed = obs_data_get_bool(data, "collapsed"); dropOnCollapsed = obs_data_get_bool(data, "collapsed");
obs_data_release(data); obs_data_release(data);
} }
@@ -1086,9 +1078,8 @@ void SourceTree::dropEvent(QDropEvent *event)
/* if dropping a group, detect if it's */ /* if dropping a group, detect if it's */
/* below another group */ /* below another group */
obs_sceneitem_t *itemBelow = row == stm->items.count() obs_sceneitem_t *itemBelow =
? nullptr row == stm->items.count() ? nullptr : stm->items[row];
: stm->items[row];
if (hasGroups) { if (hasGroups) {
if (!itemBelow || if (!itemBelow ||
obs_sceneitem_get_group(scene, itemBelow) != dropGroup) { obs_sceneitem_get_group(scene, itemBelow) != dropGroup) {
@@ -1131,8 +1122,8 @@ void SourceTree::dropEvent(QDropEvent *event)
for (int j = items.size() - 1; j >= 0; j--) { for (int j = items.size() - 1; j >= 0; j--) {
obs_sceneitem_t *subitem = items[j]; obs_sceneitem_t *subitem = items[j];
obs_sceneitem_t *subitemGroup = obs_sceneitem_t *subitemGroup =
obs_sceneitem_get_group(scene, obs_sceneitem_get_group(
subitem); scene, subitem);
if (subitemGroup == item) { if (subitemGroup == item) {
QModelIndex idx = QModelIndex idx =
@@ -1167,7 +1158,7 @@ void SourceTree::dropEvent(QDropEvent *event)
if (itemTo != from) { if (itemTo != from) {
stm->beginMoveRows(QModelIndex(), from, from, stm->beginMoveRows(QModelIndex(), from, from,
QModelIndex(), to); QModelIndex(), to);
MoveItem(items, from, itemTo); MoveItem(items, from, itemTo);
stm->endMoveRows(); stm->endMoveRows();
} }
@@ -1186,8 +1177,7 @@ void SourceTree::dropEvent(QDropEvent *event)
obs_sceneitem_t *lastGroup = nullptr; obs_sceneitem_t *lastGroup = nullptr;
int insertCollapsedIdx = 0; int insertCollapsedIdx = 0;
auto insertCollapsed = [&] (obs_sceneitem_t *item) auto insertCollapsed = [&](obs_sceneitem_t *item) {
{
struct obs_sceneitem_order_info info; struct obs_sceneitem_order_info info;
info.group = lastGroup; info.group = lastGroup;
info.item = item; info.item = item;
@@ -1197,25 +1187,23 @@ void SourceTree::dropEvent(QDropEvent *event)
using insertCollapsed_t = decltype(insertCollapsed); using insertCollapsed_t = decltype(insertCollapsed);
auto preInsertCollapsed = [] (obs_scene_t *, obs_sceneitem_t *item, auto preInsertCollapsed = [](obs_scene_t *, obs_sceneitem_t *item,
void *param) void *param) {
{
(*reinterpret_cast<insertCollapsed_t *>(param))(item); (*reinterpret_cast<insertCollapsed_t *>(param))(item);
return true; return true;
}; };
auto insertLastGroup = [&] () auto insertLastGroup = [&]() {
{ obs_data_t *data =
obs_data_t *data = obs_sceneitem_get_private_settings(lastGroup); obs_sceneitem_get_private_settings(lastGroup);
bool collapsed = obs_data_get_bool(data, "collapsed"); bool collapsed = obs_data_get_bool(data, "collapsed");
obs_data_release(data); obs_data_release(data);
if (collapsed) { if (collapsed) {
insertCollapsedIdx = 0; insertCollapsedIdx = 0;
obs_sceneitem_group_enum_items( obs_sceneitem_group_enum_items(lastGroup,
lastGroup, preInsertCollapsed,
preInsertCollapsed, &insertCollapsed);
&insertCollapsed);
} }
struct obs_sceneitem_order_info info; struct obs_sceneitem_order_info info;
@@ -1224,8 +1212,7 @@ void SourceTree::dropEvent(QDropEvent *event)
orderList.insert(0, info); orderList.insert(0, info);
}; };
auto updateScene = [&] () auto updateScene = [&]() {
{
struct obs_sceneitem_order_info info; struct obs_sceneitem_order_info info;
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
@@ -1260,14 +1247,13 @@ void SourceTree::dropEvent(QDropEvent *event)
insertLastGroup(); insertLastGroup();
} }
obs_scene_reorder_items2(scene, obs_scene_reorder_items2(scene, orderList.data(),
orderList.data(), orderList.size()); orderList.size());
}; };
using updateScene_t = decltype(updateScene); using updateScene_t = decltype(updateScene);
auto preUpdateScene = [] (void *data, obs_scene_t *) auto preUpdateScene = [](void *data, obs_scene_t *) {
{
(*reinterpret_cast<updateScene_t *>(data))(); (*reinterpret_cast<updateScene_t *>(data))();
}; };
@@ -1314,9 +1300,8 @@ void SourceTree::leaveEvent(QEvent *event)
QListView::leaveEvent(event); QListView::leaveEvent(event);
} }
void SourceTree::selectionChanged( void SourceTree::selectionChanged(const QItemSelection &selected,
const QItemSelection &selected, const QItemSelection &deselected)
const QItemSelection &deselected)
{ {
{ {
SignalBlocker sourcesSignalBlocker(this); SignalBlocker sourcesSignalBlocker(this);
@@ -1425,7 +1410,7 @@ bool SourceTree::GroupedItemsSelected() const
void SourceTree::Remove(OBSSceneItem item) void SourceTree::Remove(OBSSceneItem item)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
GetStm()->Remove(item); GetStm()->Remove(item);
main->SaveProject(); main->SaveProject();
@@ -1434,9 +1419,9 @@ void SourceTree::Remove(OBSSceneItem item)
obs_source_t *sceneSource = obs_scene_get_source(scene); obs_source_t *sceneSource = obs_scene_get_source(scene);
obs_source_t *itemSource = obs_sceneitem_get_source(item); obs_source_t *itemSource = obs_sceneitem_get_source(item);
blog(LOG_INFO, "User Removed source '%s' (%s) from scene '%s'", blog(LOG_INFO, "User Removed source '%s' (%s) from scene '%s'",
obs_source_get_name(itemSource), obs_source_get_name(itemSource),
obs_source_get_id(itemSource), obs_source_get_id(itemSource),
obs_source_get_name(sceneSource)); obs_source_get_name(sceneSource));
} }
} }
@@ -1465,9 +1450,8 @@ void SourceTree::UpdateNoSourcesMessage()
QColor color = palette().text().color(); QColor color = palette().text().color();
bool lightTheme = (color.redF() < 0.5); bool lightTheme = (color.redF() < 0.5);
QString file = lightTheme QString file = lightTheme ? ":res/images/no_sources.svg"
? ":res/images/no_sources.svg" : darkPath.c_str();
: darkPath.c_str();
iconNoSources.load(file); iconNoSources.load(file);
QTextOption opt(Qt::AlignHCenter); QTextOption opt(Qt::AlignHCenter);
+12 -9
View File
@@ -72,7 +72,7 @@ private:
OBSSignal renameSignal; OBSSignal renameSignal;
OBSSignal removeSignal; OBSSignal removeSignal;
virtual void paintEvent(QPaintEvent* event) override; virtual void paintEvent(QPaintEvent *event) override;
private slots: private slots:
void Clear(); void Clear();
@@ -123,7 +123,8 @@ public:
~SourceTreeModel(); ~SourceTreeModel();
virtual int rowCount(const QModelIndex &parent) const override; virtual int rowCount(const QModelIndex &parent) const override;
virtual QVariant data(const QModelIndex &index, int role) const override; virtual QVariant data(const QModelIndex &index,
int role) const override;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override; virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual Qt::DropActions supportedDropActions() const override; virtual Qt::DropActions supportedDropActions() const override;
@@ -161,12 +162,12 @@ public:
explicit SourceTree(QWidget *parent = nullptr); explicit SourceTree(QWidget *parent = nullptr);
inline bool IgnoreReorder() const {return ignoreReorder;} inline bool IgnoreReorder() const { return ignoreReorder; }
inline void Clear() {GetStm()->Clear();} inline void Clear() { GetStm()->Clear(); }
inline void Add(obs_sceneitem_t *item) {GetStm()->Add(item);} inline void Add(obs_sceneitem_t *item) { GetStm()->Add(item); }
inline OBSSceneItem Get(int idx) {return GetStm()->Get(idx);} inline OBSSceneItem Get(int idx) { return GetStm()->Get(idx); }
inline QString GetNewGroupName() {return GetStm()->GetNewGroupName();} inline QString GetNewGroupName() { return GetStm()->GetNewGroupName(); }
void SelectItem(obs_sceneitem_t *sceneitem, bool select); void SelectItem(obs_sceneitem_t *sceneitem, bool select);
@@ -175,7 +176,7 @@ public:
bool GroupedItemsSelected() const; bool GroupedItemsSelected() const;
public slots: public slots:
inline void ReorderItems() {GetStm()->ReorderItems();} inline void ReorderItems() { GetStm()->ReorderItems(); }
void Remove(OBSSceneItem item); void Remove(OBSSceneItem item);
void GroupSelectedItems(); void GroupSelectedItems();
void UngroupSelectedGroups(); void UngroupSelectedGroups();
@@ -189,5 +190,7 @@ protected:
virtual void leaveEvent(QEvent *event) override; virtual void leaveEvent(QEvent *event) override;
virtual void paintEvent(QPaintEvent *event) override; virtual void paintEvent(QPaintEvent *event) override;
virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; virtual void
selectionChanged(const QItemSelection &selected,
const QItemSelection &deselected) override;
}; };
+1 -2
View File
@@ -8,8 +8,7 @@ class VScrollArea : public QScrollArea {
Q_OBJECT Q_OBJECT
public: public:
inline VScrollArea(QWidget *parent = nullptr) inline VScrollArea(QWidget *parent = nullptr) : QScrollArea(parent)
: QScrollArea(parent)
{ {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
} }
+45 -46
View File
@@ -10,11 +10,11 @@
#include <QLabel> #include <QLabel>
VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_) VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_)
: source (source_), : source(source_),
enabledSignal (obs_source_get_signal_handler(source), "enable", enabledSignal(obs_source_get_signal_handler(source), "enable",
OBSSourceEnabled, this), OBSSourceEnabled, this),
renamedSignal (obs_source_get_signal_handler(source), "rename", renamedSignal(obs_source_get_signal_handler(source), "rename",
OBSSourceRenamed, this) OBSSourceRenamed, this)
{ {
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
bool enabled = obs_source_enabled(source); bool enabled = obs_source_enabled(source);
@@ -38,15 +38,15 @@ VisibilityItemWidget::VisibilityItemWidget(obs_source_t *source_)
setLayout(itemLayout); setLayout(itemLayout);
setStyleSheet("background-color: rgba(255, 255, 255, 0);"); setStyleSheet("background-color: rgba(255, 255, 255, 0);");
connect(vis, SIGNAL(clicked(bool)), connect(vis, SIGNAL(clicked(bool)), this,
this, SLOT(VisibilityClicked(bool))); SLOT(VisibilityClicked(bool)));
} }
VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_) VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
: item (item_), : item(item_),
source (obs_sceneitem_get_source(item)), source(obs_sceneitem_get_source(item)),
renamedSignal (obs_source_get_signal_handler(source), "rename", renamedSignal(obs_source_get_signal_handler(source), "rename",
OBSSourceRenamed, this) OBSSourceRenamed, this)
{ {
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
bool enabled = obs_sceneitem_visible(item); bool enabled = obs_sceneitem_visible(item);
@@ -90,18 +90,15 @@ VisibilityItemWidget::VisibilityItemWidget(obs_sceneitem_t *item_)
signal_handler_t *signal = obs_source_get_signal_handler(sceneSource); signal_handler_t *signal = obs_source_get_signal_handler(sceneSource);
signal_handler_connect(signal, "remove", OBSSceneRemove, this); signal_handler_connect(signal, "remove", OBSSceneRemove, this);
signal_handler_connect(signal, "item_remove", OBSSceneItemRemove, signal_handler_connect(signal, "item_remove", OBSSceneItemRemove, this);
this);
signal_handler_connect(signal, "item_visible", OBSSceneItemVisible, signal_handler_connect(signal, "item_visible", OBSSceneItemVisible,
this); this);
signal_handler_connect(signal, "item_locked", OBSSceneItemLocked, signal_handler_connect(signal, "item_locked", OBSSceneItemLocked, this);
this);
connect(vis, SIGNAL(clicked(bool)), connect(vis, SIGNAL(clicked(bool)), this,
this, SLOT(VisibilityClicked(bool))); SLOT(VisibilityClicked(bool)));
connect(lock, SIGNAL(clicked(bool)), connect(lock, SIGNAL(clicked(bool)), this, SLOT(LockClicked(bool)));
this, SLOT(LockClicked(bool)));
} }
VisibilityItemWidget::~VisibilityItemWidget() VisibilityItemWidget::~VisibilityItemWidget()
@@ -120,11 +117,11 @@ void VisibilityItemWidget::DisconnectItemSignals()
signal_handler_disconnect(signal, "remove", OBSSceneRemove, this); signal_handler_disconnect(signal, "remove", OBSSceneRemove, this);
signal_handler_disconnect(signal, "item_remove", OBSSceneItemRemove, signal_handler_disconnect(signal, "item_remove", OBSSceneItemRemove,
this); this);
signal_handler_disconnect(signal, "item_visible", OBSSceneItemVisible, signal_handler_disconnect(signal, "item_visible", OBSSceneItemVisible,
this); this);
signal_handler_disconnect(signal, "item_locked", OBSSceneItemLocked, signal_handler_disconnect(signal, "item_locked", OBSSceneItemLocked,
this); this);
sceneRemoved = true; sceneRemoved = true;
} }
@@ -132,7 +129,7 @@ void VisibilityItemWidget::DisconnectItemSignals()
void VisibilityItemWidget::OBSSceneRemove(void *param, calldata_t *data) void VisibilityItemWidget::OBSSceneRemove(void *param, calldata_t *data)
{ {
VisibilityItemWidget *window = VisibilityItemWidget *window =
reinterpret_cast<VisibilityItemWidget*>(param); reinterpret_cast<VisibilityItemWidget *>(param);
window->DisconnectItemSignals(); window->DisconnectItemSignals();
@@ -142,8 +139,8 @@ void VisibilityItemWidget::OBSSceneRemove(void *param, calldata_t *data)
void VisibilityItemWidget::OBSSceneItemRemove(void *param, calldata_t *data) void VisibilityItemWidget::OBSSceneItemRemove(void *param, calldata_t *data)
{ {
VisibilityItemWidget *window = VisibilityItemWidget *window =
reinterpret_cast<VisibilityItemWidget*>(param); reinterpret_cast<VisibilityItemWidget *>(param);
obs_sceneitem_t *item = (obs_sceneitem_t*)calldata_ptr(data, "item"); obs_sceneitem_t *item = (obs_sceneitem_t *)calldata_ptr(data, "item");
if (item == window->item) if (item == window->item)
window->DisconnectItemSignals(); window->DisconnectItemSignals();
@@ -152,45 +149,47 @@ void VisibilityItemWidget::OBSSceneItemRemove(void *param, calldata_t *data)
void VisibilityItemWidget::OBSSceneItemVisible(void *param, calldata_t *data) void VisibilityItemWidget::OBSSceneItemVisible(void *param, calldata_t *data)
{ {
VisibilityItemWidget *window = VisibilityItemWidget *window =
reinterpret_cast<VisibilityItemWidget*>(param); reinterpret_cast<VisibilityItemWidget *>(param);
obs_sceneitem_t *curItem = (obs_sceneitem_t*)calldata_ptr(data, "item"); obs_sceneitem_t *curItem =
(obs_sceneitem_t *)calldata_ptr(data, "item");
bool enabled = calldata_bool(data, "visible"); bool enabled = calldata_bool(data, "visible");
if (window->item == curItem) if (window->item == curItem)
QMetaObject::invokeMethod(window, "SourceEnabled", QMetaObject::invokeMethod(window, "SourceEnabled",
Q_ARG(bool, enabled)); Q_ARG(bool, enabled));
} }
void VisibilityItemWidget::OBSSceneItemLocked(void *param, calldata_t *data) void VisibilityItemWidget::OBSSceneItemLocked(void *param, calldata_t *data)
{ {
VisibilityItemWidget *window = VisibilityItemWidget *window =
reinterpret_cast<VisibilityItemWidget*>(param); reinterpret_cast<VisibilityItemWidget *>(param);
obs_sceneitem_t *curItem = (obs_sceneitem_t*)calldata_ptr(data, "item"); obs_sceneitem_t *curItem =
(obs_sceneitem_t *)calldata_ptr(data, "item");
bool locked = calldata_bool(data, "locked"); bool locked = calldata_bool(data, "locked");
if (window->item == curItem) if (window->item == curItem)
QMetaObject::invokeMethod(window, "SourceLocked", QMetaObject::invokeMethod(window, "SourceLocked",
Q_ARG(bool, locked)); Q_ARG(bool, locked));
} }
void VisibilityItemWidget::OBSSourceEnabled(void *param, calldata_t *data) void VisibilityItemWidget::OBSSourceEnabled(void *param, calldata_t *data)
{ {
VisibilityItemWidget *window = VisibilityItemWidget *window =
reinterpret_cast<VisibilityItemWidget*>(param); reinterpret_cast<VisibilityItemWidget *>(param);
bool enabled = calldata_bool(data, "enabled"); bool enabled = calldata_bool(data, "enabled");
QMetaObject::invokeMethod(window, "SourceEnabled", QMetaObject::invokeMethod(window, "SourceEnabled",
Q_ARG(bool, enabled)); Q_ARG(bool, enabled));
} }
void VisibilityItemWidget::OBSSourceRenamed(void *param, calldata_t *data) void VisibilityItemWidget::OBSSourceRenamed(void *param, calldata_t *data)
{ {
VisibilityItemWidget *window = VisibilityItemWidget *window =
reinterpret_cast<VisibilityItemWidget*>(param); reinterpret_cast<VisibilityItemWidget *>(param);
const char *name = calldata_string(data, "new_name"); const char *name = calldata_string(data, "new_name");
QMetaObject::invokeMethod(window, "SourceRenamed", QMetaObject::invokeMethod(window, "SourceRenamed",
Q_ARG(QString, QT_UTF8(name))); Q_ARG(QString, QT_UTF8(name)));
} }
void VisibilityItemWidget::VisibilityClicked(bool visible) void VisibilityItemWidget::VisibilityClicked(bool visible)
@@ -225,8 +224,8 @@ void VisibilityItemWidget::SourceRenamed(QString name)
label->setText(name); label->setText(name);
} }
void VisibilityItemWidget::SetColor(const QColor &color, void VisibilityItemWidget::SetColor(const QColor &color, bool active_,
bool active_, bool selected_) bool selected_)
{ {
/* Do not update unless the state has actually changed */ /* Do not update unless the state has actually changed */
if (active_ == active && selected_ == selected) if (active_ == active && selected_ == selected)
@@ -248,19 +247,19 @@ VisibilityItemDelegate::VisibilityItemDelegate(QObject *parent)
} }
void VisibilityItemDelegate::paint(QPainter *painter, void VisibilityItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QStyleOptionViewItem &option,
const QModelIndex &index) const const QModelIndex &index) const
{ {
QStyledItemDelegate::paint(painter, option, index); QStyledItemDelegate::paint(painter, option, index);
QObject *parentObj = parent(); QObject *parentObj = parent();
QListWidget *list = qobject_cast<QListWidget*>(parentObj); QListWidget *list = qobject_cast<QListWidget *>(parentObj);
if (!list) if (!list)
return; return;
QListWidgetItem *item = list->item(index.row()); QListWidgetItem *item = list->item(index.row());
VisibilityItemWidget *widget = VisibilityItemWidget *widget =
qobject_cast<VisibilityItemWidget*>(list->itemWidget(item)); qobject_cast<VisibilityItemWidget *>(list->itemWidget(item));
if (!widget) if (!widget)
return; return;
@@ -269,8 +268,8 @@ void VisibilityItemDelegate::paint(QPainter *painter,
QPalette palette = list->palette(); QPalette palette = list->palette();
#if defined(_WIN32) || defined(__APPLE__) #if defined(_WIN32) || defined(__APPLE__)
QPalette::ColorGroup group = active ? QPalette::ColorGroup group = active ? QPalette::Active
QPalette::Active : QPalette::Inactive; : QPalette::Inactive;
#else #else
QPalette::ColorGroup group = QPalette::Active; QPalette::ColorGroup group = QPalette::Active;
#endif #endif
@@ -292,7 +291,7 @@ void VisibilityItemDelegate::paint(QPainter *painter,
} }
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
obs_source_t *source) obs_source_t *source)
{ {
VisibilityItemWidget *baseWidget = new VisibilityItemWidget(source); VisibilityItemWidget *baseWidget = new VisibilityItemWidget(source);
@@ -301,7 +300,7 @@ void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
} }
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
obs_sceneitem_t *sceneItem) obs_sceneitem_t *sceneItem)
{ {
VisibilityItemWidget *baseWidget = new VisibilityItemWidget(sceneItem); VisibilityItemWidget *baseWidget = new VisibilityItemWidget(sceneItem);
+3 -3
View File
@@ -61,10 +61,10 @@ public:
VisibilityItemDelegate(QObject *parent = nullptr); VisibilityItemDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override; const QModelIndex &index) const override;
}; };
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
obs_source_t *source); obs_source_t *source);
void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item, void SetupVisibilityItem(QListWidget *list, QListWidgetItem *item,
obs_sceneitem_t *sceneItem); obs_sceneitem_t *sceneItem);
+201 -188
View File
@@ -21,35 +21,35 @@ QWeakPointer<VolumeMeterTimer> VolumeMeter::updateTimer;
void VolControl::OBSVolumeChanged(void *data, float db) void VolControl::OBSVolumeChanged(void *data, float db)
{ {
Q_UNUSED(db); Q_UNUSED(db);
VolControl *volControl = static_cast<VolControl*>(data); VolControl *volControl = static_cast<VolControl *>(data);
QMetaObject::invokeMethod(volControl, "VolumeChanged"); QMetaObject::invokeMethod(volControl, "VolumeChanged");
} }
void VolControl::OBSVolumeLevel(void *data, void VolControl::OBSVolumeLevel(void *data,
const float magnitude[MAX_AUDIO_CHANNELS], const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]) const float inputPeak[MAX_AUDIO_CHANNELS])
{ {
VolControl *volControl = static_cast<VolControl*>(data); VolControl *volControl = static_cast<VolControl *>(data);
volControl->volMeter->setLevels(magnitude, peak, inputPeak); volControl->volMeter->setLevels(magnitude, peak, inputPeak);
} }
void VolControl::OBSVolumeMuted(void *data, calldata_t *calldata) void VolControl::OBSVolumeMuted(void *data, calldata_t *calldata)
{ {
VolControl *volControl = static_cast<VolControl*>(data); VolControl *volControl = static_cast<VolControl *>(data);
bool muted = calldata_bool(calldata, "muted"); bool muted = calldata_bool(calldata, "muted");
QMetaObject::invokeMethod(volControl, "VolumeMuted", QMetaObject::invokeMethod(volControl, "VolumeMuted",
Q_ARG(bool, muted)); Q_ARG(bool, muted));
} }
void VolControl::VolumeChanged() void VolControl::VolumeChanged()
{ {
slider->blockSignals(true); slider->blockSignals(true);
slider->setValue((int) (obs_fader_get_deflection(obs_fader) * slider->setValue(
FADER_PRECISION)); (int)(obs_fader_get_deflection(obs_fader) * FADER_PRECISION));
slider->blockSignals(false); slider->blockSignals(false);
updateText(); updateText();
@@ -75,13 +75,12 @@ void VolControl::SliderChanged(int vol)
void VolControl::updateText() void VolControl::updateText()
{ {
QString db = QString::number(obs_fader_get_db(obs_fader), 'f', 1) QString db = QString::number(obs_fader_get_db(obs_fader), 'f', 1)
.append(" dB"); .append(" dB");
volLabel->setText(db); volLabel->setText(db);
bool muted = obs_source_muted(source); bool muted = obs_source_muted(source);
const char *accTextLookup = muted const char *accTextLookup = muted ? "VolControl.SliderMuted"
? "VolControl.SliderMuted" : "VolControl.SliderUnmuted";
: "VolControl.SliderUnmuted";
QString sourceName = obs_source_get_name(source); QString sourceName = obs_source_get_name(source);
QString accText = QTStr(accTextLookup).arg(sourceName, db); QString accText = QTStr(accTextLookup).arg(sourceName, db);
@@ -115,16 +114,16 @@ void VolControl::setPeakMeterType(enum obs_peak_meter_type peakMeterType)
} }
VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical) VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
: source (std::move(source_)), : source(std::move(source_)),
levelTotal (0.0f), levelTotal(0.0f),
levelCount (0.0f), levelCount(0.0f),
obs_fader (obs_fader_create(OBS_FADER_LOG)), obs_fader(obs_fader_create(OBS_FADER_LOG)),
obs_volmeter (obs_volmeter_create(OBS_FADER_LOG)), obs_volmeter(obs_volmeter_create(OBS_FADER_LOG)),
vertical (vertical) vertical(vertical)
{ {
nameLabel = new QLabel(); nameLabel = new QLabel();
volLabel = new QLabel(); volLabel = new QLabel();
mute = new MuteCheckBox(); mute = new MuteCheckBox();
QString sourceName = obs_source_get_name(source); QString sourceName = obs_source_get_name(source);
setObjectName(sourceName); setObjectName(sourceName);
@@ -134,15 +133,15 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
config->setProperty("themeID", "configIconSmall"); config->setProperty("themeID", "configIconSmall");
config->setFlat(true); config->setFlat(true);
config->setSizePolicy(QSizePolicy::Maximum, config->setSizePolicy(QSizePolicy::Maximum,
QSizePolicy::Maximum); QSizePolicy::Maximum);
config->setMaximumSize(22, 22); config->setMaximumSize(22, 22);
config->setAutoDefault(false); config->setAutoDefault(false);
config->setAccessibleName(QTStr("VolControl.Properties") config->setAccessibleName(
.arg(sourceName)); QTStr("VolControl.Properties").arg(sourceName));
connect(config, &QAbstractButton::clicked, connect(config, &QAbstractButton::clicked, this,
this, &VolControl::EmitConfigClicked); &VolControl::EmitConfigClicked);
} }
QVBoxLayout *mainLayout = new QVBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout;
@@ -153,10 +152,10 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
QHBoxLayout *nameLayout = new QHBoxLayout; QHBoxLayout *nameLayout = new QHBoxLayout;
QHBoxLayout *controlLayout = new QHBoxLayout; QHBoxLayout *controlLayout = new QHBoxLayout;
QHBoxLayout *volLayout = new QHBoxLayout; QHBoxLayout *volLayout = new QHBoxLayout;
QHBoxLayout *meterLayout = new QHBoxLayout; QHBoxLayout *meterLayout = new QHBoxLayout;
volMeter = new VolumeMeter(nullptr, obs_volmeter, true); volMeter = new VolumeMeter(nullptr, obs_volmeter, true);
slider = new SliderIgnoreScroll(Qt::Vertical); slider = new SliderIgnoreScroll(Qt::Vertical);
nameLayout->setAlignment(Qt::AlignCenter); nameLayout->setAlignment(Qt::AlignCenter);
meterLayout->setAlignment(Qt::AlignCenter); meterLayout->setAlignment(Qt::AlignCenter);
@@ -195,18 +194,18 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
setMaximumWidth(110); setMaximumWidth(110);
} else { } else {
QHBoxLayout *volLayout = new QHBoxLayout; QHBoxLayout *volLayout = new QHBoxLayout;
QHBoxLayout *textLayout = new QHBoxLayout; QHBoxLayout *textLayout = new QHBoxLayout;
QHBoxLayout *botLayout = new QHBoxLayout; QHBoxLayout *botLayout = new QHBoxLayout;
volMeter = new VolumeMeter(nullptr, obs_volmeter, false); volMeter = new VolumeMeter(nullptr, obs_volmeter, false);
slider = new SliderIgnoreScroll(Qt::Horizontal); slider = new SliderIgnoreScroll(Qt::Horizontal);
textLayout->setContentsMargins(0, 0, 0, 0); textLayout->setContentsMargins(0, 0, 0, 0);
textLayout->addWidget(nameLabel); textLayout->addWidget(nameLabel);
textLayout->addWidget(volLabel); textLayout->addWidget(volLabel);
textLayout->setAlignment(nameLabel, Qt::AlignLeft); textLayout->setAlignment(nameLabel, Qt::AlignLeft);
textLayout->setAlignment(volLabel, Qt::AlignRight); textLayout->setAlignment(volLabel, Qt::AlignRight);
volLayout->addWidget(slider); volLayout->addWidget(slider);
volLayout->addWidget(mute); volLayout->addWidget(mute);
@@ -229,7 +228,7 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
setLayout(mainLayout); setLayout(mainLayout);
QFont font = nameLabel->font(); QFont font = nameLabel->font();
font.setPointSize(font.pointSize()-1); font.setPointSize(font.pointSize() - 1);
nameLabel->setText(sourceName); nameLabel->setText(sourceName);
nameLabel->setFont(font); nameLabel->setFont(font);
@@ -244,13 +243,13 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
obs_fader_add_callback(obs_fader, OBSVolumeChanged, this); obs_fader_add_callback(obs_fader, OBSVolumeChanged, this);
obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this); obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this);
signal_handler_connect(obs_source_get_signal_handler(source), signal_handler_connect(obs_source_get_signal_handler(source), "mute",
"mute", OBSVolumeMuted, this); OBSVolumeMuted, this);
QWidget::connect(slider, SIGNAL(valueChanged(int)), QWidget::connect(slider, SIGNAL(valueChanged(int)), this,
this, SLOT(SliderChanged(int))); SLOT(SliderChanged(int)));
QWidget::connect(mute, SIGNAL(clicked(bool)), QWidget::connect(mute, SIGNAL(clicked(bool)), this,
this, SLOT(SetMuted(bool))); SLOT(SetMuted(bool)));
obs_fader_attach_source(obs_fader, source); obs_fader_attach_source(obs_fader, source);
obs_volmeter_attach_source(obs_volmeter, source); obs_volmeter_attach_source(obs_volmeter, source);
@@ -276,8 +275,8 @@ VolControl::~VolControl()
obs_fader_remove_callback(obs_fader, OBSVolumeChanged, this); obs_fader_remove_callback(obs_fader, OBSVolumeChanged, this);
obs_volmeter_remove_callback(obs_volmeter, OBSVolumeLevel, this); obs_volmeter_remove_callback(obs_volmeter, OBSVolumeLevel, this);
signal_handler_disconnect(obs_source_get_signal_handler(source), signal_handler_disconnect(obs_source_get_signal_handler(source), "mute",
"mute", OBSVolumeMuted, this); OBSVolumeMuted, this);
obs_fader_destroy(obs_fader); obs_fader_destroy(obs_fader);
obs_volmeter_destroy(obs_volmeter); obs_volmeter_destroy(obs_volmeter);
@@ -517,34 +516,33 @@ void VolumeMeter::wheelEvent(QWheelEvent *event)
} }
VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter, VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
bool vertical) bool vertical)
: QWidget(parent), obs_volmeter(obs_volmeter), : QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
vertical(vertical)
{ {
// Use a font that can be rendered small. // Use a font that can be rendered small.
tickFont = QFont("Arial"); tickFont = QFont("Arial");
tickFont.setPixelSize(7); tickFont.setPixelSize(7);
// Default meter color settings, they only show if // Default meter color settings, they only show if
// there is no stylesheet, do not remove. // there is no stylesheet, do not remove.
backgroundNominalColor.setRgb(0x26, 0x7f, 0x26); // Dark green backgroundNominalColor.setRgb(0x26, 0x7f, 0x26); // Dark green
backgroundWarningColor.setRgb(0x7f, 0x7f, 0x26); // Dark yellow backgroundWarningColor.setRgb(0x7f, 0x7f, 0x26); // Dark yellow
backgroundErrorColor.setRgb(0x7f, 0x26, 0x26); // Dark red backgroundErrorColor.setRgb(0x7f, 0x26, 0x26); // Dark red
foregroundNominalColor.setRgb(0x4c, 0xff, 0x4c); // Bright green foregroundNominalColor.setRgb(0x4c, 0xff, 0x4c); // Bright green
foregroundWarningColor.setRgb(0xff, 0xff, 0x4c); // Bright yellow foregroundWarningColor.setRgb(0xff, 0xff, 0x4c); // Bright yellow
foregroundErrorColor.setRgb(0xff, 0x4c, 0x4c); // Bright red foregroundErrorColor.setRgb(0xff, 0x4c, 0x4c); // Bright red
clipColor.setRgb(0xff, 0xff, 0xff); // Bright white clipColor.setRgb(0xff, 0xff, 0xff); // Bright white
magnitudeColor.setRgb(0x00, 0x00, 0x00); // Black magnitudeColor.setRgb(0x00, 0x00, 0x00); // Black
majorTickColor.setRgb(0xff, 0xff, 0xff); // Black majorTickColor.setRgb(0xff, 0xff, 0xff); // Black
minorTickColor.setRgb(0xcc, 0xcc, 0xcc); // Black minorTickColor.setRgb(0xcc, 0xcc, 0xcc); // Black
minimumLevel = -60.0; // -60 dB minimumLevel = -60.0; // -60 dB
warningLevel = -20.0; // -20 dB warningLevel = -20.0; // -20 dB
errorLevel = -9.0; // -9 dB errorLevel = -9.0; // -9 dB
clipLevel = -0.5; // -0.5 dB clipLevel = -0.5; // -0.5 dB
minimumInputLevel = -50.0; // -50 dB minimumInputLevel = -50.0; // -50 dB
peakDecayRate = 11.76; // 20 dB / 1.7 sec peakDecayRate = 11.76; // 20 dB / 1.7 sec
magnitudeIntegrationTime = 0.3; // 99% in 300 ms magnitudeIntegrationTime = 0.3; // 99% in 300 ms
peakHoldDuration = 20.0; // 20 seconds peakHoldDuration = 20.0; // 20 seconds
inputPeakHoldDuration = 1.0; // 1 second inputPeakHoldDuration = 1.0; // 1 second
channels = (int)audio_output_get_channels(obs_get_audio()); channels = (int)audio_output_get_channels(obs_get_audio());
@@ -566,8 +564,8 @@ VolumeMeter::~VolumeMeter()
} }
void VolumeMeter::setLevels(const float magnitude[MAX_AUDIO_CHANNELS], void VolumeMeter::setLevels(const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]) const float inputPeak[MAX_AUDIO_CHANNELS])
{ {
uint64_t ts = os_gettime_ns(); uint64_t ts = os_gettime_ns();
QMutexLocker locker(&dataMutex); QMutexLocker locker(&dataMutex);
@@ -632,11 +630,12 @@ inline bool VolumeMeter::detectIdle(uint64_t ts)
} }
} }
inline void VolumeMeter::calculateBallisticsForChannel(int channelNr, inline void
uint64_t ts, qreal timeSinceLastRedraw) VolumeMeter::calculateBallisticsForChannel(int channelNr, uint64_t ts,
qreal timeSinceLastRedraw)
{ {
if (currentPeak[channelNr] >= displayPeak[channelNr] || if (currentPeak[channelNr] >= displayPeak[channelNr] ||
isnan(displayPeak[channelNr])) { isnan(displayPeak[channelNr])) {
// Attack of peak is immediate. // Attack of peak is immediate.
displayPeak[channelNr] = currentPeak[channelNr]; displayPeak[channelNr] = currentPeak[channelNr];
} else { } else {
@@ -645,11 +644,11 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
// 24 dB / 2.8 seconds for Slow Profile (Type II PPM) // 24 dB / 2.8 seconds for Slow Profile (Type II PPM)
float decay = float(peakDecayRate * timeSinceLastRedraw); float decay = float(peakDecayRate * timeSinceLastRedraw);
displayPeak[channelNr] = CLAMP(displayPeak[channelNr] - decay, displayPeak[channelNr] = CLAMP(displayPeak[channelNr] - decay,
currentPeak[channelNr], 0); currentPeak[channelNr], 0);
} }
if (currentPeak[channelNr] >= displayPeakHold[channelNr] || if (currentPeak[channelNr] >= displayPeakHold[channelNr] ||
!isfinite(displayPeakHold[channelNr])) { !isfinite(displayPeakHold[channelNr])) {
// Attack of peak-hold is immediate, but keep track // Attack of peak-hold is immediate, but keep track
// when it was last updated. // when it was last updated.
displayPeakHold[channelNr] = currentPeak[channelNr]; displayPeakHold[channelNr] = currentPeak[channelNr];
@@ -657,8 +656,10 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
} else { } else {
// The peak and hold falls back to peak // The peak and hold falls back to peak
// after 20 seconds. // after 20 seconds.
qreal timeSinceLastPeak = (uint64_t)(ts - qreal timeSinceLastPeak =
displayPeakHoldLastUpdateTime[channelNr]) * 0.000000001; (uint64_t)(ts -
displayPeakHoldLastUpdateTime[channelNr]) *
0.000000001;
if (timeSinceLastPeak > peakHoldDuration) { if (timeSinceLastPeak > peakHoldDuration) {
displayPeakHold[channelNr] = currentPeak[channelNr]; displayPeakHold[channelNr] = currentPeak[channelNr];
displayPeakHoldLastUpdateTime[channelNr] = ts; displayPeakHoldLastUpdateTime[channelNr] = ts;
@@ -666,21 +667,22 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
} }
if (currentInputPeak[channelNr] >= displayInputPeakHold[channelNr] || if (currentInputPeak[channelNr] >= displayInputPeakHold[channelNr] ||
!isfinite(displayInputPeakHold[channelNr])) { !isfinite(displayInputPeakHold[channelNr])) {
// Attack of peak-hold is immediate, but keep track // Attack of peak-hold is immediate, but keep track
// when it was last updated. // when it was last updated.
displayInputPeakHold[channelNr] = currentInputPeak[channelNr]; displayInputPeakHold[channelNr] = currentInputPeak[channelNr];
displayInputPeakHoldLastUpdateTime[channelNr] = ts; displayInputPeakHoldLastUpdateTime[channelNr] = ts;
} else { } else {
// The peak and hold falls back to peak after 1 second. // The peak and hold falls back to peak after 1 second.
qreal timeSinceLastPeak = (uint64_t)(ts - qreal timeSinceLastPeak =
displayInputPeakHoldLastUpdateTime[channelNr]) * (uint64_t)(
ts -
displayInputPeakHoldLastUpdateTime[channelNr]) *
0.000000001; 0.000000001;
if (timeSinceLastPeak > inputPeakHoldDuration) { if (timeSinceLastPeak > inputPeakHoldDuration) {
displayInputPeakHold[channelNr] = displayInputPeakHold[channelNr] =
currentInputPeak[channelNr]; currentInputPeak[channelNr];
displayInputPeakHoldLastUpdateTime[channelNr] = displayInputPeakHoldLastUpdateTime[channelNr] = ts;
ts;
} }
} }
@@ -692,27 +694,29 @@ inline void VolumeMeter::calculateBallisticsForChannel(int channelNr,
// A VU meter will integrate to the new value to 99% in 300 ms. // A VU meter will integrate to the new value to 99% in 300 ms.
// The calculation here is very simplified and is more accurate // The calculation here is very simplified and is more accurate
// with higher frame-rate. // with higher frame-rate.
float attack = float((currentMagnitude[channelNr] - float attack =
displayMagnitude[channelNr]) * float((currentMagnitude[channelNr] -
(timeSinceLastRedraw / displayMagnitude[channelNr]) *
magnitudeIntegrationTime) * 0.99); (timeSinceLastRedraw / magnitudeIntegrationTime) *
displayMagnitude[channelNr] = CLAMP(displayMagnitude[channelNr] 0.99);
+ attack, (float)minimumLevel, 0); displayMagnitude[channelNr] =
CLAMP(displayMagnitude[channelNr] + attack,
(float)minimumLevel, 0);
} }
} }
inline void VolumeMeter::calculateBallistics(uint64_t ts, inline void VolumeMeter::calculateBallistics(uint64_t ts,
qreal timeSinceLastRedraw) qreal timeSinceLastRedraw)
{ {
QMutexLocker locker(&dataMutex); QMutexLocker locker(&dataMutex);
for (int channelNr = 0; channelNr < MAX_AUDIO_CHANNELS; channelNr++) for (int channelNr = 0; channelNr < MAX_AUDIO_CHANNELS; channelNr++)
calculateBallisticsForChannel(channelNr, ts, calculateBallisticsForChannel(channelNr, ts,
timeSinceLastRedraw); timeSinceLastRedraw);
} }
void VolumeMeter::paintInputMeter(QPainter &painter, int x, int y, int width, void VolumeMeter::paintInputMeter(QPainter &painter, int x, int y, int width,
int height, float peakHold) int height, float peakHold)
{ {
QMutexLocker locker(&dataMutex); QMutexLocker locker(&dataMutex);
QColor color; QColor color;
@@ -732,7 +736,7 @@ void VolumeMeter::paintInputMeter(QPainter &painter, int x, int y, int width,
} }
void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width, void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width,
int height) int height)
{ {
qreal scale = width / minimumLevel; qreal scale = width / minimumLevel;
@@ -740,7 +744,7 @@ void VolumeMeter::paintHTicks(QPainter &painter, int x, int y, int width,
painter.setPen(majorTickColor); painter.setPen(majorTickColor);
// Draw major tick lines and numeric indicators. // Draw major tick lines and numeric indicators.
for (int i = 0; i >= minimumLevel; i-= 5) { for (int i = 0; i >= minimumLevel; i -= 5) {
int position = int(x + width - (i * scale) - 1); int position = int(x + width - (i * scale) - 1);
QString str = QString::number(i); QString str = QString::number(i);
@@ -768,7 +772,7 @@ void VolumeMeter::paintVTicks(QPainter &painter, int x, int y, int height)
painter.setPen(majorTickColor); painter.setPen(majorTickColor);
// Draw major tick lines and numeric indicators. // Draw major tick lines and numeric indicators.
for (int i = 0; i >= minimumLevel; i-= 5) { for (int i = 0; i >= minimumLevel; i -= 5) {
int position = y + int((i * scale) - 1); int position = y + int((i * scale) - 1);
QString str = QString::number(i); QString str = QString::number(i);
@@ -798,22 +802,23 @@ void VolumeMeter::ClipEnding()
} }
void VolumeMeter::paintHMeter(QPainter &painter, int x, int y, int width, void VolumeMeter::paintHMeter(QPainter &painter, int x, int y, int width,
int height, float magnitude, float peak, float peakHold) int height, float magnitude, float peak,
float peakHold)
{ {
qreal scale = width / minimumLevel; qreal scale = width / minimumLevel;
QMutexLocker locker(&dataMutex); QMutexLocker locker(&dataMutex);
int minimumPosition = x + 0; int minimumPosition = x + 0;
int maximumPosition = x + width; int maximumPosition = x + width;
int magnitudePosition = int(x + width - (magnitude * scale)); int magnitudePosition = int(x + width - (magnitude * scale));
int peakPosition = int(x + width - (peak * scale)); int peakPosition = int(x + width - (peak * scale));
int peakHoldPosition = int(x + width - (peakHold * scale)); int peakHoldPosition = int(x + width - (peakHold * scale));
int warningPosition = int(x + width - (warningLevel * scale)); int warningPosition = int(x + width - (warningLevel * scale));
int errorPosition = int(x + width - (errorLevel * scale)); int errorPosition = int(x + width - (errorLevel * scale));
int nominalLength = warningPosition - minimumPosition; int nominalLength = warningPosition - minimumPosition;
int warningLength = errorPosition - warningPosition; int warningLength = errorPosition - warningPosition;
int errorLength = maximumPosition - errorPosition; int errorLength = maximumPosition - errorPosition;
locker.unlock(); locker.unlock();
if (clipping) { if (clipping) {
@@ -822,87 +827,89 @@ void VolumeMeter::paintHMeter(QPainter &painter, int x, int y, int width,
if (peakPosition < minimumPosition) { if (peakPosition < minimumPosition) {
painter.fillRect(minimumPosition, y, nominalLength, height, painter.fillRect(minimumPosition, y, nominalLength, height,
backgroundNominalColor); backgroundNominalColor);
painter.fillRect(warningPosition, y, warningLength, height, painter.fillRect(warningPosition, y, warningLength, height,
backgroundWarningColor); backgroundWarningColor);
painter.fillRect(errorPosition, y, errorLength, height, painter.fillRect(errorPosition, y, errorLength, height,
backgroundErrorColor); backgroundErrorColor);
} else if (peakPosition < warningPosition) { } else if (peakPosition < warningPosition) {
painter.fillRect(minimumPosition, y, peakPosition - painter.fillRect(minimumPosition, y,
minimumPosition, height, peakPosition - minimumPosition, height,
foregroundNominalColor); foregroundNominalColor);
painter.fillRect(peakPosition, y, warningPosition - painter.fillRect(peakPosition, y,
peakPosition, height, backgroundNominalColor); warningPosition - peakPosition, height,
backgroundNominalColor);
painter.fillRect(warningPosition, y, warningLength, height, painter.fillRect(warningPosition, y, warningLength, height,
backgroundWarningColor); backgroundWarningColor);
painter.fillRect(errorPosition, y, errorLength, height, painter.fillRect(errorPosition, y, errorLength, height,
backgroundErrorColor); backgroundErrorColor);
} else if (peakPosition < errorPosition) { } else if (peakPosition < errorPosition) {
painter.fillRect(minimumPosition, y, nominalLength, height, painter.fillRect(minimumPosition, y, nominalLength, height,
foregroundNominalColor); foregroundNominalColor);
painter.fillRect(warningPosition, y, painter.fillRect(warningPosition, y,
peakPosition - warningPosition, height, peakPosition - warningPosition, height,
foregroundWarningColor); foregroundWarningColor);
painter.fillRect(peakPosition, y, errorPosition - painter.fillRect(peakPosition, y, errorPosition - peakPosition,
peakPosition, height, backgroundWarningColor); height, backgroundWarningColor);
painter.fillRect(errorPosition, y, errorLength, height, painter.fillRect(errorPosition, y, errorLength, height,
backgroundErrorColor); backgroundErrorColor);
} else if (peakPosition < maximumPosition) { } else if (peakPosition < maximumPosition) {
painter.fillRect(minimumPosition, y, nominalLength, height, painter.fillRect(minimumPosition, y, nominalLength, height,
foregroundNominalColor); foregroundNominalColor);
painter.fillRect(warningPosition, y, warningLength, height, painter.fillRect(warningPosition, y, warningLength, height,
foregroundWarningColor); foregroundWarningColor);
painter.fillRect(errorPosition, y, peakPosition - errorPosition, painter.fillRect(errorPosition, y, peakPosition - errorPosition,
height, foregroundErrorColor); height, foregroundErrorColor);
painter.fillRect(peakPosition, y, painter.fillRect(peakPosition, y,
maximumPosition - peakPosition, height, maximumPosition - peakPosition, height,
backgroundErrorColor); backgroundErrorColor);
} else { } else {
if (!clipping) { if (!clipping) {
QTimer::singleShot(CLIP_FLASH_DURATION_MS, this, QTimer::singleShot(CLIP_FLASH_DURATION_MS, this,
SLOT(ClipEnding())); SLOT(ClipEnding()));
clipping = true; clipping = true;
} }
int end = errorLength + warningLength + nominalLength; int end = errorLength + warningLength + nominalLength;
painter.fillRect(minimumPosition, y, end, height, painter.fillRect(minimumPosition, y, end, height,
QBrush(foregroundErrorColor)); QBrush(foregroundErrorColor));
} }
if (peakHoldPosition - 3 < minimumPosition) if (peakHoldPosition - 3 < minimumPosition)
;// Peak-hold below minimum, no drawing. ; // Peak-hold below minimum, no drawing.
else if (peakHoldPosition < warningPosition) else if (peakHoldPosition < warningPosition)
painter.fillRect(peakHoldPosition - 3, y, 3, height, painter.fillRect(peakHoldPosition - 3, y, 3, height,
foregroundNominalColor); foregroundNominalColor);
else if (peakHoldPosition < errorPosition) else if (peakHoldPosition < errorPosition)
painter.fillRect(peakHoldPosition - 3, y, 3, height, painter.fillRect(peakHoldPosition - 3, y, 3, height,
foregroundWarningColor); foregroundWarningColor);
else else
painter.fillRect(peakHoldPosition - 3, y, 3, height, painter.fillRect(peakHoldPosition - 3, y, 3, height,
foregroundErrorColor); foregroundErrorColor);
if (magnitudePosition - 3 >= minimumPosition) if (magnitudePosition - 3 >= minimumPosition)
painter.fillRect(magnitudePosition - 3, y, 3, height, painter.fillRect(magnitudePosition - 3, y, 3, height,
magnitudeColor); magnitudeColor);
} }
void VolumeMeter::paintVMeter(QPainter &painter, int x, int y, int width, void VolumeMeter::paintVMeter(QPainter &painter, int x, int y, int width,
int height, float magnitude, float peak, float peakHold) int height, float magnitude, float peak,
float peakHold)
{ {
qreal scale = height / minimumLevel; qreal scale = height / minimumLevel;
QMutexLocker locker(&dataMutex); QMutexLocker locker(&dataMutex);
int minimumPosition = y + 0; int minimumPosition = y + 0;
int maximumPosition = y + height; int maximumPosition = y + height;
int magnitudePosition = int(y + height - (magnitude * scale)); int magnitudePosition = int(y + height - (magnitude * scale));
int peakPosition = int(y + height - (peak * scale)); int peakPosition = int(y + height - (peak * scale));
int peakHoldPosition = int(y + height - (peakHold * scale)); int peakHoldPosition = int(y + height - (peakHold * scale));
int warningPosition = int(y + height - (warningLevel * scale)); int warningPosition = int(y + height - (warningLevel * scale));
int errorPosition = int(y + height - (errorLevel * scale)); int errorPosition = int(y + height - (errorLevel * scale));
int nominalLength = warningPosition - minimumPosition; int nominalLength = warningPosition - minimumPosition;
int warningLength = errorPosition - warningPosition; int warningLength = errorPosition - warningPosition;
int errorLength = maximumPosition - errorPosition; int errorLength = maximumPosition - errorPosition;
locker.unlock(); locker.unlock();
if (clipping) { if (clipping) {
@@ -911,65 +918,71 @@ void VolumeMeter::paintVMeter(QPainter &painter, int x, int y, int width,
if (peakPosition < minimumPosition) { if (peakPosition < minimumPosition) {
painter.fillRect(x, minimumPosition, width, nominalLength, painter.fillRect(x, minimumPosition, width, nominalLength,
backgroundNominalColor); backgroundNominalColor);
painter.fillRect(x, warningPosition, width, warningLength, painter.fillRect(x, warningPosition, width, warningLength,
backgroundWarningColor); backgroundWarningColor);
painter.fillRect(x, errorPosition, width, errorLength, painter.fillRect(x, errorPosition, width, errorLength,
backgroundErrorColor); backgroundErrorColor);
} else if (peakPosition < warningPosition) { } else if (peakPosition < warningPosition) {
painter.fillRect(x, minimumPosition, width, peakPosition - painter.fillRect(x, minimumPosition, width,
minimumPosition, foregroundNominalColor); peakPosition - minimumPosition,
painter.fillRect(x, peakPosition, width, warningPosition - foregroundNominalColor);
peakPosition, backgroundNominalColor); painter.fillRect(x, peakPosition, width,
warningPosition - peakPosition,
backgroundNominalColor);
painter.fillRect(x, warningPosition, width, warningLength, painter.fillRect(x, warningPosition, width, warningLength,
backgroundWarningColor); backgroundWarningColor);
painter.fillRect(x, errorPosition, width, errorLength, painter.fillRect(x, errorPosition, width, errorLength,
backgroundErrorColor); backgroundErrorColor);
} else if (peakPosition < errorPosition) { } else if (peakPosition < errorPosition) {
painter.fillRect(x,minimumPosition, width, nominalLength, painter.fillRect(x, minimumPosition, width, nominalLength,
foregroundNominalColor); foregroundNominalColor);
painter.fillRect(x, warningPosition, width, peakPosition - painter.fillRect(x, warningPosition, width,
warningPosition, foregroundWarningColor); peakPosition - warningPosition,
painter.fillRect(x, peakPosition, width, errorPosition - foregroundWarningColor);
peakPosition, backgroundWarningColor); painter.fillRect(x, peakPosition, width,
errorPosition - peakPosition,
backgroundWarningColor);
painter.fillRect(x, errorPosition, width, errorLength, painter.fillRect(x, errorPosition, width, errorLength,
backgroundErrorColor); backgroundErrorColor);
} else if (peakPosition < maximumPosition) { } else if (peakPosition < maximumPosition) {
painter.fillRect(x, minimumPosition, width, nominalLength, painter.fillRect(x, minimumPosition, width, nominalLength,
foregroundNominalColor); foregroundNominalColor);
painter.fillRect(x, warningPosition, width, warningLength, painter.fillRect(x, warningPosition, width, warningLength,
foregroundWarningColor); foregroundWarningColor);
painter.fillRect(x, errorPosition, width, peakPosition - painter.fillRect(x, errorPosition, width,
errorPosition, foregroundErrorColor); peakPosition - errorPosition,
painter.fillRect(x, peakPosition, width, maximumPosition - foregroundErrorColor);
peakPosition, backgroundErrorColor); painter.fillRect(x, peakPosition, width,
maximumPosition - peakPosition,
backgroundErrorColor);
} else { } else {
if (!clipping) { if (!clipping) {
QTimer::singleShot(CLIP_FLASH_DURATION_MS, this, QTimer::singleShot(CLIP_FLASH_DURATION_MS, this,
SLOT(ClipEnding())); SLOT(ClipEnding()));
clipping = true; clipping = true;
} }
int end = errorLength + warningLength + nominalLength; int end = errorLength + warningLength + nominalLength;
painter.fillRect(x, minimumPosition, width, end, painter.fillRect(x, minimumPosition, width, end,
QBrush(foregroundErrorColor)); QBrush(foregroundErrorColor));
} }
if (peakHoldPosition - 3 < minimumPosition) if (peakHoldPosition - 3 < minimumPosition)
;// Peak-hold below minimum, no drawing. ; // Peak-hold below minimum, no drawing.
else if (peakHoldPosition < warningPosition) else if (peakHoldPosition < warningPosition)
painter.fillRect(x, peakHoldPosition - 3, width, 3, painter.fillRect(x, peakHoldPosition - 3, width, 3,
foregroundNominalColor); foregroundNominalColor);
else if (peakHoldPosition < errorPosition) else if (peakHoldPosition < errorPosition)
painter.fillRect(x, peakHoldPosition - 3, width, 3, painter.fillRect(x, peakHoldPosition - 3, width, 3,
foregroundWarningColor); foregroundWarningColor);
else else
painter.fillRect(x, peakHoldPosition - 3, width, 3, painter.fillRect(x, peakHoldPosition - 3, width, 3,
foregroundErrorColor); foregroundErrorColor);
if (magnitudePosition - 3 >= minimumPosition) if (magnitudePosition - 3 >= minimumPosition)
painter.fillRect(x, magnitudePosition - 3, width, 3, painter.fillRect(x, magnitudePosition - 3, width, 3,
magnitudeColor); magnitudeColor);
} }
void VolumeMeter::paintEvent(QPaintEvent *event) void VolumeMeter::paintEvent(QPaintEvent *event)
@@ -978,7 +991,7 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
qreal timeSinceLastRedraw = (ts - lastRedrawTime) * 0.000000001; qreal timeSinceLastRedraw = (ts - lastRedrawTime) * 0.000000001;
const QRect rect = event->region().boundingRect(); const QRect rect = event->region().boundingRect();
int width = rect.width(); int width = rect.width();
int height = rect.height(); int height = rect.height();
handleChannelCofigurationChange(); handleChannelCofigurationChange();
@@ -992,7 +1005,7 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
else else
tickPaintCacheSize = QSize(width, 9); tickPaintCacheSize = QSize(width, 9);
if (tickPaintCache == nullptr || if (tickPaintCache == nullptr ||
tickPaintCache->size() != tickPaintCacheSize) { tickPaintCache->size() != tickPaintCacheSize) {
delete tickPaintCache; delete tickPaintCache;
tickPaintCache = new QPixmap(tickPaintCacheSize); tickPaintCache = new QPixmap(tickPaintCacheSize);
@@ -1004,11 +1017,11 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
tickPainter.translate(0, height); tickPainter.translate(0, height);
tickPainter.scale(1, -1); tickPainter.scale(1, -1);
paintVTicks(tickPainter, 0, 11, paintVTicks(tickPainter, 0, 11,
tickPaintCacheSize.height() - 11); tickPaintCacheSize.height() - 11);
} else { } else {
paintHTicks(tickPainter, 6, 0, paintHTicks(tickPainter, 6, 0,
tickPaintCacheSize.width() - 6, tickPaintCacheSize.width() - 6,
tickPaintCacheSize.height()); tickPaintCacheSize.height());
} }
tickPainter.end(); tickPainter.end();
} }
@@ -1020,29 +1033,29 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
painter.translate(0, height); painter.translate(0, height);
painter.scale(1, -1); painter.scale(1, -1);
painter.drawPixmap(displayNrAudioChannels * 4 - 1, 7, painter.drawPixmap(displayNrAudioChannels * 4 - 1, 7,
*tickPaintCache); *tickPaintCache);
} else { } else {
painter.drawPixmap(0, height - 9, *tickPaintCache); painter.drawPixmap(0, height - 9, *tickPaintCache);
} }
for (int channelNr = 0; channelNr < displayNrAudioChannels; for (int channelNr = 0; channelNr < displayNrAudioChannels;
channelNr++) { channelNr++) {
int channelNrFixed = (displayNrAudioChannels == 1 && int channelNrFixed =
channels > 2) (displayNrAudioChannels == 1 && channels > 2)
? 2 ? 2
: channelNr; : channelNr;
if (vertical) if (vertical)
paintVMeter(painter, channelNr * 4, 8, 3, height - 10, paintVMeter(painter, channelNr * 4, 8, 3, height - 10,
displayMagnitude[channelNrFixed], displayMagnitude[channelNrFixed],
displayPeak[channelNrFixed], displayPeak[channelNrFixed],
displayPeakHold[channelNrFixed]); displayPeakHold[channelNrFixed]);
else else
paintHMeter(painter, 5, channelNr * 4, width - 5, 3, paintHMeter(painter, 5, channelNr * 4, width - 5, 3,
displayMagnitude[channelNrFixed], displayMagnitude[channelNrFixed],
displayPeak[channelNrFixed], displayPeak[channelNrFixed],
displayPeakHold[channelNrFixed]); displayPeakHold[channelNrFixed]);
if (idle) if (idle)
continue; continue;
@@ -1071,7 +1084,7 @@ void VolumeMeterTimer::RemoveVolControl(VolumeMeter *meter)
volumeMeters.removeOne(meter); volumeMeters.removeOne(meter);
} }
void VolumeMeterTimer::timerEvent(QTimerEvent*) void VolumeMeterTimer::timerEvent(QTimerEvent *)
{ {
for (VolumeMeter *meter : volumeMeters) for (VolumeMeter *meter : volumeMeters)
meter->update(); meter->update();
+69 -89
View File
@@ -11,74 +11,55 @@
class QPushButton; class QPushButton;
class VolumeMeterTimer; class VolumeMeterTimer;
class VolumeMeter : public QWidget class VolumeMeter : public QWidget {
{
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor backgroundNominalColor Q_PROPERTY(QColor backgroundNominalColor READ getBackgroundNominalColor
READ getBackgroundNominalColor WRITE setBackgroundNominalColor DESIGNABLE true)
WRITE setBackgroundNominalColor DESIGNABLE true) Q_PROPERTY(QColor backgroundWarningColor READ getBackgroundWarningColor
Q_PROPERTY(QColor backgroundWarningColor WRITE setBackgroundWarningColor DESIGNABLE true)
READ getBackgroundWarningColor Q_PROPERTY(QColor backgroundErrorColor READ getBackgroundErrorColor
WRITE setBackgroundWarningColor DESIGNABLE true) WRITE setBackgroundErrorColor DESIGNABLE true)
Q_PROPERTY(QColor backgroundErrorColor Q_PROPERTY(QColor foregroundNominalColor READ getForegroundNominalColor
READ getBackgroundErrorColor WRITE setForegroundNominalColor DESIGNABLE true)
WRITE setBackgroundErrorColor DESIGNABLE true) Q_PROPERTY(QColor foregroundWarningColor READ getForegroundWarningColor
Q_PROPERTY(QColor foregroundNominalColor WRITE setForegroundWarningColor DESIGNABLE true)
READ getForegroundNominalColor Q_PROPERTY(QColor foregroundErrorColor READ getForegroundErrorColor
WRITE setForegroundNominalColor DESIGNABLE true) WRITE setForegroundErrorColor DESIGNABLE true)
Q_PROPERTY(QColor foregroundWarningColor Q_PROPERTY(QColor clipColor READ getClipColor WRITE setClipColor
READ getForegroundWarningColor DESIGNABLE true)
WRITE setForegroundWarningColor DESIGNABLE true) Q_PROPERTY(QColor magnitudeColor READ getMagnitudeColor WRITE
Q_PROPERTY(QColor foregroundErrorColor setMagnitudeColor DESIGNABLE true)
READ getForegroundErrorColor Q_PROPERTY(QColor majorTickColor READ getMajorTickColor WRITE
WRITE setForegroundErrorColor DESIGNABLE true) setMajorTickColor DESIGNABLE true)
Q_PROPERTY(QColor clipColor Q_PROPERTY(QColor minorTickColor READ getMinorTickColor WRITE
READ getClipColor setMinorTickColor DESIGNABLE true)
WRITE setClipColor DESIGNABLE true)
Q_PROPERTY(QColor magnitudeColor
READ getMagnitudeColor
WRITE setMagnitudeColor DESIGNABLE true)
Q_PROPERTY(QColor majorTickColor
READ getMajorTickColor
WRITE setMajorTickColor DESIGNABLE true)
Q_PROPERTY(QColor minorTickColor
READ getMinorTickColor
WRITE setMinorTickColor DESIGNABLE true)
// Levels are denoted in dBFS. // Levels are denoted in dBFS.
Q_PROPERTY(qreal minimumLevel Q_PROPERTY(qreal minimumLevel READ getMinimumLevel WRITE setMinimumLevel
READ getMinimumLevel DESIGNABLE true)
WRITE setMinimumLevel DESIGNABLE true) Q_PROPERTY(qreal warningLevel READ getWarningLevel WRITE setWarningLevel
Q_PROPERTY(qreal warningLevel DESIGNABLE true)
READ getWarningLevel Q_PROPERTY(qreal errorLevel READ getErrorLevel WRITE setErrorLevel
WRITE setWarningLevel DESIGNABLE true) DESIGNABLE true)
Q_PROPERTY(qreal errorLevel Q_PROPERTY(qreal clipLevel READ getClipLevel WRITE setClipLevel
READ getErrorLevel DESIGNABLE true)
WRITE setErrorLevel DESIGNABLE true) Q_PROPERTY(qreal minimumInputLevel READ getMinimumInputLevel WRITE
Q_PROPERTY(qreal clipLevel setMinimumInputLevel DESIGNABLE true)
READ getClipLevel
WRITE setClipLevel DESIGNABLE true)
Q_PROPERTY(qreal minimumInputLevel
READ getMinimumInputLevel
WRITE setMinimumInputLevel DESIGNABLE true)
// Rates are denoted in dB/second. // Rates are denoted in dB/second.
Q_PROPERTY(qreal peakDecayRate Q_PROPERTY(qreal peakDecayRate READ getPeakDecayRate WRITE
READ getPeakDecayRate setPeakDecayRate DESIGNABLE true)
WRITE setPeakDecayRate DESIGNABLE true)
// Time in seconds for the VU meter to integrate over. // Time in seconds for the VU meter to integrate over.
Q_PROPERTY(qreal magnitudeIntegrationTime Q_PROPERTY(
READ getMagnitudeIntegrationTime qreal magnitudeIntegrationTime READ getMagnitudeIntegrationTime
WRITE setMagnitudeIntegrationTime DESIGNABLE true) WRITE setMagnitudeIntegrationTime DESIGNABLE true)
// Duration is denoted in seconds. // Duration is denoted in seconds.
Q_PROPERTY(qreal peakHoldDuration Q_PROPERTY(qreal peakHoldDuration READ getPeakHoldDuration WRITE
READ getPeakHoldDuration setPeakHoldDuration DESIGNABLE true)
WRITE setPeakHoldDuration DESIGNABLE true) Q_PROPERTY(qreal inputPeakHoldDuration READ getInputPeakHoldDuration
Q_PROPERTY(qreal inputPeakHoldDuration WRITE setInputPeakHoldDuration DESIGNABLE true)
READ getInputPeakHoldDuration
WRITE setInputPeakHoldDuration DESIGNABLE true)
private slots: private slots:
void ClipEnding(); void ClipEnding();
@@ -92,18 +73,18 @@ private:
inline void handleChannelCofigurationChange(); inline void handleChannelCofigurationChange();
inline bool detectIdle(uint64_t ts); inline bool detectIdle(uint64_t ts);
inline void calculateBallistics(uint64_t ts, inline void calculateBallistics(uint64_t ts,
qreal timeSinceLastRedraw=0.0); qreal timeSinceLastRedraw = 0.0);
inline void calculateBallisticsForChannel(int channelNr, inline void calculateBallisticsForChannel(int channelNr, uint64_t ts,
uint64_t ts, qreal timeSinceLastRedraw); qreal timeSinceLastRedraw);
void paintInputMeter(QPainter &painter, int x, int y, int width, void paintInputMeter(QPainter &painter, int x, int y, int width,
int height, float peakHold); int height, float peakHold);
void paintHMeter(QPainter &painter, int x, int y, int width, int height, void paintHMeter(QPainter &painter, int x, int y, int width, int height,
float magnitude, float peak, float peakHold); float magnitude, float peak, float peakHold);
void paintHTicks(QPainter &painter, int x, int y, int width, void paintHTicks(QPainter &painter, int x, int y, int width,
int height); int height);
void paintVMeter(QPainter &painter, int x, int y, int width, int height, void paintVMeter(QPainter &painter, int x, int y, int width, int height,
float magnitude, float peak, float peakHold); float magnitude, float peak, float peakHold);
void paintVTicks(QPainter &painter, int x, int y, int height); void paintVTicks(QPainter &painter, int x, int y, int height);
QMutex dataMutex; QMutex dataMutex;
@@ -150,14 +131,13 @@ private:
public: public:
explicit VolumeMeter(QWidget *parent = nullptr, explicit VolumeMeter(QWidget *parent = nullptr,
obs_volmeter_t *obs_volmeter = nullptr, obs_volmeter_t *obs_volmeter = nullptr,
bool vertical = false); bool vertical = false);
~VolumeMeter(); ~VolumeMeter();
void setLevels( void setLevels(const float magnitude[MAX_AUDIO_CHANNELS],
const float magnitude[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS], const float inputPeak[MAX_AUDIO_CHANNELS]);
const float inputPeak[MAX_AUDIO_CHANNELS]);
QColor getBackgroundNominalColor() const; QColor getBackgroundNominalColor() const;
void setBackgroundNominalColor(QColor c); void setBackgroundNominalColor(QColor c);
@@ -216,7 +196,7 @@ public:
protected: protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
QList<VolumeMeter*> volumeMeters; QList<VolumeMeter *> volumeMeters;
}; };
class QLabel; class QLabel;
@@ -228,23 +208,23 @@ class VolControl : public QWidget {
private: private:
OBSSource source; OBSSource source;
QLabel *nameLabel; QLabel *nameLabel;
QLabel *volLabel; QLabel *volLabel;
VolumeMeter *volMeter; VolumeMeter *volMeter;
QSlider *slider; QSlider *slider;
MuteCheckBox *mute; MuteCheckBox *mute;
QPushButton *config = nullptr; QPushButton *config = nullptr;
float levelTotal; float levelTotal;
float levelCount; float levelCount;
obs_fader_t *obs_fader; obs_fader_t *obs_fader;
obs_volmeter_t *obs_volmeter; obs_volmeter_t *obs_volmeter;
bool vertical; bool vertical;
static void OBSVolumeChanged(void *param, float db); static void OBSVolumeChanged(void *param, float db);
static void OBSVolumeLevel(void *data, static void OBSVolumeLevel(void *data,
const float magnitude[MAX_AUDIO_CHANNELS], const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS], const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS]); const float inputPeak[MAX_AUDIO_CHANNELS]);
static void OBSVolumeMuted(void *data, calldata_t *calldata); static void OBSVolumeMuted(void *data, calldata_t *calldata);
void EmitConfigClicked(); void EmitConfigClicked();
@@ -262,10 +242,10 @@ signals:
public: public:
explicit VolControl(OBSSource source, bool showConfig = false, explicit VolControl(OBSSource source, bool showConfig = false,
bool vertical = false); bool vertical = false);
~VolControl(); ~VolControl();
inline obs_source_t *GetSource() const {return source;} inline obs_source_t *GetSource() const { return source; }
QString GetName() const; QString GetName() const;
void SetName(const QString &newName); void SetName(const QString &newName);
+3 -4
View File
@@ -2,10 +2,9 @@
#include "obs-app.hpp" #include "obs-app.hpp"
OBSUpdate::OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text) OBSUpdate::OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text)
: QDialog (parent, Qt::WindowSystemMenuHint | : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint |
Qt::WindowTitleHint | Qt::WindowCloseButtonHint),
Qt::WindowCloseButtonHint), ui(new Ui_OBSUpdate)
ui (new Ui_OBSUpdate)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->text->setHtml(text); ui->text->setHtml(text);
+1 -5
View File
@@ -9,11 +9,7 @@ class OBSUpdate : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
enum ReturnVal { enum ReturnVal { No, Yes, Skip };
No,
Yes,
Skip
};
OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text); OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text);
+3 -3
View File
@@ -26,7 +26,7 @@ void HashToString(const uint8_t *in, wchar_t *out)
const wchar_t alphabet[] = L"0123456789abcdef"; const wchar_t alphabet[] = L"0123456789abcdef";
for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) { for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
out[2 * i] = alphabet[in[i] / 16]; out[2 * i] = alphabet[in[i] / 16];
out[2 * i + 1] = alphabet[in[i] % 16]; out[2 * i + 1] = alphabet[in[i] % 16];
} }
@@ -50,7 +50,7 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash)
return false; return false;
WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, 0, nullptr); nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return false; return false;
@@ -60,7 +60,7 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash)
for (;;) { for (;;) {
DWORD read = 0; DWORD read = 0;
if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read, if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
nullptr)) nullptr))
return false; return false;
if (!read) if (!read)
+91 -118
View File
@@ -20,7 +20,7 @@
using namespace std; using namespace std;
#define MAX_BUF_SIZE 262144 #define MAX_BUF_SIZE 262144
#define READ_BUF_SIZE 32768 #define READ_BUF_SIZE 32768
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@@ -36,8 +36,8 @@ public:
inflateEnd(&strm); inflateEnd(&strm);
} }
inline operator z_stream*() {return &strm;} inline operator z_stream *() { return &strm; }
inline z_stream *operator->() {return &strm;} inline z_stream *operator->() { return &strm; }
inline bool inflate() inline bool inflate()
{ {
@@ -50,14 +50,15 @@ public:
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm, static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
string &zipBuf, const uint8_t *buffer, DWORD outSize) string &zipBuf, const uint8_t *buffer,
DWORD outSize)
{ {
strm->avail_in = outSize; strm->avail_in = outSize;
strm->next_in = buffer; strm->next_in = buffer;
do { do {
strm->avail_out = (uInt)zipBuf.size(); strm->avail_out = (uInt)zipBuf.size();
strm->next_out = (Bytef *)zipBuf.data(); strm->next_out = (Bytef *)zipBuf.data();
int zret = inflate(strm, Z_NO_FLUSH); int zret = inflate(strm, Z_NO_FLUSH);
if (zret != Z_STREAM_END && zret != Z_OK) if (zret != Z_STREAM_END && zret != Z_OK)
@@ -65,7 +66,7 @@ static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
try { try {
responseBuf.append(zipBuf.data(), responseBuf.append(zipBuf.data(),
zipBuf.size() - strm->avail_out); zipBuf.size() - strm->avail_out);
} catch (...) { } catch (...) {
return false; return false;
} }
@@ -75,7 +76,7 @@ static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
} }
static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer, static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer,
DWORD outSize) DWORD outSize)
{ {
try { try {
responseBuf.append((const char *)buffer, outSize); responseBuf.append((const char *)buffer, outSize);
@@ -85,19 +86,16 @@ static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer,
return true; return true;
} }
bool HTTPPostData(const wchar_t *url, bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen,
const BYTE * data, const wchar_t *extraHeaders, int *responseCode,
int dataLen, string &responseBuf)
const wchar_t *extraHeaders,
int * responseCode,
string & responseBuf)
{ {
HttpHandle hSession; HttpHandle hSession;
HttpHandle hConnect; HttpHandle hConnect;
HttpHandle hRequest; HttpHandle hRequest;
string zipBuf; string zipBuf;
URL_COMPONENTS urlComponents = {}; URL_COMPONENTS urlComponents = {};
bool secure = false; bool secure = false;
wchar_t hostName[256]; wchar_t hostName[256];
wchar_t path[1024]; wchar_t path[1024];
@@ -113,10 +111,10 @@ bool HTTPPostData(const wchar_t *url,
urlComponents.dwStructSize = sizeof(urlComponents); urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = hostName; urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = _countof(hostName); urlComponents.dwHostNameLength = _countof(hostName);
urlComponents.lpszUrlPath = path; urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = _countof(path); urlComponents.dwUrlPathLength = _countof(path);
WinHttpCrackUrl(url, 0, 0, &urlComponents); WinHttpCrackUrl(url, 0, 0, &urlComponents);
@@ -128,22 +126,21 @@ bool HTTPPostData(const wchar_t *url,
* connect to server */ * connect to server */
hSession = WinHttpOpen(L"OBS Studio Updater/2.1", hSession = WinHttpOpen(L"OBS Studio Updater/2.1",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS,
WINHTTP_NO_PROXY_BYPASS, 0);
0);
if (!hSession) { if (!hSession) {
*responseCode = -1; *responseCode = -1;
return false; return false;
} }
WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS,
(LPVOID)&tlsProtocols, sizeof(tlsProtocols)); (LPVOID)&tlsProtocols, sizeof(tlsProtocols));
hConnect = WinHttpConnect(hSession, hostName, hConnect = WinHttpConnect(hSession, hostName,
secure secure ? INTERNET_DEFAULT_HTTPS_PORT
? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT,
: INTERNET_DEFAULT_HTTP_PORT, 0); 0);
if (!hConnect) { if (!hConnect) {
*responseCode = -2; *responseCode = -2;
return false; return false;
@@ -152,24 +149,19 @@ bool HTTPPostData(const wchar_t *url,
/* -------------------------------------- * /* -------------------------------------- *
* request data */ * request data */
hRequest = WinHttpOpenRequest(hConnect, hRequest = WinHttpOpenRequest(hConnect, L"POST", path, nullptr,
L"POST", WINHTTP_NO_REFERER, acceptTypes,
path, secure ? WINHTTP_FLAG_SECURE |
nullptr, WINHTTP_FLAG_REFRESH
WINHTTP_NO_REFERER, : WINHTTP_FLAG_REFRESH);
acceptTypes,
secure
? WINHTTP_FLAG_SECURE |
WINHTTP_FLAG_REFRESH
: WINHTTP_FLAG_REFRESH);
if (!hRequest) { if (!hRequest) {
*responseCode = -3; *responseCode = -3;
return false; return false;
} }
bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders, bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
extraHeaders ? -1 : 0, extraHeaders ? -1 : 0,
(void *)data, dataLen, dataLen, 0); (void *)data, dataLen, dataLen, 0);
/* -------------------------------------- * /* -------------------------------------- *
* end request */ * end request */
@@ -185,18 +177,15 @@ bool HTTPPostData(const wchar_t *url,
* get headers */ * get headers */
wchar_t encoding[64]; wchar_t encoding[64];
DWORD encodingLen; DWORD encodingLen;
wchar_t statusCode[8]; wchar_t statusCode[8];
DWORD statusCodeLen; DWORD statusCodeLen;
statusCodeLen = sizeof(statusCode); statusCodeLen = sizeof(statusCode);
if (!WinHttpQueryHeaders(hRequest, if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE,
WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode,
WINHTTP_HEADER_NAME_BY_INDEX, &statusCodeLen, WINHTTP_NO_HEADER_INDEX)) {
&statusCode,
&statusCodeLen,
WINHTTP_NO_HEADER_INDEX)) {
*responseCode = -4; *responseCode = -4;
return false; return false;
} else { } else {
@@ -204,12 +193,9 @@ bool HTTPPostData(const wchar_t *url,
} }
encodingLen = sizeof(encoding); encodingLen = sizeof(encoding);
if (!WinHttpQueryHeaders(hRequest, if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_ENCODING,
WINHTTP_QUERY_CONTENT_ENCODING, WINHTTP_HEADER_NAME_BY_INDEX, encoding,
WINHTTP_HEADER_NAME_BY_INDEX, &encodingLen, WINHTTP_NO_HEADER_INDEX)) {
encoding,
&encodingLen,
WINHTTP_NO_HEADER_INDEX)) {
encoding[0] = 0; encoding[0] = 0;
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) { if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
*responseCode = -5; *responseCode = -5;
@@ -238,11 +224,11 @@ bool HTTPPostData(const wchar_t *url,
bool gzip = wcscmp(encoding, L"gzip") == 0; bool gzip = wcscmp(encoding, L"gzip") == 0;
if (gzip) { if (gzip) {
strm->zalloc = Z_NULL; strm->zalloc = Z_NULL;
strm->zfree = Z_NULL; strm->zfree = Z_NULL;
strm->opaque = Z_NULL; strm->opaque = Z_NULL;
strm->avail_in = 0; strm->avail_in = 0;
strm->next_in = Z_NULL; strm->next_in = Z_NULL;
if (!strm.inflate()) if (!strm.inflate())
return false; return false;
@@ -278,7 +264,7 @@ bool HTTPPostData(const wchar_t *url,
dwSize = std::min(dwSize, (DWORD)sizeof(buffer)); dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
if (!WinHttpReadData(hRequest, (void *)buffer, dwSize, if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
&outSize)) { &outSize)) {
*responseCode = -9; *responseCode = -9;
return false; return false;
} }
@@ -311,25 +297,23 @@ bool HTTPPostData(const wchar_t *url,
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile, static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile,
string &zipBuf, const uint8_t *buffer, DWORD outSize, string &zipBuf, const uint8_t *buffer,
int *responseCode) DWORD outSize, int *responseCode)
{ {
strm->avail_in = outSize; strm->avail_in = outSize;
strm->next_in = buffer; strm->next_in = buffer;
do { do {
strm->avail_out = (uInt)zipBuf.size(); strm->avail_out = (uInt)zipBuf.size();
strm->next_out = (Bytef *)zipBuf.data(); strm->next_out = (Bytef *)zipBuf.data();
int zret = inflate(strm, Z_NO_FLUSH); int zret = inflate(strm, Z_NO_FLUSH);
if (zret != Z_STREAM_END && zret != Z_OK) if (zret != Z_STREAM_END && zret != Z_OK)
return false; return false;
DWORD written; DWORD written;
if (!WriteFile(updateFile, if (!WriteFile(updateFile, zipBuf.data(),
zipBuf.data(), MAX_BUF_SIZE - strm->avail_out, &written,
MAX_BUF_SIZE - strm->avail_out,
&written,
nullptr)) { nullptr)) {
*responseCode = -10; *responseCode = -10;
return false; return false;
@@ -346,7 +330,7 @@ static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile,
} }
static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer, static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer,
DWORD outSize, int *responseCode) DWORD outSize, int *responseCode)
{ {
DWORD written; DWORD written;
if (!WriteFile(updateFile, buffer, outSize, &written, nullptr)) { if (!WriteFile(updateFile, buffer, outSize, &written, nullptr)) {
@@ -363,20 +347,18 @@ static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer,
return true; return true;
} }
bool HTTPGetFile(HINTERNET hConnect, bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url,
const wchar_t *url, const wchar_t *outputPath, const wchar_t *extraHeaders,
const wchar_t *outputPath, int *responseCode)
const wchar_t *extraHeaders,
int * responseCode)
{ {
HttpHandle hRequest; HttpHandle hRequest;
const wchar_t *acceptTypes[] = {L"*/*", nullptr}; const wchar_t *acceptTypes[] = {L"*/*", nullptr};
URL_COMPONENTS urlComponents = {}; URL_COMPONENTS urlComponents = {};
bool secure = false; bool secure = false;
string zipBuf; string zipBuf;
wchar_t hostName[256]; wchar_t hostName[256];
wchar_t path[1024]; wchar_t path[1024];
@@ -385,10 +367,10 @@ bool HTTPGetFile(HINTERNET hConnect,
urlComponents.dwStructSize = sizeof(urlComponents); urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = hostName; urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = _countof(hostName); urlComponents.dwHostNameLength = _countof(hostName);
urlComponents.lpszUrlPath = path; urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = _countof(path); urlComponents.dwUrlPathLength = _countof(path);
WinHttpCrackUrl(url, 0, 0, &urlComponents); WinHttpCrackUrl(url, 0, 0, &urlComponents);
@@ -399,23 +381,19 @@ bool HTTPGetFile(HINTERNET hConnect,
/* -------------------------------------- * /* -------------------------------------- *
* request data */ * request data */
hRequest = WinHttpOpenRequest(hConnect, hRequest = WinHttpOpenRequest(hConnect, L"GET", path, nullptr,
L"GET", WINHTTP_NO_REFERER, acceptTypes,
path, secure ? WINHTTP_FLAG_SECURE |
nullptr, WINHTTP_FLAG_REFRESH
WINHTTP_NO_REFERER, : WINHTTP_FLAG_REFRESH);
acceptTypes,
secure
? WINHTTP_FLAG_SECURE |
WINHTTP_FLAG_REFRESH
: WINHTTP_FLAG_REFRESH);
if (!hRequest) { if (!hRequest) {
*responseCode = -3; *responseCode = -3;
return false; return false;
} }
bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders, bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); extraHeaders ? -1 : 0,
WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
/* -------------------------------------- * /* -------------------------------------- *
* end request */ * end request */
@@ -431,18 +409,15 @@ bool HTTPGetFile(HINTERNET hConnect,
* get headers */ * get headers */
wchar_t encoding[64]; wchar_t encoding[64];
DWORD encodingLen; DWORD encodingLen;
wchar_t statusCode[8]; wchar_t statusCode[8];
DWORD statusCodeLen; DWORD statusCodeLen;
statusCodeLen = sizeof(statusCode); statusCodeLen = sizeof(statusCode);
if (!WinHttpQueryHeaders(hRequest, if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE,
WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode,
WINHTTP_HEADER_NAME_BY_INDEX, &statusCodeLen, WINHTTP_NO_HEADER_INDEX)) {
&statusCode,
&statusCodeLen,
WINHTTP_NO_HEADER_INDEX)) {
*responseCode = -4; *responseCode = -4;
return false; return false;
} else { } else {
@@ -450,12 +425,9 @@ bool HTTPGetFile(HINTERNET hConnect,
} }
encodingLen = sizeof(encoding); encodingLen = sizeof(encoding);
if (!WinHttpQueryHeaders(hRequest, if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_ENCODING,
WINHTTP_QUERY_CONTENT_ENCODING, WINHTTP_HEADER_NAME_BY_INDEX, encoding,
WINHTTP_HEADER_NAME_BY_INDEX, &encodingLen, WINHTTP_NO_HEADER_INDEX)) {
encoding,
&encodingLen,
WINHTTP_NO_HEADER_INDEX)) {
encoding[0] = 0; encoding[0] = 0;
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) { if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
*responseCode = -5; *responseCode = -5;
@@ -472,11 +444,11 @@ bool HTTPGetFile(HINTERNET hConnect,
bool gzip = wcscmp(encoding, L"gzip") == 0; bool gzip = wcscmp(encoding, L"gzip") == 0;
if (gzip) { if (gzip) {
strm->zalloc = Z_NULL; strm->zalloc = Z_NULL;
strm->zfree = Z_NULL; strm->zfree = Z_NULL;
strm->opaque = Z_NULL; strm->opaque = Z_NULL;
strm->avail_in = 0; strm->avail_in = 0;
strm->next_in = Z_NULL; strm->next_in = Z_NULL;
if (!strm.inflate()) if (!strm.inflate())
return false; return false;
@@ -498,12 +470,12 @@ bool HTTPGetFile(HINTERNET hConnect,
if (!bResults || *responseCode != 200) if (!bResults || *responseCode != 200)
return true; return true;
BYTE buffer[READ_BUF_SIZE]; BYTE buffer[READ_BUF_SIZE];
DWORD dwSize, outSize; DWORD dwSize, outSize;
int lastPosition = 0; int lastPosition = 0;
WinHandle updateFile = CreateFile(outputPath, GENERIC_WRITE, 0, WinHandle updateFile = CreateFile(outputPath, GENERIC_WRITE, 0, nullptr,
nullptr, CREATE_ALWAYS, 0, nullptr); CREATE_ALWAYS, 0, nullptr);
if (!updateFile.Valid()) { if (!updateFile.Valid()) {
*responseCode = -7; *responseCode = -7;
return false; return false;
@@ -520,7 +492,7 @@ bool HTTPGetFile(HINTERNET hConnect,
dwSize = std::min(dwSize, (DWORD)sizeof(buffer)); dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
if (!WinHttpReadData(hRequest, (void *)buffer, dwSize, if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
&outSize)) { &outSize)) {
*responseCode = -9; *responseCode = -9;
return false; return false;
} else { } else {
@@ -529,21 +501,22 @@ bool HTTPGetFile(HINTERNET hConnect,
if (gzip) { if (gzip) {
if (!ReadHTTPZippedFile(strm, updateFile, if (!ReadHTTPZippedFile(strm, updateFile,
zipBuf, buffer, zipBuf, buffer, outSize,
outSize, responseCode)) responseCode))
return false; return false;
} else { } else {
if (!ReadHTTPFile(updateFile, buffer, if (!ReadHTTPFile(updateFile, buffer, outSize,
outSize, responseCode)) responseCode))
return false; return false;
} }
int position = (int)(((float)completedFileSize / int position = (int)(((float)completedFileSize /
(float)totalFileSize) * 100.0f); (float)totalFileSize) *
100.0f);
if (position > lastPosition) { if (position > lastPosition) {
lastPosition = position; lastPosition = position;
SendDlgItemMessage(hwndMain, IDC_PROGRESS, SendDlgItemMessage(hwndMain, IDC_PROGRESS,
PBM_SETPOS, position, 0); PBM_SETPOS, position, 0);
} }
} }
+31 -34
View File
@@ -20,16 +20,16 @@
#include <vector> #include <vector>
#ifdef _MSC_VER #ifdef _MSC_VER
# define restrict __restrict #define restrict __restrict
# include <lzma.h> #include <lzma.h>
# undef restrict #undef restrict
#else #else
# include <lzma.h> #include <lzma.h>
#endif #endif
using namespace std; using namespace std;
#define MAX_BUF_SIZE 262144 #define MAX_BUF_SIZE 262144
#define READ_BUF_SIZE 32768 #define READ_BUF_SIZE 32768
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@@ -48,10 +48,7 @@ public:
inline bool init_decoder() inline bool init_decoder()
{ {
lzma_ret ret = lzma_stream_decoder( lzma_ret ret = lzma_stream_decoder(&strm, 200 * 1024 * 1024, 0);
&strm,
200 * 1024 * 1024,
0);
initialized = (ret == LZMA_OK); initialized = (ret == LZMA_OK);
return initialized; return initialized;
} }
@@ -82,7 +79,7 @@ public:
struct bspatch_stream { struct bspatch_stream {
void *opaque; void *opaque;
int (*read)(const struct bspatch_stream *stream, void *buffer, int (*read)(const struct bspatch_stream *stream, void *buffer,
int length); int length);
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@@ -116,7 +113,7 @@ static int64_t offtin(const uint8_t *buf)
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp, static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp,
int64_t newsize, struct bspatch_stream *stream) int64_t newsize, struct bspatch_stream *stream)
{ {
uint8_t buf[8]; uint8_t buf[8];
int64_t oldpos, newpos; int64_t oldpos, newpos;
@@ -169,9 +166,9 @@ static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp,
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
struct patch_data { struct patch_data {
HANDLE h; HANDLE h;
lzma_stream *strm; lzma_stream *strm;
uint8_t buf[READ_BUF_SIZE]; uint8_t buf[READ_BUF_SIZE];
}; };
static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len) static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
@@ -179,24 +176,24 @@ static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
if (!len) if (!len)
return 0; return 0;
patch_data *data = (patch_data*)stream->opaque; patch_data *data = (patch_data *)stream->opaque;
HANDLE h = data->h; HANDLE h = data->h;
lzma_stream *strm = data->strm; lzma_stream *strm = data->strm;
strm->avail_out = (size_t)len; strm->avail_out = (size_t)len;
strm->next_out = (uint8_t *)buffer; strm->next_out = (uint8_t *)buffer;
for (;;) { for (;;) {
if (strm->avail_in == 0) { if (strm->avail_in == 0) {
DWORD read_size; DWORD read_size;
if (!ReadFile(h, data->buf, READ_BUF_SIZE, &read_size, if (!ReadFile(h, data->buf, READ_BUF_SIZE, &read_size,
nullptr)) nullptr))
return -1; return -1;
if (read_size == 0) if (read_size == 0)
return -1; return -1;
strm->avail_in = (size_t)read_size; strm->avail_in = (size_t)read_size;
strm->next_in = data->buf; strm->next_in = data->buf;
} }
lzma_ret ret = lzma_code(strm, LZMA_RUN); lzma_ret ret = lzma_code(strm, LZMA_RUN);
@@ -213,25 +210,25 @@ static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
int ApplyPatch(const wchar_t *patchFile, const wchar_t *targetFile) int ApplyPatch(const wchar_t *patchFile, const wchar_t *targetFile)
try { try {
uint8_t header[24]; uint8_t header[24];
int64_t newsize; int64_t newsize;
struct bspatch_stream stream; struct bspatch_stream stream;
bool success; bool success;
WinHandle hPatch; WinHandle hPatch;
WinHandle hTarget; WinHandle hTarget;
LZMAStream strm; LZMAStream strm;
/* --------------------------------- * /* --------------------------------- *
* open patch and file to patch */ * open patch and file to patch */
hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr, hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr, OPEN_EXISTING,
OPEN_EXISTING, 0, nullptr); 0, nullptr);
if (!hPatch.Valid()) if (!hPatch.Valid())
throw int(GetLastError()); throw int(GetLastError());
hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr, hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr,
OPEN_EXISTING, 0, nullptr); OPEN_EXISTING, 0, nullptr);
if (!hTarget.Valid()) if (!hTarget.Valid())
throw int(GetLastError()); throw int(GetLastError());
@@ -289,14 +286,14 @@ try {
throw int(-10); throw int(-10);
patch_data data; patch_data data;
data.h = hPatch; data.h = hPatch;
data.strm = strm.get(); data.strm = strm.get();
stream.read = read_lzma; stream.read = read_lzma;
stream.opaque = &data; stream.opaque = &data;
int ret = bspatch(oldData.data(), oldData.size(), newData.data(), int ret = bspatch(oldData.data(), oldData.size(), newData.data(),
newData.size(), &stream); newData.size(), &stream);
if (ret != 0) if (ret != 0)
throw int(-9); throw int(-9);
@@ -305,14 +302,14 @@ try {
hTarget = nullptr; hTarget = nullptr;
hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr, hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr,
CREATE_ALWAYS, 0, nullptr); CREATE_ALWAYS, 0, nullptr);
if (!hTarget.Valid()) if (!hTarget.Valid())
throw int(GetLastError()); throw int(GetLastError());
DWORD written; DWORD written;
success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize, success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize, &written,
&written, nullptr); nullptr);
if (!success || written != newsize) if (!success || written != newsize)
throw int(GetLastError()); throw int(GetLastError());
+10 -10
View File
@@ -2,20 +2,20 @@
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by updater.rc // Used by updater.rc
// //
#define IDD_UPDATEDIALOG 101 #define IDD_UPDATEDIALOG 101
#define IDI_ICON1 103 #define IDI_ICON1 103
#define IDC_PROGRESS 1001 #define IDC_PROGRESS 1001
#define IDC_STATUS 1002 #define IDC_STATUS 1002
#define IDCBUTTON 1004 #define IDCBUTTON 1004
#define IDC_BUTTON 1004 #define IDC_BUTTON 1004
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_RESOURCE_VALUE 104
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1005 #define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif
File diff suppressed because it is too large. Load diff
+34 -43
View File
@@ -45,53 +45,44 @@
#define BLAKE2_HASH_STR_LENGTH ((BLAKE2_HASH_LENGTH * 2) + 1) #define BLAKE2_HASH_STR_LENGTH ((BLAKE2_HASH_LENGTH * 2) + 1)
#if defined _M_IX86 #if defined _M_IX86
#pragma comment(linker, \ #pragma comment(linker, "/manifestdependency:\"type='win32' " \
"/manifestdependency:\"type='win32' " \ "name='Microsoft.Windows.Common-Controls' " \
"name='Microsoft.Windows.Common-Controls' " \ "version='6.0.0.0' " \
"version='6.0.0.0' " \ "processorArchitecture='x86' " \
"processorArchitecture='x86' " \ "publicKeyToken='6595b64144ccf1df' " \
"publicKeyToken='6595b64144ccf1df' " \ "language='*'\"")
"language='*'\"")
#elif defined _M_IA64 #elif defined _M_IA64
#pragma comment(linker, \ #pragma comment(linker, "/manifestdependency:\"type='win32' " \
"/manifestdependency:\"type='win32' " \ "name='Microsoft.Windows.Common-Controls' " \
"name='Microsoft.Windows.Common-Controls' " \ "version='6.0.0.0' " \
"version='6.0.0.0' " \ "processorArchitecture='ia64' " \
"processorArchitecture='ia64' " \ "publicKeyToken='6595b64144ccf1df' " \
"publicKeyToken='6595b64144ccf1df' " \ "language='*'\"")
"language='*'\"")
#elif defined _M_X64 #elif defined _M_X64
#pragma comment(linker, \ #pragma comment(linker, "/manifestdependency:\"type='win32' " \
"/manifestdependency:\"type='win32' " \ "name='Microsoft.Windows.Common-Controls' " \
"name='Microsoft.Windows.Common-Controls' " \ "version='6.0.0.0' " \
"version='6.0.0.0' " \ "processorArchitecture='amd64' " \
"processorArchitecture='amd64' " \ "publicKeyToken='6595b64144ccf1df' " \
"publicKeyToken='6595b64144ccf1df' " \ "language='*'\"")
"language='*'\"")
#else #else
#pragma comment(linker, \ #pragma comment(linker, "/manifestdependency:\"type='win32' " \
"/manifestdependency:\"type='win32' " \ "name='Microsoft.Windows.Common-Controls' " \
"name='Microsoft.Windows.Common-Controls' " \ "version='6.0.0.0' processorArchitecture='*' " \
"version='6.0.0.0' processorArchitecture='*' " \ "publicKeyToken='6595b64144ccf1df' " \
"publicKeyToken='6595b64144ccf1df' " \ "language='*'\"")
"language='*'\"")
#endif #endif
#include <util/windows/WinHandle.hpp> #include <util/windows/WinHandle.hpp>
#include <jansson.h> #include <jansson.h>
#include "resource.h" #include "resource.h"
bool HTTPGetFile(HINTERNET hConnect, bool HTTPGetFile(HINTERNET hConnect, const wchar_t *url,
const wchar_t *url, const wchar_t *outputPath, const wchar_t *extraHeaders,
const wchar_t *outputPath, int *responseCode);
const wchar_t *extraHeaders, bool HTTPPostData(const wchar_t *url, const BYTE *data, int dataLen,
int * responseCode); const wchar_t *extraHeaders, int *responseCode,
bool HTTPPostData(const wchar_t *url, std::string &response);
const BYTE * data,
int dataLen,
const wchar_t *extraHeaders,
int * responseCode,
std::string & response);
void HashToString(const BYTE *in, wchar_t *out); void HashToString(const BYTE *in, wchar_t *out);
void StringToHash(const wchar_t *in, BYTE *out); void StringToHash(const wchar_t *in, BYTE *out);
@@ -100,17 +91,17 @@ bool CalculateFileHash(const wchar_t *path, BYTE *hash);
int ApplyPatch(LPCTSTR patchFile, LPCTSTR targetFile); int ApplyPatch(LPCTSTR patchFile, LPCTSTR targetFile);
extern HWND hwndMain; extern HWND hwndMain;
extern HCRYPTPROV hProvider; extern HCRYPTPROV hProvider;
extern int totalFileSize; extern int totalFileSize;
extern int completedFileSize; extern int completedFileSize;
extern HANDLE cancelRequested; extern HANDLE cancelRequested;
#pragma pack(push, r1, 1) #pragma pack(push, r1, 1)
typedef struct { typedef struct {
BLOBHEADER blobheader; BLOBHEADER blobheader;
RSAPUBKEY rsapubkey; RSAPUBKEY rsapubkey;
} PUBLICKEYHEADER; } PUBLICKEYHEADER;
#pragma pack(pop, r1) #pragma pack(pop, r1)
+18 -17
View File
@@ -23,9 +23,9 @@ public:
freefunc(handle); freefunc(handle);
} }
inline T *operator&() {return &handle;} inline T *operator&() { return &handle; }
inline operator T() const {return handle;} inline operator T() const { return handle; }
inline T get() const {return handle;} inline T get() const { return handle; }
inline CustomHandle<T, freefunc> &operator=(T in) inline CustomHandle<T, freefunc> &operator=(T in)
{ {
@@ -35,7 +35,7 @@ public:
return *this; return *this;
} }
inline bool operator!() const {return !handle;} inline bool operator!() const { return !handle; }
}; };
void FreeProvider(HCRYPTPROV prov); void FreeProvider(HCRYPTPROV prov);
@@ -43,8 +43,8 @@ void FreeHash(HCRYPTHASH hash);
void FreeKey(HCRYPTKEY key); void FreeKey(HCRYPTKEY key);
using CryptProvider = CustomHandle<HCRYPTPROV, FreeProvider>; using CryptProvider = CustomHandle<HCRYPTPROV, FreeProvider>;
using CryptHash = CustomHandle<HCRYPTHASH, FreeHash>; using CryptHash = CustomHandle<HCRYPTHASH, FreeHash>;
using CryptKey = CustomHandle<HCRYPTKEY, FreeKey>; using CryptKey = CustomHandle<HCRYPTKEY, FreeKey>;
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@@ -58,13 +58,13 @@ public:
LocalFree(ptr); LocalFree(ptr);
} }
inline T **operator&() {return &ptr;} inline T **operator&() { return &ptr; }
inline operator T() const {return ptr;} inline operator T() const { return ptr; }
inline T *get() const {return ptr;} inline T *get() const { return ptr; }
inline bool operator!() const {return !ptr;} inline bool operator!() const { return !ptr; }
inline T *operator->() {return ptr;} inline T *operator->() { return ptr; }
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@@ -76,9 +76,10 @@ public:
inline Json() : json(nullptr) {} inline Json() : json(nullptr) {}
explicit inline Json(json_t *json_) : json(json_) {} explicit inline Json(json_t *json_) : json(json_) {}
inline Json(const Json &from) : json(json_incref(from.json)) {} inline Json(const Json &from) : json(json_incref(from.json)) {}
inline Json(Json &&from) : json(from.json) {from.json = nullptr;} inline Json(Json &&from) : json(from.json) { from.json = nullptr; }
inline ~Json() { inline ~Json()
{
if (json) if (json)
json_decref(json); json_decref(json);
} }
@@ -106,12 +107,12 @@ public:
return *this; return *this;
} }
inline operator json_t *() const {return json;} inline operator json_t *() const { return json; }
inline bool operator!() const {return !json;} inline bool operator!() const { return !json; }
inline const char *GetString(const char *name, inline const char *GetString(const char *name,
const char *def = nullptr) const const char *def = nullptr) const
{ {
json_t *obj(json_object_get(json, name)); json_t *obj(json_object_get(json, name));
if (!obj) if (!obj)
@@ -130,7 +131,7 @@ public:
return json_object_get(json, name); return json_object_get(json, name);
} }
inline json_t *get() const {return json;} inline json_t *get() const { return json; }
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
+111 -155
View File
@@ -42,7 +42,7 @@ static __declspec(thread) HCRYPTPROV provider = 0;
typedef struct { typedef struct {
BLOBHEADER blobheader; BLOBHEADER blobheader;
RSAPUBKEY rsapubkey; RSAPUBKEY rsapubkey;
} PUBLICKEYHEADER; } PUBLICKEYHEADER;
#pragma pack(pop, r1) #pragma pack(pop, r1)
@@ -120,8 +120,7 @@ static const unsigned char obs_pub[] = {
0x42, 0x61, 0x35, 0x66, 0x37, 0x4c, 0x6f, 0x4b, 0x38, 0x43, 0x41, 0x77, 0x42, 0x61, 0x35, 0x66, 0x37, 0x4c, 0x6f, 0x4b, 0x38, 0x43, 0x41, 0x77,
0x45, 0x41, 0x41, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x41, 0x41, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b,
0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
};
static const unsigned int obs_pub_len = 800; static const unsigned int obs_pub_len = 800;
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@@ -132,23 +131,18 @@ try {
if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0) if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0)
return false; return false;
WinHandle handle = CreateFileW( WinHandle handle = CreateFileW(w_file, GENERIC_WRITE, 0, nullptr,
w_file, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
GENERIC_WRITE, nullptr);
0,
nullptr,
CREATE_ALWAYS,
FILE_FLAG_WRITE_THROUGH,
nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
throw strprintf("Failed to open file '%s': %lu", throw strprintf("Failed to open file '%s': %lu", file,
file, GetLastError()); GetLastError());
DWORD written; DWORD written;
if (!WriteFile(handle, data, (DWORD)size, &written, nullptr)) if (!WriteFile(handle, data, (DWORD)size, &written, nullptr))
throw strprintf("Failed to write file '%s': %lu", throw strprintf("Failed to write file '%s': %lu", file,
file, GetLastError()); GetLastError());
return true; return true;
@@ -163,26 +157,20 @@ try {
if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0) if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0)
return false; return false;
WinHandle handle = CreateFileW( WinHandle handle = CreateFileW(w_file, GENERIC_READ, FILE_SHARE_READ,
w_file, nullptr, OPEN_EXISTING, 0, nullptr);
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
0,
nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
throw strprintf("Failed to open file '%s': %lu", throw strprintf("Failed to open file '%s': %lu", file,
file, GetLastError()); GetLastError());
DWORD size = GetFileSize(handle, nullptr); DWORD size = GetFileSize(handle, nullptr);
data.resize(size); data.resize(size);
DWORD read; DWORD read;
if (!ReadFile(handle, &data[0], size, &read, nullptr)) if (!ReadFile(handle, &data[0], size, &read, nullptr))
throw strprintf("Failed to write file '%s': %lu", throw strprintf("Failed to write file '%s': %lu", file,
file, GetLastError()); GetLastError());
return true; return true;
@@ -196,7 +184,7 @@ static void HashToString(const uint8_t *in, char *out)
const char alphabet[] = "0123456789abcdef"; const char alphabet[] = "0123456789abcdef";
for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) { for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
out[2 * i] = alphabet[in[i] / 16]; out[2 * i] = alphabet[in[i] / 16];
out[2 * i + 1] = alphabet[in[i] % 16]; out[2 * i + 1] = alphabet[in[i] % 16];
} }
@@ -214,10 +202,10 @@ try {
return false; return false;
WinHandle handle = CreateFileW(w_path, GENERIC_READ, FILE_SHARE_READ, WinHandle handle = CreateFileW(w_path, GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, 0, nullptr); nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
throw strprintf("Failed to open file '%s': %lu", throw strprintf("Failed to open file '%s': %lu", path,
path, GetLastError()); GetLastError());
vector<BYTE> buf; vector<BYTE> buf;
buf.resize(65536); buf.resize(65536);
@@ -225,9 +213,9 @@ try {
for (;;) { for (;;) {
DWORD read = 0; DWORD read = 0;
if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read, if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
nullptr)) nullptr))
throw strprintf("Failed to read file '%s': %lu", throw strprintf("Failed to read file '%s': %lu", path,
path, GetLastError()); GetLastError());
if (!read) if (!read)
break; break;
@@ -249,19 +237,19 @@ try {
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig, static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
size_t sigLen) size_t sigLen)
{ {
/* ASN of PEM public key */ /* ASN of PEM public key */
BYTE binaryKey[1024]; BYTE binaryKey[1024];
DWORD binaryKeyLen = sizeof(binaryKey); DWORD binaryKeyLen = sizeof(binaryKey);
/* Windows X509 public key info from ASN */ /* Windows X509 public key info from ASN */
LocalPtr<CERT_PUBLIC_KEY_INFO> publicPBLOB; LocalPtr<CERT_PUBLIC_KEY_INFO> publicPBLOB;
DWORD iPBLOBSize; DWORD iPBLOBSize;
/* RSA BLOB info from X509 public key */ /* RSA BLOB info from X509 public key */
LocalPtr<PUBLICKEYHEADER> rsaPublicBLOB; LocalPtr<PUBLICKEYHEADER> rsaPublicBLOB;
DWORD rsaPublicBLOBSize; DWORD rsaPublicBLOBSize;
/* Handle to public key */ /* Handle to public key */
CryptKey keyOut; CryptKey keyOut;
@@ -272,41 +260,26 @@ static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
/* Signature in little-endian format */ /* Signature in little-endian format */
vector<BYTE> reversedSig; vector<BYTE> reversedSig;
if (!CryptStringToBinaryA((LPCSTR)obs_pub, if (!CryptStringToBinaryA((LPCSTR)obs_pub, obs_pub_len,
obs_pub_len, CRYPT_STRING_BASE64HEADER, binaryKey,
CRYPT_STRING_BASE64HEADER, &binaryKeyLen, nullptr, nullptr))
binaryKey,
&binaryKeyLen,
nullptr,
nullptr))
return false; return false;
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
X509_PUBLIC_KEY_INFO, binaryKey, binaryKeyLen,
binaryKey, CRYPT_ENCODE_ALLOC_FLAG, nullptr, &publicPBLOB,
binaryKeyLen, &iPBLOBSize))
CRYPT_ENCODE_ALLOC_FLAG,
nullptr,
&publicPBLOB,
&iPBLOBSize))
return false; return false;
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, if (!CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
RSA_CSP_PUBLICKEYBLOB, publicPBLOB->PublicKey.pbData,
publicPBLOB->PublicKey.pbData, publicPBLOB->PublicKey.cbData,
publicPBLOB->PublicKey.cbData, CRYPT_ENCODE_ALLOC_FLAG, nullptr,
CRYPT_ENCODE_ALLOC_FLAG, &rsaPublicBLOB, &rsaPublicBLOBSize))
nullptr,
&rsaPublicBLOB,
&rsaPublicBLOBSize))
return false; return false;
if (!CryptImportKey(provider, if (!CryptImportKey(provider, (const BYTE *)rsaPublicBLOB.get(),
(const BYTE *)rsaPublicBLOB.get(), rsaPublicBLOBSize, 0, 0, &keyOut))
rsaPublicBLOBSize,
0,
0,
&keyOut))
return false; return false;
if (!CryptCreateHash(provider, CALG_SHA_512, 0, 0, &hash)) if (!CryptCreateHash(provider, CALG_SHA_512, 0, 0, &hash))
@@ -321,19 +294,15 @@ static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
for (size_t i = 0; i < sigLen; i++) for (size_t i = 0; i < sigLen; i++)
reversedSig[i] = sig[sigLen - i - 1]; reversedSig[i] = sig[sigLen - i - 1];
if (!CryptVerifySignature(hash, if (!CryptVerifySignature(hash, reversedSig.data(), (DWORD)sigLen,
reversedSig.data(), keyOut, nullptr, 0))
(DWORD)sigLen,
keyOut,
nullptr,
0))
return false; return false;
return true; return true;
} }
static inline void HexToByteArray(const char *hexStr, size_t hexLen, static inline void HexToByteArray(const char *hexStr, size_t hexLen,
vector<uint8_t> &out) vector<uint8_t> &out)
{ {
char ptr[3]; char ptr[3];
@@ -347,7 +316,7 @@ static inline void HexToByteArray(const char *hexStr, size_t hexLen,
} }
static bool CheckDataSignature(const string &data, const char *name, static bool CheckDataSignature(const string &data, const char *name,
const char *hexSig, size_t sigLen) const char *hexSig, size_t sigLen)
try { try {
if (sigLen == 0 || sigLen > 0xFFFF || (sigLen & 1) != 0) if (sigLen == 0 || sigLen > 0xFFFF || (sigLen & 1) != 0)
throw strprintf("Missing or invalid signature for %s", name); throw strprintf("Missing or invalid signature for %s", name);
@@ -357,10 +326,8 @@ try {
signature.reserve(sigLen); signature.reserve(sigLen);
HexToByteArray(hexSig, sigLen, signature); HexToByteArray(hexSig, sigLen, signature);
if (!VerifyDigitalSignature((uint8_t*)data.data(), if (!VerifyDigitalSignature((uint8_t *)data.data(), data.size(),
data.size(), signature.data(), signature.size()))
signature.data(),
signature.size()))
throw strprintf("Signature check failed for %s", name); throw strprintf("Signature check failed for %s", name);
return true; return true;
@@ -374,12 +341,12 @@ try {
static bool FetchUpdaterModule(const char *url) static bool FetchUpdaterModule(const char *url)
try { try {
long responseCode; long responseCode;
uint8_t updateFileHash[BLAKE2_HASH_LENGTH]; uint8_t updateFileHash[BLAKE2_HASH_LENGTH];
vector<string> extraHeaders; vector<string> extraHeaders;
BPtr<char> updateFilePath = GetConfigPathPtr( BPtr<char> updateFilePath =
"obs-studio\\updates\\updater.exe"); GetConfigPathPtr("obs-studio\\updates\\updater.exe");
if (CalculateFileHash(updateFilePath, updateFileHash)) { if (CalculateFileHash(updateFilePath, updateFileHash)) {
char hashString[BLAKE2_HASH_STR_LENGTH]; char hashString[BLAKE2_HASH_STR_LENGTH];
@@ -394,8 +361,8 @@ try {
string error; string error;
string data; string data;
bool success = GetRemoteFile(url, data, error, &responseCode, bool success = GetRemoteFile(url, data, error, &responseCode, nullptr,
nullptr, nullptr, extraHeaders, &signature); nullptr, extraHeaders, &signature);
if (!success || (responseCode != 200 && responseCode != 304)) { if (!success || (responseCode != 200 && responseCode != 304)) {
if (responseCode == 404) if (responseCode == 404)
@@ -407,7 +374,7 @@ try {
/* A new file must be digitally signed */ /* A new file must be digitally signed */
if (responseCode == 200) { if (responseCode == 200) {
bool valid = CheckDataSignature(data, url, signature.data(), bool valid = CheckDataSignature(data, url, signature.data(),
signature.size()); signature.size());
if (!valid) if (!valid)
throw string("Invalid updater module signature"); throw string("Invalid updater module signature");
@@ -425,7 +392,7 @@ try {
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable, static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable,
string &notes_str, int &updateVer) string &notes_str, int &updateVer)
try { try {
json_error_t error; json_error_t error;
@@ -442,10 +409,8 @@ try {
int patch = root.GetInt("version_patch"); int patch = root.GetInt("version_patch");
if (major == 0) if (major == 0)
throw strprintf("Invalid version number: %d.%d.%d", throw strprintf("Invalid version number: %d.%d.%d", major,
major, minor, patch);
minor,
patch);
json_t *notes = json_object_get(root, "notes"); json_t *notes = json_object_get(root, "notes");
if (!json_is_string(notes)) if (!json_is_string(notes))
@@ -491,8 +456,8 @@ string GetProgramGUID()
/* NOTE: this is an arbitrary random number that we use to count the /* NOTE: this is an arbitrary random number that we use to count the
* number of unique OBS installations and is not associated with any * number of unique OBS installations and is not associated with any
* kind of identifiable information */ * kind of identifiable information */
const char *pguid = config_get_string(GetGlobalConfig(), const char *pguid =
"General", "InstallGUID"); config_get_string(GetGlobalConfig(), "General", "InstallGUID");
string guid; string guid;
if (pguid) if (pguid)
guid = pguid; guid = pguid;
@@ -501,9 +466,8 @@ string GetProgramGUID()
GenerateGUID(guid); GenerateGUID(guid);
if (!guid.empty()) if (!guid.empty())
config_set_string(GetGlobalConfig(), config_set_string(GetGlobalConfig(), "General",
"General", "InstallGUID", "InstallGUID", guid.c_str());
guid.c_str());
} }
return guid; return guid;
@@ -516,13 +480,12 @@ void AutoUpdateThread::infoMsg(const QString &title, const QString &text)
void AutoUpdateThread::info(const QString &title, const QString &text) void AutoUpdateThread::info(const QString &title, const QString &text)
{ {
QMetaObject::invokeMethod(this, "infoMsg", QMetaObject::invokeMethod(this, "infoMsg", Qt::BlockingQueuedConnection,
Qt::BlockingQueuedConnection, Q_ARG(QString, title), Q_ARG(QString, text));
Q_ARG(QString, title),
Q_ARG(QString, text));
} }
int AutoUpdateThread::queryUpdateSlot(bool localManualUpdate, const QString &text) int AutoUpdateThread::queryUpdateSlot(bool localManualUpdate,
const QString &text)
{ {
OBSUpdate updateDlg(App()->GetMainWindow(), localManualUpdate, text); OBSUpdate updateDlg(App()->GetMainWindow(), localManualUpdate, text);
return updateDlg.exec(); return updateDlg.exec();
@@ -533,17 +496,17 @@ int AutoUpdateThread::queryUpdate(bool localManualUpdate, const char *text_utf8)
int ret = OBSUpdate::No; int ret = OBSUpdate::No;
QString text = text_utf8; QString text = text_utf8;
QMetaObject::invokeMethod(this, "queryUpdateSlot", QMetaObject::invokeMethod(this, "queryUpdateSlot",
Qt::BlockingQueuedConnection, Qt::BlockingQueuedConnection,
Q_RETURN_ARG(int, ret), Q_RETURN_ARG(int, ret),
Q_ARG(bool, localManualUpdate), Q_ARG(bool, localManualUpdate),
Q_ARG(QString, text)); Q_ARG(QString, text));
return ret; return ret;
} }
static bool IsFileInUse(const wstring &file) static bool IsFileInUse(const wstring &file)
{ {
WinHandle f = CreateFile(file.c_str(), GENERIC_WRITE, 0, nullptr, WinHandle f = CreateFile(file.c_str(), GENERIC_WRITE, 0, nullptr,
OPEN_EXISTING, 0, nullptr); OPEN_EXISTING, 0, nullptr);
if (!f.Valid()) { if (!f.Valid()) {
int err = GetLastError(); int err = GetLastError();
if (err == ERROR_SHARING_VIOLATION || if (err == ERROR_SHARING_VIOLATION ||
@@ -557,35 +520,33 @@ static bool IsFileInUse(const wstring &file)
static bool IsGameCaptureInUse() static bool IsGameCaptureInUse()
{ {
wstring path = L"..\\..\\data\\obs-plugins\\win-capture\\graphics-hook"; wstring path = L"..\\..\\data\\obs-plugins\\win-capture\\graphics-hook";
return IsFileInUse(path + L"32.dll") || return IsFileInUse(path + L"32.dll") || IsFileInUse(path + L"64.dll");
IsFileInUse(path + L"64.dll");
} }
void AutoUpdateThread::run() void AutoUpdateThread::run()
try { try {
long responseCode; long responseCode;
vector<string> extraHeaders; vector<string> extraHeaders;
string text; string text;
string error; string error;
string signature; string signature;
CryptProvider localProvider; CryptProvider localProvider;
BYTE manifestHash[BLAKE2_HASH_LENGTH]; BYTE manifestHash[BLAKE2_HASH_LENGTH];
bool updatesAvailable = false; bool updatesAvailable = false;
bool success; bool success;
struct FinishedTrigger { struct FinishedTrigger {
inline ~FinishedTrigger() inline ~FinishedTrigger()
{ {
QMetaObject::invokeMethod(App()->GetMainWindow(), QMetaObject::invokeMethod(App()->GetMainWindow(),
"updateCheckFinished"); "updateCheckFinished");
} }
} finishedTrigger; } finishedTrigger;
BPtr<char> manifestPath = GetConfigPathPtr( BPtr<char> manifestPath =
"obs-studio\\updates\\manifest.json"); GetConfigPathPtr("obs-studio\\updates\\manifest.json");
auto ActiveOrGameCaptureLocked = [this] () auto ActiveOrGameCaptureLocked = [this]() {
{
if (obs_video_active()) { if (obs_video_active()) {
if (manualUpdate) if (manualUpdate)
info(QTStr("Updater.Running.Title"), info(QTStr("Updater.Running.Title"),
@@ -611,11 +572,8 @@ try {
/* ----------------------------------- * /* ----------------------------------- *
* create signature provider */ * create signature provider */
if (!CryptAcquireContext(&localProvider, if (!CryptAcquireContext(&localProvider, nullptr, MS_ENH_RSA_AES_PROV,
nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
MS_ENH_RSA_AES_PROV,
PROV_RSA_AES,
CRYPT_VERIFYCONTEXT))
throw strprintf("CryptAcquireContext failed: %lu", throw strprintf("CryptAcquireContext failed: %lu",
GetLastError()); GetLastError());
@@ -647,13 +605,14 @@ try {
* get manifest from server */ * get manifest from server */
success = GetRemoteFile(WIN_MANIFEST_URL, text, error, &responseCode, success = GetRemoteFile(WIN_MANIFEST_URL, text, error, &responseCode,
nullptr, nullptr, extraHeaders, &signature); nullptr, nullptr, extraHeaders, &signature);
if (!success || (responseCode != 200 && responseCode != 304)) { if (!success || (responseCode != 200 && responseCode != 304)) {
if (responseCode == 404) if (responseCode == 404)
return; return;
throw strprintf("Failed to fetch manifest file: %s", error.c_str()); throw strprintf("Failed to fetch manifest file: %s",
error.c_str());
} }
/* ----------------------------------- * /* ----------------------------------- *
@@ -661,8 +620,8 @@ try {
/* a new file must be digitally signed */ /* a new file must be digitally signed */
if (responseCode == 200) { if (responseCode == 200) {
success = CheckDataSignature(text, "manifest", success = CheckDataSignature(text, "manifest", signature.data(),
signature.data(), signature.size()); signature.size());
if (!success) if (!success)
throw string("Invalid manifest signature"); throw string("Invalid manifest signature");
} }
@@ -687,7 +646,7 @@ try {
int updateVer = 0; int updateVer = 0;
success = ParseUpdateManifest(text.c_str(), &updatesAvailable, notes, success = ParseUpdateManifest(text.c_str(), &updatesAvailable, notes,
updateVer); updateVer);
if (!success) if (!success)
throw string("Failed to parse manifest"); throw string("Failed to parse manifest");
@@ -702,7 +661,7 @@ try {
* skip this version if set to skip */ * skip this version if set to skip */
int skipUpdateVer = config_get_int(GetGlobalConfig(), "General", int skipUpdateVer = config_get_int(GetGlobalConfig(), "General",
"SkipUpdateVersion"); "SkipUpdateVersion");
if (!manualUpdate && updateVer == skipUpdateVer) if (!manualUpdate && updateVer == skipUpdateVer)
return; return;
@@ -727,13 +686,13 @@ try {
if (!manualUpdate) { if (!manualUpdate) {
long long t = (long long)time(nullptr); long long t = (long long)time(nullptr);
config_set_int(GetGlobalConfig(), "General", config_set_int(GetGlobalConfig(), "General",
"LastUpdateCheck", t); "LastUpdateCheck", t);
} }
return; return;
} else if (queryResult == OBSUpdate::Skip) { } else if (queryResult == OBSUpdate::Skip) {
config_set_int(GetGlobalConfig(), "General", config_set_int(GetGlobalConfig(), "General",
"SkipUpdateVersion", updateVer); "SkipUpdateVersion", updateVer);
return; return;
} }
@@ -749,8 +708,8 @@ try {
/* ----------------------------------- * /* ----------------------------------- *
* execute updater */ * execute updater */
BPtr<char> updateFilePath = GetConfigPathPtr( BPtr<char> updateFilePath =
"obs-studio\\updates\\updater.exe"); GetConfigPathPtr("obs-studio\\updates\\updater.exe");
BPtr<wchar_t> wUpdateFilePath; BPtr<wchar_t> wUpdateFilePath;
size_t size = os_utf8_to_wcs_ptr(updateFilePath, 0, &wUpdateFilePath); size_t size = os_utf8_to_wcs_ptr(updateFilePath, 0, &wUpdateFilePath);
@@ -773,7 +732,7 @@ try {
execInfo.lpParameters = UPDATE_ARG_SUFFIX; execInfo.lpParameters = UPDATE_ARG_SUFFIX;
execInfo.lpDirectory = cwd; execInfo.lpDirectory = cwd;
execInfo.nShow = SW_SHOWNORMAL; execInfo.nShow = SW_SHOWNORMAL;
if (!ShellExecuteEx(&execInfo)) { if (!ShellExecuteEx(&execInfo)) {
QString msg = QTStr("Updater.FailedToLaunch"); QString msg = QTStr("Updater.FailedToLaunch");
@@ -787,7 +746,7 @@ try {
config_set_int(GetGlobalConfig(), "General", "LastUpdateCheck", 0); config_set_int(GetGlobalConfig(), "General", "LastUpdateCheck", 0);
config_set_int(GetGlobalConfig(), "General", "SkipUpdateVersion", 0); config_set_int(GetGlobalConfig(), "General", "SkipUpdateVersion", 0);
config_set_string(GetGlobalConfig(), "General", "InstallGUID", config_set_string(GetGlobalConfig(), "General", "InstallGUID",
guid.c_str()); guid.c_str());
QMetaObject::invokeMethod(App()->GetMainWindow(), "close"); QMetaObject::invokeMethod(App()->GetMainWindow(), "close");
@@ -799,26 +758,23 @@ try {
void WhatsNewInfoThread::run() void WhatsNewInfoThread::run()
try { try {
long responseCode; long responseCode;
vector<string> extraHeaders; vector<string> extraHeaders;
string text; string text;
string error; string error;
string signature; string signature;
CryptProvider localProvider; CryptProvider localProvider;
BYTE whatsnewHash[BLAKE2_HASH_LENGTH]; BYTE whatsnewHash[BLAKE2_HASH_LENGTH];
bool success; bool success;
BPtr<char> whatsnewPath = GetConfigPathPtr( BPtr<char> whatsnewPath =
"obs-studio\\updates\\whatsnew.json"); GetConfigPathPtr("obs-studio\\updates\\whatsnew.json");
/* ----------------------------------- * /* ----------------------------------- *
* create signature provider */ * create signature provider */
if (!CryptAcquireContext(&localProvider, if (!CryptAcquireContext(&localProvider, nullptr, MS_ENH_RSA_AES_PROV,
nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
MS_ENH_RSA_AES_PROV,
PROV_RSA_AES,
CRYPT_VERIFYCONTEXT))
throw strprintf("CryptAcquireContext failed: %lu", throw strprintf("CryptAcquireContext failed: %lu",
GetLastError()); GetLastError());
@@ -851,7 +807,7 @@ try {
* get json from server */ * get json from server */
success = GetRemoteFile(WIN_WHATSNEW_URL, text, error, &responseCode, success = GetRemoteFile(WIN_WHATSNEW_URL, text, error, &responseCode,
nullptr, nullptr, extraHeaders, &signature); nullptr, nullptr, extraHeaders, &signature);
if (!success || (responseCode != 200 && responseCode != 304)) { if (!success || (responseCode != 200 && responseCode != 304)) {
if (responseCode == 404) if (responseCode == 404)
@@ -865,8 +821,8 @@ try {
* verify file signature */ * verify file signature */
if (responseCode == 200) { if (responseCode == 200) {
success = CheckDataSignature(text, "whatsnew", success = CheckDataSignature(text, "whatsnew", signature.data(),
signature.data(), signature.size()); signature.size());
if (!success) if (!success)
throw string("Invalid whatsnew signature"); throw string("Invalid whatsnew signature");
} }
+20 -19
View File
@@ -9,9 +9,7 @@
using namespace json11; using namespace json11;
OBSAbout::OBSAbout(QWidget *parent) OBSAbout::OBSAbout(QWidget *parent) : QDialog(parent), ui(new Ui::OBSAbout)
: QDialog(parent),
ui(new Ui::OBSAbout)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -20,29 +18,30 @@ OBSAbout::OBSAbout(QWidget *parent)
QString bitness; QString bitness;
QString ver; QString ver;
if(sizeof(void*) == 4) if (sizeof(void *) == 4)
bitness = " (32 bit)"; bitness = " (32 bit)";
else if(sizeof(void*) == 8) else if (sizeof(void *) == 8)
bitness = " (64 bit)"; bitness = " (64 bit)";
#ifdef HAVE_OBSCONFIG_H #ifdef HAVE_OBSCONFIG_H
ver += OBS_VERSION; ver += OBS_VERSION;
#else #else
ver += LIBOBS_API_MAJOR_VER + "." + ver += LIBOBS_API_MAJOR_VER + "." + LIBOBS_API_MINOR_VER + "." +
LIBOBS_API_MINOR_VER + "." + LIBOBS_API_PATCH_VER;
LIBOBS_API_PATCH_VER;
#endif #endif
ui->version->setText(ver + bitness); ui->version->setText(ver + bitness);
ui->contribute->setText(QTStr("About.Contribute")); ui->contribute->setText(QTStr("About.Contribute"));
ui->donate->setText("&nbsp;&nbsp;<a href='https://obsproject.com/donate'>" + ui->donate->setText(
QTStr("About.Donate") + "</a>"); "&nbsp;&nbsp;<a href='https://obsproject.com/donate'>" +
QTStr("About.Donate") + "</a>");
ui->donate->setTextInteractionFlags(Qt::TextBrowserInteraction); ui->donate->setTextInteractionFlags(Qt::TextBrowserInteraction);
ui->donate->setOpenExternalLinks(true); ui->donate->setOpenExternalLinks(true);
ui->getInvolved->setText("&nbsp;&nbsp;<a href='https://github.com/obsproject/obs-studio/blob/master/CONTRIBUTING.rst'>" + ui->getInvolved->setText(
QTStr("About.GetInvolved") + "</a>"); "&nbsp;&nbsp;<a href='https://github.com/obsproject/obs-studio/blob/master/CONTRIBUTING.rst'>" +
QTStr("About.GetInvolved") + "</a>");
ui->getInvolved->setTextInteractionFlags(Qt::TextBrowserInteraction); ui->getInvolved->setTextInteractionFlags(Qt::TextBrowserInteraction);
ui->getInvolved->setOpenExternalLinks(true); ui->getInvolved->setOpenExternalLinks(true);
@@ -66,12 +65,14 @@ OBSAbout::OBSAbout(QWidget *parent)
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
if (main->patronJson.empty() && !main->patronJsonThread) { if (main->patronJson.empty() && !main->patronJsonThread) {
RemoteTextThread *thread = new RemoteTextThread( RemoteTextThread *thread = new RemoteTextThread(
"https://obsproject.com/patreon/about-box.json", "https://obsproject.com/patreon/about-box.json",
"application/json"); "application/json");
QObject::connect(thread, &RemoteTextThread::Result, QObject::connect(thread, &RemoteTextThread::Result, main,
main, &OBSBasic::UpdatePatronJson); &OBSBasic::UpdatePatronJson);
QObject::connect(thread, SIGNAL(Result(const QString &, const QString &)), QObject::connect(
this, SLOT(ShowAbout())); thread,
SIGNAL(Result(const QString &, const QString &)), this,
SLOT(ShowAbout()));
main->patronJsonThread.reset(thread); main->patronJsonThread.reset(thread);
thread->start(); thread->start();
} else { } else {
+12 -12
View File
@@ -16,9 +16,9 @@ Q_DECLARE_METATYPE(OBSSource);
OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent) OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
: QDialog(parent), : QDialog(parent),
sourceAddedSignal(obs_get_signal_handler(), "source_activate", sourceAddedSignal(obs_get_signal_handler(), "source_activate",
OBSSourceAdded, this), OBSSourceAdded, this),
sourceRemovedSignal(obs_get_signal_handler(), "source_deactivate", sourceRemovedSignal(obs_get_signal_handler(), "source_deactivate",
OBSSourceRemoved, this) OBSSourceRemoved, this)
{ {
QScrollArea *scrollArea; QScrollArea *scrollArea;
QVBoxLayout *vlayout; QVBoxLayout *vlayout;
@@ -55,7 +55,7 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
controlArea = new QWidget; controlArea = new QWidget;
controlArea->setLayout(mainLayout); controlArea->setLayout(mainLayout);
controlArea->setSizePolicy(QSizePolicy::Preferred, controlArea->setSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Preferred); QSizePolicy::Preferred);
vlayout = new QVBoxLayout; vlayout = new QVBoxLayout;
vlayout->addWidget(controlArea); vlayout->addWidget(controlArea);
@@ -80,7 +80,7 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
vlayout->addLayout(buttonLayout); vlayout->addLayout(buttonLayout);
setLayout(vlayout); setLayout(vlayout);
connect(closeButton, &QPushButton::clicked, [this] () {close();}); connect(closeButton, &QPushButton::clicked, [this]() { close(); });
installEventFilter(CreateShortcutFilter()); installEventFilter(CreateShortcutFilter());
@@ -97,7 +97,7 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
OBSBasicAdvAudio::~OBSBasicAdvAudio() OBSBasicAdvAudio::~OBSBasicAdvAudio()
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(parent()); OBSBasic *main = reinterpret_cast<OBSBasic *>(parent());
for (size_t i = 0; i < controls.size(); ++i) for (size_t i = 0; i < controls.size(); ++i)
delete controls[i]; delete controls[i];
@@ -107,7 +107,7 @@ OBSBasicAdvAudio::~OBSBasicAdvAudio()
bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source) bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source)
{ {
OBSBasicAdvAudio *dialog = reinterpret_cast<OBSBasicAdvAudio*>(param); OBSBasicAdvAudio *dialog = reinterpret_cast<OBSBasicAdvAudio *>(param);
uint32_t flags = obs_source_get_output_flags(source); uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_AUDIO) != 0 && obs_source_active(source)) if ((flags & OBS_SOURCE_AUDIO) != 0 && obs_source_active(source))
@@ -118,18 +118,18 @@ bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source)
void OBSBasicAdvAudio::OBSSourceAdded(void *param, calldata_t *calldata) void OBSBasicAdvAudio::OBSSourceAdded(void *param, calldata_t *calldata)
{ {
OBSSource source((obs_source_t*)calldata_ptr(calldata, "source")); OBSSource source((obs_source_t *)calldata_ptr(calldata, "source"));
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio *>(param),
"SourceAdded", Q_ARG(OBSSource, source)); "SourceAdded", Q_ARG(OBSSource, source));
} }
void OBSBasicAdvAudio::OBSSourceRemoved(void *param, calldata_t *calldata) void OBSBasicAdvAudio::OBSSourceRemoved(void *param, calldata_t *calldata)
{ {
OBSSource source((obs_source_t*)calldata_ptr(calldata, "source")); OBSSource source((obs_source_t *)calldata_ptr(calldata, "source"));
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio *>(param),
"SourceRemoved", Q_ARG(OBSSource, source)); "SourceRemoved", Q_ARG(OBSSource, source));
} }
inline void OBSBasicAdvAudio::AddAudioSource(obs_source_t *source) inline void OBSBasicAdvAudio::AddAudioSource(obs_source_t *source)
+1 -1
View File
@@ -18,7 +18,7 @@ private:
OBSSignal sourceAddedSignal; OBSSignal sourceAddedSignal;
OBSSignal sourceRemovedSignal; OBSSignal sourceRemovedSignal;
std::vector<OBSAdvAudioCtrl*> controls; std::vector<OBSAdvAudioCtrl *> controls;
inline void AddAudioSource(obs_source_t *source); inline void AddAudioSource(obs_source_t *source);
+164 -160
View File
@@ -15,7 +15,7 @@
#include "ui_AutoConfigTestPage.h" #include "ui_AutoConfigTestPage.h"
#define wiz reinterpret_cast<AutoConfig*>(wizard()) #define wiz reinterpret_cast<AutoConfig *>(wizard())
using namespace std; using namespace std;
@@ -31,17 +31,14 @@ class TestMode {
gs_eparam_t *randomvals[3] = { gs_eparam_t *randomvals[3] = {
gs_effect_get_param_by_name(solid, "randomvals1"), gs_effect_get_param_by_name(solid, "randomvals1"),
gs_effect_get_param_by_name(solid, "randomvals2"), gs_effect_get_param_by_name(solid, "randomvals2"),
gs_effect_get_param_by_name(solid, "randomvals3") gs_effect_get_param_by_name(solid, "randomvals3")};
};
struct vec4 r; struct vec4 r;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
vec4_set(&r, vec4_set(&r, rand_float(true) * 100.0f,
rand_float(true) * 100.0f, rand_float(true) * 100.0f,
rand_float(true) * 100.0f, rand_float(true) * 50000.0f + 10000.0f, 0.0f);
rand_float(true) * 50000.0f + 10000.0f,
0.0f);
gs_effect_set_vec4(randomvals[i], &r); gs_effect_set_vec4(randomvals[i], &r);
} }
@@ -86,37 +83,37 @@ public:
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#define TEST_STR(x) "Basic.AutoConfig.TestPage." x #define TEST_STR(x) "Basic.AutoConfig.TestPage." x
#define SUBTITLE_TESTING TEST_STR("Subtitle.Testing") #define SUBTITLE_TESTING TEST_STR("Subtitle.Testing")
#define SUBTITLE_COMPLETE TEST_STR("Subtitle.Complete") #define SUBTITLE_COMPLETE TEST_STR("Subtitle.Complete")
#define TEST_BW TEST_STR("TestingBandwidth") #define TEST_BW TEST_STR("TestingBandwidth")
#define TEST_BW_CONNECTING TEST_STR("TestingBandwidth.Connecting") #define TEST_BW_CONNECTING TEST_STR("TestingBandwidth.Connecting")
#define TEST_BW_CONNECT_FAIL TEST_STR("TestingBandwidth.ConnectFailed") #define TEST_BW_CONNECT_FAIL TEST_STR("TestingBandwidth.ConnectFailed")
#define TEST_BW_SERVER TEST_STR("TestingBandwidth.Server") #define TEST_BW_SERVER TEST_STR("TestingBandwidth.Server")
#define TEST_RES TEST_STR("TestingRes") #define TEST_RES TEST_STR("TestingRes")
#define TEST_RES_VAL TEST_STR("TestingRes.Resolution") #define TEST_RES_VAL TEST_STR("TestingRes.Resolution")
#define TEST_RES_FAIL TEST_STR("TestingRes.Fail") #define TEST_RES_FAIL TEST_STR("TestingRes.Fail")
#define TEST_SE TEST_STR("TestingStreamEncoder") #define TEST_SE TEST_STR("TestingStreamEncoder")
#define TEST_RE TEST_STR("TestingRecordingEncoder") #define TEST_RE TEST_STR("TestingRecordingEncoder")
#define TEST_RESULT_SE TEST_STR("Result.StreamingEncoder") #define TEST_RESULT_SE TEST_STR("Result.StreamingEncoder")
#define TEST_RESULT_RE TEST_STR("Result.RecordingEncoder") #define TEST_RESULT_RE TEST_STR("Result.RecordingEncoder")
void AutoConfigTestPage::StartBandwidthStage() void AutoConfigTestPage::StartBandwidthStage()
{ {
ui->progressLabel->setText(QTStr(TEST_BW)); ui->progressLabel->setText(QTStr(TEST_BW));
testThread = std::thread([this] () {TestBandwidthThread();}); testThread = std::thread([this]() { TestBandwidthThread(); });
} }
void AutoConfigTestPage::StartStreamEncoderStage() void AutoConfigTestPage::StartStreamEncoderStage()
{ {
ui->progressLabel->setText(QTStr(TEST_SE)); ui->progressLabel->setText(QTStr(TEST_SE));
testThread = std::thread([this] () {TestStreamEncoderThread();}); testThread = std::thread([this]() { TestStreamEncoderThread(); });
} }
void AutoConfigTestPage::StartRecordingEncoderStage() void AutoConfigTestPage::StartRecordingEncoderStage()
{ {
ui->progressLabel->setText(QTStr(TEST_RE)); ui->progressLabel->setText(QTStr(TEST_RE));
testThread = std::thread([this] () {TestRecordingEncoderThread();}); testThread = std::thread([this]() { TestRecordingEncoderThread(); });
} }
void AutoConfigTestPage::GetServers(std::vector<ServerInfo> &servers) void AutoConfigTestPage::GetServers(std::vector<ServerInfo> &servers)
@@ -176,21 +173,20 @@ void AutoConfigTestPage::TestBandwidthThread()
*/ */
QMetaObject::invokeMethod(this, "UpdateMessage", QMetaObject::invokeMethod(this, "UpdateMessage",
Q_ARG(QString, QStringLiteral(""))); Q_ARG(QString, QStringLiteral("")));
/* -----------------------------------*/ /* -----------------------------------*/
/* create obs objects */ /* create obs objects */
const char *serverType = wiz->customServer const char *serverType = wiz->customServer ? "rtmp_custom"
? "rtmp_custom" : "rtmp_common";
: "rtmp_common";
OBSEncoder vencoder = obs_video_encoder_create("obs_x264", OBSEncoder vencoder = obs_video_encoder_create("obs_x264", "test_x264",
"test_x264", nullptr, nullptr); nullptr, nullptr);
OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac", OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac", "test_aac",
"test_aac", nullptr, 0, nullptr); nullptr, 0, nullptr);
OBSService service = obs_service_create(serverType, OBSService service = obs_service_create(serverType, "test_service",
"test_service", nullptr, nullptr); nullptr, nullptr);
obs_encoder_release(vencoder); obs_encoder_release(vencoder);
obs_encoder_release(aencoder); obs_encoder_release(aencoder);
obs_service_release(service); obs_service_release(service);
@@ -218,14 +214,14 @@ void AutoConfigTestPage::TestBandwidthThread()
if (wiz->service == AutoConfig::Service::Twitch) { if (wiz->service == AutoConfig::Service::Twitch) {
string_depad_key(key); string_depad_key(key);
key += "?bandwidthtest"; key += "?bandwidthtest";
} } else if (wiz->serviceName == "Restream.io" ||
else if(wiz->serviceName == "Restream.io" || wiz->serviceName == "Restream.io - RTMP") { wiz->serviceName == "Restream.io - RTMP") {
string_depad_key(key); string_depad_key(key);
key += "?test=true"; key += "?test=true";
} }
obs_data_set_string(service_settings, "service", obs_data_set_string(service_settings, "service",
wiz->serviceName.c_str()); wiz->serviceName.c_str());
obs_data_set_string(service_settings, "key", key.c_str()); obs_data_set_string(service_settings, "key", key.c_str());
obs_data_set_int(vencoder_settings, "bitrate", wiz->startingBitrate); obs_data_set_int(vencoder_settings, "bitrate", wiz->startingBitrate);
@@ -235,9 +231,9 @@ void AutoConfigTestPage::TestBandwidthThread()
obs_data_set_int(aencoder_settings, "bitrate", 32); obs_data_set_int(aencoder_settings, "bitrate", 32);
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
const char *bind_ip = config_get_string(main->Config(), "Output", const char *bind_ip =
"BindIP"); config_get_string(main->Config(), "Output", "BindIP");
obs_data_set_string(output_settings, "bind_ip", bind_ip); obs_data_set_string(output_settings, "bind_ip", bind_ip);
/* -----------------------------------*/ /* -----------------------------------*/
@@ -252,11 +248,11 @@ void AutoConfigTestPage::TestBandwidthThread()
/* just use the first server if it only has one alternate server, /* just use the first server if it only has one alternate server,
* or if using Mixer or Restream due to their "auto" servers */ * or if using Mixer or Restream due to their "auto" servers */
if (servers.size() < 3 || wiz->serviceName == "Mixer.com - FTL" || if (servers.size() < 3 || wiz->serviceName == "Mixer.com - FTL" ||
wiz->serviceName.substr(0, 11)=="Restream.io") { wiz->serviceName.substr(0, 11) == "Restream.io") {
servers.resize(1); servers.resize(1);
} else if (wiz->service == AutoConfig::Service::Twitch && } else if (wiz->service == AutoConfig::Service::Twitch &&
wiz->twitchAuto) { wiz->twitchAuto) {
/* if using Twitch and "Auto" is available, test 3 closest /* if using Twitch and "Auto" is available, test 3 closest
* server */ * server */
servers.erase(servers.begin() + 1); servers.erase(servers.begin() + 1);
@@ -267,8 +263,8 @@ void AutoConfigTestPage::TestBandwidthThread()
/* apply service settings */ /* apply service settings */
obs_service_update(service, service_settings); obs_service_update(service, service_settings);
obs_service_apply_encoder_settings(service, obs_service_apply_encoder_settings(service, vencoder_settings,
vencoder_settings, aencoder_settings); aencoder_settings);
/* -----------------------------------*/ /* -----------------------------------*/
/* create output */ /* create output */
@@ -277,18 +273,17 @@ void AutoConfigTestPage::TestBandwidthThread()
if (!output_type) if (!output_type)
output_type = "rtmp_output"; output_type = "rtmp_output";
OBSOutput output = obs_output_create(output_type, OBSOutput output =
"test_stream", nullptr, nullptr); obs_output_create(output_type, "test_stream", nullptr, nullptr);
obs_output_release(output); obs_output_release(output);
obs_output_update(output, output_settings); obs_output_update(output, output_settings);
const char *audio_codec = const char *audio_codec = obs_output_get_supported_audio_codecs(output);
obs_output_get_supported_audio_codecs(output);
if (strcmp(audio_codec, "aac") != 0) { if (strcmp(audio_codec, "aac") != 0) {
const char *id = FindAudioEncoderFromCodec(audio_codec); const char *id = FindAudioEncoderFromCodec(audio_codec);
aencoder = obs_audio_encoder_create(id, aencoder = obs_audio_encoder_create(id, "test_audio", nullptr,
"test_audio", nullptr, 0, nullptr); 0, nullptr);
obs_encoder_release(aencoder); obs_encoder_release(aencoder);
} }
@@ -308,16 +303,14 @@ void AutoConfigTestPage::TestBandwidthThread()
/* -----------------------------------*/ /* -----------------------------------*/
/* connect signals */ /* connect signals */
auto on_started = [&] () auto on_started = [&]() {
{
unique_lock<mutex> lock(m); unique_lock<mutex> lock(m);
connected = true; connected = true;
stopped = false; stopped = false;
cv.notify_one(); cv.notify_one();
}; };
auto on_stopped = [&] () auto on_stopped = [&]() {
{
unique_lock<mutex> lock(m); unique_lock<mutex> lock(m);
connected = false; connected = false;
stopped = true; stopped = true;
@@ -327,17 +320,15 @@ void AutoConfigTestPage::TestBandwidthThread()
using on_started_t = decltype(on_started); using on_started_t = decltype(on_started);
using on_stopped_t = decltype(on_stopped); using on_stopped_t = decltype(on_stopped);
auto pre_on_started = [] (void *data, calldata_t *) auto pre_on_started = [](void *data, calldata_t *) {
{
on_started_t &on_started = on_started_t &on_started =
*reinterpret_cast<on_started_t*>(data); *reinterpret_cast<on_started_t *>(data);
on_started(); on_started();
}; };
auto pre_on_stopped = [] (void *data, calldata_t *) auto pre_on_stopped = [](void *data, calldata_t *) {
{
on_stopped_t &on_stopped = on_stopped_t &on_stopped =
*reinterpret_cast<on_stopped_t*>(data); *reinterpret_cast<on_stopped_t *>(data);
on_stopped(); on_stopped();
}; };
@@ -358,12 +349,13 @@ void AutoConfigTestPage::TestBandwidthThread()
int per = int((i + 1) * 100 / servers.size()); int per = int((i + 1) * 100 / servers.size());
QMetaObject::invokeMethod(this, "Progress", Q_ARG(int, per)); QMetaObject::invokeMethod(this, "Progress", Q_ARG(int, per));
QMetaObject::invokeMethod(this, "UpdateMessage", QMetaObject::invokeMethod(
Q_ARG(QString, QTStr(TEST_BW_CONNECTING) this, "UpdateMessage",
.arg(server.name.c_str()))); Q_ARG(QString, QTStr(TEST_BW_CONNECTING)
.arg(server.name.c_str())));
obs_data_set_string(service_settings, "server", obs_data_set_string(service_settings, "server",
server.address.c_str()); server.address.c_str());
obs_service_update(service, service_settings); obs_service_update(service, service_settings);
if (!obs_output_start(output)) if (!obs_output_start(output))
@@ -385,9 +377,10 @@ void AutoConfigTestPage::TestBandwidthThread()
if (!connected) if (!connected)
continue; continue;
QMetaObject::invokeMethod(this, "UpdateMessage", QMetaObject::invokeMethod(
Q_ARG(QString, QTStr(TEST_BW_SERVER) this, "UpdateMessage",
.arg(server.name.c_str()))); Q_ARG(QString,
QTStr(TEST_BW_SERVER).arg(server.name.c_str())));
/* ignore first 2.5 seconds due to possible buffering skewing /* ignore first 2.5 seconds due to possible buffering skewing
* the result */ * the result */
@@ -418,10 +411,10 @@ void AutoConfigTestPage::TestBandwidthThread()
uint64_t total_time = os_gettime_ns() - t_start; uint64_t total_time = os_gettime_ns() - t_start;
int total_bytes = (int)obs_output_get_total_bytes(output) - int total_bytes =
start_bytes; (int)obs_output_get_total_bytes(output) - start_bytes;
uint64_t bitrate = (uint64_t)total_bytes * 8 uint64_t bitrate = (uint64_t)total_bytes * 8 * 1000000000 /
* 1000000000 / total_time / 1000; total_time / 1000;
if (obs_output_get_frames_dropped(output) || if (obs_output_get_frames_dropped(output) ||
(int)bitrate < (wiz->startingBitrate * 75 / 100)) { (int)bitrate < (wiz->startingBitrate * 75 / 100)) {
@@ -436,7 +429,8 @@ void AutoConfigTestPage::TestBandwidthThread()
if (!success) { if (!success) {
QMetaObject::invokeMethod(this, "Failure", QMetaObject::invokeMethod(this, "Failure",
Q_ARG(QString, QTStr(TEST_BW_CONNECT_FAIL))); Q_ARG(QString,
QTStr(TEST_BW_CONNECT_FAIL)));
return; return;
} }
@@ -480,7 +474,8 @@ static long double EstimateMinBitrate(int cx, int cy, int fps_num, int fps_den)
return EstimateBitrateVal(cx, cy, fps_num, fps_den) / val; return EstimateBitrateVal(cx, cy, fps_num, fps_den) / val;
} }
static long double EstimateUpperBitrate(int cx, int cy, int fps_num, int fps_den) static long double EstimateUpperBitrate(int cx, int cy, int fps_num,
int fps_den)
{ {
long double val = EstimateBitrateVal(1280, 720, 30, 1) / 3000.0l; long double val = EstimateBitrateVal(1280, 720, 30, 1) / 3000.0l;
return EstimateBitrateVal(cx, cy, fps_num, fps_den) / val; return EstimateBitrateVal(cx, cy, fps_num, fps_den) / val;
@@ -520,17 +515,17 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
{ {
TestMode testMode; TestMode testMode;
QMetaObject::invokeMethod(this, "UpdateMessage", QMetaObject::invokeMethod(this, "UpdateMessage",
Q_ARG(QString, QStringLiteral(""))); Q_ARG(QString, QStringLiteral("")));
/* -----------------------------------*/ /* -----------------------------------*/
/* create obs objects */ /* create obs objects */
OBSEncoder vencoder = obs_video_encoder_create("obs_x264", OBSEncoder vencoder = obs_video_encoder_create("obs_x264", "test_x264",
"test_x264", nullptr, nullptr); nullptr, nullptr);
OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac", OBSEncoder aencoder = obs_audio_encoder_create("ffmpeg_aac", "test_aac",
"test_aac", nullptr, 0, nullptr); nullptr, 0, nullptr);
OBSOutput output = obs_output_create("null_output", OBSOutput output =
"null", nullptr, nullptr); obs_output_create("null_output", "null", nullptr, nullptr);
obs_output_release(output); obs_output_release(output);
obs_encoder_release(vencoder); obs_encoder_release(vencoder);
obs_encoder_release(aencoder); obs_encoder_release(aencoder);
@@ -547,7 +542,7 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
if (wiz->type != AutoConfig::Type::Recording) { if (wiz->type != AutoConfig::Type::Recording) {
obs_data_set_int(vencoder_settings, "keyint_sec", 2); obs_data_set_int(vencoder_settings, "keyint_sec", 2);
obs_data_set_int(vencoder_settings, "bitrate", obs_data_set_int(vencoder_settings, "bitrate",
wiz->idealBitrate); wiz->idealBitrate);
obs_data_set_string(vencoder_settings, "rate_control", "CBR"); obs_data_set_string(vencoder_settings, "rate_control", "CBR");
obs_data_set_string(vencoder_settings, "profile", "main"); obs_data_set_string(vencoder_settings, "profile", "main");
obs_data_set_string(vencoder_settings, "preset", "veryfast"); obs_data_set_string(vencoder_settings, "preset", "veryfast");
@@ -573,18 +568,16 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
/* -----------------------------------*/ /* -----------------------------------*/
/* connect signals */ /* connect signals */
auto on_stopped = [&] () auto on_stopped = [&]() {
{
unique_lock<mutex> lock(m); unique_lock<mutex> lock(m);
cv.notify_one(); cv.notify_one();
}; };
using on_stopped_t = decltype(on_stopped); using on_stopped_t = decltype(on_stopped);
auto pre_on_stopped = [] (void *data, calldata_t *) auto pre_on_stopped = [](void *data, calldata_t *) {
{
on_stopped_t &on_stopped = on_stopped_t &on_stopped =
*reinterpret_cast<on_stopped_t*>(data); *reinterpret_cast<on_stopped_t *>(data);
on_stopped(); on_stopped();
}; };
@@ -628,9 +621,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
int i = 0; int i = 0;
int count = 1; int count = 1;
auto testRes = [&] (long double div, int fps_num, int fps_den, auto testRes = [&](long double div, int fps_num, int fps_den,
bool force) bool force) {
{
int per = ++i * 100 / count; int per = ++i * 100 / count;
QMetaObject::invokeMethod(this, "Progress", Q_ARG(int, per)); QMetaObject::invokeMethod(this, "Progress", Q_ARG(int, per));
@@ -669,13 +661,13 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
QString cxStr = QString::number(cx); QString cxStr = QString::number(cx);
QString cyStr = QString::number(cy); QString cyStr = QString::number(cy);
QString fpsStr = (fps_den > 1) QString fpsStr = (fps_den > 1) ? QString::number(fps, 'f', 2)
? QString::number(fps, 'f', 2) : QString::number(fps, 'g', 2);
: QString::number(fps, 'g', 2);
QMetaObject::invokeMethod(this, "UpdateMessage", QMetaObject::invokeMethod(
Q_ARG(QString, QTStr(TEST_RES_VAL) this, "UpdateMessage",
.arg(cxStr, cyStr, fpsStr))); Q_ARG(QString,
QTStr(TEST_RES_VAL).arg(cxStr, cyStr, fpsStr)));
unique_lock<mutex> ul(m); unique_lock<mutex> ul(m);
if (cancel) if (cancel)
@@ -683,7 +675,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
if (!obs_output_start(output)) { if (!obs_output_start(output)) {
QMetaObject::invokeMethod(this, "Failure", QMetaObject::invokeMethod(this, "Failure",
Q_ARG(QString, QTStr(TEST_RES_FAIL))); Q_ARG(QString,
QTStr(TEST_RES_FAIL)));
return false; return false;
} }
@@ -692,8 +685,8 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
obs_output_stop(output); obs_output_stop(output);
cv.wait(ul); cv.wait(ul);
int skipped = (int)video_output_get_skipped_frames( int skipped =
obs_get_video()); (int)video_output_get_skipped_frames(obs_get_video());
if (force || skipped <= 10) if (force || skipped <= 10)
results.emplace_back(cx, cy, fps_num, fps_den); results.emplace_back(cx, cy, fps_num, fps_den);
@@ -702,23 +695,38 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
if (wiz->specificFPSNum && wiz->specificFPSDen) { if (wiz->specificFPSNum && wiz->specificFPSDen) {
count = 5; count = 5;
if (!testRes(1.0, 0, 0, false)) return false; if (!testRes(1.0, 0, 0, false))
if (!testRes(1.5, 0, 0, false)) return false; return false;
if (!testRes(1.0 / 0.6, 0, 0, false)) return false; if (!testRes(1.5, 0, 0, false))
if (!testRes(2.0, 0, 0, false)) return false; return false;
if (!testRes(2.25, 0, 0, true)) return false; if (!testRes(1.0 / 0.6, 0, 0, false))
return false;
if (!testRes(2.0, 0, 0, false))
return false;
if (!testRes(2.25, 0, 0, true))
return false;
} else { } else {
count = 10; count = 10;
if (!testRes(1.0, 60, 1, false)) return false; if (!testRes(1.0, 60, 1, false))
if (!testRes(1.0, 30, 1, false)) return false; return false;
if (!testRes(1.5, 60, 1, false)) return false; if (!testRes(1.0, 30, 1, false))
if (!testRes(1.5, 30, 1, false)) return false; return false;
if (!testRes(1.0 / 0.6, 60, 1, false)) return false; if (!testRes(1.5, 60, 1, false))
if (!testRes(1.0 / 0.6, 30, 1, false)) return false; return false;
if (!testRes(2.0, 60, 1, false)) return false; if (!testRes(1.5, 30, 1, false))
if (!testRes(2.0, 30, 1, false)) return false; return false;
if (!testRes(2.25, 60, 1, false)) return false; if (!testRes(1.0 / 0.6, 60, 1, false))
if (!testRes(2.25, 30, 1, true)) return false; return false;
if (!testRes(1.0 / 0.6, 30, 1, false))
return false;
if (!testRes(2.0, 60, 1, false))
return false;
if (!testRes(2.0, 30, 1, false))
return false;
if (!testRes(2.25, 60, 1, false))
return false;
if (!testRes(2.25, 30, 1, true))
return false;
} }
/* -----------------------------------*/ /* -----------------------------------*/
@@ -744,7 +752,7 @@ bool AutoConfigTestPage::TestSoftwareEncoding()
wiz->idealFPSDen = result.fps_den; wiz->idealFPSDen = result.fps_den;
long double fUpperBitrate = EstimateUpperBitrate( long double fUpperBitrate = EstimateUpperBitrate(
result.cx, result.cy, result.fps_num, result.fps_den); result.cx, result.cy, result.fps_num, result.fps_den);
int upperBitrate = int(floor(fUpperBitrate / 50.0l) * 50.0l); int upperBitrate = int(floor(fUpperBitrate / 50.0l) * 50.0l);
@@ -776,9 +784,8 @@ void AutoConfigTestPage::FindIdealHardwareResolution()
maxDataRate = 1280 * 720 * 30 + 1000; maxDataRate = 1280 * 720 * 30 + 1000;
} }
auto testRes = [&] (long double div, int fps_num, int fps_den, auto testRes = [&](long double div, int fps_num, int fps_den,
bool force) bool force) {
{
if (results.size() >= 3) if (results.size() >= 3)
return; return;
@@ -805,7 +812,8 @@ void AutoConfigTestPage::FindIdealHardwareResolution()
* ratio, so increase the minimum bitrate estimate for them. * ratio, so increase the minimum bitrate estimate for them.
* NVENC currently is the exception because of the improvements * NVENC currently is the exception because of the improvements
* its made to its quality in recent generations. */ * its made to its quality in recent generations. */
if (!nvenc) minBitrate = minBitrate * 114 / 100; if (!nvenc)
minBitrate = minBitrate * 114 / 100;
if (wiz->type == AutoConfig::Type::Recording) if (wiz->type == AutoConfig::Type::Recording)
force = true; force = true;
@@ -919,9 +927,9 @@ void AutoConfigTestPage::TestRecordingEncoderThread()
#define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x #define ENCODER_TEXT(x) "Basic.Settings.Output.Simple.Encoder." x
#define ENCODER_SOFTWARE ENCODER_TEXT("Software") #define ENCODER_SOFTWARE ENCODER_TEXT("Software")
#define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC") #define ENCODER_NVENC ENCODER_TEXT("Hardware.NVENC")
#define ENCODER_QSV ENCODER_TEXT("Hardware.QSV") #define ENCODER_QSV ENCODER_TEXT("Hardware.QSV")
#define ENCODER_AMD ENCODER_TEXT("Hardware.AMD") #define ENCODER_AMD ENCODER_TEXT("Hardware.AMD")
#define QUALITY_SAME "Basic.Settings.Output.Simple.RecordingQuality.Stream" #define QUALITY_SAME "Basic.Settings.Output.Simple.RecordingQuality.Stream"
#define QUALITY_HIGH "Basic.Settings.Output.Simple.RecordingQuality.Small" #define QUALITY_HIGH "Basic.Settings.Output.Simple.RecordingQuality.Small"
@@ -933,8 +941,7 @@ void AutoConfigTestPage::FinalizeResults()
QFormLayout *form = results; QFormLayout *form = results;
auto encName = [] (AutoConfig::Encoder enc) -> QString auto encName = [](AutoConfig::Encoder enc) -> QString {
{
switch (enc) { switch (enc) {
case AutoConfig::Encoder::x264: case AutoConfig::Encoder::x264:
return QTStr(ENCODER_SOFTWARE); return QTStr(ENCODER_SOFTWARE);
@@ -951,18 +958,16 @@ void AutoConfigTestPage::FinalizeResults()
return QTStr(ENCODER_SOFTWARE); return QTStr(ENCODER_SOFTWARE);
}; };
auto newLabel = [this] (const char *str) -> QLabel * auto newLabel = [this](const char *str) -> QLabel * {
{
return new QLabel(QTStr(str), this); return new QLabel(QTStr(str), this);
}; };
if (wiz->type != AutoConfig::Type::Recording) { if (wiz->type != AutoConfig::Type::Recording) {
const char *serverType = wiz->customServer const char *serverType = wiz->customServer ? "rtmp_custom"
? "rtmp_custom" : "rtmp_common";
: "rtmp_common";
OBSService service = obs_service_create(serverType, OBSService service = obs_service_create(
"temp_service", nullptr, nullptr); serverType, "temp_service", nullptr, nullptr);
obs_service_release(service); obs_service_release(service);
OBSData service_settings = obs_data_create(); OBSData service_settings = obs_data_create();
@@ -971,44 +976,45 @@ void AutoConfigTestPage::FinalizeResults()
obs_data_release(vencoder_settings); obs_data_release(vencoder_settings);
obs_data_set_int(vencoder_settings, "bitrate", obs_data_set_int(vencoder_settings, "bitrate",
wiz->idealBitrate); wiz->idealBitrate);
obs_data_set_string(service_settings, "service", obs_data_set_string(service_settings, "service",
wiz->serviceName.c_str()); wiz->serviceName.c_str());
obs_service_update(service, service_settings); obs_service_update(service, service_settings);
obs_service_apply_encoder_settings(service, obs_service_apply_encoder_settings(service, vencoder_settings,
vencoder_settings, nullptr); nullptr);
wiz->idealBitrate = (int)obs_data_get_int(vencoder_settings, wiz->idealBitrate =
"bitrate"); (int)obs_data_get_int(vencoder_settings, "bitrate");
if (!wiz->customServer) if (!wiz->customServer)
form->addRow( form->addRow(
newLabel("Basic.AutoConfig.StreamPage.Service"), newLabel("Basic.AutoConfig.StreamPage.Service"),
new QLabel(wiz->serviceName.c_str(), new QLabel(wiz->serviceName.c_str(),
ui->finishPage)); ui->finishPage));
form->addRow(newLabel("Basic.AutoConfig.StreamPage.Server"), form->addRow(newLabel("Basic.AutoConfig.StreamPage.Server"),
new QLabel(wiz->serverName.c_str(), ui->finishPage)); new QLabel(wiz->serverName.c_str(),
ui->finishPage));
form->addRow(newLabel("Basic.Settings.Output.VideoBitrate"), form->addRow(newLabel("Basic.Settings.Output.VideoBitrate"),
new QLabel(QString::number(wiz->idealBitrate), new QLabel(QString::number(wiz->idealBitrate),
ui->finishPage)); ui->finishPage));
form->addRow(newLabel(TEST_RESULT_SE), form->addRow(newLabel(TEST_RESULT_SE),
new QLabel(encName(wiz->streamingEncoder), new QLabel(encName(wiz->streamingEncoder),
ui->finishPage)); ui->finishPage));
} }
QString baseRes = QString("%1x%2").arg( QString baseRes =
QString::number(wiz->baseResolutionCX), QString("%1x%2").arg(QString::number(wiz->baseResolutionCX),
QString::number(wiz->baseResolutionCY)); QString::number(wiz->baseResolutionCY));
QString scaleRes = QString("%1x%2").arg( QString scaleRes =
QString::number(wiz->idealResolutionCX), QString("%1x%2").arg(QString::number(wiz->idealResolutionCX),
QString::number(wiz->idealResolutionCY)); QString::number(wiz->idealResolutionCY));
if (wiz->recordingEncoder != AutoConfig::Encoder::Stream || if (wiz->recordingEncoder != AutoConfig::Encoder::Stream ||
wiz->recordingQuality != AutoConfig::Quality::Stream) wiz->recordingQuality != AutoConfig::Quality::Stream)
form->addRow(newLabel(TEST_RESULT_RE), form->addRow(newLabel(TEST_RESULT_RE),
new QLabel(encName(wiz->recordingEncoder), new QLabel(encName(wiz->recordingEncoder),
ui->finishPage)); ui->finishPage));
QString recQuality; QString recQuality;
@@ -1022,21 +1028,20 @@ void AutoConfigTestPage::FinalizeResults()
} }
form->addRow(newLabel("Basic.Settings.Output.Simple.RecordingQuality"), form->addRow(newLabel("Basic.Settings.Output.Simple.RecordingQuality"),
new QLabel(recQuality, ui->finishPage)); new QLabel(recQuality, ui->finishPage));
long double fps = long double fps =
(long double)wiz->idealFPSNum / (long double)wiz->idealFPSDen; (long double)wiz->idealFPSNum / (long double)wiz->idealFPSDen;
QString fpsStr = (wiz->idealFPSDen > 1) QString fpsStr = (wiz->idealFPSDen > 1) ? QString::number(fps, 'f', 2)
? QString::number(fps, 'f', 2) : QString::number(fps, 'g', 2);
: QString::number(fps, 'g', 2);
form->addRow(newLabel("Basic.Settings.Video.BaseResolution"), form->addRow(newLabel("Basic.Settings.Video.BaseResolution"),
new QLabel(baseRes, ui->finishPage)); new QLabel(baseRes, ui->finishPage));
form->addRow(newLabel("Basic.Settings.Video.ScaledResolution"), form->addRow(newLabel("Basic.Settings.Video.ScaledResolution"),
new QLabel(scaleRes, ui->finishPage)); new QLabel(scaleRes, ui->finishPage));
form->addRow(newLabel("Basic.Settings.Video.FPS"), form->addRow(newLabel("Basic.Settings.Video.FPS"),
new QLabel(fpsStr, ui->finishPage)); new QLabel(fpsStr, ui->finishPage));
} }
#define STARTING_SEPARATOR \ #define STARTING_SEPARATOR \
@@ -1103,8 +1108,7 @@ void AutoConfigTestPage::Progress(int percentage)
} }
AutoConfigTestPage::AutoConfigTestPage(QWidget *parent) AutoConfigTestPage::AutoConfigTestPage(QWidget *parent)
: QWizardPage (parent), : QWizardPage(parent), ui(new Ui_AutoConfigTestPage)
ui (new Ui_AutoConfigTestPage)
{ {
ui->setupUi(this); ui->setupUi(this);
setTitle(QTStr("Basic.AutoConfig.TestPage")); setTitle(QTStr("Basic.AutoConfig.TestPage"));
+101 -112
View File
@@ -20,10 +20,10 @@
struct QCef; struct QCef;
struct QCefCookieManager; struct QCefCookieManager;
extern QCef *cef; extern QCef *cef;
extern QCefCookieManager *panel_cookies; extern QCefCookieManager *panel_cookies;
#define wiz reinterpret_cast<AutoConfig*>(wizard()) #define wiz reinterpret_cast<AutoConfig *>(wizard())
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -33,12 +33,12 @@ static OBSData OpenServiceSettings(std::string &type)
{ {
char serviceJsonPath[512]; char serviceJsonPath[512];
int ret = GetProfilePath(serviceJsonPath, sizeof(serviceJsonPath), int ret = GetProfilePath(serviceJsonPath, sizeof(serviceJsonPath),
SERVICE_PATH); SERVICE_PATH);
if (ret <= 0) if (ret <= 0)
return OBSData(); return OBSData();
OBSData data = obs_data_create_from_json_file_safe(serviceJsonPath, OBSData data =
"bak"); obs_data_create_from_json_file_safe(serviceJsonPath, "bak");
obs_data_release(data); obs_data_release(data);
obs_data_set_default_string(data, "type", "rtmp_common"); obs_data_set_default_string(data, "type", "rtmp_common");
@@ -51,7 +51,7 @@ static OBSData OpenServiceSettings(std::string &type)
} }
static void GetServiceInfo(std::string &type, std::string &service, static void GetServiceInfo(std::string &type, std::string &service,
std::string &server, std::string &key) std::string &server, std::string &key)
{ {
OBSData settings = OpenServiceSettings(type); OBSData settings = OpenServiceSettings(type);
@@ -63,8 +63,7 @@ static void GetServiceInfo(std::string &type, std::string &service,
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
AutoConfigStartPage::AutoConfigStartPage(QWidget *parent) AutoConfigStartPage::AutoConfigStartPage(QWidget *parent)
: QWizardPage (parent), : QWizardPage(parent), ui(new Ui_AutoConfigStartPage)
ui (new Ui_AutoConfigStartPage)
{ {
ui->setupUi(this); ui->setupUi(this);
setTitle(QTStr("Basic.AutoConfig.StartPage")); setTitle(QTStr("Basic.AutoConfig.StartPage"));
@@ -93,16 +92,15 @@ void AutoConfigStartPage::on_prioritizeRecording_clicked()
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#define RES_TEXT(x) "Basic.AutoConfig.VideoPage." x #define RES_TEXT(x) "Basic.AutoConfig.VideoPage." x
#define RES_USE_CURRENT RES_TEXT("BaseResolution.UseCurrent") #define RES_USE_CURRENT RES_TEXT("BaseResolution.UseCurrent")
#define RES_USE_DISPLAY RES_TEXT("BaseResolution.Display") #define RES_USE_DISPLAY RES_TEXT("BaseResolution.Display")
#define FPS_USE_CURRENT RES_TEXT("FPS.UseCurrent") #define FPS_USE_CURRENT RES_TEXT("FPS.UseCurrent")
#define FPS_PREFER_HIGH_FPS RES_TEXT("FPS.PreferHighFPS") #define FPS_PREFER_HIGH_FPS RES_TEXT("FPS.PreferHighFPS")
#define FPS_PREFER_HIGH_RES RES_TEXT("FPS.PreferHighRes") #define FPS_PREFER_HIGH_RES RES_TEXT("FPS.PreferHighRes")
AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent) AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
: QWizardPage (parent), : QWizardPage(parent), ui(new Ui_AutoConfigVideoPage)
ui (new Ui_AutoConfigVideoPage)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -115,16 +113,15 @@ AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
long double fpsVal = long double fpsVal =
(long double)ovi.fps_num / (long double)ovi.fps_den; (long double)ovi.fps_num / (long double)ovi.fps_den;
QString fpsStr = (ovi.fps_den > 1) QString fpsStr = (ovi.fps_den > 1) ? QString::number(fpsVal, 'f', 2)
? QString::number(fpsVal, 'f', 2) : QString::number(fpsVal, 'g', 2);
: QString::number(fpsVal, 'g', 2);
ui->fps->addItem(QTStr(FPS_PREFER_HIGH_FPS), ui->fps->addItem(QTStr(FPS_PREFER_HIGH_FPS),
(int)AutoConfig::FPSType::PreferHighFPS); (int)AutoConfig::FPSType::PreferHighFPS);
ui->fps->addItem(QTStr(FPS_PREFER_HIGH_RES), ui->fps->addItem(QTStr(FPS_PREFER_HIGH_RES),
(int)AutoConfig::FPSType::PreferHighRes); (int)AutoConfig::FPSType::PreferHighRes);
ui->fps->addItem(QTStr(FPS_USE_CURRENT).arg(fpsStr), ui->fps->addItem(QTStr(FPS_USE_CURRENT).arg(fpsStr),
(int)AutoConfig::FPSType::UseCurrent); (int)AutoConfig::FPSType::UseCurrent);
ui->fps->addItem(QStringLiteral("30"), (int)AutoConfig::FPSType::fps30); ui->fps->addItem(QStringLiteral("30"), (int)AutoConfig::FPSType::fps30);
ui->fps->addItem(QStringLiteral("60"), (int)AutoConfig::FPSType::fps60); ui->fps->addItem(QStringLiteral("60"), (int)AutoConfig::FPSType::fps60);
ui->fps->setCurrentIndex(0); ui->fps->setCurrentIndex(0);
@@ -134,9 +131,9 @@ AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
int encRes = int(ovi.base_width << 16) | int(ovi.base_height); int encRes = int(ovi.base_width << 16) | int(ovi.base_height);
ui->canvasRes->addItem(QTStr(RES_USE_CURRENT).arg(cxStr, cyStr), ui->canvasRes->addItem(QTStr(RES_USE_CURRENT).arg(cxStr, cyStr),
(int)encRes); (int)encRes);
QList<QScreen*> screens = QGuiApplication::screens(); QList<QScreen *> screens = QGuiApplication::screens();
for (int i = 0; i < screens.size(); i++) { for (int i = 0; i < screens.size(); i++) {
QScreen *screen = screens[i]; QScreen *screen = screens[i];
QSize as = screen->size(); QSize as = screen->size();
@@ -144,19 +141,17 @@ AutoConfigVideoPage::AutoConfigVideoPage(QWidget *parent)
encRes = int(as.width() << 16) | int(as.height()); encRes = int(as.width() << 16) | int(as.height());
QString str = QTStr(RES_USE_DISPLAY) QString str = QTStr(RES_USE_DISPLAY)
.arg(QString::number(i + 1), .arg(QString::number(i + 1),
QString::number(as.width()), QString::number(as.width()),
QString::number(as.height())); QString::number(as.height()));
ui->canvasRes->addItem(str, encRes); ui->canvasRes->addItem(str, encRes);
} }
auto addRes = [&] (int cx, int cy) auto addRes = [&](int cx, int cy) {
{
encRes = (cx << 16) | cy; encRes = (cx << 16) | cy;
QString str = QString("%1x%2").arg( QString str = QString("%1x%2").arg(QString::number(cx),
QString::number(cx), QString::number(cy));
QString::number(cy));
ui->canvasRes->addItem(str, encRes); ui->canvasRes->addItem(str, encRes);
}; };
@@ -174,8 +169,8 @@ AutoConfigVideoPage::~AutoConfigVideoPage()
int AutoConfigVideoPage::nextId() const int AutoConfigVideoPage::nextId() const
{ {
return wiz->type == AutoConfig::Type::Recording return wiz->type == AutoConfig::Type::Recording
? AutoConfig::TestPage ? AutoConfig::TestPage
: AutoConfig::StreamPage; : AutoConfig::StreamPage;
} }
bool AutoConfigVideoPage::validatePage() bool AutoConfigVideoPage::validatePage()
@@ -223,12 +218,11 @@ bool AutoConfigVideoPage::validatePage()
enum class ListOpt : int { enum class ListOpt : int {
ShowAll = 1, ShowAll = 1,
Custom Custom,
}; };
AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent) AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
: QWizardPage (parent), : QWizardPage(parent), ui(new Ui_AutoConfigStreamPage)
ui (new Ui_AutoConfigStreamPage)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->bitrateLabel->setVisible(false); ui->bitrateLabel->setVisible(false);
@@ -255,29 +249,29 @@ AutoConfigStreamPage::AutoConfigStreamPage(QWidget *parent)
LoadServices(false); LoadServices(false);
connect(ui->service, SIGNAL(currentIndexChanged(int)), connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
this, SLOT(ServiceChanged())); SLOT(ServiceChanged()));
connect(ui->customServer, SIGNAL(textChanged(const QString &)), connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
this, SLOT(ServiceChanged())); SLOT(ServiceChanged()));
connect(ui->doBandwidthTest, SIGNAL(toggled(bool)), connect(ui->doBandwidthTest, SIGNAL(toggled(bool)), this,
this, SLOT(ServiceChanged())); SLOT(ServiceChanged()));
connect(ui->service, SIGNAL(currentIndexChanged(int)), connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
this, SLOT(UpdateServerList())); SLOT(UpdateServerList()));
connect(ui->service, SIGNAL(currentIndexChanged(int)), connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
this, SLOT(UpdateKeyLink())); SLOT(UpdateKeyLink()));
connect(ui->key, SIGNAL(textChanged(const QString &)), connect(ui->key, SIGNAL(textChanged(const QString &)), this,
this, SLOT(UpdateCompleted())); SLOT(UpdateCompleted()));
connect(ui->regionUS, SIGNAL(toggled(bool)), connect(ui->regionUS, SIGNAL(toggled(bool)), this,
this, SLOT(UpdateCompleted())); SLOT(UpdateCompleted()));
connect(ui->regionEU, SIGNAL(toggled(bool)), connect(ui->regionEU, SIGNAL(toggled(bool)), this,
this, SLOT(UpdateCompleted())); SLOT(UpdateCompleted()));
connect(ui->regionAsia, SIGNAL(toggled(bool)), connect(ui->regionAsia, SIGNAL(toggled(bool)), this,
this, SLOT(UpdateCompleted())); SLOT(UpdateCompleted()));
connect(ui->regionOther, SIGNAL(toggled(bool)), connect(ui->regionOther, SIGNAL(toggled(bool)), this,
this, SLOT(UpdateCompleted())); SLOT(UpdateCompleted()));
} }
AutoConfigStreamPage::~AutoConfigStreamPage() AutoConfigStreamPage::~AutoConfigStreamPage()
@@ -307,17 +301,16 @@ bool AutoConfigStreamPage::validatePage()
wiz->customServer = IsCustom(); wiz->customServer = IsCustom();
const char *serverType = wiz->customServer const char *serverType = wiz->customServer ? "rtmp_custom"
? "rtmp_custom" : "rtmp_common";
: "rtmp_common";
if (!wiz->customServer) { if (!wiz->customServer) {
obs_data_set_string(service_settings, "service", obs_data_set_string(service_settings, "service",
QT_TO_UTF8(ui->service->currentText())); QT_TO_UTF8(ui->service->currentText()));
} }
OBSService service = obs_service_create(serverType, "temp_service", OBSService service = obs_service_create(serverType, "temp_service",
service_settings, nullptr); service_settings, nullptr);
obs_service_release(service); obs_service_release(service);
int bitrate = 10000; int bitrate = 10000;
@@ -365,9 +358,8 @@ bool AutoConfigStreamPage::validatePage()
if (wiz->service != AutoConfig::Service::Twitch && wiz->bandwidthTest) { if (wiz->service != AutoConfig::Service::Twitch && wiz->bandwidthTest) {
QMessageBox::StandardButton button; QMessageBox::StandardButton button;
#define WARNING_TEXT(x) QTStr("Basic.AutoConfig.StreamPage.StreamWarning." x) #define WARNING_TEXT(x) QTStr("Basic.AutoConfig.StreamPage.StreamWarning." x)
button = OBSMessageBox::question(this, button = OBSMessageBox::question(this, WARNING_TEXT("Title"),
WARNING_TEXT("Title"), WARNING_TEXT("Text"));
WARNING_TEXT("Text"));
#undef WARNING_TEXT #undef WARNING_TEXT
if (button == QMessageBox::No) if (button == QMessageBox::No)
@@ -391,7 +383,7 @@ void AutoConfigStreamPage::on_show_clicked()
void AutoConfigStreamPage::OnOAuthStreamKeyConnected() void AutoConfigStreamPage::OnOAuthStreamKeyConnected()
{ {
#ifdef BROWSER_AVAILABLE #ifdef BROWSER_AVAILABLE
OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey*>(auth.get()); OAuthStreamKey *a = reinterpret_cast<OAuthStreamKey *>(auth.get());
if (a) { if (a) {
bool validKey = !a->key().empty(); bool validKey = !a->key().empty();
@@ -440,9 +432,8 @@ void AutoConfigStreamPage::on_disconnectAccount_clicked()
{ {
QMessageBox::StandardButton button; QMessageBox::StandardButton button;
button = OBSMessageBox::question(this, button = OBSMessageBox::question(this, QTStr(DISCONNECT_COMFIRM_TITLE),
QTStr(DISCONNECT_COMFIRM_TITLE), QTStr(DISCONNECT_COMFIRM_TEXT));
QTStr(DISCONNECT_COMFIRM_TEXT));
if (button == QMessageBox::No) { if (button == QMessageBox::No) {
return; return;
@@ -479,14 +470,13 @@ static inline bool is_auth_service(const std::string &service)
void AutoConfigStreamPage::ServiceChanged() void AutoConfigStreamPage::ServiceChanged()
{ {
bool showMore = bool showMore = ui->service->currentData().toInt() ==
ui->service->currentData().toInt() == (int)ListOpt::ShowAll; (int)ListOpt::ShowAll;
if (showMore) if (showMore)
return; return;
std::string service = QT_TO_UTF8(ui->service->currentText()); std::string service = QT_TO_UTF8(ui->service->currentText());
bool regionBased = service == "Twitch" || bool regionBased = service == "Twitch" || service == "Smashcast";
service == "Smashcast";
bool testBandwidth = ui->doBandwidthTest->isChecked(); bool testBandwidth = ui->doBandwidthTest->isChecked();
bool custom = IsCustom(); bool custom = IsCustom();
@@ -496,9 +486,8 @@ void AutoConfigStreamPage::ServiceChanged()
if (cef) { if (cef) {
if (lastService != service.c_str()) { if (lastService != service.c_str()) {
bool can_auth = is_auth_service(service); bool can_auth = is_auth_service(service);
int page = can_auth int page = can_auth ? (int)Section::Connect
? (int)Section::Connect : (int)Section::StreamKey;
: (int)Section::StreamKey;
ui->stackedWidget->setCurrentIndex(page); ui->stackedWidget->setCurrentIndex(page);
ui->streamKeyWidget->setVisible(true); ui->streamKeyWidget->setVisible(true);
@@ -525,7 +514,7 @@ void AutoConfigStreamPage::ServiceChanged()
if (custom) { if (custom) {
ui->streamkeyPageLayout->insertRow(1, ui->serverLabel, ui->streamkeyPageLayout->insertRow(1, ui->serverLabel,
ui->serverStackedWidget); ui->serverStackedWidget);
ui->region->setVisible(false); ui->region->setVisible(false);
ui->serverStackedWidget->setCurrentIndex(1); ui->serverStackedWidget->setCurrentIndex(1);
@@ -533,8 +522,8 @@ void AutoConfigStreamPage::ServiceChanged()
ui->serverLabel->setVisible(true); ui->serverLabel->setVisible(true);
} else { } else {
if (!testBandwidth) if (!testBandwidth)
ui->streamkeyPageLayout->insertRow(2, ui->serverLabel, ui->streamkeyPageLayout->insertRow(
ui->serverStackedWidget); 2, ui->serverLabel, ui->serverStackedWidget);
ui->region->setVisible(regionBased && testBandwidth); ui->region->setVisible(regionBased && testBandwidth);
ui->serverStackedWidget->setCurrentIndex(0); ui->serverStackedWidget->setCurrentIndex(0);
@@ -574,13 +563,15 @@ void AutoConfigStreamPage::UpdateKeyLink()
text += " <a href=\"https://"; text += " <a href=\"https://";
text += "www.twitch.tv/broadcast/dashboard/streamkey"; text += "www.twitch.tv/broadcast/dashboard/streamkey";
text += "\">"; text += "\">";
text += QTStr("Basic.AutoConfig.StreamPage.StreamKey.LinkToSite"); text += QTStr(
"Basic.AutoConfig.StreamPage.StreamKey.LinkToSite");
text += "</a>"; text += "</a>";
} else if (serviceName == "YouTube / YouTube Gaming") { } else if (serviceName == "YouTube / YouTube Gaming") {
text += " <a href=\"https://"; text += " <a href=\"https://";
text += "www.youtube.com/live_dashboard"; text += "www.youtube.com/live_dashboard";
text += "\">"; text += "\">";
text += QTStr("Basic.AutoConfig.StreamPage.StreamKey.LinkToSite"); text += QTStr(
"Basic.AutoConfig.StreamPage.StreamKey.LinkToSite");
text += "</a>"; text += "</a>";
isYoutube = true; isYoutube = true;
@@ -632,9 +623,9 @@ void AutoConfigStreamPage::LoadServices(bool showAll)
QVariant((int)ListOpt::ShowAll)); QVariant((int)ListOpt::ShowAll));
} }
ui->service->insertItem(0, ui->service->insertItem(
QTStr("Basic.AutoConfig.StreamPage.Service.Custom"), 0, QTStr("Basic.AutoConfig.StreamPage.Service.Custom"),
QVariant((int)ListOpt::Custom)); QVariant((int)ListOpt::Custom));
if (!lastService.isEmpty()) { if (!lastService.isEmpty()) {
int idx = ui->service->findText(lastService); int idx = ui->service->findText(lastService);
@@ -650,8 +641,8 @@ void AutoConfigStreamPage::LoadServices(bool showAll)
void AutoConfigStreamPage::UpdateServerList() void AutoConfigStreamPage::UpdateServerList()
{ {
QString serviceName = ui->service->currentText(); QString serviceName = ui->service->currentText();
bool showMore = bool showMore = ui->service->currentData().toInt() ==
ui->service->currentData().toInt() == (int)ListOpt::ShowAll; (int)ListOpt::ShowAll;
if (showMore) { if (showMore) {
LoadServices(true); LoadServices(true);
@@ -706,8 +697,7 @@ void AutoConfigStreamPage::UpdateCompleted()
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
AutoConfig::AutoConfig(QWidget *parent) AutoConfig::AutoConfig(QWidget *parent) : QWizard(parent)
: QWizard(parent)
{ {
EnableThreadedMessageBoxes(true); EnableThreadedMessageBoxes(true);
@@ -718,7 +708,7 @@ AutoConfig::AutoConfig(QWidget *parent)
proc_handler_call(ph, "twitch_ingests_refresh", &cd); proc_handler_call(ph, "twitch_ingests_refresh", &cd);
calldata_free(&cd); calldata_free(&cd);
OBSBasic *main = reinterpret_cast<OBSBasic*>(parent); OBSBasic *main = reinterpret_cast<OBSBasic *>(parent);
main->EnableOutputs(false); main->EnableOutputs(false);
installEventFilter(CreateShortcutFilter()); installEventFilter(CreateShortcutFilter());
@@ -805,14 +795,15 @@ AutoConfig::AutoConfig(QWidget *parent)
} else { } else {
streamPage->ui->customServer->setText(server.c_str()); streamPage->ui->customServer->setText(server.c_str());
int idx = streamPage->ui->service->findData( int idx = streamPage->ui->service->findData(
QVariant((int)ListOpt::Custom)); QVariant((int)ListOpt::Custom));
streamPage->ui->service->setCurrentIndex(idx); streamPage->ui->service->setCurrentIndex(idx);
} }
if (!key.empty()) if (!key.empty())
streamPage->ui->key->setText(key.c_str()); streamPage->ui->key->setText(key.c_str());
int bitrate = config_get_int(main->Config(), "SimpleOutput", "VBitrate"); int bitrate =
config_get_int(main->Config(), "SimpleOutput", "VBitrate");
streamPage->ui->bitrate->setValue(bitrate); streamPage->ui->bitrate->setValue(bitrate);
streamPage->ServiceChanged(); streamPage->ServiceChanged();
@@ -825,13 +816,13 @@ AutoConfig::AutoConfig(QWidget *parent)
* bitrate ratio that if NVENC is available, it makes sense to * bitrate ratio that if NVENC is available, it makes sense to
* just always prefer hardware encoding by default */ * just always prefer hardware encoding by default */
bool preferHardware = nvencAvailable || bool preferHardware = nvencAvailable ||
os_get_physical_cores() <= 4; os_get_physical_cores() <= 4;
streamPage->ui->preferHardware->setChecked(preferHardware); streamPage->ui->preferHardware->setChecked(preferHardware);
} }
setOptions(0); setOptions(0);
setButtonText(QWizard::FinishButton, setButtonText(QWizard::FinishButton,
QTStr("Basic.AutoConfig.ApplySettings")); QTStr("Basic.AutoConfig.ApplySettings"));
setButtonText(QWizard::BackButton, QTStr("Back")); setButtonText(QWizard::BackButton, QTStr("Back"));
setButtonText(QWizard::NextButton, QTStr("Next")); setButtonText(QWizard::NextButton, QTStr("Next"));
setButtonText(QWizard::CancelButton, QTStr("Cancel")); setButtonText(QWizard::CancelButton, QTStr("Cancel"));
@@ -839,7 +830,7 @@ AutoConfig::AutoConfig(QWidget *parent)
AutoConfig::~AutoConfig() AutoConfig::~AutoConfig()
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
main->EnableOutputs(true); main->EnableOutputs(true);
EnableThreadedMessageBoxes(false); EnableThreadedMessageBoxes(false);
} }
@@ -879,13 +870,13 @@ bool AutoConfig::CanTestServer(const char *server)
if (strcmp(server, "Default") == 0) { if (strcmp(server, "Default") == 0) {
return true; return true;
} else if (astrcmp_n(server, "US-West:", 8) == 0 || } else if (astrcmp_n(server, "US-West:", 8) == 0 ||
astrcmp_n(server, "US-East:", 8) == 0) { astrcmp_n(server, "US-East:", 8) == 0) {
return regionUS; return regionUS;
} else if (astrcmp_n(server, "EU-", 3) == 0) { } else if (astrcmp_n(server, "EU-", 3) == 0) {
return regionEU; return regionEU;
} else if (astrcmp_n(server, "South Korea:", 12) == 0 || } else if (astrcmp_n(server, "South Korea:", 12) == 0 ||
astrcmp_n(server, "Asia:", 5) == 0 || astrcmp_n(server, "Asia:", 5) == 0 ||
astrcmp_n(server, "China:", 6) == 0) { astrcmp_n(server, "China:", 6) == 0) {
return regionAsia; return regionAsia;
} else if (regionOther) { } else if (regionOther) {
return true; return true;
@@ -924,14 +915,12 @@ inline const char *AutoConfig::GetEncoderId(Encoder enc)
void AutoConfig::SaveStreamSettings() void AutoConfig::SaveStreamSettings()
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
/* ---------------------------------- */ /* ---------------------------------- */
/* save service */ /* save service */
const char *service_id = customServer const char *service_id = customServer ? "rtmp_custom" : "rtmp_common";
? "rtmp_custom"
: "rtmp_common";
obs_service_t *oldService = main->GetService(); obs_service_t *oldService = main->GetService();
OBSData hotkeyData = obs_hotkeys_save_service(oldService); OBSData hotkeyData = obs_hotkeys_save_service(oldService);
@@ -945,8 +934,8 @@ void AutoConfig::SaveStreamSettings()
obs_data_set_string(settings, "server", server.c_str()); obs_data_set_string(settings, "server", server.c_str());
obs_data_set_string(settings, "key", key.c_str()); obs_data_set_string(settings, "key", key.c_str());
OBSService newService = obs_service_create(service_id, OBSService newService = obs_service_create(
"default_service", settings, hotkeyData); service_id, "default_service", settings, hotkeyData);
obs_service_release(newService); obs_service_release(newService);
if (!newService) if (!newService)
@@ -962,26 +951,26 @@ void AutoConfig::SaveStreamSettings()
/* save stream settings */ /* save stream settings */
config_set_int(main->Config(), "SimpleOutput", "VBitrate", config_set_int(main->Config(), "SimpleOutput", "VBitrate",
idealBitrate); idealBitrate);
config_set_string(main->Config(), "SimpleOutput", "StreamEncoder", config_set_string(main->Config(), "SimpleOutput", "StreamEncoder",
GetEncoderId(streamingEncoder)); GetEncoderId(streamingEncoder));
config_remove_value(main->Config(), "SimpleOutput", "UseAdvanced"); config_remove_value(main->Config(), "SimpleOutput", "UseAdvanced");
} }
void AutoConfig::SaveSettings() void AutoConfig::SaveSettings()
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
if (recordingEncoder != Encoder::Stream) if (recordingEncoder != Encoder::Stream)
config_set_string(main->Config(), "SimpleOutput", "RecEncoder", config_set_string(main->Config(), "SimpleOutput", "RecEncoder",
GetEncoderId(recordingEncoder)); GetEncoderId(recordingEncoder));
const char *quality = recordingQuality == Quality::High const char *quality = recordingQuality == Quality::High ? "Small"
? "Small" : "Stream";
: "Stream";
config_set_string(main->Config(), "Output", "Mode", "Simple"); config_set_string(main->Config(), "Output", "Mode", "Simple");
config_set_string(main->Config(), "SimpleOutput", "RecQuality", quality); config_set_string(main->Config(), "SimpleOutput", "RecQuality",
quality);
config_set_int(main->Config(), "Video", "BaseCX", baseResolutionCX); config_set_int(main->Config(), "Video", "BaseCX", baseResolutionCX);
config_set_int(main->Config(), "Video", "BaseCY", baseResolutionCY); config_set_int(main->Config(), "Video", "BaseCY", baseResolutionCY);
config_set_int(main->Config(), "Video", "OutputCX", idealResolutionCX); config_set_int(main->Config(), "Video", "OutputCX", idealResolutionCX);
@@ -990,7 +979,7 @@ void AutoConfig::SaveSettings()
if (fpsType != FPSType::UseCurrent) { if (fpsType != FPSType::UseCurrent) {
config_set_uint(main->Config(), "Video", "FPSType", 0); config_set_uint(main->Config(), "Video", "FPSType", 0);
config_set_string(main->Config(), "Video", "FPSCommon", config_set_string(main->Config(), "Video", "FPSCommon",
std::to_string(idealFPSNum).c_str()); std::to_string(idealFPSNum).c_str());
} }
main->ResetVideo(); main->ResetVideo();
+7 -7
View File
@@ -32,13 +32,13 @@ class AutoConfig : public QWizard {
enum class Type { enum class Type {
Invalid, Invalid,
Streaming, Streaming,
Recording Recording,
}; };
enum class Service { enum class Service {
Twitch, Twitch,
Smashcast, Smashcast,
Other Other,
}; };
enum class Encoder { enum class Encoder {
@@ -46,12 +46,12 @@ class AutoConfig : public QWizard {
NVENC, NVENC,
QSV, QSV,
AMD, AMD,
Stream Stream,
}; };
enum class Quality { enum class Quality {
Stream, Stream,
High High,
}; };
enum class FPSType : int { enum class FPSType : int {
@@ -59,7 +59,7 @@ class AutoConfig : public QWizard {
PreferHighRes, PreferHighRes,
UseCurrent, UseCurrent,
fps30, fps30,
fps60 fps60,
}; };
static inline const char *GetEncoderId(Encoder enc); static inline const char *GetEncoderId(Encoder enc);
@@ -119,7 +119,7 @@ public:
StartPage, StartPage,
VideoPage, VideoPage,
StreamPage, StreamPage,
TestPage TestPage,
}; };
}; };
@@ -216,7 +216,7 @@ class AutoConfigTestPage : public QWizardPage {
BandwidthTest, BandwidthTest,
StreamEncoder, StreamEncoder,
RecordingEncoder, RecordingEncoder,
Finished Finished,
}; };
Stage stage = Stage::Starting; Stage stage = Stage::Starting;
+156 -158
View File
@@ -36,45 +36,39 @@ using namespace std;
Q_DECLARE_METATYPE(OBSSource); Q_DECLARE_METATYPE(OBSSource);
OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_) OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
: QDialog (parent), : QDialog(parent),
ui (new Ui::OBSBasicFilters), ui(new Ui::OBSBasicFilters),
source (source_), source(source_),
addSignal (obs_source_get_signal_handler(source), addSignal(obs_source_get_signal_handler(source), "filter_add",
"filter_add", OBSBasicFilters::OBSSourceFilterAdded, this),
OBSBasicFilters::OBSSourceFilterAdded, removeSignal(obs_source_get_signal_handler(source), "filter_remove",
this), OBSBasicFilters::OBSSourceFilterRemoved, this),
removeSignal (obs_source_get_signal_handler(source), reorderSignal(obs_source_get_signal_handler(source),
"filter_remove", "reorder_filters", OBSBasicFilters::OBSSourceReordered,
OBSBasicFilters::OBSSourceFilterRemoved, this),
this), removeSourceSignal(obs_source_get_signal_handler(source), "remove",
reorderSignal (obs_source_get_signal_handler(source), OBSBasicFilters::SourceRemoved, this),
"reorder_filters", renameSourceSignal(obs_source_get_signal_handler(source), "rename",
OBSBasicFilters::OBSSourceReordered, OBSBasicFilters::SourceRenamed, this),
this), noPreviewMargin(13)
removeSourceSignal (obs_source_get_signal_handler(source),
"remove",
OBSBasicFilters::SourceRemoved, this),
renameSourceSignal (obs_source_get_signal_handler(source),
"rename",
OBSBasicFilters::SourceRenamed, this),
noPreviewMargin (13)
{ {
main = reinterpret_cast<OBSBasic*>(parent); main = reinterpret_cast<OBSBasic *>(parent);
ui->setupUi(this); ui->setupUi(this);
UpdateFilters(); UpdateFilters();
ui->asyncFilters->setItemDelegate( ui->asyncFilters->setItemDelegate(
new VisibilityItemDelegate(ui->asyncFilters)); new VisibilityItemDelegate(ui->asyncFilters));
ui->effectFilters->setItemDelegate( ui->effectFilters->setItemDelegate(
new VisibilityItemDelegate(ui->effectFilters)); new VisibilityItemDelegate(ui->effectFilters));
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
setWindowTitle(QTStr("Basic.Filters.Title").arg(QT_UTF8(name))); setWindowTitle(QTStr("Basic.Filters.Title").arg(QT_UTF8(name)));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
#ifndef QT_NO_SHORTCUT #ifndef QT_NO_SHORTCUT
ui->actionRemoveFilter->setShortcut(QApplication::translate("OBSBasicFilters", "Del", nullptr)); ui->actionRemoveFilter->setShortcut(
QApplication::translate("OBSBasicFilters", "Del", nullptr));
#endif // QT_NO_SHORTCUT #endif // QT_NO_SHORTCUT
addAction(ui->actionRemoveFilter); addAction(ui->actionRemoveFilter);
@@ -84,33 +78,33 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
installEventFilter(CreateShortcutFilter()); installEventFilter(CreateShortcutFilter());
connect(ui->asyncFilters->itemDelegate(), connect(ui->asyncFilters->itemDelegate(),
SIGNAL(closeEditor(QWidget*, SIGNAL(closeEditor(QWidget *,
QAbstractItemDelegate::EndEditHint)), QAbstractItemDelegate::EndEditHint)),
this, this,
SLOT(AsyncFilterNameEdited(QWidget*, SLOT(AsyncFilterNameEdited(
QAbstractItemDelegate::EndEditHint))); QWidget *, QAbstractItemDelegate::EndEditHint)));
connect(ui->effectFilters->itemDelegate(), connect(ui->effectFilters->itemDelegate(),
SIGNAL(closeEditor(QWidget*, SIGNAL(closeEditor(QWidget *,
QAbstractItemDelegate::EndEditHint)), QAbstractItemDelegate::EndEditHint)),
this, this,
SLOT(EffectFilterNameEdited(QWidget*, SLOT(EffectFilterNameEdited(
QAbstractItemDelegate::EndEditHint))); QWidget *, QAbstractItemDelegate::EndEditHint)));
QPushButton *close = ui->buttonBox->button(QDialogButtonBox::Close); QPushButton *close = ui->buttonBox->button(QDialogButtonBox::Close);
connect(close, SIGNAL(clicked()), this, SLOT(close())); connect(close, SIGNAL(clicked()), this, SLOT(close()));
close->setDefault(true); close->setDefault(true);
ui->buttonBox->button(QDialogButtonBox::Reset)->setText( ui->buttonBox->button(QDialogButtonBox::Reset)
QTStr("Defaults")); ->setText(QTStr("Defaults"));
connect(ui->buttonBox->button(QDialogButtonBox::Reset), connect(ui->buttonBox->button(QDialogButtonBox::Reset),
SIGNAL(clicked()), this, SLOT(ResetFilters())); SIGNAL(clicked()), this, SLOT(ResetFilters()));
uint32_t caps = obs_source_get_output_flags(source); uint32_t caps = obs_source_get_output_flags(source);
bool audio = (caps & OBS_SOURCE_AUDIO) != 0; bool audio = (caps & OBS_SOURCE_AUDIO) != 0;
bool audioOnly = (caps & OBS_SOURCE_VIDEO) == 0; bool audioOnly = (caps & OBS_SOURCE_VIDEO) == 0;
bool async = (caps & OBS_SOURCE_ASYNC) != 0; bool async = (caps & OBS_SOURCE_ASYNC) != 0;
if (!async && !audio) { if (!async && !audio) {
ui->asyncWidget->setVisible(false); ui->asyncWidget->setVisible(false);
@@ -124,22 +118,22 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
if (audioOnly || (audio && !async)) if (audioOnly || (audio && !async))
ui->asyncLabel->setText(QTStr("Basic.Filters.AudioFilters")); ui->asyncLabel->setText(QTStr("Basic.Filters.AudioFilters"));
auto addDrawCallback = [this] () auto addDrawCallback = [this]() {
{
obs_display_add_draw_callback(ui->preview->GetDisplay(), obs_display_add_draw_callback(ui->preview->GetDisplay(),
OBSBasicFilters::DrawPreview, this); OBSBasicFilters::DrawPreview,
this);
}; };
enum obs_source_type type = obs_source_get_type(source); enum obs_source_type type = obs_source_get_type(source);
bool drawable_type = type == OBS_SOURCE_TYPE_INPUT || bool drawable_type = type == OBS_SOURCE_TYPE_INPUT ||
type == OBS_SOURCE_TYPE_SCENE; type == OBS_SOURCE_TYPE_SCENE;
if ((caps & OBS_SOURCE_VIDEO) != 0) { if ((caps & OBS_SOURCE_VIDEO) != 0) {
ui->rightLayout->setContentsMargins(0, 0, 0, 0); ui->rightLayout->setContentsMargins(0, 0, 0, 0);
ui->preview->show(); ui->preview->show();
if (drawable_type) if (drawable_type)
connect(ui->preview, &OBSQTDisplay::DisplayCreated, connect(ui->preview, &OBSQTDisplay::DisplayCreated,
addDrawCallback); addDrawCallback);
} else { } else {
ui->rightLayout->setContentsMargins(0, noPreviewMargin, 0, 0); ui->rightLayout->setContentsMargins(0, noPreviewMargin, 0, 0);
ui->rightContainerLayout->insertStretch(1); ui->rightContainerLayout->insertStretch(1);
@@ -187,14 +181,14 @@ void OBSBasicFilters::UpdatePropertiesView(int row, bool async)
obs_data_t *settings = obs_source_get_settings(filter); obs_data_t *settings = obs_source_get_settings(filter);
view = new OBSPropertiesView(settings, filter, view = new OBSPropertiesView(
(PropertiesReloadCallback)obs_source_properties, settings, filter,
(PropertiesUpdateCallback)obs_source_update); (PropertiesReloadCallback)obs_source_properties,
(PropertiesUpdateCallback)obs_source_update);
updatePropertiesSignal.Connect(obs_source_get_signal_handler(filter), updatePropertiesSignal.Connect(obs_source_get_signal_handler(filter),
"update_properties", "update_properties",
OBSBasicFilters::UpdateProperties, OBSBasicFilters::UpdateProperties, this);
this);
obs_data_release(settings); obs_data_release(settings);
@@ -206,8 +200,8 @@ void OBSBasicFilters::UpdatePropertiesView(int row, bool async)
void OBSBasicFilters::UpdateProperties(void *data, calldata_t *) void OBSBasicFilters::UpdateProperties(void *data, calldata_t *)
{ {
QMetaObject::invokeMethod(static_cast<OBSBasicFilters*>(data)->view, QMetaObject::invokeMethod(static_cast<OBSBasicFilters *>(data)->view,
"ReloadProperties"); "ReloadProperties");
} }
void OBSBasicFilters::AddFilter(OBSSource filter) void OBSBasicFilters::AddFilter(OBSSource filter)
@@ -252,7 +246,7 @@ void OBSBasicFilters::RemoveFilter(OBSSource filter)
const char *filterId = obs_source_get_id(filter); const char *filterId = obs_source_get_id(filter);
blog(LOG_INFO, "User removed filter '%s' (%s) from source '%s'", blog(LOG_INFO, "User removed filter '%s' (%s) from source '%s'",
filterName, filterId, sourceName); filterName, filterId, sourceName);
main->SaveProject(); main->SaveProject();
} }
@@ -265,8 +259,8 @@ struct FilterOrderInfo {
inline FilterOrderInfo(OBSBasicFilters *window_) : window(window_) {} inline FilterOrderInfo(OBSBasicFilters *window_) : window(window_) {}
}; };
void OBSBasicFilters::ReorderFilter(QListWidget *list, void OBSBasicFilters::ReorderFilter(QListWidget *list, obs_source_t *filter,
obs_source_t *filter, size_t idx) size_t idx)
{ {
int count = list->count(); int count = list->count();
@@ -280,10 +274,10 @@ void OBSBasicFilters::ReorderFilter(QListWidget *list,
bool sel = (list->currentRow() == i); bool sel = (list->currentRow() == i);
listItem = TakeListItem(list, i); listItem = TakeListItem(list, i);
if (listItem) { if (listItem) {
list->insertItem((int)idx, listItem); list->insertItem((int)idx, listItem);
SetupVisibilityItem(list, SetupVisibilityItem(list, listItem,
listItem, filterItem); filterItem);
if (sel) if (sel)
list->setCurrentRow((int)idx); list->setCurrentRow((int)idx);
@@ -299,27 +293,28 @@ void OBSBasicFilters::ReorderFilters()
{ {
FilterOrderInfo info(this); FilterOrderInfo info(this);
obs_source_enum_filters(source, obs_source_enum_filters(
[] (obs_source_t*, obs_source_t *filter, void *p) source,
{ [](obs_source_t *, obs_source_t *filter, void *p) {
FilterOrderInfo *info = FilterOrderInfo *info =
reinterpret_cast<FilterOrderInfo*>(p); reinterpret_cast<FilterOrderInfo *>(p);
uint32_t flags; uint32_t flags;
bool async; bool async;
flags = obs_source_get_output_flags(filter); flags = obs_source_get_output_flags(filter);
async = (flags & OBS_SOURCE_ASYNC) != 0; async = (flags & OBS_SOURCE_ASYNC) != 0;
if (async) { if (async) {
info->window->ReorderFilter( info->window->ReorderFilter(
info->window->ui->asyncFilters, info->window->ui->asyncFilters, filter,
filter, info->asyncIdx++); info->asyncIdx++);
} else { } else {
info->window->ReorderFilter( info->window->ReorderFilter(
info->window->ui->effectFilters, info->window->ui->effectFilters, filter,
filter, info->effectIdx++); info->effectIdx++);
} }
}, &info); },
&info);
} }
void OBSBasicFilters::UpdateFilters() void OBSBasicFilters::UpdateFilters()
@@ -330,33 +325,34 @@ void OBSBasicFilters::UpdateFilters()
ClearListItems(ui->effectFilters); ClearListItems(ui->effectFilters);
ClearListItems(ui->asyncFilters); ClearListItems(ui->asyncFilters);
obs_source_enum_filters(source, obs_source_enum_filters(
[] (obs_source_t*, obs_source_t *filter, void *p) source,
{ [](obs_source_t *, obs_source_t *filter, void *p) {
OBSBasicFilters *window = OBSBasicFilters *window =
reinterpret_cast<OBSBasicFilters*>(p); reinterpret_cast<OBSBasicFilters *>(p);
window->AddFilter(filter); window->AddFilter(filter);
}, this); },
this);
main->SaveProject(); main->SaveProject();
} }
static bool filter_compatible(bool async, uint32_t sourceFlags, static bool filter_compatible(bool async, uint32_t sourceFlags,
uint32_t filterFlags) uint32_t filterFlags)
{ {
bool filterVideo = (filterFlags & OBS_SOURCE_VIDEO) != 0; bool filterVideo = (filterFlags & OBS_SOURCE_VIDEO) != 0;
bool filterAsync = (filterFlags & OBS_SOURCE_ASYNC) != 0; bool filterAsync = (filterFlags & OBS_SOURCE_ASYNC) != 0;
bool filterAudio = (filterFlags & OBS_SOURCE_AUDIO) != 0; bool filterAudio = (filterFlags & OBS_SOURCE_AUDIO) != 0;
bool audio = (sourceFlags & OBS_SOURCE_AUDIO) != 0; bool audio = (sourceFlags & OBS_SOURCE_AUDIO) != 0;
bool audioOnly = (sourceFlags & OBS_SOURCE_VIDEO) == 0; bool audioOnly = (sourceFlags & OBS_SOURCE_VIDEO) == 0;
bool asyncSource = (sourceFlags & OBS_SOURCE_ASYNC) != 0; bool asyncSource = (sourceFlags & OBS_SOURCE_ASYNC) != 0;
if (async && ((audioOnly && filterVideo) || (!audio && !asyncSource))) if (async && ((audioOnly && filterVideo) || (!audio && !asyncSource)))
return false; return false;
return (async && (filterAudio || filterAsync)) || return (async && (filterAudio || filterAsync)) ||
(!async && !filterAudio && !filterAsync); (!async && !filterAudio && !filterAsync);
} }
QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async) QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
@@ -372,7 +368,8 @@ QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
inline FilterInfo(const char *type_, const char *name_) inline FilterInfo(const char *type_, const char *name_)
: type(type_), name(name_) : type(type_), name(name_)
{} {
}
}; };
vector<FilterInfo> types; vector<FilterInfo> types;
@@ -396,17 +393,17 @@ QMenu *OBSBasicFilters::CreateAddFilterPopupMenu(bool async)
QMenu *popup = new QMenu(QTStr("Add"), this); QMenu *popup = new QMenu(QTStr("Add"), this);
for (FilterInfo &type : types) { for (FilterInfo &type : types) {
uint32_t filterFlags = obs_get_source_output_flags( uint32_t filterFlags =
type.type.c_str()); obs_get_source_output_flags(type.type.c_str());
if (!filter_compatible(async, sourceFlags, filterFlags)) if (!filter_compatible(async, sourceFlags, filterFlags))
continue; continue;
QAction *popupItem = new QAction(QT_UTF8(type.name.c_str()), QAction *popupItem =
this); new QAction(QT_UTF8(type.name.c_str()), this);
popupItem->setData(QT_UTF8(type.type.c_str())); popupItem->setData(QT_UTF8(type.type.c_str()));
connect(popupItem, SIGNAL(triggered(bool)), connect(popupItem, SIGNAL(triggered(bool)), this,
this, SLOT(AddFilterFromAction())); SLOT(AddFilterFromAction()));
popup->addAction(popupItem); popup->addAction(popupItem);
foundValues = true; foundValues = true;
@@ -426,40 +423,40 @@ void OBSBasicFilters::AddNewFilter(const char *id)
obs_source_t *existing_filter; obs_source_t *existing_filter;
string name = obs_source_get_display_name(id); string name = obs_source_get_display_name(id);
bool success = NameDialog::AskForName(this, bool success = NameDialog::AskForName(
QTStr("Basic.Filters.AddFilter.Title"), this, QTStr("Basic.Filters.AddFilter.Title"),
QTStr("Basic.FIlters.AddFilter.Text"), name, QTStr("Basic.FIlters.AddFilter.Text"), name,
QT_UTF8(name.c_str())); QT_UTF8(name.c_str()));
if (!success) if (!success)
return; return;
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(this, OBSMessageBox::warning(this,
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Text")); QTStr("NoNameEntered.Text"));
AddNewFilter(id); AddNewFilter(id);
return; return;
} }
existing_filter = obs_source_get_filter_by_name(source, existing_filter =
name.c_str()); obs_source_get_filter_by_name(source, name.c_str());
if (existing_filter) { if (existing_filter) {
OBSMessageBox::warning(this, OBSMessageBox::warning(this, QTStr("NameExists.Title"),
QTStr("NameExists.Title"), QTStr("NameExists.Text"));
QTStr("NameExists.Text"));
obs_source_release(existing_filter); obs_source_release(existing_filter);
AddNewFilter(id); AddNewFilter(id);
return; return;
} }
obs_source_t *filter = obs_source_create(id, name.c_str(), obs_source_t *filter =
nullptr, nullptr); obs_source_create(id, name.c_str(), nullptr, nullptr);
if (filter) { if (filter) {
const char *sourceName = obs_source_get_name(source); const char *sourceName = obs_source_get_name(source);
blog(LOG_INFO, "User added filter '%s' (%s) " blog(LOG_INFO,
"to source '%s'", "User added filter '%s' (%s) "
name.c_str(), id, sourceName); "to source '%s'",
name.c_str(), id, sourceName);
obs_source_filter_add(source, filter); obs_source_filter_add(source, filter);
obs_source_release(filter); obs_source_release(filter);
@@ -469,7 +466,7 @@ void OBSBasicFilters::AddNewFilter(const char *id)
void OBSBasicFilters::AddFilterFromAction() void OBSBasicFilters::AddFilterFromAction()
{ {
QAction *action = qobject_cast<QAction*>(sender()); QAction *action = qobject_cast<QAction *>(sender());
if (!action) if (!action)
return; return;
@@ -482,8 +479,8 @@ void OBSBasicFilters::closeEvent(QCloseEvent *event)
if (!event->isAccepted()) if (!event->isAccepted())
return; return;
obs_display_remove_draw_callback (ui->preview->GetDisplay(), obs_display_remove_draw_callback(ui->preview->GetDisplay(),
OBSBasicFilters::DrawPreview, this); OBSBasicFilters::DrawPreview, this);
main->SaveProject(); main->SaveProject();
} }
@@ -492,26 +489,26 @@ void OBSBasicFilters::closeEvent(QCloseEvent *event)
void OBSBasicFilters::OBSSourceFilterAdded(void *param, calldata_t *data) void OBSBasicFilters::OBSSourceFilterAdded(void *param, calldata_t *data)
{ {
OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters*>(param); OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters *>(param);
obs_source_t *filter = (obs_source_t*)calldata_ptr(data, "filter"); obs_source_t *filter = (obs_source_t *)calldata_ptr(data, "filter");
QMetaObject::invokeMethod(window, "AddFilter", QMetaObject::invokeMethod(window, "AddFilter",
Q_ARG(OBSSource, OBSSource(filter))); Q_ARG(OBSSource, OBSSource(filter)));
} }
void OBSBasicFilters::OBSSourceFilterRemoved(void *param, calldata_t *data) void OBSBasicFilters::OBSSourceFilterRemoved(void *param, calldata_t *data)
{ {
OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters*>(param); OBSBasicFilters *window = reinterpret_cast<OBSBasicFilters *>(param);
obs_source_t *filter = (obs_source_t*)calldata_ptr(data, "filter"); obs_source_t *filter = (obs_source_t *)calldata_ptr(data, "filter");
QMetaObject::invokeMethod(window, "RemoveFilter", QMetaObject::invokeMethod(window, "RemoveFilter",
Q_ARG(OBSSource, OBSSource(filter))); Q_ARG(OBSSource, OBSSource(filter)));
} }
void OBSBasicFilters::OBSSourceReordered(void *param, calldata_t *data) void OBSBasicFilters::OBSSourceReordered(void *param, calldata_t *data)
{ {
QMetaObject::invokeMethod(reinterpret_cast<OBSBasicFilters*>(param), QMetaObject::invokeMethod(reinterpret_cast<OBSBasicFilters *>(param),
"ReorderFilters"); "ReorderFilters");
UNUSED_PARAMETER(data); UNUSED_PARAMETER(data);
} }
@@ -520,8 +517,8 @@ void OBSBasicFilters::SourceRemoved(void *param, calldata_t *data)
{ {
UNUSED_PARAMETER(data); UNUSED_PARAMETER(data);
QMetaObject::invokeMethod(static_cast<OBSBasicFilters*>(param), QMetaObject::invokeMethod(static_cast<OBSBasicFilters *>(param),
"close"); "close");
} }
void OBSBasicFilters::SourceRenamed(void *param, calldata_t *data) void OBSBasicFilters::SourceRenamed(void *param, calldata_t *data)
@@ -529,13 +526,13 @@ void OBSBasicFilters::SourceRenamed(void *param, calldata_t *data)
const char *name = calldata_string(data, "new_name"); const char *name = calldata_string(data, "new_name");
QString title = QTStr("Basic.Filters.Title").arg(QT_UTF8(name)); QString title = QTStr("Basic.Filters.Title").arg(QT_UTF8(name));
QMetaObject::invokeMethod(static_cast<OBSBasicFilters*>(param), QMetaObject::invokeMethod(static_cast<OBSBasicFilters *>(param),
"setWindowTitle", Q_ARG(QString, title)); "setWindowTitle", Q_ARG(QString, title));
} }
void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy) void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
{ {
OBSBasicFilters *window = static_cast<OBSBasicFilters*>(data); OBSBasicFilters *window = static_cast<OBSBasicFilters *>(data);
if (!window->source) if (!window->source)
return; return;
@@ -543,8 +540,8 @@ void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
int x, y; int x, y;
int newCX, newCY; int newCX, newCY;
float scale; float scale;
GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale); GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale);
@@ -567,15 +564,15 @@ void OBSBasicFilters::DrawPreview(void *data, uint32_t cx, uint32_t cy)
static bool QueryRemove(QWidget *parent, obs_source_t *source) static bool QueryRemove(QWidget *parent, obs_source_t *source)
{ {
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
QString text = QTStr("ConfirmRemove.Text"); QString text = QTStr("ConfirmRemove.Text");
text.replace("$1", QT_UTF8(name)); text.replace("$1", QT_UTF8(name));
QMessageBox remove_source(parent); QMessageBox remove_source(parent);
remove_source.setText(text); remove_source.setText(text);
QAbstractButton *Yes = remove_source.addButton(QTStr("Yes"), QAbstractButton *Yes =
QMessageBox::YesRole); remove_source.addButton(QTStr("Yes"), QMessageBox::YesRole);
remove_source.addButton(QTStr("No"), QMessageBox::NoRole); remove_source.addButton(QTStr("No"), QMessageBox::NoRole);
remove_source.setIcon(QMessageBox::Question); remove_source.setIcon(QMessageBox::Question);
remove_source.setWindowTitle(QTStr("ConfirmRemove.Title")); remove_source.setWindowTitle(QTStr("ConfirmRemove.Title"));
@@ -612,7 +609,7 @@ void OBSBasicFilters::on_moveAsyncFilterDown_clicked()
OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true); OBSSource filter = GetFilter(ui->asyncFilters->currentRow(), true);
if (filter) if (filter)
obs_source_filter_set_order(source, filter, obs_source_filter_set_order(source, filter,
OBS_ORDER_MOVE_DOWN); OBS_ORDER_MOVE_DOWN);
} }
void OBSBasicFilters::on_asyncFilters_GotFocus() void OBSBasicFilters::on_asyncFilters_GotFocus()
@@ -654,7 +651,7 @@ void OBSBasicFilters::on_moveEffectFilterDown_clicked()
OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false); OBSSource filter = GetFilter(ui->effectFilters->currentRow(), false);
if (filter) if (filter)
obs_source_filter_set_order(source, filter, obs_source_filter_set_order(source, filter,
OBS_ORDER_MOVE_DOWN); OBS_ORDER_MOVE_DOWN);
} }
void OBSBasicFilters::on_effectFilters_GotFocus() void OBSBasicFilters::on_effectFilters_GotFocus()
@@ -704,11 +701,11 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
popup.addMenu(addMenu); popup.addMenu(addMenu);
if (item) { if (item) {
const char *renameSlot = async ? const char *renameSlot = async ? SLOT(RenameAsyncFilter())
SLOT(RenameAsyncFilter()) : SLOT(RenameEffectFilter()); : SLOT(RenameEffectFilter());
const char *removeSlot = async ? const char *removeSlot =
SLOT(on_removeAsyncFilter_clicked()) : async ? SLOT(on_removeAsyncFilter_clicked())
SLOT(on_removeEffectFilter_clicked()); : SLOT(on_removeEffectFilter_clicked());
popup.addSeparator(); popup.addSeparator();
popup.addAction(QTStr("Rename"), this, renameSlot); popup.addAction(QTStr("Rename"), this, renameSlot);
@@ -721,9 +718,9 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async)
void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async) void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async)
{ {
Qt::ItemFlags flags = item->flags(); Qt::ItemFlags flags = item->flags();
OBSSource filter = item->data(Qt::UserRole).value<OBSSource>(); OBSSource filter = item->data(Qt::UserRole).value<OBSSource>();
const char *name = obs_source_get_name(filter); const char *name = obs_source_get_name(filter);
QListWidget *list = async ? ui->asyncFilters : ui->effectFilters; QListWidget *list = async ? ui->asyncFilters : ui->effectFilters;
item->setText(QT_UTF8(name)); item->setText(QT_UTF8(name));
item->setFlags(flags | Qt::ItemIsEditable); item->setFlags(flags | Qt::ItemIsEditable);
@@ -733,13 +730,13 @@ void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async)
} }
void OBSBasicFilters::on_asyncFilters_customContextMenuRequested( void OBSBasicFilters::on_asyncFilters_customContextMenuRequested(
const QPoint &pos) const QPoint &pos)
{ {
CustomContextMenu(pos, true); CustomContextMenu(pos, true);
} }
void OBSBasicFilters::on_effectFilters_customContextMenuRequested( void OBSBasicFilters::on_effectFilters_customContextMenuRequested(
const QPoint &pos) const QPoint &pos)
{ {
CustomContextMenu(pos, false); CustomContextMenu(pos, false);
} }
@@ -758,7 +755,7 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
{ {
QListWidgetItem *listItem = list->currentItem(); QListWidgetItem *listItem = list->currentItem();
OBSSource filter = listItem->data(Qt::UserRole).value<OBSSource>(); OBSSource filter = listItem->data(Qt::UserRole).value<OBSSource>();
QLineEdit *edit = qobject_cast<QLineEdit*>(editor); QLineEdit *edit = qobject_cast<QLineEdit *>(editor);
string name = QT_TO_UTF8(edit->text().trimmed()); string name = QT_TO_UTF8(edit->text().trimmed());
const char *prevName = obs_source_get_name(filter); const char *prevName = obs_source_get_name(filter);
@@ -766,28 +763,29 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
obs_source_t *foundFilter = nullptr; obs_source_t *foundFilter = nullptr;
if (!sameName) if (!sameName)
foundFilter = obs_source_get_filter_by_name(source, foundFilter =
name.c_str()); obs_source_get_filter_by_name(source, name.c_str());
if (foundFilter || name.empty() || sameName) { if (foundFilter || name.empty() || sameName) {
listItem->setText(QT_UTF8(prevName)); listItem->setText(QT_UTF8(prevName));
if (foundFilter) { if (foundFilter) {
OBSMessageBox::information(window(), OBSMessageBox::information(window(),
QTStr("NameExists.Title"), QTStr("NameExists.Title"),
QTStr("NameExists.Text")); QTStr("NameExists.Text"));
obs_source_release(foundFilter); obs_source_release(foundFilter);
} else if (name.empty()) { } else if (name.empty()) {
OBSMessageBox::information(window(), OBSMessageBox::information(window(),
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Text")); QTStr("NoNameEntered.Text"));
} }
} else { } else {
const char *sourceName = obs_source_get_name(source); const char *sourceName = obs_source_get_name(source);
blog(LOG_INFO, "User renamed filter '%s' on source '%s' to '%s'", blog(LOG_INFO,
prevName, sourceName, name.c_str()); "User renamed filter '%s' on source '%s' to '%s'",
prevName, sourceName, name.c_str());
listItem->setText(QT_UTF8(name.c_str())); listItem->setText(QT_UTF8(name.c_str()));
obs_source_set_name(filter, name.c_str()); obs_source_set_name(filter, name.c_str());
@@ -797,15 +795,15 @@ void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list)
SetupVisibilityItem(list, listItem, filter); SetupVisibilityItem(list, listItem, filter);
} }
void OBSBasicFilters::AsyncFilterNameEdited(QWidget *editor, void OBSBasicFilters::AsyncFilterNameEdited(
QAbstractItemDelegate::EndEditHint endHint) QWidget *editor, QAbstractItemDelegate::EndEditHint endHint)
{ {
FilterNameEdited(editor, ui->asyncFilters); FilterNameEdited(editor, ui->asyncFilters);
UNUSED_PARAMETER(endHint); UNUSED_PARAMETER(endHint);
} }
void OBSBasicFilters::EffectFilterNameEdited(QWidget *editor, void OBSBasicFilters::EffectFilterNameEdited(
QAbstractItemDelegate::EndEditHint endHint) QWidget *editor, QAbstractItemDelegate::EndEditHint endHint)
{ {
FilterNameEdited(editor, ui->effectFilters); FilterNameEdited(editor, ui->effectFilters);
UNUSED_PARAMETER(endHint); UNUSED_PARAMETER(endHint);
+2 -2
View File
@@ -105,9 +105,9 @@ private slots:
void on_actionMoveDown_triggered(); void on_actionMoveDown_triggered();
void AsyncFilterNameEdited(QWidget *editor, void AsyncFilterNameEdited(QWidget *editor,
QAbstractItemDelegate::EndEditHint endHint); QAbstractItemDelegate::EndEditHint endHint);
void EffectFilterNameEdited(QWidget *editor, void EffectFilterNameEdited(QWidget *editor,
QAbstractItemDelegate::EndEditHint endHint); QAbstractItemDelegate::EndEditHint endHint);
public: public:
OBSBasicFilters(QWidget *parent, OBSSource source_); OBSBasicFilters(QWidget *parent, OBSSource source_);
+49 -52
View File
@@ -29,20 +29,20 @@
using namespace std; using namespace std;
OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_) OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_)
: QDialog (parent), : QDialog(parent),
main (qobject_cast<OBSBasic*>(parent)), main(qobject_cast<OBSBasic *>(parent)),
ui (new Ui::OBSBasicInteraction), ui(new Ui::OBSBasicInteraction),
source (source_), source(source_),
removedSignal (obs_source_get_signal_handler(source), "remove", removedSignal(obs_source_get_signal_handler(source), "remove",
OBSBasicInteraction::SourceRemoved, this), OBSBasicInteraction::SourceRemoved, this),
renamedSignal (obs_source_get_signal_handler(source), "rename", renamedSignal(obs_source_get_signal_handler(source), "rename",
OBSBasicInteraction::SourceRenamed, this), OBSBasicInteraction::SourceRenamed, this),
eventFilter (BuildEventFilter()) eventFilter(BuildEventFilter())
{ {
int cx = (int)config_get_int(App()->GlobalConfig(), "InteractionWindow", int cx = (int)config_get_int(App()->GlobalConfig(), "InteractionWindow",
"cx"); "cx");
int cy = (int)config_get_int(App()->GlobalConfig(), "InteractionWindow", int cy = (int)config_get_int(App()->GlobalConfig(), "InteractionWindow",
"cy"); "cy");
ui->setupUi(this); ui->setupUi(this);
@@ -59,10 +59,10 @@ OBSBasicInteraction::OBSBasicInteraction(QWidget *parent, OBSSource source_)
const char *name = obs_source_get_name(source); const char *name = obs_source_get_name(source);
setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name))); setWindowTitle(QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)));
auto addDrawCallback = [this] () auto addDrawCallback = [this]() {
{
obs_display_add_draw_callback(ui->preview->GetDisplay(), obs_display_add_draw_callback(ui->preview->GetDisplay(),
OBSBasicInteraction::DrawPreview, this); OBSBasicInteraction::DrawPreview,
this);
}; };
connect(ui->preview, &OBSQTDisplay::DisplayCreated, addDrawCallback); connect(ui->preview, &OBSQTDisplay::DisplayCreated, addDrawCallback);
@@ -77,34 +77,32 @@ OBSBasicInteraction::~OBSBasicInteraction()
OBSEventFilter *OBSBasicInteraction::BuildEventFilter() OBSEventFilter *OBSBasicInteraction::BuildEventFilter()
{ {
return new OBSEventFilter( return new OBSEventFilter([this](QObject *obj, QEvent *event) {
[this](QObject *obj, QEvent *event)
{
UNUSED_PARAMETER(obj); UNUSED_PARAMETER(obj);
switch(event->type()) { switch (event->type()) {
case QEvent::MouseButtonPress: case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease: case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick: case QEvent::MouseButtonDblClick:
return this->HandleMouseClickEvent( return this->HandleMouseClickEvent(
static_cast<QMouseEvent *>(event)); static_cast<QMouseEvent *>(event));
case QEvent::MouseMove: case QEvent::MouseMove:
case QEvent::Enter: case QEvent::Enter:
case QEvent::Leave: case QEvent::Leave:
return this->HandleMouseMoveEvent( return this->HandleMouseMoveEvent(
static_cast<QMouseEvent *>(event)); static_cast<QMouseEvent *>(event));
case QEvent::Wheel: case QEvent::Wheel:
return this->HandleMouseWheelEvent( return this->HandleMouseWheelEvent(
static_cast<QWheelEvent *>(event)); static_cast<QWheelEvent *>(event));
case QEvent::FocusIn: case QEvent::FocusIn:
case QEvent::FocusOut: case QEvent::FocusOut:
return this->HandleFocusEvent( return this->HandleFocusEvent(
static_cast<QFocusEvent *>(event)); static_cast<QFocusEvent *>(event));
case QEvent::KeyPress: case QEvent::KeyPress:
case QEvent::KeyRelease: case QEvent::KeyRelease:
return this->HandleKeyEvent( return this->HandleKeyEvent(
static_cast<QKeyEvent *>(event)); static_cast<QKeyEvent *>(event));
default: default:
return false; return false;
} }
@@ -113,8 +111,8 @@ OBSEventFilter *OBSBasicInteraction::BuildEventFilter()
void OBSBasicInteraction::SourceRemoved(void *data, calldata_t *params) void OBSBasicInteraction::SourceRemoved(void *data, calldata_t *params)
{ {
QMetaObject::invokeMethod(static_cast<OBSBasicInteraction*>(data), QMetaObject::invokeMethod(static_cast<OBSBasicInteraction *>(data),
"close"); "close");
UNUSED_PARAMETER(params); UNUSED_PARAMETER(params);
} }
@@ -124,13 +122,13 @@ void OBSBasicInteraction::SourceRenamed(void *data, calldata_t *params)
const char *name = calldata_string(params, "new_name"); const char *name = calldata_string(params, "new_name");
QString title = QTStr("Basic.InteractionWindow").arg(QT_UTF8(name)); QString title = QTStr("Basic.InteractionWindow").arg(QT_UTF8(name));
QMetaObject::invokeMethod(static_cast<OBSBasicProperties*>(data), QMetaObject::invokeMethod(static_cast<OBSBasicProperties *>(data),
"setWindowTitle", Q_ARG(QString, title)); "setWindowTitle", Q_ARG(QString, title));
} }
void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy) void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
{ {
OBSBasicInteraction *window = static_cast<OBSBasicInteraction*>(data); OBSBasicInteraction *window = static_cast<OBSBasicInteraction *>(data);
if (!window->source) if (!window->source)
return; return;
@@ -138,8 +136,8 @@ void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
int x, y; int x, y;
int newCX, newCY; int newCX, newCY;
float scale; float scale;
GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale); GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale);
@@ -149,8 +147,7 @@ void OBSBasicInteraction::DrawPreview(void *data, uint32_t cx, uint32_t cy)
gs_viewport_push(); gs_viewport_push();
gs_projection_push(); gs_projection_push();
gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), -100.0f, 100.0f);
-100.0f, 100.0f);
gs_set_viewport(x, y, newCX, newCY); gs_set_viewport(x, y, newCX, newCY);
obs_source_video_render(window->source); obs_source_video_render(window->source);
@@ -165,15 +162,18 @@ void OBSBasicInteraction::closeEvent(QCloseEvent *event)
return; return;
config_set_int(App()->GlobalConfig(), "InteractionWindow", "cx", config_set_int(App()->GlobalConfig(), "InteractionWindow", "cx",
width()); width());
config_set_int(App()->GlobalConfig(), "InteractionWindow", "cy", config_set_int(App()->GlobalConfig(), "InteractionWindow", "cy",
height()); height());
obs_display_remove_draw_callback(ui->preview->GetDisplay(), obs_display_remove_draw_callback(ui->preview->GetDisplay(),
OBSBasicInteraction::DrawPreview, this); OBSBasicInteraction::DrawPreview,
this);
} }
static int TranslateQtKeyboardEventModifiers(QInputEvent *event, bool mouseEvent) { static int TranslateQtKeyboardEventModifiers(QInputEvent *event,
bool mouseEvent)
{
int obsModifiers = INTERACT_NONE; int obsModifiers = INTERACT_NONE;
if (event->modifiers().testFlag(Qt::ShiftModifier)) if (event->modifiers().testFlag(Qt::ShiftModifier))
@@ -200,8 +200,7 @@ static int TranslateQtKeyboardEventModifiers(QInputEvent *event, bool mouseEvent
return obsModifiers; return obsModifiers;
} }
static int TranslateQtMouseEventModifiers( static int TranslateQtMouseEventModifiers(QMouseEvent *event)
QMouseEvent *event)
{ {
int modifiers = TranslateQtKeyboardEventModifiers(event, true); int modifiers = TranslateQtKeyboardEventModifiers(event, true);
@@ -215,19 +214,19 @@ static int TranslateQtMouseEventModifiers(
return modifiers; return modifiers;
} }
bool OBSBasicInteraction::GetSourceRelativeXY( bool OBSBasicInteraction::GetSourceRelativeXY(int mouseX, int mouseY, int &relX,
int mouseX, int mouseY, int &relX, int &relY) int &relY)
{ {
QSize size = GetPixelSize(ui->preview); QSize size = GetPixelSize(ui->preview);
uint32_t sourceCX = max(obs_source_get_width(source), 1u); uint32_t sourceCX = max(obs_source_get_width(source), 1u);
uint32_t sourceCY = max(obs_source_get_height(source), 1u); uint32_t sourceCY = max(obs_source_get_height(source), 1u);
int x, y; int x, y;
float scale; float scale;
GetScaleAndCenterPos(sourceCX, sourceCY, size.width(), size.height(), GetScaleAndCenterPos(sourceCX, sourceCY, size.width(), size.height(), x,
x, y, scale); y, scale);
if (x > 0) { if (x > 0) {
relX = int(float(mouseX - x) / scale); relX = int(float(mouseX - x) / scale);
@@ -246,8 +245,7 @@ bool OBSBasicInteraction::GetSourceRelativeXY(
return true; return true;
} }
bool OBSBasicInteraction::HandleMouseClickEvent( bool OBSBasicInteraction::HandleMouseClickEvent(QMouseEvent *event)
QMouseEvent *event)
{ {
bool mouseUp = event->type() == QEvent::MouseButtonRelease; bool mouseUp = event->type() == QEvent::MouseButtonRelease;
int clickCount = 1; int clickCount = 1;
@@ -271,8 +269,7 @@ bool OBSBasicInteraction::HandleMouseClickEvent(
button = MOUSE_RIGHT; button = MOUSE_RIGHT;
break; break;
default: default:
blog(LOG_WARNING, "unknown button type %d", blog(LOG_WARNING, "unknown button type %d", event->button());
event->button());
return false; return false;
} }
@@ -281,11 +278,11 @@ bool OBSBasicInteraction::HandleMouseClickEvent(
// clickCount = 2; // clickCount = 2;
bool insideSource = GetSourceRelativeXY(event->x(), event->y(), bool insideSource = GetSourceRelativeXY(event->x(), event->y(),
mouseEvent.x, mouseEvent.y); mouseEvent.x, mouseEvent.y);
if (mouseUp || insideSource) if (mouseUp || insideSource)
obs_source_send_mouse_click(source, &mouseEvent, button, obs_source_send_mouse_click(source, &mouseEvent, button,
mouseUp, clickCount); mouseUp, clickCount);
return true; return true;
} }
@@ -299,7 +296,7 @@ bool OBSBasicInteraction::HandleMouseMoveEvent(QMouseEvent *event)
if (!mouseLeave) { if (!mouseLeave) {
mouseEvent.modifiers = TranslateQtMouseEventModifiers(event); mouseEvent.modifiers = TranslateQtMouseEventModifiers(event);
mouseLeave = !GetSourceRelativeXY(event->x(), event->y(), mouseLeave = !GetSourceRelativeXY(event->x(), event->y(),
mouseEvent.x, mouseEvent.y); mouseEvent.x, mouseEvent.y);
} }
obs_source_send_mouse_move(source, &mouseEvent, mouseLeave); obs_source_send_mouse_move(source, &mouseEvent, mouseLeave);
@@ -329,9 +326,9 @@ bool OBSBasicInteraction::HandleMouseWheelEvent(QWheelEvent *event)
} }
if (GetSourceRelativeXY(event->x(), event->y(), mouseEvent.x, if (GetSourceRelativeXY(event->x(), event->y(), mouseEvent.x,
mouseEvent.y)) mouseEvent.y))
obs_source_send_mouse_wheel(source, &mouseEvent, xDelta, obs_source_send_mouse_wheel(source, &mouseEvent, xDelta,
yDelta); yDelta);
return true; return true;
} }
+6 -9
View File
@@ -35,12 +35,12 @@ class OBSBasicInteraction : public QDialog {
Q_OBJECT Q_OBJECT
private: private:
OBSBasic *main; OBSBasic *main;
std::unique_ptr<Ui::OBSBasicInteraction> ui; std::unique_ptr<Ui::OBSBasicInteraction> ui;
OBSSource source; OBSSource source;
OBSSignal removedSignal; OBSSignal removedSignal;
OBSSignal renamedSignal; OBSSignal renamedSignal;
std::unique_ptr<OBSEventFilter> eventFilter; std::unique_ptr<OBSEventFilter> eventFilter;
static void SourceRemoved(void *data, calldata_t *params); static void SourceRemoved(void *data, calldata_t *params);
@@ -69,13 +69,10 @@ protected:
typedef std::function<bool(QObject *, QEvent *)> EventFilterFunc; typedef std::function<bool(QObject *, QEvent *)> EventFilterFunc;
class OBSEventFilter : public QObject class OBSEventFilter : public QObject {
{
Q_OBJECT Q_OBJECT
public: public:
OBSEventFilter(EventFilterFunc filter_) OBSEventFilter(EventFilterFunc filter_) : filter(filter_) {}
: filter(filter_)
{}
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) bool eventFilter(QObject *obj, QEvent *event)
+12 -12
View File
@@ -30,7 +30,7 @@
struct QCef; struct QCef;
struct QCefCookieManager; struct QCefCookieManager;
extern QCef *cef; extern QCef *cef;
extern QCefCookieManager *panel_cookies; extern QCefCookieManager *panel_cookies;
static std::string GenId() static std::string GenId()
@@ -52,7 +52,8 @@ void CheckExistingCookieId()
if (config_has_user_value(main->Config(), "Panels", "CookieId")) if (config_has_user_value(main->Config(), "Panels", "CookieId"))
return; return;
config_set_string(main->Config(), "Panels", "CookieId", GenId().c_str()); config_set_string(main->Config(), "Panels", "CookieId",
GenId().c_str());
} }
#ifdef BROWSER_AVAILABLE #ifdef BROWSER_AVAILABLE
@@ -66,8 +67,8 @@ static void InitPanelCookieManager()
CheckExistingCookieId(); CheckExistingCookieId();
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
const char *cookie_id = config_get_string(main->Config(), const char *cookie_id =
"Panels", "CookieId"); config_get_string(main->Config(), "Panels", "CookieId");
std::string sub_path; std::string sub_path;
sub_path += "obs_profile_cookies/"; sub_path += "obs_profile_cookies/";
@@ -102,8 +103,8 @@ void DuplicateCurrentCookieProfile(ConfigFile &config)
#ifdef BROWSER_AVAILABLE #ifdef BROWSER_AVAILABLE
if (cef) { if (cef) {
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
std::string cookie_id = config_get_string(main->Config(), std::string cookie_id =
"Panels", "CookieId"); config_get_string(main->Config(), "Panels", "CookieId");
std::string src_path; std::string src_path;
src_path += "obs_profile_cookies/"; src_path += "obs_profile_cookies/";
@@ -136,9 +137,9 @@ void DuplicateCurrentCookieProfile(ConfigFile &config)
} }
config_set_string(config, "Panels", "CookieId", config_set_string(config, "Panels", "CookieId",
cookie_id.c_str()); cookie_id.c_str());
config_set_string(main->Config(), "Panels", "CookieId", config_set_string(main->Config(), "Panels", "CookieId",
new_id.c_str()); new_id.c_str());
} }
#else #else
UNUSED_PARAMETER(config); UNUSED_PARAMETER(config);
@@ -155,10 +156,9 @@ void OBSBasic::InitBrowserPanelSafeBlock()
return; return;
} }
ExecThreadedWithoutBlocking( ExecThreadedWithoutBlocking([] { cef->wait_for_browser_init(); },
[] {cef->wait_for_browser_init();}, QTStr("BrowserPanelInit.Title"),
QTStr("BrowserPanelInit.Title"), QTStr("BrowserPanelInit.Text"));
QTStr("BrowserPanelInit.Text"));
InitPanelCookieManager(); InitPanelCookieManager();
#endif #endif
} }
+38 -44
View File
@@ -11,34 +11,29 @@
using namespace std; using namespace std;
static const char *textExtensions[] = { static const char *textExtensions[] = {"txt", "log", nullptr};
"txt", "log", nullptr
};
static const char *imageExtensions[] = { static const char *imageExtensions[] = {"bmp", "tga", "png", "jpg",
"bmp", "tga", "png", "jpg", "jpeg", "gif", nullptr "jpeg", "gif", nullptr};
};
static const char *htmlExtensions[] = { static const char *htmlExtensions[] = {"htm", "html", nullptr};
"htm", "html", nullptr
};
static const char *mediaExtensions[] = { static const char *mediaExtensions[] = {
"3ga", "669", "a52", "aac", "ac3", "adt", "adts", "aif", "aifc", "3ga", "669", "a52", "aac", "ac3", "adt", "adts", "aif",
"aiff", "amb", "amr", "aob", "ape", "au", "awb", "caf", "dts", "aifc", "aiff", "amb", "amr", "aob", "ape", "au", "awb",
"flac", "it", "kar", "m4a", "m4b", "m4p", "m5p", "mid", "mka", "caf", "dts", "flac", "it", "kar", "m4a", "m4b", "m4p",
"mlp", "mod", "mpa", "mp1", "mp2", "mp3", "mpc", "mpga", "mus", "m5p", "mid", "mka", "mlp", "mod", "mpa", "mp1", "mp2",
"oga", "ogg", "oma", "opus", "qcp", "ra", "rmi", "s3m", "sid", "mp3", "mpc", "mpga", "mus", "oga", "ogg", "oma", "opus",
"spx", "tak", "thd", "tta", "voc", "vqf", "w64", "wav", "wma", "qcp", "ra", "rmi", "s3m", "sid", "spx", "tak", "thd",
"wv", "xa", "xm", "3g2", "3gp", "3gp2", "3gpp", "amv", "asf", "avi", "tta", "voc", "vqf", "w64", "wav", "wma", "wv", "xa",
"bik", "crf", "divx", "drc", "dv", "evo", "f4v", "flv", "gvi", "xm", "3g2", "3gp", "3gp2", "3gpp", "amv", "asf", "avi",
"gxf", "iso", "m1v", "m2v", "m2t", "m2ts", "m4v", "mkv", "mov", "bik", "crf", "divx", "drc", "dv", "evo", "f4v", "flv",
"mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg1", "mpeg2", "gvi", "gxf", "iso", "m1v", "m2v", "m2t", "m2ts", "m4v",
"mpeg4", "mpg", "mpv2", "mts", "mtv", "mxf", "mxg", "nsv", "nuv", "mkv", "mov", "mp2", "mp2v", "mp4", "mp4v", "mpe", "mpeg",
"ogg", "ogm", "ogv", "ogx", "ps", "rec", "rm", "rmvb", "rpl", "thp", "mpeg1", "mpeg2", "mpeg4", "mpg", "mpv2", "mts", "mtv", "mxf",
"tod", "ts", "tts", "txd", "vob", "vro", "webm", "wm", "wmv", "wtv", "mxg", "nsv", "nuv", "ogg", "ogm", "ogv", "ogx", "ps",
nullptr "rec", "rm", "rmvb", "rpl", "thp", "tod", "ts", "tts",
}; "txd", "vob", "vro", "webm", "wm", "wmv", "wtv", nullptr};
static string GenerateSourceName(const char *base) static string GenerateSourceName(const char *base)
{ {
@@ -50,7 +45,7 @@ static string GenerateSourceName(const char *base)
if (inc) { if (inc) {
name += " ("; name += " (";
name += to_string(inc+1); name += to_string(inc + 1);
name += ")"; name += ")";
} }
@@ -62,7 +57,7 @@ static string GenerateSourceName(const char *base)
void OBSBasic::AddDropSource(const char *data, DropType image) void OBSBasic::AddDropSource(const char *data, DropType image)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
obs_data_t *settings = obs_data_create(); obs_data_t *settings = obs_data_create();
obs_source_t *source = nullptr; obs_source_t *source = nullptr;
const char *type = nullptr; const char *type = nullptr;
@@ -115,8 +110,8 @@ void OBSBasic::AddDropSource(const char *data, DropType image)
if (name.isEmpty()) if (name.isEmpty())
name = obs_source_get_display_name(type); name = obs_source_get_display_name(type);
source = obs_source_create(type, source = obs_source_create(type,
GenerateSourceName(QT_TO_UTF8(name)).c_str(), GenerateSourceName(QT_TO_UTF8(name)).c_str(),
settings, nullptr); settings, nullptr);
if (source) { if (source) {
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
obs_scene_add(scene, source); obs_scene_add(scene, source);
@@ -143,7 +138,7 @@ void OBSBasic::dragMoveEvent(QDragMoveEvent *event)
void OBSBasic::dropEvent(QDropEvent *event) void OBSBasic::dropEvent(QDropEvent *event)
{ {
const QMimeData* mimeData = event->mimeData(); const QMimeData *mimeData = event->mimeData();
if (mimeData->hasUrls()) { if (mimeData->hasUrls()) {
QList<QUrl> urls = mimeData->urls(); QList<QUrl> urls = mimeData->urls();
@@ -162,20 +157,20 @@ void OBSBasic::dropEvent(QDropEvent *event)
const char **cmp; const char **cmp;
#define CHECK_SUFFIX(extensions, type) \ #define CHECK_SUFFIX(extensions, type) \
cmp = extensions; \ cmp = extensions; \
while (*cmp) { \ while (*cmp) { \
if (strcmp(*cmp, suffix) == 0) { \ if (strcmp(*cmp, suffix) == 0) { \
AddDropSource(QT_TO_UTF8(file), type); \ AddDropSource(QT_TO_UTF8(file), type); \
found = true; \ found = true; \
break; \ break; \
} \ } \
\ \
cmp++; \ cmp++; \
} \ } \
\ \
if (found) \ if (found) \
continue; continue;
CHECK_SUFFIX(textExtensions, DropType_Text); CHECK_SUFFIX(textExtensions, DropType_Text);
CHECK_SUFFIX(htmlExtensions, DropType_Html); CHECK_SUFFIX(htmlExtensions, DropType_Html);
@@ -188,4 +183,3 @@ if (found) \
AddDropSource(QT_TO_UTF8(mimeData->text()), DropType_RawText); AddDropSource(QT_TO_UTF8(mimeData->text()), DropType_RawText);
} }
} }
File diff suppressed because it is too large. Load diff
+25 -25
View File
@@ -5,49 +5,49 @@
class OBSBasic; class OBSBasic;
struct BasicOutputHandler { struct BasicOutputHandler {
OBSOutput fileOutput; OBSOutput fileOutput;
OBSOutput streamOutput; OBSOutput streamOutput;
OBSOutput replayBuffer; OBSOutput replayBuffer;
bool streamingActive = false; bool streamingActive = false;
bool recordingActive = false; bool recordingActive = false;
bool delayActive = false; bool delayActive = false;
bool replayBufferActive = false; bool replayBufferActive = false;
OBSBasic *main; OBSBasic *main;
std::string outputType; std::string outputType;
std::string lastError; std::string lastError;
OBSSignal startRecording; OBSSignal startRecording;
OBSSignal stopRecording; OBSSignal stopRecording;
OBSSignal startReplayBuffer; OBSSignal startReplayBuffer;
OBSSignal stopReplayBuffer; OBSSignal stopReplayBuffer;
OBSSignal startStreaming; OBSSignal startStreaming;
OBSSignal stopStreaming; OBSSignal stopStreaming;
OBSSignal streamDelayStarting; OBSSignal streamDelayStarting;
OBSSignal streamStopping; OBSSignal streamStopping;
OBSSignal recordStopping; OBSSignal recordStopping;
OBSSignal replayBufferStopping; OBSSignal replayBufferStopping;
inline BasicOutputHandler(OBSBasic *main_) : main(main_) {} inline BasicOutputHandler(OBSBasic *main_) : main(main_) {}
virtual ~BasicOutputHandler() {}; virtual ~BasicOutputHandler(){};
virtual bool StartStreaming(obs_service_t *service) = 0; virtual bool StartStreaming(obs_service_t *service) = 0;
virtual bool StartRecording() = 0; virtual bool StartRecording() = 0;
virtual bool StartReplayBuffer() {return false;} virtual bool StartReplayBuffer() { return false; }
virtual void StopStreaming(bool force = false) = 0; virtual void StopStreaming(bool force = false) = 0;
virtual void StopRecording(bool force = false) = 0; virtual void StopRecording(bool force = false) = 0;
virtual void StopReplayBuffer(bool force = false) {(void)force;} virtual void StopReplayBuffer(bool force = false) { (void)force; }
virtual bool StreamingActive() const = 0; virtual bool StreamingActive() const = 0;
virtual bool RecordingActive() const = 0; virtual bool RecordingActive() const = 0;
virtual bool ReplayBufferActive() const {return false;} virtual bool ReplayBufferActive() const { return false; }
virtual void Update() = 0; virtual void Update() = 0;
inline bool Active() const inline bool Active() const
{ {
return streamingActive || recordingActive || delayActive || return streamingActive || recordingActive || delayActive ||
replayBufferActive; replayBufferActive;
} }
}; };
+98 -112
View File
@@ -30,13 +30,13 @@ extern void DuplicateCurrentCookieProfile(ConfigFile &config);
extern void CheckExistingCookieId(); extern void CheckExistingCookieId();
extern void DeleteCookies(); extern void DeleteCookies();
void EnumProfiles(std::function<bool (const char *, const char *)> &&cb) void EnumProfiles(std::function<bool(const char *, const char *)> &&cb)
{ {
char path[512]; char path[512];
os_glob_t *glob; os_glob_t *glob;
int ret = GetConfigPath(path, sizeof(path), int ret = GetConfigPath(path, sizeof(path),
"obs-studio/basic/profiles/*"); "obs-studio/basic/profiles/*");
if (ret <= 0) { if (ret <= 0) {
blog(LOG_WARNING, "Failed to get profiles config path"); blog(LOG_WARNING, "Failed to get profiles config path");
return; return;
@@ -54,8 +54,7 @@ void EnumProfiles(std::function<bool (const char *, const char *)> &&cb)
if (!glob->gl_pathv[i].directory) if (!glob->gl_pathv[i].directory)
continue; continue;
if (strcmp(dirName, ".") == 0 || if (strcmp(dirName, ".") == 0 || strcmp(dirName, "..") == 0)
strcmp(dirName, "..") == 0)
continue; continue;
std::string file = filePath; std::string file = filePath;
@@ -80,8 +79,7 @@ void EnumProfiles(std::function<bool (const char *, const char *)> &&cb)
static bool ProfileExists(const char *findName) static bool ProfileExists(const char *findName)
{ {
bool found = false; bool found = false;
auto func = [&](const char *name, const char*) auto func = [&](const char *name, const char *) {
{
if (strcmp(name, findName) == 0) { if (strcmp(name, findName) == 0) {
found = true; found = true;
return false; return false;
@@ -94,28 +92,28 @@ static bool ProfileExists(const char *findName)
} }
static bool GetProfileName(QWidget *parent, std::string &name, static bool GetProfileName(QWidget *parent, std::string &name,
std::string &file, const char *title, const char *text, std::string &file, const char *title,
const char *oldName = nullptr) const char *text, const char *oldName = nullptr)
{ {
char path[512]; char path[512];
int ret; int ret;
for (;;) { for (;;) {
bool success = NameDialog::AskForName(parent, title, text, bool success = NameDialog::AskForName(parent, title, text, name,
name, QT_UTF8(oldName)); QT_UTF8(oldName));
if (!success) { if (!success) {
return false; return false;
} }
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(parent, OBSMessageBox::warning(parent,
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Text")); QTStr("NoNameEntered.Text"));
continue; continue;
} }
if (ProfileExists(name.c_str())) { if (ProfileExists(name.c_str())) {
OBSMessageBox::warning(parent, OBSMessageBox::warning(parent,
QTStr("NameExists.Title"), QTStr("NameExists.Title"),
QTStr("NameExists.Text")); QTStr("NameExists.Text"));
continue; continue;
} }
break; break;
@@ -123,7 +121,7 @@ static bool GetProfileName(QWidget *parent, std::string &name,
if (!GetFileSafeName(name.c_str(), file)) { if (!GetFileSafeName(name.c_str(), file)) {
blog(LOG_WARNING, "Failed to create safe file name for '%s'", blog(LOG_WARNING, "Failed to create safe file name for '%s'",
name.c_str()); name.c_str());
return false; return false;
} }
@@ -137,7 +135,7 @@ static bool GetProfileName(QWidget *parent, std::string &name,
if (!GetClosestUnusedFileName(file, nullptr)) { if (!GetClosestUnusedFileName(file, nullptr)) {
blog(LOG_WARNING, "Failed to get closest file name for %s", blog(LOG_WARNING, "Failed to get closest file name for %s",
file.c_str()); file.c_str());
return false; return false;
} }
@@ -170,13 +168,14 @@ static bool CopyProfile(const char *fromPartial, const char *to)
if (glob->gl_pathv[i].directory) if (glob->gl_pathv[i].directory)
continue; continue;
ret = snprintf(path, sizeof(path), "%s/%s", ret = snprintf(path, sizeof(path), "%s/%s", to,
to, strrchr(filePath, '/') + 1); strrchr(filePath, '/') + 1);
if (ret > 0) { if (ret > 0) {
if (os_copyfile(filePath, path) != 0) { if (os_copyfile(filePath, path) != 0) {
blog(LOG_WARNING, "CopyProfile: Failed to " blog(LOG_WARNING,
"copy file %s to %s", "CopyProfile: Failed to "
filePath, path); "copy file %s to %s",
filePath, path);
} }
} }
} }
@@ -187,7 +186,7 @@ static bool CopyProfile(const char *fromPartial, const char *to)
} }
bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text, bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
const char *init_text, bool rename) const char *init_text, bool rename)
{ {
std::string newName; std::string newName;
std::string newDir; std::string newDir;
@@ -197,12 +196,12 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
if (!GetProfileName(this, newName, newDir, title, text, init_text)) if (!GetProfileName(this, newName, newDir, title, text, init_text))
return false; return false;
std::string curDir = config_get_string(App()->GlobalConfig(), std::string curDir =
"Basic", "ProfileDir"); config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir");
char baseDir[512]; char baseDir[512];
int ret = GetConfigPath(baseDir, sizeof(baseDir), int ret = GetConfigPath(baseDir, sizeof(baseDir),
"obs-studio/basic/profiles/"); "obs-studio/basic/profiles/");
if (ret <= 0) { if (ret <= 0) {
blog(LOG_WARNING, "Failed to get profiles config path"); blog(LOG_WARNING, "Failed to get profiles config path");
return false; return false;
@@ -213,7 +212,7 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
if (os_mkdir(newPath.c_str()) < 0) { if (os_mkdir(newPath.c_str()) < 0) {
blog(LOG_WARNING, "Failed to create profile directory '%s'", blog(LOG_WARNING, "Failed to create profile directory '%s'",
newDir.c_str()); newDir.c_str());
return false; return false;
} }
@@ -224,14 +223,14 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
if (config.Open(newPath.c_str(), CONFIG_OPEN_ALWAYS) != 0) { if (config.Open(newPath.c_str(), CONFIG_OPEN_ALWAYS) != 0) {
blog(LOG_ERROR, "Failed to open new config file '%s'", blog(LOG_ERROR, "Failed to open new config file '%s'",
newDir.c_str()); newDir.c_str());
return false; return false;
} }
config_set_string(App()->GlobalConfig(), "Basic", "Profile", config_set_string(App()->GlobalConfig(), "Basic", "Profile",
newName.c_str()); newName.c_str());
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir",
newDir.c_str()); newDir.c_str());
Auth::Save(); Auth::Save();
if (create_new) { if (create_new) {
@@ -253,7 +252,7 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text,
ResetProfileData(); ResetProfileData();
blog(LOG_INFO, "Created profile '%s' (%s, %s)", newName.c_str(), blog(LOG_INFO, "Created profile '%s' (%s, %s)", newName.c_str(),
create_new ? "clean" : "duplicate", newDir.c_str()); create_new ? "clean" : "duplicate", newDir.c_str());
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
config_save_safe(App()->GlobalConfig(), "tmp", nullptr); config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
@@ -280,14 +279,14 @@ void OBSBasic::DeleteProfile(const char *profileName, const char *profileDir)
ret = snprintf(profilePath, 512, "%s/%s/*", basePath, profileDir); ret = snprintf(profilePath, 512, "%s/%s/*", basePath, profileDir);
if (ret <= 0) { if (ret <= 0) {
blog(LOG_WARNING, "Failed to get path for profile dir '%s'", blog(LOG_WARNING, "Failed to get path for profile dir '%s'",
profileDir); profileDir);
return; return;
} }
os_glob_t *glob; os_glob_t *glob;
if (os_glob(profilePath, 0, &glob) != 0) { if (os_glob(profilePath, 0, &glob) != 0) {
blog(LOG_WARNING, "Failed to glob profile dir '%s'", blog(LOG_WARNING, "Failed to glob profile dir '%s'",
profileDir); profileDir);
return; return;
} }
@@ -305,21 +304,20 @@ void OBSBasic::DeleteProfile(const char *profileName, const char *profileDir)
ret = snprintf(profilePath, 512, "%s/%s", basePath, profileDir); ret = snprintf(profilePath, 512, "%s/%s", basePath, profileDir);
if (ret <= 0) { if (ret <= 0) {
blog(LOG_WARNING, "Failed to get path for profile dir '%s'", blog(LOG_WARNING, "Failed to get path for profile dir '%s'",
profileDir); profileDir);
return; return;
} }
os_rmdir(profilePath); os_rmdir(profilePath);
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
blog(LOG_INFO, "Removed profile '%s' (%s)", blog(LOG_INFO, "Removed profile '%s' (%s)", profileName, profileDir);
profileName, profileDir);
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
} }
void OBSBasic::RefreshProfiles() void OBSBasic::RefreshProfiles()
{ {
QList<QAction*> menuActions = ui->profileMenu->actions(); QList<QAction *> menuActions = ui->profileMenu->actions();
int count = 0; int count = 0;
for (int i = 0; i < menuActions.count(); i++) { for (int i = 0; i < menuActions.count(); i++) {
@@ -328,17 +326,16 @@ void OBSBasic::RefreshProfiles()
delete menuActions[i]; delete menuActions[i];
} }
const char *curName = config_get_string(App()->GlobalConfig(), const char *curName =
"Basic", "Profile"); config_get_string(App()->GlobalConfig(), "Basic", "Profile");
auto addProfile = [&](const char *name, const char *path) auto addProfile = [&](const char *name, const char *path) {
{
std::string file = strrchr(path, '/') + 1; std::string file = strrchr(path, '/') + 1;
QAction *action = new QAction(QT_UTF8(name), this); QAction *action = new QAction(QT_UTF8(name), this);
action->setProperty("file_name", QT_UTF8(path)); action->setProperty("file_name", QT_UTF8(path));
connect(action, &QAction::triggered, connect(action, &QAction::triggered, this,
this, &OBSBasic::ChangeProfile); &OBSBasic::ChangeProfile);
action->setCheckable(true); action->setCheckable(true);
action->setChecked(strcmp(name, curName) == 0); action->setChecked(strcmp(name, curName) == 0);
@@ -364,15 +361,15 @@ void OBSBasic::ResetProfileData()
/* load audio monitoring */ /* load audio monitoring */
#if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO #if defined(_WIN32) || defined(__APPLE__) || HAVE_PULSEAUDIO
const char *device_name = config_get_string(basicConfig, "Audio", const char *device_name =
"MonitoringDeviceName"); config_get_string(basicConfig, "Audio", "MonitoringDeviceName");
const char *device_id = config_get_string(basicConfig, "Audio", const char *device_id =
"MonitoringDeviceId"); config_get_string(basicConfig, "Audio", "MonitoringDeviceId");
obs_set_audio_monitoring_device(device_name, device_id); obs_set_audio_monitoring_device(device_name, device_id);
blog(LOG_INFO, "Audio monitoring device:\n\tname: %s\n\tid: %s", blog(LOG_INFO, "Audio monitoring device:\n\tname: %s\n\tid: %s",
device_name, device_id); device_name, device_id);
#endif #endif
} }
@@ -388,14 +385,15 @@ void OBSBasic::on_actionDupProfile_triggered()
void OBSBasic::on_actionRenameProfile_triggered() void OBSBasic::on_actionRenameProfile_triggered()
{ {
std::string curDir = config_get_string(App()->GlobalConfig(), std::string curDir =
"Basic", "ProfileDir"); config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir");
std::string curName = config_get_string(App()->GlobalConfig(), std::string curName =
"Basic", "Profile"); config_get_string(App()->GlobalConfig(), "Basic", "Profile");
/* Duplicate and delete in case there are any issues in the process */ /* Duplicate and delete in case there are any issues in the process */
bool success = AddProfile(false, Str("RenameProfile.Title"), bool success = AddProfile(false, Str("RenameProfile.Title"),
Str("AddProfile.Text"), curName.c_str(), true); Str("AddProfile.Text"), curName.c_str(),
true);
if (success) { if (success) {
DeleteProfile(curName.c_str(), curDir.c_str()); DeleteProfile(curName.c_str(), curDir.c_str());
RefreshProfiles(); RefreshProfiles();
@@ -413,13 +411,12 @@ void OBSBasic::on_actionRemoveProfile_triggered()
std::string newPath; std::string newPath;
ConfigFile config; ConfigFile config;
std::string oldDir = config_get_string(App()->GlobalConfig(), std::string oldDir =
"Basic", "ProfileDir"); config_get_string(App()->GlobalConfig(), "Basic", "ProfileDir");
std::string oldName = config_get_string(App()->GlobalConfig(), std::string oldName =
"Basic", "Profile"); config_get_string(App()->GlobalConfig(), "Basic", "Profile");
auto cb = [&](const char *name, const char *filePath) auto cb = [&](const char *name, const char *filePath) {
{
if (strcmp(oldName.c_str(), name) != 0) { if (strcmp(oldName.c_str(), name) != 0) {
newName = name; newName = name;
newPath = filePath; newPath = filePath;
@@ -438,8 +435,8 @@ void OBSBasic::on_actionRemoveProfile_triggered()
QString text = QTStr("ConfirmRemove.Text"); QString text = QTStr("ConfirmRemove.Text");
text.replace("$1", QT_UTF8(oldName.c_str())); text.replace("$1", QT_UTF8(oldName.c_str()));
QMessageBox::StandardButton button = OBSMessageBox::question(this, QMessageBox::StandardButton button = OBSMessageBox::question(
QTStr("ConfirmRemove.Title"), text); this, QTStr("ConfirmRemove.Title"), text);
if (button == QMessageBox::No) if (button == QMessageBox::No)
return; return;
@@ -448,7 +445,7 @@ void OBSBasic::on_actionRemoveProfile_triggered()
if (config.Open(newPath.c_str(), CONFIG_OPEN_ALWAYS) != 0) { if (config.Open(newPath.c_str(), CONFIG_OPEN_ALWAYS) != 0) {
blog(LOG_ERROR, "ChangeProfile: Failed to load file '%s'", blog(LOG_ERROR, "ChangeProfile: Failed to load file '%s'",
newPath.c_str()); newPath.c_str());
return; return;
} }
@@ -457,9 +454,8 @@ void OBSBasic::on_actionRemoveProfile_triggered()
const char *newDir = strrchr(newPath.c_str(), '/') + 1; const char *newDir = strrchr(newPath.c_str(), '/') + 1;
config_set_string(App()->GlobalConfig(), "Basic", "Profile", config_set_string(App()->GlobalConfig(), "Basic", "Profile",
newName.c_str()); newName.c_str());
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", newDir);
newDir);
Auth::Save(); Auth::Save();
auth.reset(); auth.reset();
@@ -474,8 +470,8 @@ void OBSBasic::on_actionRemoveProfile_triggered()
RefreshProfiles(); RefreshProfiles();
config_save_safe(App()->GlobalConfig(), "tmp", nullptr); config_save_safe(App()->GlobalConfig(), "tmp", nullptr);
blog(LOG_INFO, "Switched to profile '%s' (%s)", blog(LOG_INFO, "Switched to profile '%s' (%s)", newName.c_str(),
newName.c_str(), newDir); newDir);
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
UpdateTitleBar(); UpdateTitleBar();
@@ -501,11 +497,8 @@ void OBSBasic::on_actionImportProfile_triggered()
} }
QString dir = QFileDialog::getExistingDirectory( QString dir = QFileDialog::getExistingDirectory(
this, this, QTStr("Basic.MainMenu.Profile.Import"), home,
QTStr("Basic.MainMenu.Profile.Import"), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
home,
QFileDialog::ShowDirsOnly |
QFileDialog::DontResolveSymlinks);
if (!dir.isEmpty() && !dir.isNull()) { if (!dir.isEmpty() && !dir.isNull()) {
QString inputPath = QString::fromUtf8(path); QString inputPath = QString::fromUtf8(path);
@@ -517,18 +510,18 @@ void OBSBasic::on_actionImportProfile_triggered()
if (!folder.exists()) { if (!folder.exists()) {
folder.mkpath(profileDir); folder.mkpath(profileDir);
QFile::copy(dir + "/basic.ini", QFile::copy(dir + "/basic.ini",
profileDir + "/basic.ini"); profileDir + "/basic.ini");
QFile::copy(dir + "/service.json", QFile::copy(dir + "/service.json",
profileDir + "/service.json"); profileDir + "/service.json");
QFile::copy(dir + "/streamEncoder.json", QFile::copy(dir + "/streamEncoder.json",
profileDir + "/streamEncoder.json"); profileDir + "/streamEncoder.json");
QFile::copy(dir + "/recordEncoder.json", QFile::copy(dir + "/recordEncoder.json",
profileDir + "/recordEncoder.json"); profileDir + "/recordEncoder.json");
RefreshProfiles(); RefreshProfiles();
} else { } else {
OBSMessageBox::warning(this, OBSMessageBox::warning(
QTStr("Basic.MainMenu.Profile.Import"), this, QTStr("Basic.MainMenu.Profile.Import"),
QTStr("Basic.MainMenu.Profile.Exists")); QTStr("Basic.MainMenu.Profile.Exists"));
} }
} }
} }
@@ -539,9 +532,8 @@ void OBSBasic::on_actionExportProfile_triggered()
QString home = QDir::homePath(); QString home = QDir::homePath();
QString currentProfile = QString currentProfile = QString::fromUtf8(config_get_string(
QString::fromUtf8(config_get_string(App()->GlobalConfig(), App()->GlobalConfig(), "Basic", "ProfileDir"));
"Basic", "ProfileDir"));
int ret = GetConfigPath(path, 512, "obs-studio/basic/profiles/"); int ret = GetConfigPath(path, 512, "obs-studio/basic/profiles/");
if (ret <= 0) { if (ret <= 0) {
@@ -550,11 +542,8 @@ void OBSBasic::on_actionExportProfile_triggered()
} }
QString dir = QFileDialog::getExistingDirectory( QString dir = QFileDialog::getExistingDirectory(
this, this, QTStr("Basic.MainMenu.Profile.Export"), home,
QTStr("Basic.MainMenu.Profile.Export"), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
home,
QFileDialog::ShowDirsOnly |
QFileDialog::DontResolveSymlinks);
if (!dir.isEmpty() && !dir.isNull()) { if (!dir.isEmpty() && !dir.isNull()) {
QString outputDir = dir + "/" + currentProfile; QString outputDir = dir + "/" + currentProfile;
@@ -571,26 +560,28 @@ void OBSBasic::on_actionExportProfile_triggered()
QFile::remove(outputDir + "/service.json"); QFile::remove(outputDir + "/service.json");
if (QFile::exists(outputDir + "/streamEncoder.json")) if (QFile::exists(outputDir + "/streamEncoder.json"))
QFile::remove(outputDir + "/streamEncoder.json"); QFile::remove(outputDir +
"/streamEncoder.json");
if (QFile::exists(outputDir + "/recordEncoder.json")) if (QFile::exists(outputDir + "/recordEncoder.json"))
QFile::remove(outputDir + "/recordEncoder.json"); QFile::remove(outputDir +
"/recordEncoder.json");
} }
QFile::copy(inputPath + currentProfile + "/basic.ini", QFile::copy(inputPath + currentProfile + "/basic.ini",
outputDir + "/basic.ini"); outputDir + "/basic.ini");
QFile::copy(inputPath + currentProfile + "/service.json", QFile::copy(inputPath + currentProfile + "/service.json",
outputDir + "/service.json"); outputDir + "/service.json");
QFile::copy(inputPath + currentProfile + "/streamEncoder.json", QFile::copy(inputPath + currentProfile + "/streamEncoder.json",
outputDir + "/streamEncoder.json"); outputDir + "/streamEncoder.json");
QFile::copy(inputPath + currentProfile + "/recordEncoder.json", QFile::copy(inputPath + currentProfile + "/recordEncoder.json",
outputDir + "/recordEncoder.json"); outputDir + "/recordEncoder.json");
} }
} }
void OBSBasic::ChangeProfile() void OBSBasic::ChangeProfile()
{ {
QAction *action = reinterpret_cast<QAction*>(sender()); QAction *action = reinterpret_cast<QAction *>(sender());
ConfigFile config; ConfigFile config;
std::string path; std::string path;
@@ -601,8 +592,8 @@ void OBSBasic::ChangeProfile()
if (path.empty()) if (path.empty())
return; return;
const char *oldName = config_get_string(App()->GlobalConfig(), const char *oldName =
"Basic", "Profile"); config_get_string(App()->GlobalConfig(), "Basic", "Profile");
if (action->text().compare(QT_UTF8(oldName)) == 0) { if (action->text().compare(QT_UTF8(oldName)) == 0) {
action->setChecked(true); action->setChecked(true);
return; return;
@@ -613,7 +604,7 @@ void OBSBasic::ChangeProfile()
if (config.Open(path.c_str(), CONFIG_OPEN_ALWAYS) != 0) { if (config.Open(path.c_str(), CONFIG_OPEN_ALWAYS) != 0) {
blog(LOG_ERROR, "ChangeProfile: Failed to load file '%s'", blog(LOG_ERROR, "ChangeProfile: Failed to load file '%s'",
path.c_str()); path.c_str());
return; return;
} }
@@ -623,8 +614,7 @@ void OBSBasic::ChangeProfile()
const char *newDir = strrchr(path.c_str(), '/') + 1; const char *newDir = strrchr(path.c_str(), '/') + 1;
config_set_string(App()->GlobalConfig(), "Basic", "Profile", newName); config_set_string(App()->GlobalConfig(), "Basic", "Profile", newName);
config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", config_set_string(App()->GlobalConfig(), "Basic", "ProfileDir", newDir);
newDir);
Auth::Save(); Auth::Save();
auth.reset(); auth.reset();
@@ -642,8 +632,7 @@ void OBSBasic::ChangeProfile()
CheckForSimpleModeX264Fallback(); CheckForSimpleModeX264Fallback();
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) if (api)
@@ -652,10 +641,10 @@ void OBSBasic::ChangeProfile()
void OBSBasic::CheckForSimpleModeX264Fallback() void OBSBasic::CheckForSimpleModeX264Fallback()
{ {
const char *curStreamEncoder = config_get_string(basicConfig, const char *curStreamEncoder =
"SimpleOutput", "StreamEncoder"); config_get_string(basicConfig, "SimpleOutput", "StreamEncoder");
const char *curRecEncoder = config_get_string(basicConfig, const char *curRecEncoder =
"SimpleOutput", "RecEncoder"); config_get_string(basicConfig, "SimpleOutput", "RecEncoder");
bool qsv_supported = false; bool qsv_supported = false;
bool amd_supported = false; bool amd_supported = false;
bool nve_supported = false; bool nve_supported = false;
@@ -672,8 +661,7 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
nve_supported = true; nve_supported = true;
} }
auto CheckEncoder = [&] (const char *&name) auto CheckEncoder = [&](const char *&name) {
{
if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) { if (strcmp(name, SIMPLE_ENCODER_QSV) == 0) {
if (!qsv_supported) { if (!qsv_supported) {
changed = true; changed = true;
@@ -698,13 +686,11 @@ void OBSBasic::CheckForSimpleModeX264Fallback()
}; };
if (!CheckEncoder(curStreamEncoder)) if (!CheckEncoder(curStreamEncoder))
config_set_string(basicConfig, config_set_string(basicConfig, "SimpleOutput", "StreamEncoder",
"SimpleOutput", "StreamEncoder", curStreamEncoder);
curStreamEncoder);
if (!CheckEncoder(curRecEncoder)) if (!CheckEncoder(curRecEncoder))
config_set_string(basicConfig, config_set_string(basicConfig, "SimpleOutput", "RecEncoder",
"SimpleOutput", "RecEncoder", curRecEncoder);
curRecEncoder);
if (changed) if (changed)
config_save_safe(basicConfig, "tmp", nullptr); config_save_safe(basicConfig, "tmp", nullptr);
} }
+73 -78
View File
@@ -28,16 +28,16 @@
using namespace std; using namespace std;
void EnumSceneCollections(std::function<bool (const char *, const char *)> &&cb) void EnumSceneCollections(std::function<bool(const char *, const char *)> &&cb)
{ {
char path[512]; char path[512];
os_glob_t *glob; os_glob_t *glob;
int ret = GetConfigPath(path, sizeof(path), int ret = GetConfigPath(path, sizeof(path),
"obs-studio/basic/scenes/*.json"); "obs-studio/basic/scenes/*.json");
if (ret <= 0) { if (ret <= 0) {
blog(LOG_WARNING, "Failed to get config path for scene " blog(LOG_WARNING, "Failed to get config path for scene "
"collections"); "collections");
return; return;
} }
@@ -52,8 +52,8 @@ void EnumSceneCollections(std::function<bool (const char *, const char *)> &&cb)
if (glob->gl_pathv[i].directory) if (glob->gl_pathv[i].directory)
continue; continue;
obs_data_t *data = obs_data_create_from_json_file_safe(filePath, obs_data_t *data =
"bak"); obs_data_create_from_json_file_safe(filePath, "bak");
std::string name = obs_data_get_string(data, "name"); std::string name = obs_data_get_string(data, "name");
/* if no name found, use the file name as the name /* if no name found, use the file name as the name
@@ -75,8 +75,7 @@ void EnumSceneCollections(std::function<bool (const char *, const char *)> &&cb)
static bool SceneCollectionExists(const char *findName) static bool SceneCollectionExists(const char *findName)
{ {
bool found = false; bool found = false;
auto func = [&](const char *name, const char*) auto func = [&](const char *name, const char *) {
{
if (strcmp(name, findName) == 0) { if (strcmp(name, findName) == 0) {
found = true; found = true;
return false; return false;
@@ -90,7 +89,8 @@ static bool SceneCollectionExists(const char *findName)
} }
static bool GetSceneCollectionName(QWidget *parent, std::string &name, static bool GetSceneCollectionName(QWidget *parent, std::string &name,
std::string &file, const char *oldName = nullptr) std::string &file,
const char *oldName = nullptr)
{ {
bool rename = oldName != nullptr; bool rename = oldName != nullptr;
const char *title; const char *title;
@@ -101,28 +101,28 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
if (rename) { if (rename) {
title = Str("Basic.Main.RenameSceneCollection.Title"); title = Str("Basic.Main.RenameSceneCollection.Title");
text = Str("Basic.Main.AddSceneCollection.Text"); text = Str("Basic.Main.AddSceneCollection.Text");
} else { } else {
title = Str("Basic.Main.AddSceneCollection.Title"); title = Str("Basic.Main.AddSceneCollection.Title");
text = Str("Basic.Main.AddSceneCollection.Text"); text = Str("Basic.Main.AddSceneCollection.Text");
} }
for (;;) { for (;;) {
bool success = NameDialog::AskForName(parent, title, text, bool success = NameDialog::AskForName(parent, title, text, name,
name, QT_UTF8(oldName)); QT_UTF8(oldName));
if (!success) { if (!success) {
return false; return false;
} }
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(parent, OBSMessageBox::warning(parent,
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Text")); QTStr("NoNameEntered.Text"));
continue; continue;
} }
if (SceneCollectionExists(name.c_str())) { if (SceneCollectionExists(name.c_str())) {
OBSMessageBox::warning(parent, OBSMessageBox::warning(parent,
QTStr("NameExists.Title"), QTStr("NameExists.Title"),
QTStr("NameExists.Text")); QTStr("NameExists.Text"));
continue; continue;
} }
break; break;
@@ -130,7 +130,7 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
if (!GetFileSafeName(name.c_str(), file)) { if (!GetFileSafeName(name.c_str(), file)) {
blog(LOG_WARNING, "Failed to create safe file name for '%s'", blog(LOG_WARNING, "Failed to create safe file name for '%s'",
name.c_str()); name.c_str());
return false; return false;
} }
@@ -145,7 +145,7 @@ static bool GetSceneCollectionName(QWidget *parent, std::string &name,
if (!GetClosestUnusedFileName(file, "json")) { if (!GetClosestUnusedFileName(file, "json")) {
blog(LOG_WARNING, "Failed to get closest file name for %s", blog(LOG_WARNING, "Failed to get closest file name for %s",
file.c_str()); file.c_str());
return false; return false;
} }
@@ -171,9 +171,9 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
SaveProjectNow(); SaveProjectNow();
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollection", config_set_string(App()->GlobalConfig(), "Basic", "SceneCollection",
name.c_str()); name.c_str());
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollectionFile", config_set_string(App()->GlobalConfig(), "Basic", "SceneCollectionFile",
file.c_str()); file.c_str());
if (create_new) { if (create_new) {
CreateDefaultScene(false); CreateDefaultScene(false);
} }
@@ -181,8 +181,7 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
RefreshSceneCollections(); RefreshSceneCollections();
blog(LOG_INFO, "Added scene collection '%s' (%s, %s.json)", blog(LOG_INFO, "Added scene collection '%s' (%s, %s.json)",
name.c_str(), create_new ? "clean" : "duplicate", name.c_str(), create_new ? "clean" : "duplicate", file.c_str());
file.c_str());
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
UpdateTitleBar(); UpdateTitleBar();
@@ -197,7 +196,7 @@ bool OBSBasic::AddSceneCollection(bool create_new, const QString &qname)
void OBSBasic::RefreshSceneCollections() void OBSBasic::RefreshSceneCollections()
{ {
QList<QAction*> menuActions = ui->sceneCollectionMenu->actions(); QList<QAction *> menuActions = ui->sceneCollectionMenu->actions();
int count = 0; int count = 0;
for (int i = 0; i < menuActions.count(); i++) { for (int i = 0; i < menuActions.count(); i++) {
@@ -206,18 +205,17 @@ void OBSBasic::RefreshSceneCollections()
delete menuActions[i]; delete menuActions[i];
} }
const char *cur_name = config_get_string(App()->GlobalConfig(), const char *cur_name = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollection"); "SceneCollection");
auto addCollection = [&](const char *name, const char *path) auto addCollection = [&](const char *name, const char *path) {
{
std::string file = strrchr(path, '/') + 1; std::string file = strrchr(path, '/') + 1;
file.erase(file.size() - 5, 5); file.erase(file.size() - 5, 5);
QAction *action = new QAction(QT_UTF8(name), this); QAction *action = new QAction(QT_UTF8(name), this);
action->setProperty("file_name", QT_UTF8(path)); action->setProperty("file_name", QT_UTF8(path));
connect(action, &QAction::triggered, connect(action, &QAction::triggered, this,
this, &OBSBasic::ChangeSceneCollection); &OBSBasic::ChangeSceneCollection);
action->setCheckable(true); action->setCheckable(true);
action->setChecked(strcmp(name, cur_name) == 0); action->setChecked(strcmp(name, cur_name) == 0);
@@ -243,7 +241,7 @@ void OBSBasic::RefreshSceneCollections()
ui->actionRemoveSceneCollection->setEnabled(count > 1); ui->actionRemoveSceneCollection->setEnabled(count > 1);
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
main->ui->actionPasteFilters->setEnabled(false); main->ui->actionPasteFilters->setEnabled(false);
main->ui->actionPasteRef->setEnabled(false); main->ui->actionPasteRef->setEnabled(false);
@@ -265,19 +263,19 @@ void OBSBasic::on_actionRenameSceneCollection_triggered()
std::string name; std::string name;
std::string file; std::string file;
std::string oldFile = config_get_string(App()->GlobalConfig(), std::string oldFile = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollectionFile"); "SceneCollectionFile");
const char *oldName = config_get_string(App()->GlobalConfig(), const char *oldName = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollection"); "SceneCollection");
bool success = GetSceneCollectionName(this, name, file, oldName); bool success = GetSceneCollectionName(this, name, file, oldName);
if (!success) if (!success)
return; return;
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollection", config_set_string(App()->GlobalConfig(), "Basic", "SceneCollection",
name.c_str()); name.c_str());
config_set_string(App()->GlobalConfig(), "Basic", "SceneCollectionFile", config_set_string(App()->GlobalConfig(), "Basic", "SceneCollectionFile",
file.c_str()); file.c_str());
SaveProjectNow(); SaveProjectNow();
char path[512]; char path[512];
@@ -295,7 +293,7 @@ void OBSBasic::on_actionRenameSceneCollection_triggered()
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
blog(LOG_INFO, "Renamed scene collection to '%s' (%s.json)", blog(LOG_INFO, "Renamed scene collection to '%s' (%s.json)",
name.c_str(), file.c_str()); name.c_str(), file.c_str());
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
UpdateTitleBar(); UpdateTitleBar();
@@ -312,13 +310,12 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
std::string newName; std::string newName;
std::string newPath; std::string newPath;
std::string oldFile = config_get_string(App()->GlobalConfig(), std::string oldFile = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollectionFile"); "SceneCollectionFile");
std::string oldName = config_get_string(App()->GlobalConfig(), std::string oldName = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollection"); "SceneCollection");
auto cb = [&](const char *name, const char *filePath) auto cb = [&](const char *name, const char *filePath) {
{
if (strcmp(oldName.c_str(), name) != 0) { if (strcmp(oldName.c_str(), name) != 0) {
newName = name; newName = name;
newPath = filePath; newPath = filePath;
@@ -337,8 +334,8 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
QString text = QTStr("ConfirmRemove.Text"); QString text = QTStr("ConfirmRemove.Text");
text.replace("$1", QT_UTF8(oldName.c_str())); text.replace("$1", QT_UTF8(oldName.c_str()));
QMessageBox::StandardButton button = OBSMessageBox::question(this, QMessageBox::StandardButton button = OBSMessageBox::question(
QTStr("ConfirmRemove.Title"), text); this, QTStr("ConfirmRemove.Title"), text);
if (button == QMessageBox::No) if (button == QMessageBox::No)
return; return;
@@ -358,13 +355,13 @@ void OBSBasic::on_actionRemoveSceneCollection_triggered()
Load(newPath.c_str()); Load(newPath.c_str());
RefreshSceneCollections(); RefreshSceneCollections();
const char *newFile = config_get_string(App()->GlobalConfig(), const char *newFile = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollectionFile"); "SceneCollectionFile");
blog(LOG_INFO, "Removed scene collection '%s' (%s.json), " blog(LOG_INFO,
"switched to '%s' (%s.json)", "Removed scene collection '%s' (%s.json), "
oldName.c_str(), oldFile.c_str(), "switched to '%s' (%s.json)",
newName.c_str(), newFile); oldName.c_str(), oldFile.c_str(), newName.c_str(), newFile);
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
UpdateTitleBar(); UpdateTitleBar();
@@ -388,10 +385,8 @@ void OBSBasic::on_actionImportSceneCollection_triggered()
} }
QString qfilePath = QFileDialog::getOpenFileName( QString qfilePath = QFileDialog::getOpenFileName(
this, this, QTStr("Basic.MainMenu.SceneCollection.Import"), qhome,
QTStr("Basic.MainMenu.SceneCollection.Import"), "JSON Files (*.json)");
qhome,
"JSON Files (*.json)");
QFileInfo finfo(qfilePath); QFileInfo finfo(qfilePath);
QString qfilename = finfo.fileName(); QString qfilename = finfo.fileName();
@@ -416,23 +411,25 @@ void OBSBasic::on_actionImportSceneCollection_triggered()
obs_data_set_string(scenedata, "name", name.c_str()); obs_data_set_string(scenedata, "name", name.c_str());
if (!GetFileSafeName(name.c_str(), file)) { if (!GetFileSafeName(name.c_str(), file)) {
blog(LOG_WARNING, "Failed to create " blog(LOG_WARNING,
"safe file name for '%s'", "Failed to create "
name.c_str()); "safe file name for '%s'",
name.c_str());
return; return;
} }
string filePath = path + file; string filePath = path + file;
if (!GetClosestUnusedFileName(filePath, "json")) { if (!GetClosestUnusedFileName(filePath, "json")) {
blog(LOG_WARNING, "Failed to get " blog(LOG_WARNING,
"closest file name for %s", "Failed to get "
file.c_str()); "closest file name for %s",
file.c_str());
return; return;
} }
obs_data_save_json_safe(scenedata, filePath.c_str(), obs_data_save_json_safe(scenedata, filePath.c_str(), "tmp",
"tmp", "bak"); "bak");
RefreshSceneCollections(); RefreshSceneCollections();
} }
} }
@@ -445,8 +442,8 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
QString home = QDir::homePath(); QString home = QDir::homePath();
QString currentFile = QT_UTF8(config_get_string(App()->GlobalConfig(), QString currentFile = QT_UTF8(config_get_string(
"Basic", "SceneCollectionFile")); App()->GlobalConfig(), "Basic", "SceneCollectionFile"));
int ret = GetConfigPath(path, 512, "obs-studio/basic/scenes/"); int ret = GetConfigPath(path, 512, "obs-studio/basic/scenes/");
if (ret <= 0) { if (ret <= 0) {
@@ -455,10 +452,8 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
} }
QString exportFile = QFileDialog::getSaveFileName( QString exportFile = QFileDialog::getSaveFileName(
this, this, QTStr("Basic.MainMenu.SceneCollection.Export"),
QTStr("Basic.MainMenu.SceneCollection.Export"), home + "/" + currentFile, "JSON Files (*.json)");
home + "/" + currentFile,
"JSON Files (*.json)");
string file = QT_TO_UTF8(exportFile); string file = QT_TO_UTF8(exportFile);
@@ -472,7 +467,7 @@ void OBSBasic::on_actionExportSceneCollection_triggered()
void OBSBasic::ChangeSceneCollection() void OBSBasic::ChangeSceneCollection()
{ {
QAction *action = reinterpret_cast<QAction*>(sender()); QAction *action = reinterpret_cast<QAction *>(sender());
std::string fileName; std::string fileName;
if (!action) if (!action)
@@ -482,8 +477,8 @@ void OBSBasic::ChangeSceneCollection()
if (fileName.empty()) if (fileName.empty())
return; return;
const char *oldName = config_get_string(App()->GlobalConfig(), const char *oldName = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollection"); "SceneCollection");
if (action->text().compare(QT_UTF8(oldName)) == 0) { if (action->text().compare(QT_UTF8(oldName)) == 0) {
action->setChecked(true); action->setChecked(true);
return; return;
@@ -494,13 +489,13 @@ void OBSBasic::ChangeSceneCollection()
Load(fileName.c_str()); Load(fileName.c_str());
RefreshSceneCollections(); RefreshSceneCollections();
const char *newName = config_get_string(App()->GlobalConfig(), const char *newName = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollection"); "SceneCollection");
const char *newFile = config_get_string(App()->GlobalConfig(), const char *newFile = config_get_string(App()->GlobalConfig(), "Basic",
"Basic", "SceneCollectionFile"); "SceneCollectionFile");
blog(LOG_INFO, "Switched to scene collection '%s' (%s.json)", blog(LOG_INFO, "Switched to scene collection '%s' (%s.json)", newName,
newName, newFile); newFile);
blog(LOG_INFO, "------------------------------------------------"); blog(LOG_INFO, "------------------------------------------------");
UpdateTitleBar(); UpdateTitleBar();
+155 -151
View File
@@ -54,8 +54,8 @@ void OBSBasic::InitDefaultTransitions()
if (!obs_is_source_configurable(id)) { if (!obs_is_source_configurable(id)) {
const char *name = obs_source_get_display_name(id); const char *name = obs_source_get_display_name(id);
obs_source_t *tr = obs_source_create_private( obs_source_t *tr =
id, name, NULL); obs_source_create_private(id, name, NULL);
InitTransition(tr); InitTransition(tr);
transitions.emplace_back(tr); transitions.emplace_back(tr);
@@ -68,7 +68,7 @@ void OBSBasic::InitDefaultTransitions()
for (OBSSource &tr : transitions) { for (OBSSource &tr : transitions) {
ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)), ui->transitions->addItem(QT_UTF8(obs_source_get_name(tr)),
QVariant::fromValue(OBSSource(tr))); QVariant::fromValue(OBSSource(tr)));
} }
} }
@@ -79,33 +79,33 @@ void OBSBasic::AddQuickTransitionHotkey(QuickTransition *qt)
dstr_printf(hotkeyId, "OBSBasic.QuickTransition.%d", qt->id); dstr_printf(hotkeyId, "OBSBasic.QuickTransition.%d", qt->id);
hotkeyName = QTStr("QuickTransitions.HotkeyName") hotkeyName = QTStr("QuickTransitions.HotkeyName")
.arg(MakeQuickTransitionText(qt)); .arg(MakeQuickTransitionText(qt));
auto quickTransition = [] (void *data, obs_hotkey_id, obs_hotkey_t*, auto quickTransition = [](void *data, obs_hotkey_id, obs_hotkey_t *,
bool pressed) bool pressed) {
{
int id = (int)(uintptr_t)data; int id = (int)(uintptr_t)data;
OBSBasic *main = OBSBasic *main =
reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
if (pressed) if (pressed)
QMetaObject::invokeMethod(main, QMetaObject::invokeMethod(main,
"TriggerQuickTransition", "TriggerQuickTransition",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(int, id)); Q_ARG(int, id));
}; };
qt->hotkey = obs_hotkey_register_frontend(hotkeyId->array, qt->hotkey = obs_hotkey_register_frontend(hotkeyId->array,
QT_TO_UTF8(hotkeyName), quickTransition, QT_TO_UTF8(hotkeyName),
(void*)(uintptr_t)qt->id); quickTransition,
(void *)(uintptr_t)qt->id);
} }
void QuickTransition::SourceRenamed(void *param, calldata_t *data) void QuickTransition::SourceRenamed(void *param, calldata_t *data)
{ {
QuickTransition *qt = reinterpret_cast<QuickTransition*>(param); QuickTransition *qt = reinterpret_cast<QuickTransition *>(param);
QString hotkeyName = QTStr("QuickTransitions.HotkeyName") QString hotkeyName = QTStr("QuickTransitions.HotkeyName")
.arg(MakeQuickTransitionText(qt)); .arg(MakeQuickTransitionText(qt));
obs_hotkey_set_description(qt->hotkey, QT_TO_UTF8(hotkeyName)); obs_hotkey_set_description(qt->hotkey, QT_TO_UTF8(hotkeyName));
@@ -135,23 +135,23 @@ void OBSBasic::RemoveQuickTransitionHotkey(QuickTransition *qt)
void OBSBasic::InitTransition(obs_source_t *transition) void OBSBasic::InitTransition(obs_source_t *transition)
{ {
auto onTransitionStop = [] (void *data, calldata_t*) { auto onTransitionStop = [](void *data, calldata_t *) {
OBSBasic *window = (OBSBasic*)data; OBSBasic *window = (OBSBasic *)data;
QMetaObject::invokeMethod(window, "TransitionStopped", QMetaObject::invokeMethod(window, "TransitionStopped",
Qt::QueuedConnection); Qt::QueuedConnection);
}; };
auto onTransitionFullStop = [] (void *data, calldata_t*) { auto onTransitionFullStop = [](void *data, calldata_t *) {
OBSBasic *window = (OBSBasic*)data; OBSBasic *window = (OBSBasic *)data;
QMetaObject::invokeMethod(window, "TransitionFullyStopped", QMetaObject::invokeMethod(window, "TransitionFullyStopped",
Qt::QueuedConnection); Qt::QueuedConnection);
}; };
signal_handler_t *handler = obs_source_get_signal_handler(transition); signal_handler_t *handler = obs_source_get_signal_handler(transition);
signal_handler_connect(handler, "transition_video_stop", signal_handler_connect(handler, "transition_video_stop",
onTransitionStop, this); onTransitionStop, this);
signal_handler_connect(handler, "transition_stop", signal_handler_connect(handler, "transition_stop", onTransitionFullStop,
onTransitionFullStop, this); this);
} }
static inline OBSSource GetTransitionComboItem(QComboBox *combo, int idx) static inline OBSSource GetTransitionComboItem(QComboBox *combo, int idx)
@@ -163,12 +163,12 @@ void OBSBasic::CreateDefaultQuickTransitions()
{ {
/* non-configurable transitions are always available, so add them /* non-configurable transitions are always available, so add them
* to the "default quick transitions" list */ * to the "default quick transitions" list */
quickTransitions.emplace_back( quickTransitions.emplace_back(GetTransitionComboItem(ui->transitions,
GetTransitionComboItem(ui->transitions, 0), 0),
300, quickTransitionIdCounter++); 300, quickTransitionIdCounter++);
quickTransitions.emplace_back( quickTransitions.emplace_back(GetTransitionComboItem(ui->transitions,
GetTransitionComboItem(ui->transitions, 1), 1),
300, quickTransitionIdCounter++); 300, quickTransitionIdCounter++);
} }
void OBSBasic::LoadQuickTransitions(obs_data_array_t *array) void OBSBasic::LoadQuickTransitions(obs_data_array_t *array)
@@ -188,13 +188,14 @@ void OBSBasic::LoadQuickTransitions(obs_data_array_t *array)
obs_source_t *source = FindTransition(name); obs_source_t *source = FindTransition(name);
if (source) { if (source) {
quickTransitions.emplace_back(source, duration, quickTransitions.emplace_back(source, duration,
id); id);
if (quickTransitionIdCounter <= id) if (quickTransitionIdCounter <= id)
quickTransitionIdCounter = id + 1; quickTransitionIdCounter = id + 1;
int idx = (int)quickTransitions.size() - 1; int idx = (int)quickTransitions.size() - 1;
AddQuickTransitionHotkey(&quickTransitions[idx]); AddQuickTransitionHotkey(
&quickTransitions[idx]);
obs_hotkey_load(quickTransitions[idx].hotkey, obs_hotkey_load(quickTransitions[idx].hotkey,
hotkeys); hotkeys);
} }
@@ -214,7 +215,7 @@ obs_data_array_t *OBSBasic::SaveQuickTransitions()
obs_data_array_t *hotkeys = obs_hotkey_save(qt.hotkey); obs_data_array_t *hotkeys = obs_hotkey_save(qt.hotkey);
obs_data_set_string(data, "name", obs_data_set_string(data, "name",
obs_source_get_name(qt.source)); obs_source_get_name(qt.source));
obs_data_set_int(data, "duration", qt.duration); obs_data_set_int(data, "duration", qt.duration);
obs_data_set_array(data, "hotkeys", hotkeys); obs_data_set_array(data, "hotkeys", hotkeys);
obs_data_set_int(data, "id", qt.id); obs_data_set_int(data, "id", qt.id);
@@ -231,8 +232,7 @@ obs_data_array_t *OBSBasic::SaveQuickTransitions()
obs_source_t *OBSBasic::FindTransition(const char *name) obs_source_t *OBSBasic::FindTransition(const char *name)
{ {
for (int i = 0; i < ui->transitions->count(); i++) { for (int i = 0; i < ui->transitions->count(); i++) {
OBSSource tr = ui->transitions->itemData(i) OBSSource tr = ui->transitions->itemData(i).value<OBSSource>();
.value<OBSSource>();
const char *trName = obs_source_get_name(tr); const char *trName = obs_source_get_name(tr);
if (strcmp(trName, name) == 0) if (strcmp(trName, name) == 0)
@@ -292,7 +292,7 @@ void OBSBasic::TransitionFullyStopped()
} }
void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct, void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
bool quickTransition) bool quickTransition)
{ {
obs_scene_t *scene = obs_scene_from_source(source); obs_scene_t *scene = obs_scene_from_source(source);
bool usingPreviewProgram = IsPreviewProgramMode(); bool usingPreviewProgram = IsPreviewProgramMode();
@@ -317,10 +317,10 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
} }
if (usingPreviewProgram && sceneDuplicationMode) { if (usingPreviewProgram && sceneDuplicationMode) {
scene = obs_scene_duplicate(scene, NULL, scene = obs_scene_duplicate(
editPropertiesMode ? scene, NULL,
OBS_SCENE_DUP_PRIVATE_COPY : editPropertiesMode ? OBS_SCENE_DUP_PRIVATE_COPY
OBS_SCENE_DUP_PRIVATE_REFS); : OBS_SCENE_DUP_PRIVATE_REFS);
source = obs_scene_get_source(scene); source = obs_scene_get_source(scene);
} }
@@ -342,8 +342,8 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
OBSData data = obs_source_get_private_settings(source); OBSData data = obs_source_get_private_settings(source);
obs_data_release(data); obs_data_release(data);
const char *trOverrideName = obs_data_get_string(data, const char *trOverrideName =
"transition"); obs_data_get_string(data, "transition");
int duration = ui->transitionDuration->value(); int duration = ui->transitionDuration->value();
if (trOverrideName && *trOverrideName && !quickTransition) { if (trOverrideName && *trOverrideName && !quickTransition) {
@@ -351,18 +351,18 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force, bool direct,
if (trOverride) { if (trOverride) {
transition = trOverride; transition = trOverride;
obs_data_set_default_int(data, obs_data_set_default_int(
"transition_duration", 300); data, "transition_duration", 300);
duration = (int)obs_data_get_int(data, duration = (int)obs_data_get_int(
"transition_duration"); data, "transition_duration");
OverrideTransition(trOverride); OverrideTransition(trOverride);
overridingTransition = true; overridingTransition = true;
} }
} }
bool success = obs_transition_start(transition, bool success = obs_transition_start(
OBS_TRANSITION_MODE_AUTO, duration, source); transition, OBS_TRANSITION_MODE_AUTO, duration, source);
if (!success) if (!success)
TransitionFullyStopped(); TransitionFullyStopped();
} }
@@ -432,12 +432,12 @@ void OBSBasic::on_transitions_currentIndexChanged(int)
void OBSBasic::AddTransition() void OBSBasic::AddTransition()
{ {
QAction *action = reinterpret_cast<QAction*>(sender()); QAction *action = reinterpret_cast<QAction *>(sender());
QString idStr = action->property("id").toString(); QString idStr = action->property("id").toString();
string name; string name;
QString placeHolderText = QT_UTF8( QString placeHolderText =
obs_source_get_display_name(QT_TO_UTF8(idStr))); QT_UTF8(obs_source_get_display_name(QT_TO_UTF8(idStr)));
QString format = placeHolderText + " (%1)"; QString format = placeHolderText + " (%1)";
obs_source_t *source = nullptr; obs_source_t *source = nullptr;
int i = 1; int i = 1;
@@ -447,40 +447,41 @@ void OBSBasic::AddTransition()
} }
bool accepted = NameDialog::AskForName(this, bool accepted = NameDialog::AskForName(this,
QTStr("TransitionNameDlg.Title"), QTStr("TransitionNameDlg.Title"),
QTStr("TransitionNameDlg.Text"), QTStr("TransitionNameDlg.Text"),
name, placeHolderText); name, placeHolderText);
if (accepted) { if (accepted) {
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(this, OBSMessageBox::warning(this,
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Text")); QTStr("NoNameEntered.Text"));
AddTransition(); AddTransition();
return; return;
} }
source = FindTransition(name.c_str()); source = FindTransition(name.c_str());
if (source) { if (source) {
OBSMessageBox::warning(this, OBSMessageBox::warning(this, QTStr("NameExists.Title"),
QTStr("NameExists.Title"), QTStr("NameExists.Text"));
QTStr("NameExists.Text"));
AddTransition(); AddTransition();
return; return;
} }
source = obs_source_create_private(QT_TO_UTF8(idStr), source = obs_source_create_private(QT_TO_UTF8(idStr),
name.c_str(), NULL); name.c_str(), NULL);
InitTransition(source); InitTransition(source);
ui->transitions->addItem(QT_UTF8(name.c_str()), ui->transitions->addItem(
QVariant::fromValue(OBSSource(source))); QT_UTF8(name.c_str()),
QVariant::fromValue(OBSSource(source)));
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) if (api)
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); api->on_event(
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
ClearQuickTransitionWidgets(); ClearQuickTransitionWidgets();
RefreshQuickTransitions(); RefreshQuickTransitions();
@@ -500,8 +501,8 @@ void OBSBasic::on_transitionAdd_clicked()
QAction *action = new QAction(name, this); QAction *action = new QAction(name, this);
action->setProperty("id", id); action->setProperty("id", id);
connect(action, SIGNAL(triggered()), connect(action, SIGNAL(triggered()), this,
this, SLOT(AddTransition())); SLOT(AddTransition()));
menu.addAction(action); menu.addAction(action);
foundConfigurableTransitions = true; foundConfigurableTransitions = true;
@@ -529,7 +530,8 @@ void OBSBasic::on_transitionRemove_clicked()
if (qt.button) if (qt.button)
qt.button->deleteLater(); qt.button->deleteLater();
RemoveQuickTransitionHotkey(&qt); RemoveQuickTransitionHotkey(&qt);
quickTransitions.erase(quickTransitions.begin() + i - 1); quickTransitions.erase(quickTransitions.begin() + i -
1);
} }
} }
@@ -544,7 +546,7 @@ void OBSBasic::on_transitionRemove_clicked()
void OBSBasic::RenameTransition() void OBSBasic::RenameTransition()
{ {
QAction *action = reinterpret_cast<QAction*>(sender()); QAction *action = reinterpret_cast<QAction *>(sender());
QVariant variant = action->property("transition"); QVariant variant = action->property("transition");
obs_source_t *transition = variant.value<OBSSource>(); obs_source_t *transition = variant.value<OBSSource>();
@@ -553,24 +555,23 @@ void OBSBasic::RenameTransition()
obs_source_t *source = nullptr; obs_source_t *source = nullptr;
bool accepted = NameDialog::AskForName(this, bool accepted = NameDialog::AskForName(this,
QTStr("TransitionNameDlg.Title"), QTStr("TransitionNameDlg.Title"),
QTStr("TransitionNameDlg.Text"), QTStr("TransitionNameDlg.Text"),
name, placeHolderText); name, placeHolderText);
if (accepted) { if (accepted) {
if (name.empty()) { if (name.empty()) {
OBSMessageBox::warning(this, OBSMessageBox::warning(this,
QTStr("NoNameEntered.Title"), QTStr("NoNameEntered.Title"),
QTStr("NoNameEntered.Text")); QTStr("NoNameEntered.Text"));
RenameTransition(); RenameTransition();
return; return;
} }
source = FindTransition(name.c_str()); source = FindTransition(name.c_str());
if (source) { if (source) {
OBSMessageBox::warning(this, OBSMessageBox::warning(this, QTStr("NameExists.Title"),
QTStr("NameExists.Title"), QTStr("NameExists.Text"));
QTStr("NameExists.Text"));
RenameTransition(); RenameTransition();
return; return;
@@ -579,10 +580,12 @@ void OBSBasic::RenameTransition()
obs_source_set_name(transition, name.c_str()); obs_source_set_name(transition, name.c_str());
int idx = ui->transitions->findData(variant); int idx = ui->transitions->findData(variant);
if (idx != -1) { if (idx != -1) {
ui->transitions->setItemText(idx, QT_UTF8(name.c_str())); ui->transitions->setItemText(idx,
QT_UTF8(name.c_str()));
if (api) if (api)
api->on_event(OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED); api->on_event(
OBS_FRONTEND_EVENT_TRANSITION_LIST_CHANGED);
ClearQuickTransitionWidgets(); ClearQuickTransitionWidgets();
RefreshQuickTransitions(); RefreshQuickTransitions();
@@ -597,9 +600,7 @@ void OBSBasic::on_transitionProps_clicked()
if (!obs_source_configurable(source)) if (!obs_source_configurable(source))
return; return;
auto properties = [&] () { auto properties = [&]() { CreatePropertiesWindow(source); };
CreatePropertiesWindow(source);
};
QMenu menu(this); QMenu menu(this);
@@ -643,8 +644,7 @@ void OBSBasic::SetCurrentScene(obs_scene_t *scene, bool force, bool direct)
SetCurrentScene(source, force, direct); SetCurrentScene(source, force, direct);
} }
template <typename T> template<typename T> static T GetOBSRef(QListWidgetItem *item)
static T GetOBSRef(QListWidgetItem *item)
{ {
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>(); return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
} }
@@ -679,7 +679,8 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force, bool direct)
ui->scenes->setCurrentItem(item); ui->scenes->setCurrentItem(item);
ui->scenes->blockSignals(false); ui->scenes->blockSignals(false);
if (api) if (api)
api->on_event(OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED); api->on_event(
OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED);
break; break;
} }
} }
@@ -689,8 +690,8 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force, bool direct)
bool userSwitched = (!force && !disableSaving); bool userSwitched = (!force && !disableSaving);
blog(LOG_INFO, "%s to scene '%s'", blog(LOG_INFO, "%s to scene '%s'",
userSwitched ? "User switched" : "Switched", userSwitched ? "User switched" : "Switched",
obs_source_get_name(scene)); obs_source_get_name(scene));
} }
void OBSBasic::CreateProgramDisplay() void OBSBasic::CreateProgramDisplay()
@@ -698,8 +699,8 @@ void OBSBasic::CreateProgramDisplay()
program = new OBSQTDisplay(); program = new OBSQTDisplay();
program->setContextMenuPolicy(Qt::CustomContextMenu); program->setContextMenuPolicy(Qt::CustomContextMenu);
connect(program.data(), &QWidget::customContextMenuRequested, connect(program.data(), &QWidget::customContextMenuRequested, this,
this, &OBSBasic::on_program_customContextMenuRequested); &OBSBasic::on_program_customContextMenuRequested);
auto displayResize = [this]() { auto displayResize = [this]() {
struct obs_video_info ovi; struct obs_video_info ovi;
@@ -708,13 +709,11 @@ void OBSBasic::CreateProgramDisplay()
ResizeProgram(ovi.base_width, ovi.base_height); ResizeProgram(ovi.base_width, ovi.base_height);
}; };
connect(program.data(), &OBSQTDisplay::DisplayResized, connect(program.data(), &OBSQTDisplay::DisplayResized, displayResize);
displayResize);
auto addDisplay = [this] (OBSQTDisplay *window) auto addDisplay = [this](OBSQTDisplay *window) {
{
obs_display_add_draw_callback(window->GetDisplay(), obs_display_add_draw_callback(window->GetDisplay(),
OBSBasic::RenderProgram, this); OBSBasic::RenderProgram, this);
struct obs_video_info ovi; struct obs_video_info ovi;
if (obs_get_video_info(&ovi)) if (obs_get_video_info(&ovi))
@@ -723,8 +722,7 @@ void OBSBasic::CreateProgramDisplay()
connect(program.data(), &OBSQTDisplay::DisplayCreated, addDisplay); connect(program.data(), &OBSQTDisplay::DisplayCreated, addDisplay);
program->setSizePolicy(QSizePolicy::Expanding, program->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QSizePolicy::Expanding);
} }
void OBSBasic::TransitionClicked() void OBSBasic::TransitionClicked()
@@ -771,16 +769,16 @@ void OBSBasic::CreateProgramOptions()
programOptions->setLayout(layout); programOptions->setLayout(layout);
auto onAdd = [this] () { auto onAdd = [this]() {
QScopedPointer<QMenu> menu(CreateTransitionMenu(this, nullptr)); QScopedPointer<QMenu> menu(CreateTransitionMenu(this, nullptr));
menu->exec(QCursor::pos()); menu->exec(QCursor::pos());
}; };
auto onConfig = [this] () { auto onConfig = [this]() {
QMenu menu(this); QMenu menu(this);
QAction *action; QAction *action;
auto toggleEditProperties = [this] () { auto toggleEditProperties = [this]() {
editPropertiesMode = !editPropertiesMode; editPropertiesMode = !editPropertiesMode;
OBSSource actualScene = OBSGetStrongRef(programScene); OBSSource actualScene = OBSGetStrongRef(programScene);
@@ -788,11 +786,11 @@ void OBSBasic::CreateProgramOptions()
TransitionToScene(actualScene, true); TransitionToScene(actualScene, true);
}; };
auto toggleSwapScenesMode = [this] () { auto toggleSwapScenesMode = [this]() {
swapScenesMode = !swapScenesMode; swapScenesMode = !swapScenesMode;
}; };
auto toggleSceneDuplication = [this] () { auto toggleSceneDuplication = [this]() {
sceneDuplicationMode = !sceneDuplicationMode; sceneDuplicationMode = !sceneDuplicationMode;
OBSSource actualScene = OBSGetStrongRef(programScene); OBSSource actualScene = OBSGetStrongRef(programScene);
@@ -800,20 +798,22 @@ void OBSBasic::CreateProgramOptions()
TransitionToScene(actualScene, true); TransitionToScene(actualScene, true);
}; };
auto showToolTip = [&] () { auto showToolTip = [&]() {
QAction *act = menu.activeAction(); QAction *act = menu.activeAction();
QToolTip::showText(QCursor::pos(), act->toolTip(), QToolTip::showText(QCursor::pos(), act->toolTip(),
&menu, menu.actionGeometry(act)); &menu, menu.actionGeometry(act));
}; };
action = menu.addAction(QTStr("QuickTransitions.DuplicateScene")); action = menu.addAction(
QTStr("QuickTransitions.DuplicateScene"));
action->setToolTip(QTStr("QuickTransitions.DuplicateSceneTT")); action->setToolTip(QTStr("QuickTransitions.DuplicateSceneTT"));
action->setCheckable(true); action->setCheckable(true);
action->setChecked(sceneDuplicationMode); action->setChecked(sceneDuplicationMode);
connect(action, &QAction::triggered, toggleSceneDuplication); connect(action, &QAction::triggered, toggleSceneDuplication);
connect(action, &QAction::hovered, showToolTip); connect(action, &QAction::hovered, showToolTip);
action = menu.addAction(QTStr("QuickTransitions.EditProperties")); action = menu.addAction(
QTStr("QuickTransitions.EditProperties"));
action->setToolTip(QTStr("QuickTransitions.EditPropertiesTT")); action->setToolTip(QTStr("QuickTransitions.EditPropertiesTT"));
action->setCheckable(true); action->setCheckable(true);
action->setChecked(editPropertiesMode); action->setChecked(editPropertiesMode);
@@ -831,8 +831,8 @@ void OBSBasic::CreateProgramOptions()
menu.exec(QCursor::pos()); menu.exec(QCursor::pos());
}; };
connect(transitionButton.data(), &QAbstractButton::clicked, connect(transitionButton.data(), &QAbstractButton::clicked, this,
this, &OBSBasic::TransitionClicked); &OBSBasic::TransitionClicked);
connect(addQuickTransition, &QAbstractButton::clicked, onAdd); connect(addQuickTransition, &QAbstractButton::clicked, onAdd);
connect(configTransitions, &QAbstractButton::clicked, onConfig); connect(configTransitions, &QAbstractButton::clicked, onConfig);
} }
@@ -868,8 +868,7 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
duration->setSingleStep(50); duration->setSingleStep(50);
duration->setValue(curDuration); duration->setValue(curDuration);
auto setTransition = [this] (QAction *action) auto setTransition = [this](QAction *action) {
{
int idx = action->property("transition_index").toInt(); int idx = action->property("transition_index").toInt();
OBSSource scene = GetCurrentSceneSource(); OBSSource scene = GetCurrentSceneSource();
OBSData data = obs_source_get_private_settings(scene); OBSData data = obs_source_get_private_settings(scene);
@@ -886,8 +885,7 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
obs_data_set_string(data, "transition", name); obs_data_set_string(data, "transition", name);
}; };
auto setDuration = [this] (int duration) auto setDuration = [this](int duration) {
{
OBSSource scene = GetCurrentSceneSource(); OBSSource scene = GetCurrentSceneSource();
OBSData data = obs_source_get_private_settings(scene); OBSData data = obs_source_get_private_settings(scene);
obs_data_release(data); obs_data_release(data);
@@ -895,8 +893,8 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
obs_data_set_int(data, "transition_duration", duration); obs_data_set_int(data, "transition_duration", duration);
}; };
connect(duration, (void (QSpinBox::*)(int))&QSpinBox::valueChanged, connect(duration, (void (QSpinBox::*)(int)) & QSpinBox::valueChanged,
setDuration); setDuration);
for (int i = -1; i < ui->transitions->count(); i++) { for (int i = -1; i < ui->transitions->count(); i++) {
const char *name = ""; const char *name = "";
@@ -918,7 +916,7 @@ QMenu *OBSBasic::CreatePerSceneTransitionMenu()
action->setChecked(match); action->setChecked(match);
connect(action, &QAction::triggered, connect(action, &QAction::triggered,
std::bind(setTransition, action)); std::bind(setTransition, action));
} }
QWidgetAction *durationAction = new QWidgetAction(menu); QWidgetAction *durationAction = new QWidgetAction(menu);
@@ -937,8 +935,8 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
if (qt) { if (qt) {
action = menu->addAction(QTStr("Remove")); action = menu->addAction(QTStr("Remove"));
action->setProperty("id", qt->id); action->setProperty("id", qt->id);
connect(action, &QAction::triggered, connect(action, &QAction::triggered, this,
this, &OBSBasic::QuickTransitionRemoveClicked); &OBSBasic::QuickTransitionRemoveClicked);
menu->addSeparator(); menu->addSeparator();
} }
@@ -953,8 +951,9 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
duration->setValue(qt ? qt->duration : 300); duration->setValue(qt ? qt->duration : 300);
if (qt) { if (qt) {
connect(duration, (void (QSpinBox::*)(int))&QSpinBox::valueChanged, connect(duration,
this, &OBSBasic::QuickTransitionChangeDuration); (void (QSpinBox::*)(int)) & QSpinBox::valueChanged,
this, &OBSBasic::QuickTransitionChangeDuration);
} }
for (int i = 0; i < ui->transitions->count(); i++) { for (int i = 0; i < ui->transitions->count(); i++) {
@@ -966,12 +965,13 @@ QMenu *OBSBasic::CreateTransitionMenu(QWidget *parent, QuickTransition *qt)
if (qt) { if (qt) {
action->setProperty("id", qt->id); action->setProperty("id", qt->id);
connect(action, &QAction::triggered, this, connect(action, &QAction::triggered, this,
&OBSBasic::QuickTransitionChange); &OBSBasic::QuickTransitionChange);
} else { } else {
action->setProperty("duration", action->setProperty(
QVariant::fromValue<QWidget*>(duration)); "duration",
QVariant::fromValue<QWidget *>(duration));
connect(action, &QAction::triggered, this, connect(action, &QAction::triggered, this,
&OBSBasic::AddQuickTransition); &OBSBasic::AddQuickTransition);
} }
} }
@@ -1004,11 +1004,11 @@ void OBSBasic::AddQuickTransitionId(int id)
/* --------------------------------- */ /* --------------------------------- */
button->setMenu(buttonMenu); button->setMenu(buttonMenu);
connect(button, &QAbstractButton::clicked, connect(button, &QAbstractButton::clicked, this,
this, &OBSBasic::QuickTransitionClicked); &OBSBasic::QuickTransitionClicked);
QVBoxLayout *programLayout = QVBoxLayout *programLayout =
reinterpret_cast<QVBoxLayout*>(programOptions->layout()); reinterpret_cast<QVBoxLayout *>(programOptions->layout());
int idx = 3; int idx = 3;
for (;; idx++) { for (;; idx++) {
@@ -1027,7 +1027,7 @@ void OBSBasic::AddQuickTransitionId(int id)
void OBSBasic::AddQuickTransition() void OBSBasic::AddQuickTransition()
{ {
int trIdx = sender()->property("transition_index").toInt(); int trIdx = sender()->property("transition_index").toInt();
QSpinBox *duration = sender()->property("duration").value<QSpinBox*>(); QSpinBox *duration = sender()->property("duration").value<QSpinBox *>();
OBSSource transition = GetTransitionComboItem(ui->transitions, trIdx); OBSSource transition = GetTransitionComboItem(ui->transitions, trIdx);
int id = quickTransitionIdCounter++; int id = quickTransitionIdCounter++;
@@ -1048,7 +1048,7 @@ void OBSBasic::ClearQuickTransitions()
return; return;
QVBoxLayout *programLayout = QVBoxLayout *programLayout =
reinterpret_cast<QVBoxLayout*>(programOptions->layout()); reinterpret_cast<QVBoxLayout *>(programOptions->layout());
for (int idx = 0;; idx++) { for (int idx = 0;; idx++) {
QLayoutItem *item = programLayout->itemAt(idx); QLayoutItem *item = programLayout->itemAt(idx);
@@ -1118,7 +1118,7 @@ void OBSBasic::ClearQuickTransitionWidgets()
return; return;
QVBoxLayout *programLayout = QVBoxLayout *programLayout =
reinterpret_cast<QVBoxLayout*>(programOptions->layout()); reinterpret_cast<QVBoxLayout *>(programOptions->layout());
for (int idx = 0;; idx++) { for (int idx = 0;; idx++) {
QLayoutItem *item = programLayout->itemAt(idx); QLayoutItem *item = programLayout->itemAt(idx);
@@ -1152,7 +1152,7 @@ void OBSBasic::DisableQuickTransitionWidgets()
return; return;
QVBoxLayout *programLayout = QVBoxLayout *programLayout =
reinterpret_cast<QVBoxLayout*>(programOptions->layout()); reinterpret_cast<QVBoxLayout *>(programOptions->layout());
for (int idx = 0;; idx++) { for (int idx = 0;; idx++) {
QLayoutItem *item = programLayout->itemAt(idx); QLayoutItem *item = programLayout->itemAt(idx);
@@ -1173,7 +1173,7 @@ void OBSBasic::EnableQuickTransitionWidgets()
return; return;
QVBoxLayout *programLayout = QVBoxLayout *programLayout =
reinterpret_cast<QVBoxLayout*>(programOptions->layout()); reinterpret_cast<QVBoxLayout *>(programOptions->layout());
for (int idx = 0;; idx++) { for (int idx = 0;; idx++) {
QLayoutItem *item = programLayout->itemAt(idx); QLayoutItem *item = programLayout->itemAt(idx);
@@ -1209,10 +1209,11 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
obs_scene_t *dup; obs_scene_t *dup;
if (sceneDuplicationMode) { if (sceneDuplicationMode) {
dup = obs_scene_duplicate(curScene, nullptr, dup = obs_scene_duplicate(
editPropertiesMode ? curScene, nullptr,
OBS_SCENE_DUP_PRIVATE_COPY : editPropertiesMode
OBS_SCENE_DUP_PRIVATE_REFS); ? OBS_SCENE_DUP_PRIVATE_COPY
: OBS_SCENE_DUP_PRIVATE_REFS);
} else { } else {
dup = curScene; dup = curScene;
obs_scene_addref(dup); obs_scene_addref(dup);
@@ -1235,7 +1236,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
programLabel = new QLabel(QTStr("StudioMode.Program")); programLabel = new QLabel(QTStr("StudioMode.Program"));
programLabel->setSizePolicy(QSizePolicy::Preferred, programLabel->setSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Preferred); QSizePolicy::Preferred);
programLabel->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); programLabel->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
programLabel->setProperty("themeID", "previewProgramLabels"); programLabel->setProperty("themeID", "previewProgramLabels");
@@ -1248,8 +1249,8 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
programLayout->addWidget(programLabel); programLayout->addWidget(programLabel);
programLayout->addWidget(program); programLayout->addWidget(program);
bool labels = config_get_bool(GetGlobalConfig(), bool labels = config_get_bool(GetGlobalConfig(), "BasicWindow",
"BasicWindow", "StudioModeLabels"); "StudioModeLabels");
programLabel->setHidden(!labels); programLabel->setHidden(!labels);
@@ -1257,14 +1258,15 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
ui->previewLayout->addWidget(programOptions); ui->previewLayout->addWidget(programOptions);
ui->previewLayout->addWidget(programWidget); ui->previewLayout->addWidget(programWidget);
ui->previewLayout->setAlignment(programOptions, Qt::AlignCenter); ui->previewLayout->setAlignment(programOptions,
Qt::AlignCenter);
if (api) if (api)
api->on_event(OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED); api->on_event(OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED);
blog(LOG_INFO, "Switched to Preview/Program mode"); blog(LOG_INFO, "Switched to Preview/Program mode");
blog(LOG_INFO, "-----------------------------" blog(LOG_INFO, "-----------------------------"
"-------------------"); "-------------------");
} else { } else {
OBSSource actualProgramScene = OBSGetStrongRef(programScene); OBSSource actualProgramScene = OBSGetStrongRef(programScene);
if (!actualProgramScene) if (!actualProgramScene)
@@ -1299,7 +1301,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
blog(LOG_INFO, "Switched to regular Preview mode"); blog(LOG_INFO, "Switched to regular Preview mode");
blog(LOG_INFO, "-----------------------------" blog(LOG_INFO, "-----------------------------"
"-------------------"); "-------------------");
} }
ResetUI(); ResetUI();
@@ -1310,7 +1312,7 @@ void OBSBasic::RenderProgram(void *data, uint32_t cx, uint32_t cy)
{ {
GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "RenderProgram"); GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "RenderProgram");
OBSBasic *window = static_cast<OBSBasic*>(data); OBSBasic *window = static_cast<OBSBasic *>(data);
obs_video_info ovi; obs_video_info ovi;
obs_get_video_info(&ovi); obs_get_video_info(&ovi);
@@ -1324,9 +1326,9 @@ void OBSBasic::RenderProgram(void *data, uint32_t cx, uint32_t cy)
/* --------------------------------------- */ /* --------------------------------------- */
gs_ortho(0.0f, float(ovi.base_width), 0.0f, float(ovi.base_height), gs_ortho(0.0f, float(ovi.base_width), 0.0f, float(ovi.base_height),
-100.0f, 100.0f); -100.0f, 100.0f);
gs_set_viewport(window->programX, window->programY, gs_set_viewport(window->programX, window->programY, window->programCX,
window->programCX, window->programCY); window->programCY);
window->DrawBackdrop(float(ovi.base_width), float(ovi.base_height)); window->DrawBackdrop(float(ovi.base_width), float(ovi.base_height));
@@ -1351,9 +1353,9 @@ void OBSBasic::ResizeProgram(uint32_t cx, uint32_t cy)
/* resize program panel to fix to the top section of the window */ /* resize program panel to fix to the top section of the window */
targetSize = GetPixelSize(program); targetSize = GetPixelSize(program);
GetScaleAndCenterPos(int(cx), int(cy), GetScaleAndCenterPos(int(cx), int(cy),
targetSize.width() - PREVIEW_EDGE_SIZE * 2, targetSize.width() - PREVIEW_EDGE_SIZE * 2,
targetSize.height() - PREVIEW_EDGE_SIZE * 2, targetSize.height() - PREVIEW_EDGE_SIZE * 2,
programX, programY, programScale); programX, programY, programScale);
programX += float(PREVIEW_EDGE_SIZE); programX += float(PREVIEW_EDGE_SIZE);
programY += float(PREVIEW_EDGE_SIZE); programY += float(PREVIEW_EDGE_SIZE);
@@ -1371,7 +1373,8 @@ obs_data_array_t *OBSBasic::SaveTransitions()
obs_data_t *sourceData = obs_data_create(); obs_data_t *sourceData = obs_data_create();
obs_data_t *settings = obs_source_get_settings(tr); obs_data_t *settings = obs_source_get_settings(tr);
obs_data_set_string(sourceData, "name", obs_source_get_name(tr)); obs_data_set_string(sourceData, "name",
obs_source_get_name(tr));
obs_data_set_string(sourceData, "id", obs_obj_get_id(tr)); obs_data_set_string(sourceData, "id", obs_obj_get_id(tr));
obs_data_set_obj(sourceData, "settings", settings); obs_data_set_obj(sourceData, "settings", settings);
@@ -1394,14 +1397,15 @@ void OBSBasic::LoadTransitions(obs_data_array_t *transitions)
const char *id = obs_data_get_string(item, "id"); const char *id = obs_data_get_string(item, "id");
obs_data_t *settings = obs_data_get_obj(item, "settings"); obs_data_t *settings = obs_data_get_obj(item, "settings");
obs_source_t *source = obs_source_create_private(id, name, obs_source_t *source =
settings); obs_source_create_private(id, name, settings);
if (!obs_obj_invalid(source)) { if (!obs_obj_invalid(source)) {
InitTransition(source); InitTransition(source);
ui->transitions->addItem(QT_UTF8(name), ui->transitions->addItem(
QVariant::fromValue(OBSSource(source))); QT_UTF8(name),
QVariant::fromValue(OBSSource(source)));
ui->transitions->setCurrentIndex( ui->transitions->setCurrentIndex(
ui->transitions->count() - 1); ui->transitions->count() - 1);
} }
obs_data_release(settings); obs_data_release(settings);
+1227 -1277
View File
File diff suppressed because it is too large. Load diff
+108 -114
View File
@@ -53,16 +53,16 @@ class OBSBasicStats;
#define DESKTOP_AUDIO_1 Str("DesktopAudioDevice1") #define DESKTOP_AUDIO_1 Str("DesktopAudioDevice1")
#define DESKTOP_AUDIO_2 Str("DesktopAudioDevice2") #define DESKTOP_AUDIO_2 Str("DesktopAudioDevice2")
#define AUX_AUDIO_1 Str("AuxAudioDevice1") #define AUX_AUDIO_1 Str("AuxAudioDevice1")
#define AUX_AUDIO_2 Str("AuxAudioDevice2") #define AUX_AUDIO_2 Str("AuxAudioDevice2")
#define AUX_AUDIO_3 Str("AuxAudioDevice3") #define AUX_AUDIO_3 Str("AuxAudioDevice3")
#define AUX_AUDIO_4 Str("AuxAudioDevice4") #define AUX_AUDIO_4 Str("AuxAudioDevice4")
#define SIMPLE_ENCODER_X264 "x264" #define SIMPLE_ENCODER_X264 "x264"
#define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu" #define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
#define SIMPLE_ENCODER_QSV "qsv" #define SIMPLE_ENCODER_QSV "qsv"
#define SIMPLE_ENCODER_NVENC "nvenc" #define SIMPLE_ENCODER_NVENC "nvenc"
#define SIMPLE_ENCODER_AMD "amd" #define SIMPLE_ENCODER_AMD "amd"
#define PREVIEW_EDGE_SIZE 10 #define PREVIEW_EDGE_SIZE 10
@@ -89,13 +89,14 @@ struct QuickTransition {
inline QuickTransition() {} inline QuickTransition() {}
inline QuickTransition(OBSSource source_, int duration_, int id_) inline QuickTransition(OBSSource source_, int duration_, int id_)
: source (source_), : source(source_),
duration (duration_), duration(duration_),
id (id_), id(id_),
renamedSignal (std::make_shared<OBSSignal>( renamedSignal(std::make_shared<OBSSignal>(
obs_source_get_signal_handler(source), obs_source_get_signal_handler(source), "rename",
"rename", SourceRenamed, this)) SourceRenamed, this))
{} {
}
private: private:
static void SourceRenamed(void *param, calldata_t *data); static void SourceRenamed(void *param, calldata_t *data);
@@ -124,19 +125,14 @@ class OBSBasic : public OBSMainWindow {
friend class AutoConfigStreamPage; friend class AutoConfigStreamPage;
friend struct OBSStudioAPI; friend struct OBSStudioAPI;
enum class MoveDir { enum class MoveDir { Up, Down, Left, Right };
Up,
Down,
Left,
Right
};
enum DropType { enum DropType {
DropType_RawText, DropType_RawText,
DropType_Text, DropType_Text,
DropType_Image, DropType_Image,
DropType_Media, DropType_Media,
DropType_Html DropType_Html,
}; };
private: private:
@@ -144,7 +140,7 @@ private:
std::shared_ptr<Auth> auth; std::shared_ptr<Auth> auth;
std::vector<VolControl*> volumes; std::vector<VolControl *> volumes;
std::vector<OBSSignal> signalHandlers; std::vector<OBSSignal> signalHandlers;
@@ -172,7 +168,7 @@ private:
QPointer<QDockWidget> statsDock; QPointer<QDockWidget> statsDock;
QPointer<OBSAbout> about; QPointer<OBSAbout> about;
QPointer<QTimer> cpuUsageTimer; QPointer<QTimer> cpuUsageTimer;
os_cpu_usage_info_t *cpuUsageInfo = nullptr; os_cpu_usage_info_t *cpuUsageInfo = nullptr;
OBSService service; OBSService service;
@@ -188,16 +184,16 @@ private:
gs_vertbuffer_t *boxBottom = nullptr; gs_vertbuffer_t *boxBottom = nullptr;
gs_vertbuffer_t *circle = nullptr; gs_vertbuffer_t *circle = nullptr;
bool sceneChanging = false; bool sceneChanging = false;
bool ignoreSelectionUpdate = false; bool ignoreSelectionUpdate = false;
int previewX = 0, previewY = 0; int previewX = 0, previewY = 0;
int previewCX = 0, previewCY = 0; int previewCX = 0, previewCY = 0;
float previewScale = 0.0f; float previewScale = 0.0f;
ConfigFile basicConfig; ConfigFile basicConfig;
std::vector<SavedProjectorInfo*> savedProjectorsArray; std::vector<SavedProjectorInfo *> savedProjectorsArray;
QPointer<QWidget> projectors[10]; QPointer<QWidget> projectors[10];
QList<QPointer<QWidget>> windowProjectors; QList<QPointer<QWidget>> windowProjectors;
@@ -210,26 +206,26 @@ private:
QPointer<QPushButton> replayBufferButton; QPointer<QPushButton> replayBufferButton;
QScopedPointer<QSystemTrayIcon> trayIcon; QScopedPointer<QSystemTrayIcon> trayIcon;
QPointer<QAction> sysTrayStream; QPointer<QAction> sysTrayStream;
QPointer<QAction> sysTrayRecord; QPointer<QAction> sysTrayRecord;
QPointer<QAction> sysTrayReplayBuffer; QPointer<QAction> sysTrayReplayBuffer;
QPointer<QAction> showHide; QPointer<QAction> showHide;
QPointer<QAction> exit; QPointer<QAction> exit;
QPointer<QMenu> trayMenu; QPointer<QMenu> trayMenu;
QPointer<QMenu> previewProjector; QPointer<QMenu> previewProjector;
QPointer<QMenu> studioProgramProjector; QPointer<QMenu> studioProgramProjector;
QPointer<QMenu> multiviewProjectorMenu; QPointer<QMenu> multiviewProjectorMenu;
QPointer<QMenu> previewProjectorSource; QPointer<QMenu> previewProjectorSource;
QPointer<QMenu> previewProjectorMain; QPointer<QMenu> previewProjectorMain;
QPointer<QMenu> sceneProjectorMenu; QPointer<QMenu> sceneProjectorMenu;
QPointer<QMenu> sourceProjector; QPointer<QMenu> sourceProjector;
QPointer<QMenu> scaleFilteringMenu; QPointer<QMenu> scaleFilteringMenu;
QPointer<QMenu> colorMenu; QPointer<QMenu> colorMenu;
QPointer<QWidgetAction> colorWidgetAction; QPointer<QWidgetAction> colorWidgetAction;
QPointer<ColorSelect> colorSelect; QPointer<ColorSelect> colorSelect;
QPointer<QMenu> deinterlaceMenu; QPointer<QMenu> deinterlaceMenu;
QPointer<QMenu> perSceneTransitionMenu; QPointer<QMenu> perSceneTransitionMenu;
QPointer<QObject> shortcutFilter; QPointer<QObject> shortcutFilter;
QPointer<QWidget> programWidget; QPointer<QWidget> programWidget;
QPointer<QVBoxLayout> programLayout; QPointer<QVBoxLayout> programLayout;
@@ -238,47 +234,47 @@ private:
QScopedPointer<QThread> patronJsonThread; QScopedPointer<QThread> patronJsonThread;
std::string patronJson; std::string patronJson;
void UpdateMultiviewProjectorMenu(); void UpdateMultiviewProjectorMenu();
void DrawBackdrop(float cx, float cy); void DrawBackdrop(float cx, float cy);
void SetupEncoders(); void SetupEncoders();
void CreateFirstRunSources(); void CreateFirstRunSources();
void CreateDefaultScene(bool firstStart); void CreateDefaultScene(bool firstStart);
void UpdateVolumeControlsDecayRate(); void UpdateVolumeControlsDecayRate();
void UpdateVolumeControlsPeakMeterType(); void UpdateVolumeControlsPeakMeterType();
void ClearVolumeControls(); void ClearVolumeControls();
void UploadLog(const char *subdir, const char *file); void UploadLog(const char *subdir, const char *file);
void Save(const char *file); void Save(const char *file);
void Load(const char *file); void Load(const char *file);
void InitHotkeys(); void InitHotkeys();
void CreateHotkeys(); void CreateHotkeys();
void ClearHotkeys(); void ClearHotkeys();
bool InitService(); bool InitService();
bool InitBasicConfigDefaults(); bool InitBasicConfigDefaults();
void InitBasicConfigDefaults2(); void InitBasicConfigDefaults2();
bool InitBasicConfig(); bool InitBasicConfig();
void InitOBSCallbacks(); void InitOBSCallbacks();
void InitPrimitives(); void InitPrimitives();
void OnFirstLoad(); void OnFirstLoad();
OBSSceneItem GetSceneItem(QListWidgetItem *item); OBSSceneItem GetSceneItem(QListWidgetItem *item);
OBSSceneItem GetCurrentSceneItem(); OBSSceneItem GetCurrentSceneItem();
bool QueryRemoveSource(obs_source_t *source); bool QueryRemoveSource(obs_source_t *source);
void TimedCheckForUpdates(); void TimedCheckForUpdates();
void CheckForUpdates(bool manualUpdate); void CheckForUpdates(bool manualUpdate);
void GetFPSCommon(uint32_t &num, uint32_t &den) const; void GetFPSCommon(uint32_t &num, uint32_t &den) const;
void GetFPSInteger(uint32_t &num, uint32_t &den) const; void GetFPSInteger(uint32_t &num, uint32_t &den) const;
@@ -293,8 +289,8 @@ private:
void ChangeSceneIndex(bool relative, int idx, int invalidIdx); void ChangeSceneIndex(bool relative, int idx, int invalidIdx);
void TempFileOutput(const char *path, int vBitrate, int aBitrate); void TempFileOutput(const char *path, int vBitrate, int aBitrate);
void TempStreamOutput(const char *url, const char *key, void TempStreamOutput(const char *url, const char *key, int vBitrate,
int vBitrate, int aBitrate); int aBitrate);
void CloseDialogs(); void CloseDialogs();
void ClearSceneData(); void ClearSceneData();
@@ -302,7 +298,7 @@ private:
void Nudge(int dist, MoveDir dir); void Nudge(int dist, MoveDir dir);
OBSProjector *OpenProjector(obs_source_t *source, int monitor, OBSProjector *OpenProjector(obs_source_t *source, int monitor,
QString title, ProjectorType type); QString title, ProjectorType type);
void GetAudioSourceFilters(); void GetAudioSourceFilters();
void GetAudioSourceProperties(); void GetAudioSourceProperties();
@@ -327,8 +323,8 @@ private:
int GetTopSelectedSourceItem(); int GetTopSelectedSourceItem();
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, replayBufHotkeys,
replayBufHotkeys, togglePreviewHotkeys; togglePreviewHotkeys;
obs_hotkey_id forceStreamingStopHotkey; obs_hotkey_id forceStreamingStopHotkey;
void InitDefaultTransitions(); void InitDefaultTransitions();
@@ -368,7 +364,7 @@ private:
void SetPreviewProgramMode(bool enabled); void SetPreviewProgramMode(bool enabled);
void ResizeProgram(uint32_t cx, uint32_t cy); void ResizeProgram(uint32_t cx, uint32_t cy);
void SetCurrentScene(obs_scene_t *scene, bool force = false, void SetCurrentScene(obs_scene_t *scene, bool force = false,
bool direct = false); bool direct = false);
static void RenderProgram(void *data, uint32_t cx, uint32_t cy); static void RenderProgram(void *data, uint32_t cx, uint32_t cy);
std::vector<QuickTransition> quickTransitions; std::vector<QuickTransition> quickTransitions;
@@ -386,8 +382,8 @@ private:
int quickTransitionIdCounter = 1; int quickTransitionIdCounter = 1;
bool overridingTransition = false; bool overridingTransition = false;
int programX = 0, programY = 0; int programX = 0, programY = 0;
int programCX = 0, programCY = 0; int programCX = 0, programCY = 0;
float programScale = 0.0f; float programScale = 0.0f;
int disableOutputsRef = 0; int disableOutputsRef = 0;
@@ -407,9 +403,9 @@ private:
void EnumDialogs(); void EnumDialogs();
QList<QDialog*> visDialogs; QList<QDialog *> visDialogs;
QList<QDialog*> modalDialogs; QList<QDialog *> modalDialogs;
QList<QMessageBox*> visMsgBoxes; QList<QMessageBox *> visMsgBoxes;
QList<QPoint> visDlgPositions; QList<QPoint> visDlgPositions;
@@ -457,15 +453,15 @@ public slots:
void SetTransition(OBSSource transition); void SetTransition(OBSSource transition);
void TransitionToScene(OBSScene scene, bool force = false, void TransitionToScene(OBSScene scene, bool force = false,
bool direct = false); bool direct = false);
void TransitionToScene(OBSSource scene, bool force = false, void TransitionToScene(OBSSource scene, bool force = false,
bool direct = false, bool quickTransition = false); bool direct = false,
bool quickTransition = false);
void SetCurrentScene(OBSSource scene, bool force = false, void SetCurrentScene(OBSSource scene, bool force = false,
bool direct = false); bool direct = false);
bool AddSceneCollection( bool AddSceneCollection(bool create_new,
bool create_new, const QString &name = QString());
const QString &name = QString());
void UpdatePatronJson(const QString &text, const QString &error); void UpdatePatronJson(const QString &text, const QString &error);
@@ -575,7 +571,7 @@ public:
} }
obs_service_t *GetService(); obs_service_t *GetService();
void SetService(obs_service_t *service); void SetService(obs_service_t *service);
int GetTransitionDuration(); int GetTransitionDuration();
@@ -588,29 +584,26 @@ public:
bool Active() const; bool Active() const;
void ResetUI(); void ResetUI();
int ResetVideo(); int ResetVideo();
bool ResetAudio(); bool ResetAudio();
void ResetOutputs(); void ResetOutputs();
void ResetAudioDevice(const char *sourceId, const char *deviceId, void ResetAudioDevice(const char *sourceId, const char *deviceId,
const char *deviceDesc, int channel); const char *deviceDesc, int channel);
void NewProject(); void NewProject();
void LoadProject(); void LoadProject();
inline void GetDisplayRect(int &x, int &y, int &cx, int &cy) inline void GetDisplayRect(int &x, int &y, int &cx, int &cy)
{ {
x = previewX; x = previewX;
y = previewY; y = previewY;
cx = previewCX; cx = previewCX;
cy = previewCY; cy = previewCY;
} }
inline bool SavingDisabled() const inline bool SavingDisabled() const { return disableSaving; }
{
return disableSaving;
}
inline double GetCPUUsage() const inline double GetCPUUsage() const
{ {
@@ -620,7 +613,7 @@ public:
void SaveService(); void SaveService();
bool LoadService(); bool LoadService();
inline Auth *GetAuth() {return auth.get();} inline Auth *GetAuth() { return auth.get(); }
inline void EnableOutputs(bool enable) inline void EnableOutputs(bool enable)
{ {
@@ -635,7 +628,8 @@ public:
QMenu *AddDeinterlacingMenu(QMenu *menu, obs_source_t *source); QMenu *AddDeinterlacingMenu(QMenu *menu, obs_source_t *source);
QMenu *AddScaleFilteringMenu(QMenu *menu, obs_sceneitem_t *item); QMenu *AddScaleFilteringMenu(QMenu *menu, obs_sceneitem_t *item);
QMenu *AddBackgroundColorMenu(QMenu *menu, QWidgetAction *widgetAction, QMenu *AddBackgroundColorMenu(QMenu *menu, QWidgetAction *widgetAction,
ColorSelect *select, obs_sceneitem_t *item); ColorSelect *select,
obs_sceneitem_t *item);
void CreateSourcePopupMenu(int idx, bool preview); void CreateSourcePopupMenu(int idx, bool preview);
void UpdateTitleBar(); void UpdateTitleBar();
@@ -691,7 +685,7 @@ private slots:
void on_actionHorizontalCenter_triggered(); void on_actionHorizontalCenter_triggered();
void on_scenes_currentItemChanged(QListWidgetItem *current, void on_scenes_currentItemChanged(QListWidgetItem *current,
QListWidgetItem *prev); QListWidgetItem *prev);
void on_scenes_customContextMenuRequested(const QPoint &pos); void on_scenes_customContextMenuRequested(const QPoint &pos);
void on_actionAddScene_triggered(); void on_actionAddScene_triggered();
void on_actionRemoveScene_triggered(); void on_actionRemoveScene_triggered();
@@ -728,8 +722,8 @@ private slots:
void on_preview_customContextMenuRequested(const QPoint &pos); void on_preview_customContextMenuRequested(const QPoint &pos);
void on_program_customContextMenuRequested(const QPoint &pos); void on_program_customContextMenuRequested(const QPoint &pos);
void on_previewDisabledLabel_customContextMenuRequested( void
const QPoint &pos); on_previewDisabledLabel_customContextMenuRequested(const QPoint &pos);
void on_actionNewSceneCollection_triggered(); void on_actionNewSceneCollection_triggered();
void on_actionDupSceneCollection_triggered(); void on_actionDupSceneCollection_triggered();
@@ -779,7 +773,7 @@ private slots:
void EditSceneItemName(); void EditSceneItemName();
void SceneNameEdited(QWidget *editor, void SceneNameEdited(QWidget *editor,
QAbstractItemDelegate::EndEditHint endHint); QAbstractItemDelegate::EndEditHint endHint);
void OpenSceneFilters(); void OpenSceneFilters();
void OpenFilters(); void OpenFilters();
@@ -825,8 +819,8 @@ public:
virtual config_t *Config() const override; virtual config_t *Config() const override;
virtual int GetProfilePath(char *path, size_t size, const char *file) virtual int GetProfilePath(char *path, size_t size,
const override; const char *file) const override;
static void InitBrowserPanelSafeBlock(); static void InitBrowserPanelSafeBlock();
@@ -839,8 +833,8 @@ class SceneRenameDelegate : public QStyledItemDelegate {
public: public:
SceneRenameDelegate(QObject *parent); SceneRenameDelegate(QObject *parent);
virtual void setEditorData(QWidget *editor, const QModelIndex &index) virtual void setEditorData(QWidget *editor,
const override; const QModelIndex &index) const override;
protected: protected:
virtual bool eventFilter(QObject *editor, QEvent *event) override; virtual bool eventFilter(QObject *editor, QEvent *event) override;
+219 -222
View File
@@ -11,7 +11,7 @@
#include "obs-app.hpp" #include "obs-app.hpp"
#include "platform.hpp" #include "platform.hpp"
#define HANDLE_RADIUS 4.0f #define HANDLE_RADIUS 4.0f
#define HANDLE_SEL_RADIUS (HANDLE_RADIUS * 1.5f) #define HANDLE_SEL_RADIUS (HANDLE_RADIUS * 1.5f)
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
#define SUPPORTS_FRACTIONAL_SCALING #define SUPPORTS_FRACTIONAL_SCALING
@@ -37,7 +37,7 @@ OBSBasicPreview::~OBSBasicPreview()
vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event) vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
#ifdef SUPPORTS_FRACTIONAL_SCALING #ifdef SUPPORTS_FRACTIONAL_SCALING
float pixelRatio = main->devicePixelRatioF(); float pixelRatio = main->devicePixelRatioF();
#else #else
@@ -46,28 +46,28 @@ vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event)
float scale = pixelRatio / main->previewScale; float scale = pixelRatio / main->previewScale;
vec2 pos; vec2 pos;
vec2_set(&pos, vec2_set(&pos,
(float(event->x()) - main->previewX / pixelRatio) * scale, (float(event->x()) - main->previewX / pixelRatio) * scale,
(float(event->y()) - main->previewY / pixelRatio) * scale); (float(event->y()) - main->previewY / pixelRatio) * scale);
return pos; return pos;
} }
struct SceneFindData { struct SceneFindData {
const vec2 &pos; const vec2 &pos;
OBSSceneItem item; OBSSceneItem item;
bool selectBelow; bool selectBelow;
obs_sceneitem_t *group = nullptr; obs_sceneitem_t *group = nullptr;
SceneFindData(const SceneFindData &) = delete; SceneFindData(const SceneFindData &) = delete;
SceneFindData(SceneFindData &&) = delete; SceneFindData(SceneFindData &&) = delete;
SceneFindData& operator=(const SceneFindData &) = delete; SceneFindData &operator=(const SceneFindData &) = delete;
SceneFindData& operator=(SceneFindData &&) = delete; SceneFindData &operator=(SceneFindData &&) = delete;
inline SceneFindData(const vec2 &pos_, bool selectBelow_) inline SceneFindData(const vec2 &pos_, bool selectBelow_)
: pos (pos_), : pos(pos_), selectBelow(selectBelow_)
selectBelow (selectBelow_) {
{} }
}; };
static bool SceneItemHasVideo(obs_sceneitem_t *item) static bool SceneItemHasVideo(obs_sceneitem_t *item)
@@ -77,21 +77,21 @@ static bool SceneItemHasVideo(obs_sceneitem_t *item)
return (flags & OBS_SOURCE_VIDEO) != 0; return (flags & OBS_SOURCE_VIDEO) != 0;
} }
static bool CloseFloat(float a, float b, float epsilon=0.01) static bool CloseFloat(float a, float b, float epsilon = 0.01)
{ {
using std::abs; using std::abs;
return abs(a-b) <= epsilon; return abs(a - b) <= epsilon;
} }
static bool FindItemAtPos(obs_scene_t *scene, obs_sceneitem_t *item, static bool FindItemAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
void *param) void *param)
{ {
SceneFindData *data = reinterpret_cast<SceneFindData*>(param); SceneFindData *data = reinterpret_cast<SceneFindData *>(param);
matrix4 transform; matrix4 transform;
matrix4 invTransform; matrix4 invTransform;
vec3 transformedPos; vec3 transformedPos;
vec3 pos3; vec3 pos3;
vec3 pos3_; vec3 pos3_;
if (!SceneItemHasVideo(item)) if (!SceneItemHasVideo(item))
return true; return true;
@@ -147,54 +147,50 @@ static inline vec2 GetOBSScreenSize()
vec3 OBSBasicPreview::GetSnapOffset(const vec3 &tl, const vec3 &br) vec3 OBSBasicPreview::GetSnapOffset(const vec3 &tl, const vec3 &br)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
vec2 screenSize = GetOBSScreenSize(); vec2 screenSize = GetOBSScreenSize();
vec3 clampOffset; vec3 clampOffset;
vec3_zero(&clampOffset); vec3_zero(&clampOffset);
const bool snap = config_get_bool(GetGlobalConfig(), const bool snap = config_get_bool(GetGlobalConfig(), "BasicWindow",
"BasicWindow", "SnappingEnabled"); "SnappingEnabled");
if (snap == false) if (snap == false)
return clampOffset; return clampOffset;
const bool screenSnap = config_get_bool(GetGlobalConfig(), const bool screenSnap = config_get_bool(
"BasicWindow", "ScreenSnapping"); GetGlobalConfig(), "BasicWindow", "ScreenSnapping");
const bool centerSnap = config_get_bool(GetGlobalConfig(), const bool centerSnap = config_get_bool(
"BasicWindow", "CenterSnapping"); GetGlobalConfig(), "BasicWindow", "CenterSnapping");
const float clampDist = config_get_double(GetGlobalConfig(), const float clampDist = config_get_double(GetGlobalConfig(),
"BasicWindow", "SnapDistance") / main->previewScale; "BasicWindow",
"SnapDistance") /
main->previewScale;
const float centerX = br.x - (br.x - tl.x) / 2.0f; const float centerX = br.x - (br.x - tl.x) / 2.0f;
const float centerY = br.y - (br.y - tl.y) / 2.0f; const float centerY = br.y - (br.y - tl.y) / 2.0f;
// Left screen edge. // Left screen edge.
if (screenSnap && if (screenSnap && fabsf(tl.x) < clampDist)
fabsf(tl.x) < clampDist)
clampOffset.x = -tl.x; clampOffset.x = -tl.x;
// Right screen edge. // Right screen edge.
if (screenSnap && if (screenSnap && fabsf(clampOffset.x) < EPSILON &&
fabsf(clampOffset.x) < EPSILON &&
fabsf(screenSize.x - br.x) < clampDist) fabsf(screenSize.x - br.x) < clampDist)
clampOffset.x = screenSize.x - br.x; clampOffset.x = screenSize.x - br.x;
// Horizontal center. // Horizontal center.
if (centerSnap && if (centerSnap && fabsf(screenSize.x - (br.x - tl.x)) > clampDist &&
fabsf(screenSize.x - (br.x - tl.x)) > clampDist &&
fabsf(screenSize.x / 2.0f - centerX) < clampDist) fabsf(screenSize.x / 2.0f - centerX) < clampDist)
clampOffset.x = screenSize.x / 2.0f - centerX; clampOffset.x = screenSize.x / 2.0f - centerX;
// Top screen edge. // Top screen edge.
if (screenSnap && if (screenSnap && fabsf(tl.y) < clampDist)
fabsf(tl.y) < clampDist)
clampOffset.y = -tl.y; clampOffset.y = -tl.y;
// Bottom screen edge. // Bottom screen edge.
if (screenSnap && if (screenSnap && fabsf(clampOffset.y) < EPSILON &&
fabsf(clampOffset.y) < EPSILON &&
fabsf(screenSize.y - br.y) < clampDist) fabsf(screenSize.y - br.y) < clampDist)
clampOffset.y = screenSize.y - br.y; clampOffset.y = screenSize.y - br.y;
// Vertical center. // Vertical center.
if (centerSnap && if (centerSnap && fabsf(screenSize.y - (br.y - tl.y)) > clampDist &&
fabsf(screenSize.y - (br.y - tl.y)) > clampDist &&
fabsf(screenSize.y / 2.0f - centerY) < clampDist) fabsf(screenSize.y / 2.0f - centerY) < clampDist)
clampOffset.y = screenSize.y / 2.0f - centerY; clampOffset.y = screenSize.y / 2.0f - centerY;
@@ -203,7 +199,7 @@ vec3 OBSBasicPreview::GetSnapOffset(const vec3 &tl, const vec3 &br)
OBSSceneItem OBSBasicPreview::GetItemAtPos(const vec2 &pos, bool selectBelow) OBSSceneItem OBSBasicPreview::GetItemAtPos(const vec2 &pos, bool selectBelow)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
if (!scene) if (!scene)
@@ -215,12 +211,12 @@ OBSSceneItem OBSBasicPreview::GetItemAtPos(const vec2 &pos, bool selectBelow)
} }
static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item, static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item,
void *param) void *param)
{ {
SceneFindData *data = reinterpret_cast<SceneFindData*>(param); SceneFindData *data = reinterpret_cast<SceneFindData *>(param);
matrix4 transform; matrix4 transform;
vec3 transformedPos; vec3 transformedPos;
vec3 pos3; vec3 pos3;
if (!SceneItemHasVideo(item)) if (!SceneItemHasVideo(item))
return true; return true;
@@ -240,7 +236,8 @@ static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item,
if (data->group) { if (data->group) {
matrix4 parent_transform; matrix4 parent_transform;
obs_sceneitem_get_draw_transform(data->group, &parent_transform); obs_sceneitem_get_draw_transform(data->group,
&parent_transform);
matrix4_mul(&transform, &transform, &parent_transform); matrix4_mul(&transform, &transform, &parent_transform);
} }
@@ -261,7 +258,7 @@ static bool CheckItemSelected(obs_scene_t *scene, obs_sceneitem_t *item,
bool OBSBasicPreview::SelectedAtPos(const vec2 &pos) bool OBSBasicPreview::SelectedAtPos(const vec2 &pos)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
if (!scene) if (!scene)
@@ -273,46 +270,45 @@ bool OBSBasicPreview::SelectedAtPos(const vec2 &pos)
} }
struct HandleFindData { struct HandleFindData {
const vec2 &pos; const vec2 &pos;
const float radius; const float radius;
matrix4 parent_xform; matrix4 parent_xform;
OBSSceneItem item; OBSSceneItem item;
ItemHandle handle = ItemHandle::None; ItemHandle handle = ItemHandle::None;
HandleFindData(const HandleFindData &) = delete; HandleFindData(const HandleFindData &) = delete;
HandleFindData(HandleFindData &&) = delete; HandleFindData(HandleFindData &&) = delete;
HandleFindData& operator=(const HandleFindData &) = delete; HandleFindData &operator=(const HandleFindData &) = delete;
HandleFindData& operator=(HandleFindData &&) = delete; HandleFindData &operator=(HandleFindData &&) = delete;
inline HandleFindData(const vec2 &pos_, float scale) inline HandleFindData(const vec2 &pos_, float scale)
: pos (pos_), : pos(pos_), radius(HANDLE_SEL_RADIUS / scale)
radius (HANDLE_SEL_RADIUS / scale)
{ {
matrix4_identity(&parent_xform); matrix4_identity(&parent_xform);
} }
inline HandleFindData(const HandleFindData &hfd, inline HandleFindData(const HandleFindData &hfd,
obs_sceneitem_t *parent) obs_sceneitem_t *parent)
: pos (hfd.pos), : pos(hfd.pos),
radius (hfd.radius), radius(hfd.radius),
item (hfd.item), item(hfd.item),
handle (hfd.handle) handle(hfd.handle)
{ {
obs_sceneitem_get_draw_transform(parent, &parent_xform); obs_sceneitem_get_draw_transform(parent, &parent_xform);
} }
}; };
static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item, static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
void *param) void *param)
{ {
HandleFindData &data = *reinterpret_cast<HandleFindData*>(param); HandleFindData &data = *reinterpret_cast<HandleFindData *>(param);
if (!obs_sceneitem_selected(item)) { if (!obs_sceneitem_selected(item)) {
if (obs_sceneitem_is_group(item)) { if (obs_sceneitem_is_group(item)) {
HandleFindData newData(data, item); HandleFindData newData(data, item);
obs_sceneitem_group_enum_items(item, FindHandleAtPos, obs_sceneitem_group_enum_items(item, FindHandleAtPos,
&newData); &newData);
data.item = newData.item; data.item = newData.item;
data.handle = newData.handle; data.handle = newData.handle;
} }
@@ -320,16 +316,15 @@ static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
return true; return true;
} }
matrix4 transform; matrix4 transform;
vec3 pos3; vec3 pos3;
float closestHandle = data.radius; float closestHandle = data.radius;
vec3_set(&pos3, data.pos.x, data.pos.y, 0.0f); vec3_set(&pos3, data.pos.x, data.pos.y, 0.0f);
obs_sceneitem_get_box_transform(item, &transform); obs_sceneitem_get_box_transform(item, &transform);
auto TestHandle = [&] (float x, float y, ItemHandle handle) auto TestHandle = [&](float x, float y, ItemHandle handle) {
{
vec3 handlePos = GetTransformedPos(x, y, transform); vec3 handlePos = GetTransformedPos(x, y, transform);
vec3_transform(&handlePos, &handlePos, &data.parent_xform); vec3_transform(&handlePos, &handlePos, &data.parent_xform);
@@ -337,8 +332,8 @@ static bool FindHandleAtPos(obs_scene_t *scene, obs_sceneitem_t *item,
if (dist < data.radius) { if (dist < data.radius) {
if (dist < closestHandle) { if (dist < closestHandle) {
closestHandle = dist; closestHandle = dist;
data.handle = handle; data.handle = handle;
data.item = item; data.item = item;
} }
} }
}; };
@@ -370,10 +365,12 @@ static vec2 GetItemSize(obs_sceneitem_t *item)
obs_sceneitem_get_scale(item, &scale); obs_sceneitem_get_scale(item, &scale);
obs_sceneitem_get_crop(item, &crop); obs_sceneitem_get_crop(item, &crop);
size.x = float(obs_source_get_width(source) - size.x = float(obs_source_get_width(source) - crop.left -
crop.left - crop.right) * scale.x; crop.right) *
size.y = float(obs_source_get_height(source) - scale.x;
crop.top - crop.bottom) * scale.y; size.y = float(obs_source_get_height(source) - crop.top -
crop.bottom) *
scale.y;
} }
return size; return size;
@@ -381,7 +378,7 @@ static vec2 GetItemSize(obs_sceneitem_t *item)
void OBSBasicPreview::GetStretchHandleData(const vec2 &pos) void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
if (!scene) if (!scene)
@@ -397,13 +394,13 @@ void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
HandleFindData data(scaled_pos, scale); HandleFindData data(scaled_pos, scale);
obs_scene_enum_items(scene, FindHandleAtPos, &data); obs_scene_enum_items(scene, FindHandleAtPos, &data);
stretchItem = std::move(data.item); stretchItem = std::move(data.item);
stretchHandle = data.handle; stretchHandle = data.handle;
if (stretchHandle != ItemHandle::None) { if (stretchHandle != ItemHandle::None) {
matrix4 boxTransform; matrix4 boxTransform;
vec3 itemUL; vec3 itemUL;
float itemRot; float itemRot;
stretchItemSize = GetItemSize(stretchItem); stretchItemSize = GetItemSize(stretchItem);
@@ -413,32 +410,31 @@ void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
/* build the item space conversion matrices */ /* build the item space conversion matrices */
matrix4_identity(&itemToScreen); matrix4_identity(&itemToScreen);
matrix4_rotate_aa4f(&itemToScreen, &itemToScreen, matrix4_rotate_aa4f(&itemToScreen, &itemToScreen, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, RAD(itemRot)); 1.0f, RAD(itemRot));
matrix4_translate3f(&itemToScreen, &itemToScreen, matrix4_translate3f(&itemToScreen, &itemToScreen, itemUL.x,
itemUL.x, itemUL.y, 0.0f); itemUL.y, 0.0f);
matrix4_identity(&screenToItem); matrix4_identity(&screenToItem);
matrix4_translate3f(&screenToItem, &screenToItem, matrix4_translate3f(&screenToItem, &screenToItem, -itemUL.x,
-itemUL.x, -itemUL.y, 0.0f); -itemUL.y, 0.0f);
matrix4_rotate_aa4f(&screenToItem, &screenToItem, matrix4_rotate_aa4f(&screenToItem, &screenToItem, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, RAD(-itemRot)); 1.0f, RAD(-itemRot));
obs_sceneitem_get_crop(stretchItem, &startCrop); obs_sceneitem_get_crop(stretchItem, &startCrop);
obs_sceneitem_get_pos(stretchItem, &startItemPos); obs_sceneitem_get_pos(stretchItem, &startItemPos);
obs_source_t *source = obs_sceneitem_get_source(stretchItem); obs_source_t *source = obs_sceneitem_get_source(stretchItem);
cropSize.x = float(obs_source_get_width(source) - cropSize.x = float(obs_source_get_width(source) -
startCrop.left - startCrop.right); startCrop.left - startCrop.right);
cropSize.y = float(obs_source_get_height(source) - cropSize.y = float(obs_source_get_height(source) -
startCrop.top - startCrop.bottom); startCrop.top - startCrop.bottom);
stretchGroup = obs_sceneitem_get_group(scene, stretchItem); stretchGroup = obs_sceneitem_get_group(scene, stretchItem);
if (stretchGroup) { if (stretchGroup) {
obs_sceneitem_get_draw_transform(stretchGroup, obs_sceneitem_get_draw_transform(stretchGroup,
&invGroupTransform); &invGroupTransform);
matrix4_inv(&invGroupTransform, matrix4_inv(&invGroupTransform, &invGroupTransform);
&invGroupTransform);
obs_sceneitem_defer_group_resize_begin(stretchGroup); obs_sceneitem_defer_group_resize_begin(stretchGroup);
} }
} }
@@ -480,8 +476,8 @@ void OBSBasicPreview::keyReleaseEvent(QKeyEvent *event)
void OBSBasicPreview::wheelEvent(QWheelEvent *event) void OBSBasicPreview::wheelEvent(QWheelEvent *event)
{ {
if (scrollMode && IsFixedScaling() if (scrollMode && IsFixedScaling() &&
&& event->orientation() == Qt::Vertical) { event->orientation() == Qt::Vertical) {
if (event->delta() > 0) if (event->delta() > 0)
SetScalingLevel(scalingLevel + 1); SetScalingLevel(scalingLevel + 1);
else if (event->delta() < 0) else if (event->delta() < 0)
@@ -512,7 +508,7 @@ void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
return; return;
} }
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
#ifdef SUPPORTS_FRACTIONAL_SCALING #ifdef SUPPORTS_FRACTIONAL_SCALING
float pixelRatio = main->devicePixelRatioF(); float pixelRatio = main->devicePixelRatioF();
#else #else
@@ -549,7 +545,7 @@ void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
static bool select_one(obs_scene_t *scene, obs_sceneitem_t *item, void *param) static bool select_one(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
{ {
obs_sceneitem_t *selectedItem = obs_sceneitem_t *selectedItem =
reinterpret_cast<obs_sceneitem_t*>(param); reinterpret_cast<obs_sceneitem_t *>(param);
if (obs_sceneitem_is_group(item)) if (obs_sceneitem_is_group(item))
obs_sceneitem_group_enum_items(item, select_one, param); obs_sceneitem_group_enum_items(item, select_one, param);
@@ -561,12 +557,12 @@ static bool select_one(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
void OBSBasicPreview::DoSelect(const vec2 &pos) void OBSBasicPreview::DoSelect(const vec2 &pos)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
OBSSceneItem item = GetItemAtPos(pos, true); OBSSceneItem item = GetItemAtPos(pos, true);
obs_scene_enum_items(scene, select_one, (obs_sceneitem_t*)item); obs_scene_enum_items(scene, select_one, (obs_sceneitem_t *)item);
} }
void OBSBasicPreview::DoCtrlSelect(const vec2 &pos) void OBSBasicPreview::DoCtrlSelect(const vec2 &pos)
@@ -609,11 +605,11 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
obs_sceneitem_defer_group_resize_end(stretchGroup); obs_sceneitem_defer_group_resize_end(stretchGroup);
} }
stretchItem = nullptr; stretchItem = nullptr;
stretchGroup = nullptr; stretchGroup = nullptr;
mouseDown = false; mouseDown = false;
mouseMoved = false; mouseMoved = false;
cropping = false; cropping = false;
OBSSceneItem item = GetItemAtPos(pos, true); OBSSceneItem item = GetItemAtPos(pos, true);
hoveredPreviewItem = item; hoveredPreviewItem = item;
@@ -626,13 +622,13 @@ struct SelectedItemBounds {
}; };
static bool AddItemBounds(obs_scene_t *scene, obs_sceneitem_t *item, static bool AddItemBounds(obs_scene_t *scene, obs_sceneitem_t *item,
void *param) void *param)
{ {
SelectedItemBounds *data = reinterpret_cast<SelectedItemBounds*>(param); SelectedItemBounds *data =
reinterpret_cast<SelectedItemBounds *>(param);
vec3 t[4]; vec3 t[4];
auto add_bounds = [data, &t] () auto add_bounds = [data, &t]() {
{
for (const vec3 &v : t) { for (const vec3 &v : t) {
if (data->first) { if (data->first) {
vec3_copy(&data->tl, &v); vec3_copy(&data->tl, &v);
@@ -686,9 +682,9 @@ struct OffsetData {
}; };
static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item, static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
void *param) void *param)
{ {
OffsetData *data = reinterpret_cast<OffsetData*>(param); OffsetData *data = reinterpret_cast<OffsetData *>(param);
if (obs_sceneitem_selected(item)) if (obs_sceneitem_selected(item))
return true; return true;
@@ -696,12 +692,10 @@ static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
matrix4 boxTransform; matrix4 boxTransform;
obs_sceneitem_get_box_transform(item, &boxTransform); obs_sceneitem_get_box_transform(item, &boxTransform);
vec3 t[4] = { vec3 t[4] = {GetTransformedPos(0.0f, 0.0f, boxTransform),
GetTransformedPos(0.0f, 0.0f, boxTransform), GetTransformedPos(1.0f, 0.0f, boxTransform),
GetTransformedPos(1.0f, 0.0f, boxTransform), GetTransformedPos(0.0f, 1.0f, boxTransform),
GetTransformedPos(0.0f, 1.0f, boxTransform), GetTransformedPos(1.0f, 1.0f, boxTransform)};
GetTransformedPos(1.0f, 1.0f, boxTransform)
};
bool first = true; bool first = true;
vec3 tl, br; vec3 tl, br;
@@ -719,15 +713,15 @@ static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
} }
// Snap to other source edges // Snap to other source edges
#define EDGE_SNAP(l, r, x, y) \ #define EDGE_SNAP(l, r, x, y) \
do { \ do { \
double dist = fabsf(l.x - data->r.x); \ double dist = fabsf(l.x - data->r.x); \
if (dist < data->clampDist && \ if (dist < data->clampDist && \
fabsf(data->offset.x) < EPSILON && \ fabsf(data->offset.x) < EPSILON && data->tl.y < br.y && \
data->tl.y < br.y && \ data->br.y > tl.y && \
data->br.y > tl.y && \ (fabsf(data->offset.x) > dist || \
(fabsf(data->offset.x) > dist || data->offset.x < EPSILON)) \ data->offset.x < EPSILON)) \
data->offset.x = l.x - data->r.x; \ data->offset.x = l.x - data->r.x; \
} while (false) } while (false)
EDGE_SNAP(tl, br, x, y); EDGE_SNAP(tl, br, x, y);
@@ -742,7 +736,7 @@ static bool GetSourceSnapOffset(obs_scene_t *scene, obs_sceneitem_t *item,
void OBSBasicPreview::SnapItemMovement(vec2 &offset) void OBSBasicPreview::SnapItemMovement(vec2 &offset)
{ {
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
SelectedItemBounds data; SelectedItemBounds data;
@@ -755,10 +749,10 @@ void OBSBasicPreview::SnapItemMovement(vec2 &offset)
vec3 snapOffset = GetSnapOffset(data.tl, data.br); vec3 snapOffset = GetSnapOffset(data.tl, data.br);
const bool snap = config_get_bool(GetGlobalConfig(), const bool snap = config_get_bool(GetGlobalConfig(), "BasicWindow",
"BasicWindow", "SnappingEnabled"); "SnappingEnabled");
const bool sourcesSnap = config_get_bool(GetGlobalConfig(), const bool sourcesSnap = config_get_bool(
"BasicWindow", "SourceSnapping"); GetGlobalConfig(), "BasicWindow", "SourceSnapping");
if (snap == false) if (snap == false)
return; return;
if (sourcesSnap == false) { if (sourcesSnap == false) {
@@ -768,7 +762,9 @@ void OBSBasicPreview::SnapItemMovement(vec2 &offset)
} }
const float clampDist = config_get_double(GetGlobalConfig(), const float clampDist = config_get_double(GetGlobalConfig(),
"BasicWindow", "SnapDistance") / main->previewScale; "BasicWindow",
"SnapDistance") /
main->previewScale;
OffsetData offsetData; OffsetData offsetData;
offsetData.clampDist = clampDist; offsetData.clampDist = clampDist;
@@ -794,7 +790,7 @@ static bool move_items(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
return true; return true;
bool selected = obs_sceneitem_selected(item); bool selected = obs_sceneitem_selected(item);
vec2 *offset = reinterpret_cast<vec2*>(param); vec2 *offset = reinterpret_cast<vec2 *>(param);
if (obs_sceneitem_is_group(item) && !selected) { if (obs_sceneitem_is_group(item) && !selected) {
matrix4 transform; matrix4 transform;
@@ -822,7 +818,7 @@ static bool move_items(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
void OBSBasicPreview::MoveItems(const vec2 &pos) void OBSBasicPreview::MoveItems(const vec2 &pos)
{ {
Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers(); Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
vec2 offset, moveOffset; vec2 offset, moveOffset;
@@ -862,14 +858,14 @@ vec3 OBSBasicPreview::CalculateStretchPos(const vec3 &tl, const vec3 &br)
} }
void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size, void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
const vec2 &baseSize) const vec2 &baseSize)
{ {
float baseAspect = baseSize.x / baseSize.y; float baseAspect = baseSize.x / baseSize.y;
float aspect = size.x / size.y; float aspect = size.x / size.y;
uint32_t stretchFlags = (uint32_t)stretchHandle; uint32_t stretchFlags = (uint32_t)stretchHandle;
if (stretchHandle == ItemHandle::TopLeft || if (stretchHandle == ItemHandle::TopLeft ||
stretchHandle == ItemHandle::TopRight || stretchHandle == ItemHandle::TopRight ||
stretchHandle == ItemHandle::BottomLeft || stretchHandle == ItemHandle::BottomLeft ||
stretchHandle == ItemHandle::BottomRight) { stretchHandle == ItemHandle::BottomRight) {
if (aspect < baseAspect) { if (aspect < baseAspect) {
@@ -887,7 +883,7 @@ void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
} }
} else if (stretchHandle == ItemHandle::TopCenter || } else if (stretchHandle == ItemHandle::TopCenter ||
stretchHandle == ItemHandle::BottomCenter) { stretchHandle == ItemHandle::BottomCenter) {
if ((size.y >= 0.0f && size.x >= 0.0f) || if ((size.y >= 0.0f && size.x >= 0.0f) ||
(size.y <= 0.0f && size.x <= 0.0f)) (size.y <= 0.0f && size.x <= 0.0f))
size.x = size.y * baseAspect; size.x = size.y * baseAspect;
@@ -895,7 +891,7 @@ void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
size.x = size.y * baseAspect * -1.0f; size.x = size.y * baseAspect * -1.0f;
} else if (stretchHandle == ItemHandle::CenterLeft || } else if (stretchHandle == ItemHandle::CenterLeft ||
stretchHandle == ItemHandle::CenterRight) { stretchHandle == ItemHandle::CenterRight) {
if ((size.y >= 0.0f && size.x >= 0.0f) || if ((size.y >= 0.0f && size.x >= 0.0f) ||
(size.y <= 0.0f && size.x <= 0.0f)) (size.y <= 0.0f && size.x <= 0.0f))
size.y = size.x / baseAspect; size.y = size.x / baseAspect;
@@ -920,12 +916,12 @@ void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
void OBSBasicPreview::SnapStretchingToScreen(vec3 &tl, vec3 &br) void OBSBasicPreview::SnapStretchingToScreen(vec3 &tl, vec3 &br)
{ {
uint32_t stretchFlags = (uint32_t)stretchHandle; uint32_t stretchFlags = (uint32_t)stretchHandle;
vec3 newTL = GetTransformedPos(tl.x, tl.y, itemToScreen); vec3 newTL = GetTransformedPos(tl.x, tl.y, itemToScreen);
vec3 newTR = GetTransformedPos(br.x, tl.y, itemToScreen); vec3 newTR = GetTransformedPos(br.x, tl.y, itemToScreen);
vec3 newBL = GetTransformedPos(tl.x, br.y, itemToScreen); vec3 newBL = GetTransformedPos(tl.x, br.y, itemToScreen);
vec3 newBR = GetTransformedPos(br.x, br.y, itemToScreen); vec3 newBR = GetTransformedPos(br.x, br.y, itemToScreen);
vec3 boundingTL; vec3 boundingTL;
vec3 boundingBR; vec3 boundingBR;
vec3_copy(&boundingTL, &newTL); vec3_copy(&boundingTL, &newTL);
vec3_min(&boundingTL, &boundingTL, &newTR); vec3_min(&boundingTL, &boundingTL, &newTR);
@@ -984,14 +980,12 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
vec2 max_tl; vec2 max_tl;
vec2 max_br; vec2 max_br;
vec2_set(&max_tl, vec2_set(&max_tl, float(-crop.left) * scale.x,
float(-crop.left) * scale.x, float(-crop.top) * scale.y);
float(-crop.top) * scale.y); vec2_set(&max_br, stretchItemSize.x + crop.right * scale.x,
vec2_set(&max_br, stretchItemSize.y + crop.bottom * scale.y);
stretchItemSize.x + crop.right * scale.x,
stretchItemSize.y + crop.bottom * scale.y);
typedef std::function<float (float, float)> minmax_func_t; typedef std::function<float(float, float)> minmax_func_t;
minmax_func_t min_x = scale.x < 0.0f ? maxfunc : minfunc; minmax_func_t min_x = scale.x < 0.0f ? maxfunc : minfunc;
minmax_func_t min_y = scale.y < 0.0f ? maxfunc : minfunc; minmax_func_t min_y = scale.y < 0.0f ? maxfunc : minfunc;
@@ -1021,8 +1015,8 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
pos3.y = br.y = max_y(pos3.y, minY); pos3.y = br.y = max_y(pos3.y, minY);
} }
#define ALIGN_X (ITEM_LEFT|ITEM_RIGHT) #define ALIGN_X (ITEM_LEFT | ITEM_RIGHT)
#define ALIGN_Y (ITEM_TOP|ITEM_BOTTOM) #define ALIGN_Y (ITEM_TOP | ITEM_BOTTOM)
vec3 newPos; vec3 newPos;
vec3_zero(&newPos); vec3_zero(&newPos);
@@ -1049,12 +1043,14 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
if (stretchFlags & ITEM_LEFT) if (stretchFlags & ITEM_LEFT)
crop.left += int(std::round(tl.x / scale.x)); crop.left += int(std::round(tl.x / scale.x));
else if (stretchFlags & ITEM_RIGHT) else if (stretchFlags & ITEM_RIGHT)
crop.right += int(std::round((stretchItemSize.x - br.x) / scale.x)); crop.right +=
int(std::round((stretchItemSize.x - br.x) / scale.x));
if (stretchFlags & ITEM_TOP) if (stretchFlags & ITEM_TOP)
crop.top += int(std::round(tl.y / scale.y)); crop.top += int(std::round(tl.y / scale.y));
else if (stretchFlags & ITEM_BOTTOM) else if (stretchFlags & ITEM_BOTTOM)
crop.bottom += int(std::round((stretchItemSize.y - br.y) / scale.y)); crop.bottom +=
int(std::round((stretchItemSize.y - br.y) / scale.y));
vec3_transform(&newPos, &newPos, &itemToScreen); vec3_transform(&newPos, &newPos, &itemToScreen);
newPos.x = std::round(newPos.x); newPos.x = std::round(newPos.x);
@@ -1075,7 +1071,7 @@ void OBSBasicPreview::CropItem(const vec2 &pos)
obs_sceneitem_defer_update_begin(stretchItem); obs_sceneitem_defer_update_begin(stretchItem);
obs_sceneitem_set_crop(stretchItem, &crop); obs_sceneitem_set_crop(stretchItem, &crop);
if (boundsType == OBS_BOUNDS_NONE) if (boundsType == OBS_BOUNDS_NONE)
obs_sceneitem_set_pos(stretchItem, (vec2*)&newPos); obs_sceneitem_set_pos(stretchItem, (vec2 *)&newPos);
obs_sceneitem_defer_update_end(stretchItem); obs_sceneitem_defer_update_end(stretchItem);
} }
@@ -1109,19 +1105,20 @@ void OBSBasicPreview::StretchItem(const vec2 &pos)
obs_source_t *source = obs_sceneitem_get_source(stretchItem); obs_source_t *source = obs_sceneitem_get_source(stretchItem);
vec2 baseSize; vec2 baseSize;
vec2_set(&baseSize, vec2_set(&baseSize, float(obs_source_get_width(source)),
float(obs_source_get_width(source)), float(obs_source_get_height(source)));
float(obs_source_get_height(source)));
vec2 size; vec2 size;
vec2_set(&size,br. x - tl.x, br.y - tl.y); vec2_set(&size, br.x - tl.x, br.y - tl.y);
if (boundsType != OBS_BOUNDS_NONE) { if (boundsType != OBS_BOUNDS_NONE) {
if (shiftDown) if (shiftDown)
ClampAspect(tl, br, size, baseSize); ClampAspect(tl, br, size, baseSize);
if (tl.x > br.x) std::swap(tl.x, br.x); if (tl.x > br.x)
if (tl.y > br.y) std::swap(tl.y, br.y); std::swap(tl.x, br.x);
if (tl.y > br.y)
std::swap(tl.y, br.y);
vec2_abs(&size, &size); vec2_abs(&size, &size);
@@ -1177,16 +1174,16 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
pos.y = std::round(pos.y); pos.y = std::round(pos.y);
if (stretchHandle != ItemHandle::None) { if (stretchHandle != ItemHandle::None) {
OBSBasic *main = reinterpret_cast<OBSBasic*>( OBSBasic *main = reinterpret_cast<OBSBasic *>(
App()->GetMainWindow()); App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
obs_sceneitem_t *group = obs_sceneitem_get_group( obs_sceneitem_t *group =
scene, stretchItem); obs_sceneitem_get_group(scene, stretchItem);
if (group) { if (group) {
vec3 group_pos; vec3 group_pos;
vec3_set(&group_pos, pos.x, pos.y, 0.0f); vec3_set(&group_pos, pos.x, pos.y, 0.0f);
vec3_transform(&group_pos, &group_pos, vec3_transform(&group_pos, &group_pos,
&invGroupTransform); &invGroupTransform);
pos.x = group_pos.x; pos.x = group_pos.x;
pos.y = group_pos.y; pos.y = group_pos.y;
} }
@@ -1230,13 +1227,13 @@ static void DrawSquareAtPos(float x, float y)
gs_matrix_translate(&pos); gs_matrix_translate(&pos);
gs_matrix_translate3f(-HANDLE_RADIUS, -HANDLE_RADIUS, 0.0f); gs_matrix_translate3f(-HANDLE_RADIUS, -HANDLE_RADIUS, 0.0f);
gs_matrix_scale3f(HANDLE_RADIUS*2, HANDLE_RADIUS*2, 1.0f); gs_matrix_scale3f(HANDLE_RADIUS * 2, HANDLE_RADIUS * 2, 1.0f);
gs_draw(GS_TRISTRIP, 0, 0); gs_draw(GS_TRISTRIP, 0, 0);
gs_matrix_pop(); gs_matrix_pop();
} }
static void DrawLine(float x1, float y1, float x2, float y2, float thickness, static void DrawLine(float x1, float y1, float x2, float y2, float thickness,
vec2 scale) vec2 scale)
{ {
float ySide = (y1 == y2) ? (y1 < 0.5f ? 1.0f : -1.0f) : 0.0f; float ySide = (y1 == y2) ? (y1 < 0.5f ? 1.0f : -1.0f) : 0.0f;
float xSide = (x1 == x2) ? (x1 < 0.5f ? 1.0f : -1.0f) : 0.0f; float xSide = (x1 == x2) ? (x1 < 0.5f ? 1.0f : -1.0f) : 0.0f;
@@ -1245,9 +1242,9 @@ static void DrawLine(float x1, float y1, float x2, float y2, float thickness,
gs_vertex2f(x1, y1); gs_vertex2f(x1, y1);
gs_vertex2f(x1 + (xSide * (thickness / scale.x)), gs_vertex2f(x1 + (xSide * (thickness / scale.x)),
y1 + (ySide * (thickness / scale.y))); y1 + (ySide * (thickness / scale.y)));
gs_vertex2f(x2 + (xSide * (thickness / scale.x)), gs_vertex2f(x2 + (xSide * (thickness / scale.x)),
y2 + (ySide * (thickness / scale.y))); y2 + (ySide * (thickness / scale.y)));
gs_vertex2f(x2, y2); gs_vertex2f(x2, y2);
gs_vertex2f(x1, y1); gs_vertex2f(x1, y1);
@@ -1292,14 +1289,12 @@ static void DrawRect(float thickness, vec2 scale)
static inline bool crop_enabled(const obs_sceneitem_crop *crop) static inline bool crop_enabled(const obs_sceneitem_crop *crop)
{ {
return crop->left > 0 || return crop->left > 0 || crop->top > 0 || crop->right > 0 ||
crop->top > 0 ||
crop->right > 0 ||
crop->bottom > 0; crop->bottom > 0;
} }
bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene, bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
obs_sceneitem_t *item, void *param) obs_sceneitem_t *item, void *param)
{ {
if (obs_sceneitem_locked(item)) if (obs_sceneitem_locked(item))
return true; return true;
@@ -1308,7 +1303,7 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
return true; return true;
bool select = config_get_bool(GetGlobalConfig(), "BasicWindow", bool select = config_get_bool(GetGlobalConfig(), "BasicWindow",
"OverflowSelectionHidden"); "OverflowSelectionHidden");
if (!select && !obs_sceneitem_visible(item)) if (!select && !obs_sceneitem_visible(item))
return true; return true;
@@ -1319,17 +1314,18 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
gs_matrix_push(); gs_matrix_push();
gs_matrix_mul(&mat); gs_matrix_mul(&mat);
obs_sceneitem_group_enum_items(item, DrawSelectedOverflow, param); obs_sceneitem_group_enum_items(item, DrawSelectedOverflow,
param);
gs_matrix_pop(); gs_matrix_pop();
} }
bool always = config_get_bool(GetGlobalConfig(), "BasicWindow", bool always = config_get_bool(GetGlobalConfig(), "BasicWindow",
"OverflowAlwaysVisible"); "OverflowAlwaysVisible");
if (!always && !obs_sceneitem_selected(item)) if (!always && !obs_sceneitem_selected(item))
return true; return true;
OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param); OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview *>(param);
matrix4 boxTransform; matrix4 boxTransform;
matrix4 invBoxTransform; matrix4 invBoxTransform;
@@ -1343,14 +1339,13 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
{{{1.f, 1.f, 0.f}}}, {{{1.f, 1.f, 0.f}}},
}; };
bool visible = std::all_of(std::begin(bounds), std::end(bounds), bool visible = std::all_of(
[&](const vec3 &b) std::begin(bounds), std::end(bounds), [&](const vec3 &b) {
{ vec3 pos;
vec3 pos; vec3_transform(&pos, &b, &boxTransform);
vec3_transform(&pos, &b, &boxTransform); vec3_transform(&pos, &pos, &invBoxTransform);
vec3_transform(&pos, &pos, &invBoxTransform); return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y); });
});
if (!visible) if (!visible)
return true; return true;
@@ -1360,9 +1355,9 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
obs_transform_info info; obs_transform_info info;
obs_sceneitem_get_info(item, &info); obs_sceneitem_get_info(item, &info);
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_REPEAT); gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_REPEAT);
gs_eparam_t *image = gs_effect_get_param_by_name(solid, "image"); gs_eparam_t *image = gs_effect_get_param_by_name(solid, "image");
gs_eparam_t *scale = gs_effect_get_param_by_name(solid, "scale"); gs_eparam_t *scale = gs_effect_get_param_by_name(solid, "scale");
vec2 s; vec2 s;
vec2_set(&s, boxTransform.x.x / 96, boxTransform.y.y / 96); vec2_set(&s, boxTransform.x.x / 96, boxTransform.y.y / 96);
@@ -1389,7 +1384,7 @@ bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
} }
bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene, bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
obs_sceneitem_t *item, void *param) obs_sceneitem_t *item, void *param)
{ {
if (obs_sceneitem_locked(item)) if (obs_sceneitem_locked(item))
return true; return true;
@@ -1407,11 +1402,11 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
gs_matrix_pop(); gs_matrix_pop();
} }
OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param); OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview *>(param);
OBSBasic *main = OBSBasic::Get(); OBSBasic *main = OBSBasic::Get();
bool hovered = prev->hoveredPreviewItem == item || bool hovered = prev->hoveredPreviewItem == item ||
prev->hoveredListItem == item; prev->hoveredListItem == item;
bool selected = obs_sceneitem_selected(item); bool selected = obs_sceneitem_selected(item);
if (!selected && !hovered) if (!selected && !hovered)
@@ -1437,14 +1432,13 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
vec4_set(&green, 0.0f, 1.0f, 0.0f, 1.0f); vec4_set(&green, 0.0f, 1.0f, 0.0f, 1.0f);
vec4_set(&blue, 0.0f, 0.5f, 1.0f, 1.0f); vec4_set(&blue, 0.0f, 0.5f, 1.0f, 1.0f);
bool visible = std::all_of(std::begin(bounds), std::end(bounds), bool visible = std::all_of(
[&](const vec3 &b) std::begin(bounds), std::end(bounds), [&](const vec3 &b) {
{ vec3 pos;
vec3 pos; vec3_transform(&pos, &b, &boxTransform);
vec3_transform(&pos, &b, &boxTransform); vec3_transform(&pos, &pos, &invBoxTransform);
vec3_transform(&pos, &pos, &invBoxTransform); return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y); });
});
if (!visible) if (!visible)
return true; return true;
@@ -1471,17 +1465,17 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
gs_eparam_t *colParam = gs_effect_get_param_by_name(eff, "color"); gs_eparam_t *colParam = gs_effect_get_param_by_name(eff, "color");
if (info.bounds_type == OBS_BOUNDS_NONE && crop_enabled(&crop)) { if (info.bounds_type == OBS_BOUNDS_NONE && crop_enabled(&crop)) {
#define DRAW_SIDE(side, x1, y1, x2, y2) \ #define DRAW_SIDE(side, x1, y1, x2, y2) \
if (hovered && !selected) \ if (hovered && !selected) \
gs_effect_set_vec4(colParam, &blue); \ gs_effect_set_vec4(colParam, &blue); \
else if (crop.side > 0) \ else if (crop.side > 0) \
gs_effect_set_vec4(colParam, &green); \ gs_effect_set_vec4(colParam, &green); \
DrawLine(x1, y1, x2, y2, HANDLE_RADIUS / 2, boxScale); \ DrawLine(x1, y1, x2, y2, HANDLE_RADIUS / 2, boxScale); \
gs_effect_set_vec4(colParam, &red); gs_effect_set_vec4(colParam, &red);
DRAW_SIDE(left, 0.0f, 0.0f, 0.0f, 1.0f); DRAW_SIDE(left, 0.0f, 0.0f, 0.0f, 1.0f);
DRAW_SIDE(top, 0.0f, 0.0f, 1.0f, 0.0f); DRAW_SIDE(top, 0.0f, 0.0f, 1.0f, 0.0f);
DRAW_SIDE(right, 1.0f, 0.0f, 1.0f, 1.0f); DRAW_SIDE(right, 1.0f, 0.0f, 1.0f, 1.0f);
DRAW_SIDE(bottom, 0.0f, 1.0f, 1.0f, 1.0f); DRAW_SIDE(bottom, 0.0f, 1.0f, 1.0f, 1.0f);
#undef DRAW_SIDE #undef DRAW_SIDE
} else { } else {
@@ -1522,7 +1516,7 @@ void OBSBasicPreview::DrawOverflow()
return; return;
bool hidden = config_get_bool(GetGlobalConfig(), "BasicWindow", bool hidden = config_get_bool(GetGlobalConfig(), "BasicWindow",
"OverflowHidden"); "OverflowHidden");
if (hidden) if (hidden)
return; return;
@@ -1535,7 +1529,7 @@ void OBSBasicPreview::DrawOverflow()
overflow = gs_texture_create_from_file(path.c_str()); overflow = gs_texture_create_from_file(path.c_str());
} }
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene(); OBSScene scene = main->GetCurrentScene();
@@ -1558,10 +1552,10 @@ void OBSBasicPreview::DrawSceneEditing()
GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "DrawSceneEditing"); GS_DEBUG_MARKER_BEGIN(GS_DEBUG_COLOR_DEFAULT, "DrawSceneEditing");
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow()); OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID); gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
gs_technique_t *tech = gs_effect_get_technique(solid, "Solid"); gs_technique_t *tech = gs_effect_get_technique(solid, "Solid");
vec4 color; vec4 color;
vec4_set(&color, 1.0f, 0.0f, 0.0f, 1.0f); vec4_set(&color, 1.0f, 0.0f, 0.0f, 1.0f);
@@ -1592,13 +1586,16 @@ void OBSBasicPreview::ResetScrollingOffset()
vec2_zero(&scrollingOffset); vec2_zero(&scrollingOffset);
} }
void OBSBasicPreview::SetScalingLevel(int32_t newScalingLevelVal) { void OBSBasicPreview::SetScalingLevel(int32_t newScalingLevelVal)
float newScalingAmountVal = pow(ZOOM_SENSITIVITY, float(newScalingLevelVal)); {
float newScalingAmountVal =
pow(ZOOM_SENSITIVITY, float(newScalingLevelVal));
scalingLevel = newScalingLevelVal; scalingLevel = newScalingLevelVal;
SetScalingAmount(newScalingAmountVal); SetScalingAmount(newScalingAmountVal);
} }
void OBSBasicPreview::SetScalingAmount(float newScalingAmountVal) { void OBSBasicPreview::SetScalingAmount(float newScalingAmountVal)
{
scrollingOffset.x *= newScalingAmountVal / scalingAmount; scrollingOffset.x *= newScalingAmountVal / scalingAmount;
scrollingOffset.y *= newScalingAmountVal / scalingAmount; scrollingOffset.y *= newScalingAmountVal / scalingAmount;
scalingAmount = newScalingAmountVal; scalingAmount = newScalingAmountVal;
+50 -44
View File
@@ -9,23 +9,23 @@
class OBSBasic; class OBSBasic;
class QMouseEvent; class QMouseEvent;
#define ITEM_LEFT (1<<0) #define ITEM_LEFT (1 << 0)
#define ITEM_RIGHT (1<<1) #define ITEM_RIGHT (1 << 1)
#define ITEM_TOP (1<<2) #define ITEM_TOP (1 << 2)
#define ITEM_BOTTOM (1<<3) #define ITEM_BOTTOM (1 << 3)
#define ZOOM_SENSITIVITY 1.125f #define ZOOM_SENSITIVITY 1.125f
enum class ItemHandle : uint32_t { enum class ItemHandle : uint32_t {
None = 0, None = 0,
TopLeft = ITEM_TOP | ITEM_LEFT, TopLeft = ITEM_TOP | ITEM_LEFT,
TopCenter = ITEM_TOP, TopCenter = ITEM_TOP,
TopRight = ITEM_TOP | ITEM_RIGHT, TopRight = ITEM_TOP | ITEM_RIGHT,
CenterLeft = ITEM_LEFT, CenterLeft = ITEM_LEFT,
CenterRight = ITEM_RIGHT, CenterRight = ITEM_RIGHT,
BottomLeft = ITEM_BOTTOM | ITEM_LEFT, BottomLeft = ITEM_BOTTOM | ITEM_LEFT,
BottomCenter = ITEM_BOTTOM, BottomCenter = ITEM_BOTTOM,
BottomRight = ITEM_BOTTOM | ITEM_RIGHT BottomRight = ITEM_BOTTOM | ITEM_RIGHT,
}; };
class OBSBasicPreview : public OBSQTDisplay { class OBSBasicPreview : public OBSQTDisplay {
@@ -35,40 +35,40 @@ class OBSBasicPreview : public OBSQTDisplay {
private: private:
obs_sceneitem_crop startCrop; obs_sceneitem_crop startCrop;
vec2 startItemPos; vec2 startItemPos;
vec2 cropSize; vec2 cropSize;
OBSSceneItem stretchGroup; OBSSceneItem stretchGroup;
OBSSceneItem stretchItem; OBSSceneItem stretchItem;
ItemHandle stretchHandle = ItemHandle::None; ItemHandle stretchHandle = ItemHandle::None;
vec2 stretchItemSize; vec2 stretchItemSize;
matrix4 screenToItem; matrix4 screenToItem;
matrix4 itemToScreen; matrix4 itemToScreen;
matrix4 invGroupTransform; matrix4 invGroupTransform;
gs_texture_t *overflow = nullptr; gs_texture_t *overflow = nullptr;
vec2 startPos; vec2 startPos;
vec2 lastMoveOffset; vec2 lastMoveOffset;
vec2 scrollingFrom; vec2 scrollingFrom;
vec2 scrollingOffset; vec2 scrollingOffset;
bool mouseDown = false; bool mouseDown = false;
bool mouseMoved = false; bool mouseMoved = false;
bool mouseOverItems = false; bool mouseOverItems = false;
bool cropping = false; bool cropping = false;
bool locked = false; bool locked = false;
bool scrollMode = false; bool scrollMode = false;
bool fixedScaling = false; bool fixedScaling = false;
int32_t scalingLevel = 0; int32_t scalingLevel = 0;
float scalingAmount = 1.0f; float scalingAmount = 1.0f;
obs_sceneitem_t *hoveredPreviewItem = nullptr; obs_sceneitem_t *hoveredPreviewItem = nullptr;
obs_sceneitem_t *hoveredListItem = nullptr; obs_sceneitem_t *hoveredListItem = nullptr;
static vec2 GetMouseEventPos(QMouseEvent *event); static vec2 GetMouseEventPos(QMouseEvent *event);
static bool DrawSelectedOverflow(obs_scene_t *scene, static bool DrawSelectedOverflow(obs_scene_t *scene,
obs_sceneitem_t *item, void *param); obs_sceneitem_t *item, void *param);
static bool DrawSelectedItem(obs_scene_t *scene, obs_sceneitem_t *item, static bool DrawSelectedItem(obs_scene_t *scene, obs_sceneitem_t *item,
void *param); void *param);
static OBSSceneItem GetItemAtPos(const vec2 &pos, bool selectBelow); static OBSSceneItem GetItemAtPos(const vec2 &pos, bool selectBelow);
static bool SelectedAtPos(const vec2 &pos); static bool SelectedAtPos(const vec2 &pos);
@@ -110,11 +110,14 @@ public:
void DrawOverflow(); void DrawOverflow();
void DrawSceneEditing(); void DrawSceneEditing();
inline void SetLocked(bool newLockedVal) {locked = newLockedVal;} inline void SetLocked(bool newLockedVal) { locked = newLockedVal; }
inline void ToggleLocked() {locked = !locked;} inline void ToggleLocked() { locked = !locked; }
inline bool Locked() const {return locked;} inline bool Locked() const { return locked; }
inline void SetFixedScaling(bool newFixedScalingVal) { fixedScaling = newFixedScalingVal; } inline void SetFixedScaling(bool newFixedScalingVal)
{
fixedScaling = newFixedScalingVal;
}
inline bool IsFixedScaling() const { return fixedScaling; } inline bool IsFixedScaling() const { return fixedScaling; }
void SetScalingLevel(int32_t newScalingLevelVal); void SetScalingLevel(int32_t newScalingLevelVal);
@@ -123,14 +126,17 @@ public:
inline float GetScalingAmount() const { return scalingAmount; } inline float GetScalingAmount() const { return scalingAmount; }
void ResetScrollingOffset(); void ResetScrollingOffset();
inline void SetScrollingOffset(float x, float y) {vec2_set(&scrollingOffset, x, y);} inline void SetScrollingOffset(float x, float y)
inline float GetScrollX() const {return scrollingOffset.x;} {
inline float GetScrollY() const {return scrollingOffset.y;} vec2_set(&scrollingOffset, x, y);
}
inline float GetScrollX() const { return scrollingOffset.x; }
inline float GetScrollY() const { return scrollingOffset.y; }
/* use libobs allocator for alignment because the matrices itemToScreen /* use libobs allocator for alignment because the matrices itemToScreen
* and screenToItem may contain SSE data, which will cause SSE * and screenToItem may contain SSE data, which will cause SSE
* instructions to crash if the data is not aligned to at least a 16 * instructions to crash if the data is not aligned to at least a 16
* byte boundary. */ * byte boundary. */
static inline void* operator new(size_t size) {return bmalloc(size);} static inline void *operator new(size_t size) { return bmalloc(size); }
static inline void operator delete(void* ptr) {bfree(ptr);} static inline void operator delete(void *ptr) { bfree(ptr); }
}; };
+79 -85
View File
@@ -32,36 +32,34 @@ using namespace std;
static void CreateTransitionScene(OBSSource scene, char *text, uint32_t color); static void CreateTransitionScene(OBSSource scene, char *text, uint32_t color);
OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_) OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
: QDialog (parent), : QDialog(parent),
preview (new OBSQTDisplay(this)), preview(new OBSQTDisplay(this)),
main (qobject_cast<OBSBasic*>(parent)), main(qobject_cast<OBSBasic *>(parent)),
acceptClicked (false), acceptClicked(false),
source (source_), source(source_),
removedSignal (obs_source_get_signal_handler(source), removedSignal(obs_source_get_signal_handler(source), "remove",
"remove", OBSBasicProperties::SourceRemoved, OBSBasicProperties::SourceRemoved, this),
this), renamedSignal(obs_source_get_signal_handler(source), "rename",
renamedSignal (obs_source_get_signal_handler(source), OBSBasicProperties::SourceRenamed, this),
"rename", OBSBasicProperties::SourceRenamed, oldSettings(obs_data_create()),
this), buttonBox(new QDialogButtonBox(this))
oldSettings (obs_data_create()),
buttonBox (new QDialogButtonBox(this))
{ {
int cx = (int)config_get_int(App()->GlobalConfig(), "PropertiesWindow", int cx = (int)config_get_int(App()->GlobalConfig(), "PropertiesWindow",
"cx"); "cx");
int cy = (int)config_get_int(App()->GlobalConfig(), "PropertiesWindow", int cy = (int)config_get_int(App()->GlobalConfig(), "PropertiesWindow",
"cy"); "cy");
enum obs_source_type type = obs_source_get_type(source); enum obs_source_type type = obs_source_get_type(source);
buttonBox->setObjectName(QStringLiteral("buttonBox")); buttonBox->setObjectName(QStringLiteral("buttonBox"));
buttonBox->setStandardButtons(QDialogButtonBox::Ok | buttonBox->setStandardButtons(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel | QDialogButtonBox::Cancel |
QDialogButtonBox::RestoreDefaults); QDialogButtonBox::RestoreDefaults);
buttonBox->button(QDialogButtonBox::Ok)->setText(QTStr("OK")); buttonBox->button(QDialogButtonBox::Ok)->setText(QTStr("OK"));
buttonBox->button(QDialogButtonBox::Cancel)->setText(QTStr("Cancel")); buttonBox->button(QDialogButtonBox::Cancel)->setText(QTStr("Cancel"));
buttonBox->button(QDialogButtonBox::RestoreDefaults)-> buttonBox->button(QDialogButtonBox::RestoreDefaults)
setText(QTStr("Defaults")); ->setText(QTStr("Defaults"));
if (cx > 400 && cy > 400) if (cx > 400 && cy > 400)
resize(cx, cy); resize(cx, cy);
@@ -79,14 +77,15 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
obs_data_apply(oldSettings, settings); obs_data_apply(oldSettings, settings);
obs_data_release(settings); obs_data_release(settings);
view = new OBSPropertiesView(settings, source, view = new OBSPropertiesView(
(PropertiesReloadCallback)obs_source_properties, settings, source,
(PropertiesUpdateCallback)obs_source_update); (PropertiesReloadCallback)obs_source_properties,
(PropertiesUpdateCallback)obs_source_update);
view->setMinimumHeight(150); view->setMinimumHeight(150);
preview->setMinimumSize(20, 150); preview->setMinimumSize(20, 150);
preview->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, preview->setSizePolicy(
QSizePolicy::Expanding)); QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
// Create a QSplitter to keep a unified workflow here. // Create a QSplitter to keep a unified workflow here.
windowSplitter = new QSplitter(Qt::Orientation::Vertical, this); windowSplitter = new QSplitter(Qt::Orientation::Vertical, this);
@@ -102,8 +101,8 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
if (type == OBS_SOURCE_TYPE_TRANSITION) { if (type == OBS_SOURCE_TYPE_TRANSITION) {
AddPreviewButton(); AddPreviewButton();
connect(view, SIGNAL(PropertiesRefreshed()), connect(view, SIGNAL(PropertiesRefreshed()), this,
this, SLOT(AddPreviewButton())); SLOT(AddPreviewButton()));
} }
layout()->addWidget(buttonBox); layout()->addWidget(buttonBox);
@@ -118,35 +117,35 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
obs_source_inc_showing(source); obs_source_inc_showing(source);
updatePropertiesSignal.Connect(obs_source_get_signal_handler(source), updatePropertiesSignal.Connect(obs_source_get_signal_handler(source),
"update_properties", "update_properties",
OBSBasicProperties::UpdateProperties, OBSBasicProperties::UpdateProperties,
this); this);
auto addDrawCallback = [this] () auto addDrawCallback = [this]() {
{
obs_display_add_draw_callback(preview->GetDisplay(), obs_display_add_draw_callback(preview->GetDisplay(),
OBSBasicProperties::DrawPreview, this); OBSBasicProperties::DrawPreview,
this);
}; };
auto addTransitionDrawCallback = [this] () auto addTransitionDrawCallback = [this]() {
{ obs_display_add_draw_callback(
obs_display_add_draw_callback(preview->GetDisplay(), preview->GetDisplay(),
OBSBasicProperties::DrawTransitionPreview, this); OBSBasicProperties::DrawTransitionPreview, this);
}; };
uint32_t caps = obs_source_get_output_flags(source); uint32_t caps = obs_source_get_output_flags(source);
bool drawable_type = type == OBS_SOURCE_TYPE_INPUT || bool drawable_type = type == OBS_SOURCE_TYPE_INPUT ||
type == OBS_SOURCE_TYPE_SCENE; type == OBS_SOURCE_TYPE_SCENE;
bool drawable_preview = (caps & OBS_SOURCE_VIDEO) != 0; bool drawable_preview = (caps & OBS_SOURCE_VIDEO) != 0;
if (drawable_preview && drawable_type) { if (drawable_preview && drawable_type) {
preview->show(); preview->show();
connect(preview.data(), &OBSQTDisplay::DisplayCreated, connect(preview.data(), &OBSQTDisplay::DisplayCreated,
addDrawCallback); addDrawCallback);
} else if (type == OBS_SOURCE_TYPE_TRANSITION) { } else if (type == OBS_SOURCE_TYPE_TRANSITION) {
sourceA = obs_source_create_private("scene", "sourceA", sourceA =
nullptr); obs_source_create_private("scene", "sourceA", nullptr);
sourceB = obs_source_create_private("scene", "sourceB", sourceB =
nullptr); obs_source_create_private("scene", "sourceB", nullptr);
obs_source_release(sourceA); obs_source_release(sourceA);
obs_source_release(sourceB); obs_source_release(sourceB);
@@ -166,7 +165,7 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
obs_data_t *settings = obs_source_get_settings(source); obs_data_t *settings = obs_source_get_settings(source);
sourceClone = obs_source_create_private( sourceClone = obs_source_create_private(
obs_source_get_id(source), "clone", settings); obs_source_get_id(source), "clone", settings);
obs_source_release(sourceClone); obs_source_release(sourceClone);
obs_source_inc_active(sourceClone); obs_source_inc_active(sourceClone);
@@ -174,8 +173,7 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
obs_data_release(settings); obs_data_release(settings);
auto updateCallback = [=]() auto updateCallback = [=]() {
{
obs_data_t *settings = obs_source_get_settings(source); obs_data_t *settings = obs_source_get_settings(source);
obs_source_update(sourceClone, settings); obs_source_update(sourceClone, settings);
@@ -210,15 +208,14 @@ OBSBasicProperties::~OBSBasicProperties()
void OBSBasicProperties::AddPreviewButton() void OBSBasicProperties::AddPreviewButton()
{ {
QPushButton *playButton = new QPushButton( QPushButton *playButton =
QTStr("PreviewTransition"), this); new QPushButton(QTStr("PreviewTransition"), this);
VScrollArea *area = view; VScrollArea *area = view;
area->widget()->layout()->addWidget(playButton); area->widget()->layout()->addWidget(playButton);
playButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); playButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
auto play = [=] () auto play = [=]() {
{
OBSSource start; OBSSource start;
OBSSource end; OBSSource end;
@@ -231,9 +228,8 @@ void OBSBasicProperties::AddPreviewButton()
} }
obs_transition_set(sourceClone, start); obs_transition_set(sourceClone, start);
obs_transition_start(sourceClone, obs_transition_start(sourceClone, OBS_TRANSITION_MODE_AUTO,
OBS_TRANSITION_MODE_AUTO, main->GetTransitionDuration(), end);
main->GetTransitionDuration(), end);
direction = !direction; direction = !direction;
start = nullptr; start = nullptr;
@@ -273,8 +269,8 @@ static obs_source_t *CreateLabel(const char *name, size_t h)
const char *text_source_id = "text_ft2_source"; const char *text_source_id = "text_ft2_source";
#endif #endif
obs_source_t *txtSource = obs_source_create_private(text_source_id, obs_source_t *txtSource =
name, settings); obs_source_create_private(text_source_id, name, settings);
obs_data_release(font); obs_data_release(font);
obs_data_release(settings); obs_data_release(settings);
@@ -289,21 +285,21 @@ static void CreateTransitionScene(OBSSource scene, char *text, uint32_t color)
obs_data_set_int(settings, "height", obs_source_get_height(scene)); obs_data_set_int(settings, "height", obs_source_get_height(scene));
obs_data_set_int(settings, "color", color); obs_data_set_int(settings, "color", color);
obs_source_t *colorBG = obs_source_create_private("color_source", obs_source_t *colorBG = obs_source_create_private(
"background", settings); "color_source", "background", settings);
obs_scene_add(obs_scene_from_source(scene), colorBG); obs_scene_add(obs_scene_from_source(scene), colorBG);
obs_source_t *label = CreateLabel(text, obs_source_get_height(scene)); obs_source_t *label = CreateLabel(text, obs_source_get_height(scene));
obs_sceneitem_t *item = obs_scene_add(obs_scene_from_source(scene), obs_sceneitem_t *item =
label); obs_scene_add(obs_scene_from_source(scene), label);
vec2 size; vec2 size;
vec2_set(&size, obs_source_get_width(scene), vec2_set(&size, obs_source_get_width(scene),
#ifdef _WIN32 #ifdef _WIN32
obs_source_get_height(scene)); obs_source_get_height(scene));
#else #else
obs_source_get_height(scene) * 0.8); obs_source_get_height(scene) * 0.8);
#endif #endif
obs_sceneitem_set_bounds(item, &size); obs_sceneitem_set_bounds(item, &size);
@@ -316,8 +312,8 @@ static void CreateTransitionScene(OBSSource scene, char *text, uint32_t color)
void OBSBasicProperties::SourceRemoved(void *data, calldata_t *params) void OBSBasicProperties::SourceRemoved(void *data, calldata_t *params)
{ {
QMetaObject::invokeMethod(static_cast<OBSBasicProperties*>(data), QMetaObject::invokeMethod(static_cast<OBSBasicProperties *>(data),
"close"); "close");
UNUSED_PARAMETER(params); UNUSED_PARAMETER(params);
} }
@@ -327,14 +323,14 @@ void OBSBasicProperties::SourceRenamed(void *data, calldata_t *params)
const char *name = calldata_string(params, "new_name"); const char *name = calldata_string(params, "new_name");
QString title = QTStr("Basic.PropertiesWindow").arg(QT_UTF8(name)); QString title = QTStr("Basic.PropertiesWindow").arg(QT_UTF8(name));
QMetaObject::invokeMethod(static_cast<OBSBasicProperties*>(data), QMetaObject::invokeMethod(static_cast<OBSBasicProperties *>(data),
"setWindowTitle", Q_ARG(QString, title)); "setWindowTitle", Q_ARG(QString, title));
} }
void OBSBasicProperties::UpdateProperties(void *data, calldata_t *) void OBSBasicProperties::UpdateProperties(void *data, calldata_t *)
{ {
QMetaObject::invokeMethod(static_cast<OBSBasicProperties*>(data)->view, QMetaObject::invokeMethod(static_cast<OBSBasicProperties *>(data)->view,
"ReloadProperties"); "ReloadProperties");
} }
void OBSBasicProperties::on_buttonBox_clicked(QAbstractButton *button) void OBSBasicProperties::on_buttonBox_clicked(QAbstractButton *button)
@@ -374,7 +370,7 @@ void OBSBasicProperties::on_buttonBox_clicked(QAbstractButton *button)
void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy) void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy)
{ {
OBSBasicProperties *window = static_cast<OBSBasicProperties*>(data); OBSBasicProperties *window = static_cast<OBSBasicProperties *>(data);
if (!window->source) if (!window->source)
return; return;
@@ -382,8 +378,8 @@ void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy)
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
int x, y; int x, y;
int newCX, newCY; int newCX, newCY;
float scale; float scale;
GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale); GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale);
@@ -393,8 +389,7 @@ void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy)
gs_viewport_push(); gs_viewport_push();
gs_projection_push(); gs_projection_push();
gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), -100.0f, 100.0f);
-100.0f, 100.0f);
gs_set_viewport(x, y, newCX, newCY); gs_set_viewport(x, y, newCX, newCY);
obs_source_video_render(window->source); obs_source_video_render(window->source);
@@ -404,9 +399,9 @@ void OBSBasicProperties::DrawPreview(void *data, uint32_t cx, uint32_t cy)
} }
void OBSBasicProperties::DrawTransitionPreview(void *data, uint32_t cx, void OBSBasicProperties::DrawTransitionPreview(void *data, uint32_t cx,
uint32_t cy) uint32_t cy)
{ {
OBSBasicProperties *window = static_cast<OBSBasicProperties*>(data); OBSBasicProperties *window = static_cast<OBSBasicProperties *>(data);
if (!window->source) if (!window->source)
return; return;
@@ -414,8 +409,8 @@ void OBSBasicProperties::DrawTransitionPreview(void *data, uint32_t cx,
uint32_t sourceCX = max(obs_source_get_width(window->source), 1u); uint32_t sourceCX = max(obs_source_get_width(window->source), 1u);
uint32_t sourceCY = max(obs_source_get_height(window->source), 1u); uint32_t sourceCY = max(obs_source_get_height(window->source), 1u);
int x, y; int x, y;
int newCX, newCY; int newCX, newCY;
float scale; float scale;
GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale); GetScaleAndCenterPos(sourceCX, sourceCY, cx, cy, x, y, scale);
@@ -425,8 +420,7 @@ void OBSBasicProperties::DrawTransitionPreview(void *data, uint32_t cx,
gs_viewport_push(); gs_viewport_push();
gs_projection_push(); gs_projection_push();
gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), gs_ortho(0.0f, float(sourceCX), 0.0f, float(sourceCY), -100.0f, 100.0f);
-100.0f, 100.0f);
gs_set_viewport(x, y, newCX, newCY); gs_set_viewport(x, y, newCX, newCY);
obs_source_video_render(window->sourceClone); obs_source_video_render(window->sourceClone);
@@ -438,13 +432,14 @@ void OBSBasicProperties::DrawTransitionPreview(void *data, uint32_t cx,
void OBSBasicProperties::Cleanup() void OBSBasicProperties::Cleanup()
{ {
config_set_int(App()->GlobalConfig(), "PropertiesWindow", "cx", config_set_int(App()->GlobalConfig(), "PropertiesWindow", "cx",
width()); width());
config_set_int(App()->GlobalConfig(), "PropertiesWindow", "cy", config_set_int(App()->GlobalConfig(), "PropertiesWindow", "cy",
height()); height());
obs_display_remove_draw_callback(preview->GetDisplay(), obs_display_remove_draw_callback(preview->GetDisplay(),
OBSBasicProperties::DrawPreview, this); OBSBasicProperties::DrawPreview, this);
obs_display_remove_draw_callback(preview->GetDisplay(), obs_display_remove_draw_callback(
preview->GetDisplay(),
OBSBasicProperties::DrawTransitionPreview, this); OBSBasicProperties::DrawTransitionPreview, this);
} }
@@ -497,11 +492,10 @@ bool OBSBasicProperties::ConfirmQuit()
{ {
QMessageBox::StandardButton button; QMessageBox::StandardButton button;
button = OBSMessageBox::question(this, button = OBSMessageBox::question(
QTStr("Basic.PropertiesWindow.ConfirmTitle"), this, QTStr("Basic.PropertiesWindow.ConfirmTitle"),
QTStr("Basic.PropertiesWindow.Confirm"), QTStr("Basic.PropertiesWindow.Confirm"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
QMessageBox::Cancel);
switch (button) { switch (button) {
case QMessageBox::Save: case QMessageBox::Save:
Loaded 100 of 565 files, more files were not shown because too many files have changed in this diff. Show more