0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00

UI: Replace/simplify device toolbar

The old version of the device toolbar was a complex situation.  Because
of the fact that device properties can take significant time to query,
this put an unpleasant burden on the UI thread; so to fix this problem,
the device toolbar was made to be threaded.  However, threading is a
complex and dangerous thing, and there is a fear that this could cause
complications down the line whenever users are simply selecting devices.

So for the time being, as a safety precaution, simplify the device
toolbar down to just the "activate" button, and make it so that if users
really need to query and change the devices, that they need to
explicitly open the properties.  That way the devices aren't being
queried constantly every time a device source is selected.

Alternatively in the future, device enumeration could be cached, but
seeing as that's a significant amount of work and needs to take in to
account whether a user adds/removes a device while the process is
active, that's not going to happen any time soon.
This commit is contained in:
jp9000 2020-09-07 16:14:30 -07:00
parent 072a886453
commit 50d3130b64
6 changed files with 64 additions and 186 deletions

View File

@ -238,7 +238,6 @@ 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
@ -306,7 +305,6 @@ 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

View File

@ -1,149 +0,0 @@
#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<DeviceCaptureToolbar *>(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
}

View File

@ -1,25 +0,0 @@
#pragma once
#include <obs.hpp>
#include <string>
#include <QThread>
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();
};

View File

@ -255,6 +255,65 @@ void DisplayCaptureToolbar::Init()
/* ========================================================================= */
DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source)
: QWidget(parent),
weakSource(OBSGetWeakRef(source)),
ui(new Ui_DeviceSelectToolbar)
{
ui->setupUi(this);
delete ui->deviceLabel;
delete ui->device;
ui->deviceLabel = nullptr;
ui->device = nullptr;
obs_data_t *settings = obs_source_get_settings(source);
active = obs_data_get_bool(settings, "active");
obs_data_release(settings);
obs_module_t *mod = obs_get_module("win-dshow");
activateText = obs_module_get_locale_text(mod, "Activate");
deactivateText = obs_module_get_locale_text(mod, "Deactivate");
ui->activateButton->setText(active ? deactivateText : activateText);
}
DeviceCaptureToolbar::~DeviceCaptureToolbar()
{
delete ui;
}
void DeviceCaptureToolbar::on_activateButton_clicked()
{
OBSSource source = OBSGetStrongRef(weakSource);
if (!source) {
return;
}
obs_data_t *settings = obs_source_get_settings(source);
bool now_active = obs_data_get_bool(settings, "active");
obs_data_release(settings);
bool desyncedSetting = now_active != active;
active = !active;
const char *text = active ? deactivateText : activateText;
ui->activateButton->setText(text);
if (desyncedSetting) {
return;
}
calldata_t cd = {};
calldata_set_bool(&cd, "active", active);
proc_handler_t *ph = obs_source_get_proc_handler(source);
proc_handler_call(ph, "activate", &cd);
calldata_free(&cd);
}
/* ========================================================================= */
GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source)
: SourceToolbar(parent, source), ui(new Ui_GameCaptureToolbar)
{

View File

@ -90,20 +90,17 @@ class DeviceCaptureToolbar : public QWidget {
Q_OBJECT
OBSWeakSource weakSource;
Ui_DeviceSelectToolbar *ui;
obs_properties_t *props = nullptr;
const char *prop_name;
void UpdateActivateButtonName();
Ui_DeviceSelectToolbar *ui;
const char *activateText;
const char *deactivateText;
bool active;
public:
DeviceCaptureToolbar(QWidget *parent, OBSSource source);
~DeviceCaptureToolbar();
void SetProperties(obs_properties_t *prpos);
public slots:
void on_device_currentIndexChanged(int idx);
void on_activateButton_clicked();
};

View File

@ -2966,9 +2966,7 @@ void OBSBasic::UpdateContextBar()
c->Init();
ui->emptySpace->layout()->addWidget(c);
} else if (strcmp(id, "dshow_input") == 0 ||
strcmp(id, "av_capture_input") == 0 ||
strcmp(id, "v4l2_input") == 0) {
} else if (strcmp(id, "dshow_input") == 0) {
DeviceCaptureToolbar *c = new DeviceCaptureToolbar(
ui->emptySpace, source);
ui->emptySpace->layout()->addWidget(c);