diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt index df4d26450..964947069 100644 --- a/UI/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -238,6 +238,7 @@ set(obs_SOURCES item-widget-helpers.cpp context-bar-controls.cpp horizontal-scroll-area.cpp + context-bar-controls-devices.cpp vertical-scroll-area.cpp visibility-item-widget.cpp slider-absoluteset-style.cpp @@ -305,6 +306,7 @@ set(obs_HEADERS item-widget-helpers.hpp visibility-checkbox.hpp context-bar-controls.hpp + context-bar-controls-devices.hpp locked-checkbox.hpp horizontal-scroll-area.hpp expand-checkbox.hpp diff --git a/UI/context-bar-controls-devices.cpp b/UI/context-bar-controls-devices.cpp new file mode 100644 index 000000000..c9a6b607f --- /dev/null +++ b/UI/context-bar-controls-devices.cpp @@ -0,0 +1,149 @@ +#include "context-bar-controls.hpp" +#include "context-bar-controls-devices.hpp" +#include "window-basic-main.hpp" + +#include "ui_device-select-toolbar.h" + +#ifdef _WIN32 +#define get_os_module(win, mac, linux) obs_get_module(win) +#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win) +#elif __APPLE__ +#define get_os_module(win, mac, linux) obs_get_module(mac) +#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac) +#else +#define get_os_module(win, mac, linux) obs_get_module(linux) +#define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux) +#endif + +/* ========================================================================= */ + +DeviceToolbarPropertiesThread::~DeviceToolbarPropertiesThread() +{ + obs_properties_destroy(props); +} + +void DeviceToolbarPropertiesThread::run() +{ + props = obs_source_properties(source); + source = nullptr; + QMetaObject::invokeMethod(this, "Ready"); +} + +void DeviceToolbarPropertiesThread::Ready() +{ + OBSBasic *main = OBSBasic::Get(); + QLayoutItem *la = main->ui->emptySpace->layout()->itemAt(0); + if (la) { + DeviceCaptureToolbar *dct = + qobject_cast(la->widget()); + if (dct) { + dct->SetProperties(props); + props = nullptr; + } + } +} + +/* ========================================================================= */ + +DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) + : QWidget(parent), + weakSource(OBSGetWeakRef(source)), + ui(new Ui_DeviceSelectToolbar) +{ + ui->setupUi(this); + +#ifndef _WIN32 + delete ui->activateButton; + ui->activateButton = nullptr; +#endif + + setEnabled(false); + + obs_module_t *mod = + get_os_module("win-dshow", "mac-avcapture", "linux-v4l2"); + const char *device_str = obs_module_get_locale_text(mod, "Device"); + ui->deviceLabel->setText(device_str); + + OBSBasic *main = OBSBasic::Get(); + if (!main->devicePropertiesThread || + !main->devicePropertiesThread->isRunning()) { + main->devicePropertiesThread.reset( + new DeviceToolbarPropertiesThread(source)); + main->devicePropertiesThread->start(); + } +} + +DeviceCaptureToolbar::~DeviceCaptureToolbar() +{ + delete ui; + obs_properties_destroy(props); +} + +void DeviceCaptureToolbar::UpdateActivateButtonName() +{ + obs_property_t *p = obs_properties_get(props, "activate"); + ui->activateButton->setText(obs_property_description(p)); +} + +extern void UpdateSourceComboToolbarProperties(QComboBox *combo, + OBSSource source, + obs_properties_t *props, + const char *prop_name, + bool is_int); +extern void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, + int idx, const char *prop_name, + bool is_int); + +void DeviceCaptureToolbar::SetProperties(obs_properties_t *props_) +{ + OBSSource source = OBSGetStrongRef(weakSource); + if (!source) { + obs_properties_destroy(props_); + return; + } + +#ifdef _WIN32 + prop_name = "video_device_id"; +#elif __APPLE__ + prop_name = "device"; +#else + prop_name = "device_id"; +#endif + + props = props_; + UpdateSourceComboToolbarProperties(ui->device, source, props, prop_name, + false); +#ifdef _WIN32 + UpdateActivateButtonName(); +#endif + setEnabled(true); +} + +void DeviceCaptureToolbar::on_device_currentIndexChanged(int idx) +{ + OBSSource source = OBSGetStrongRef(weakSource); + if (idx == -1 || !source) { + return; + } + + UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name, + false); +} + +void DeviceCaptureToolbar::on_activateButton_clicked() +{ + OBSSource source = OBSGetStrongRef(weakSource); + if (!source) { + return; + } + + obs_property_t *p = obs_properties_get(props, "activate"); + if (!p) { + return; + } + + obs_property_button_clicked(p, source.Get()); +#ifdef _WIN32 + UpdateActivateButtonName(); +#endif +} diff --git a/UI/context-bar-controls-devices.hpp b/UI/context-bar-controls-devices.hpp new file mode 100644 index 000000000..60a054a81 --- /dev/null +++ b/UI/context-bar-controls-devices.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +class DeviceToolbarPropertiesThread : public QThread { + Q_OBJECT + + OBSSource source; + obs_properties_t *props; + + void run() override; + +public: + inline DeviceToolbarPropertiesThread(OBSSource source_) + : source(source_) + { + } + + ~DeviceToolbarPropertiesThread() override; + +public slots: + void Ready(); +}; diff --git a/UI/context-bar-controls.cpp b/UI/context-bar-controls.cpp index d9916b6c0..72486d4d9 100644 --- a/UI/context-bar-controls.cpp +++ b/UI/context-bar-controls.cpp @@ -152,12 +152,6 @@ void ComboSelectToolbar::Init() prop_name, is_int); } -void ComboSelectToolbar::UpdateActivateButtonName() -{ - obs_property_t *p = obs_properties_get(props.get(), "activate"); - ui->activateButton->setText(obs_property_description(p)); -} - void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx, const char *prop_name, bool is_int) { @@ -184,22 +178,6 @@ void ComboSelectToolbar::on_device_currentIndexChanged(int idx) is_int); } -void ComboSelectToolbar::on_activateButton_clicked() -{ - OBSSource source = GetSource(); - if (!source) { - return; - } - - obs_property_t *p = obs_properties_get(props.get(), "activate"); - if (!p) { - return; - } - - obs_property_button_clicked(p, source.Get()); - UpdateActivateButtonName(); -} - AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source) : ComboSelectToolbar(parent, source) { @@ -278,38 +256,6 @@ void DisplayCaptureToolbar::Init() ComboSelectToolbar::Init(); } -DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source) - : ComboSelectToolbar(parent, source) -{ -} - -void DeviceCaptureToolbar::Init() -{ -#ifndef _WIN32 - delete ui->activateButton; - ui->activateButton = nullptr; -#endif - - obs_module_t *mod = - get_os_module("win-dshow", "mac-avcapture", "linux-v4l2"); - const char *device_str = obs_module_get_locale_text(mod, "Device"); - ui->deviceLabel->setText(device_str); - -#ifdef _WIN32 - prop_name = "video_device_id"; -#elif __APPLE__ - prop_name = "device"; -#else - prop_name = "device_id"; -#endif - -#ifdef _WIN32 - UpdateActivateButtonName(); -#endif - - ComboSelectToolbar::Init(); -} - /* ========================================================================= */ GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source) diff --git a/UI/context-bar-controls.hpp b/UI/context-bar-controls.hpp index 1c03beca6..57c63c35a 100644 --- a/UI/context-bar-controls.hpp +++ b/UI/context-bar-controls.hpp @@ -53,8 +53,6 @@ protected: const char *prop_name; bool is_int = false; - void UpdateActivateButtonName(); - public: ComboSelectToolbar(QWidget *parent, OBSSource source); ~ComboSelectToolbar(); @@ -62,7 +60,6 @@ public: public slots: void on_device_currentIndexChanged(int idx); - void on_activateButton_clicked(); }; class AudioCaptureToolbar : public ComboSelectToolbar { @@ -89,12 +86,25 @@ public: void Init() override; }; -class DeviceCaptureToolbar : public ComboSelectToolbar { +class DeviceCaptureToolbar : public QWidget { Q_OBJECT + OBSWeakSource weakSource; + Ui_DeviceSelectToolbar *ui; + obs_properties_t *props = nullptr; + const char *prop_name; + + void UpdateActivateButtonName(); + public: DeviceCaptureToolbar(QWidget *parent, OBSSource source); - void Init() override; + ~DeviceCaptureToolbar(); + + void SetProperties(obs_properties_t *prpos); + +public slots: + void on_device_currentIndexChanged(int idx); + void on_activateButton_clicked(); }; class GameCaptureToolbar : public SourceToolbar { diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 1a9bb4e4e..788721215 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -908,6 +908,13 @@ void OBSBasic::Load(const char *file) InitDefaultTransitions(); ClearContextBar(); + if (devicePropertiesThread && devicePropertiesThread->isRunning()) { + devicePropertiesThread->wait(); + devicePropertiesThread.reset(); + } + + QApplication::sendPostedEvents(this); + obs_data_t *modulesObj = obs_data_get_obj(data, "modules"); if (api) api->on_preload(modulesObj); @@ -2951,7 +2958,6 @@ void OBSBasic::UpdateContextBar() strcmp(id, "v4l2_input") == 0) { DeviceCaptureToolbar *c = new DeviceCaptureToolbar( ui->emptySpace, source); - c->Init(); ui->emptySpace->layout()->addWidget(c); } else if (strcmp(id, "game_capture") == 0) { @@ -4193,6 +4199,12 @@ void OBSBasic::closeEvent(QCloseEvent *event) updateCheckThread->wait(); if (logUploadThread) logUploadThread->wait(); + if (devicePropertiesThread && devicePropertiesThread->isRunning()) { + devicePropertiesThread->wait(); + devicePropertiesThread.reset(); + } + + QApplication::sendPostedEvents(this); signalHandlers.clear(); diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index c14b3f27b..0296e512d 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -163,6 +163,8 @@ class OBSBasic : public OBSMainWindow { friend class ReplayBufferButton; friend class ExtraBrowsersModel; friend class ExtraBrowsersDelegate; + friend class DeviceCaptureToolbar; + friend class DeviceToolbarPropertiesThread; friend struct BasicOutputHandler; friend struct OBSStudioAPI; @@ -198,6 +200,7 @@ private: bool copyVisible = true; bool closing = false; + QScopedPointer devicePropertiesThread; QScopedPointer whatsNewInitThread; QScopedPointer updateCheckThread; QScopedPointer introCheckThread;