}
connect(ui->grab_btn, &QPushButton::clicked, bind(&Analyzer::grab_clicked, this));
- //ui->display->set_output(Mixer::OUTPUT_LIVE);
+ connect(ui->input_box, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), bind(&Analyzer::signal_changed, this));
+ signal_changed();
+
surface = create_surface(QSurfaceFormat::defaultFormat());
context = create_context(surface);
check_error();
}
+void Analyzer::signal_changed()
+{
+ Mixer::Output channel = static_cast<Mixer::Output>(ui->input_box->currentData().value<int>());
+ ui->display->set_output(channel);
+}
private:
void grab_clicked();
+ void signal_changed();
Ui::Analyzer *ui;
QSurface *surface;
{
}
+GLWidget::~GLWidget()
+{
+ global_mixer->remove_frame_ready_callback(output, this);
+}
+
void GLWidget::clean_context()
{
if (resource_pool != nullptr) {
global_mainwindow->mixer_created(global_mixer);
global_mixer->start();
});
- global_mixer->set_frame_ready_callback(output, [this]{
+ global_mixer->add_frame_ready_callback(output, this, [this]{
QMetaObject::invokeMethod(this, "update", Qt::AutoConnection);
});
if (output == Mixer::OUTPUT_LIVE) {
public:
GLWidget(QWidget *parent = 0);
+ ~GLWidget();
void set_output(Mixer::Output output)
{
}
ready_frame = frame;
has_ready_frame = true;
- }
- if (new_frame_ready_callback) {
- new_frame_ready_callback();
+ // Call the callbacks under the mutex (they should be short),
+ // so that we don't race against a callback removal.
+ for (const auto &key_and_callback : new_frame_ready_callbacks) {
+ key_and_callback.second();
+ }
}
// Reduce the number of callbacks by filtering duplicates. The reason
return true;
}
-void Mixer::OutputChannel::set_frame_ready_callback(Mixer::new_frame_ready_callback_t callback)
+void Mixer::OutputChannel::add_frame_ready_callback(void *key, Mixer::new_frame_ready_callback_t callback)
{
- new_frame_ready_callback = callback;
+ unique_lock<mutex> lock(frame_mutex);
+ new_frame_ready_callbacks[key] = callback;
+}
+
+void Mixer::OutputChannel::remove_frame_ready_callback(void *key)
+{
+ unique_lock<mutex> lock(frame_mutex);
+ new_frame_ready_callbacks.erase(key);
}
void Mixer::OutputChannel::set_transition_names_updated_callback(Mixer::transition_names_updated_callback_t callback)
return output_channel[output].get_display_frame(frame);
}
+ // NOTE: Callbacks will be called with a mutex held, so you should probably
+ // not do real work in them.
typedef std::function<void()> new_frame_ready_callback_t;
- void set_frame_ready_callback(Output output, new_frame_ready_callback_t callback)
+ void add_frame_ready_callback(Output output, void *key, new_frame_ready_callback_t callback)
{
- output_channel[output].set_frame_ready_callback(callback);
+ output_channel[output].add_frame_ready_callback(key, callback);
+ }
+
+ void remove_frame_ready_callback(Output output, void *key)
+ {
+ output_channel[output].remove_frame_ready_callback(key);
}
// TODO: Should this really be per-channel? Shouldn't it just be called for e.g. the live output?
~OutputChannel();
void output_frame(DisplayFrame frame);
bool get_display_frame(DisplayFrame *frame);
- void set_frame_ready_callback(new_frame_ready_callback_t callback);
+ void add_frame_ready_callback(void *key, new_frame_ready_callback_t callback);
+ void remove_frame_ready_callback(void *key);
void set_transition_names_updated_callback(transition_names_updated_callback_t callback);
void set_name_updated_callback(name_updated_callback_t callback);
void set_color_updated_callback(color_updated_callback_t callback);
std::mutex frame_mutex;
DisplayFrame current_frame, ready_frame; // protected by <frame_mutex>
bool has_current_frame = false, has_ready_frame = false; // protected by <frame_mutex>
- new_frame_ready_callback_t new_frame_ready_callback;
+ std::map<void *, new_frame_ready_callback_t> new_frame_ready_callbacks; // protected by <frame_mutex>
transition_names_updated_callback_t transition_names_updated_callback;
name_updated_callback_t name_updated_callback;
color_updated_callback_t color_updated_callback;
<property name="windowTitle">
<string>Dialog</string>
</property>
+ <widget class="GLWidget" name="display" native="true">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>320</width>
+ <height>180</height>
+ </rect>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background: rgb(233, 185, 110)</string>
+ </property>
+ </widget>
<widget class="QComboBox" name="input_box">
<property name="geometry">
<rect>
</property>
</widget>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>GLWidget</class>
+ <extends>QWidget</extends>
+ <header>glwidget.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>