It can happen that devices can be selected but not used
(permissions problems, connection issues, driver issues, etc.),
so in those cases we want to fail gracefully instead of
segfaulting.
The reason for the segfault is the device selector button
isn't reset in case the device couldn't be opened, causing
the rest of the application to try and work with a device
instance that is actually invalid.
Resetting the device selector when the device failed to
open not only fixes this but also makes the UI more
consistent with the internal state.
{
// Set the title to include the device/file name
const shared_ptr<devices::Device> device = session_.device();
{
// Set the title to include the device/file name
const shared_ptr<devices::Device> device = session_.device();
+
+ if (!device) {
+ main_bar_->reset_device_selector();
const string display_name = device->display_name(device_manager_);
setWindowTitle(tr("%1 - PulseView").arg(display_name.c_str()));
const string display_name = device->display_name(device_manager_);
setWindowTitle(tr("%1 - PulseView").arg(display_name.c_str()));
signals_changed();
device_ = std::move(device);
signals_changed();
device_ = std::move(device);
+
+ try {
+ device_->open();
+ } catch (const QString &e) {
+ device_.reset();
+ device_selected();
+ throw;
+ }
+
device_->session()->add_datafeed_callback([=]
(shared_ptr<sigrok::Device> device, shared_ptr<Packet> packet) {
data_feed_in(device, packet);
device_->session()->add_datafeed_callback([=]
(shared_ptr<sigrok::Device> device, shared_ptr<Packet> packet) {
data_feed_in(device, packet);
sample_rate_.setEnabled(ui_enabled);
}
sample_rate_.setEnabled(ui_enabled);
}
+void MainBar::reset_device_selector()
+{
+ device_selector_.reset();
+}
+
void MainBar::update_sample_rate_selector()
{
Glib::VariantContainerBase gvar_dict;
void MainBar::update_sample_rate_selector()
{
Glib::VariantContainerBase gvar_dict;
void set_capture_state(pv::Session::capture_state state);
void set_capture_state(pv::Session::capture_state state);
+ void reset_device_selector();
+
private:
void update_sample_rate_selector();
void update_sample_rate_selector_value();
private:
void update_sample_rate_selector();
void update_sample_rate_selector_value();
{
selected_device_ = selected;
setText(selected ? QString::fromStdString(
{
selected_device_ = selected;
setText(selected ? QString::fromStdString(
- selected->display_name(device_manager_)) : "<No Device>");
+ selected->display_name(device_manager_)) : tr("<No Device>"));
devices_ = vector< weak_ptr<Device> >(devices.begin(), devices.end());
update_device_list();
}
devices_ = vector< weak_ptr<Device> >(devices.begin(), devices.end());
update_device_list();
}
+void DeviceToolButton::reset()
+{
+ setText(tr("<No Device>"));
+ selected_device_.reset();
+ update_device_list();
+}
+
void DeviceToolButton::update_device_list()
{
menu_.clear();
void DeviceToolButton::update_device_list()
{
menu_.clear();
+ selected_device_.reset();
+
Device *const dev = (Device*)((QAction*)action)->data().value<void*>();
for (weak_ptr<Device> dev_weak_ptr : devices_) {
shared_ptr<Device> dev_ptr(dev_weak_ptr);
Device *const dev = (Device*)((QAction*)action)->data().value<void*>();
for (weak_ptr<Device> dev_weak_ptr : devices_) {
shared_ptr<Device> dev_ptr(dev_weak_ptr);
const std::list< std::shared_ptr<devices::Device> > &devices,
std::shared_ptr<devices::Device> selected);
const std::list< std::shared_ptr<devices::Device> > &devices,
std::shared_ptr<devices::Device> selected);
+ /**
+ * Sets the current device to "no device". Useful for when a selected
+ * device fails to open.
+ */
+ void reset();
+
private:
/**
* Repopulates the menu from the device list.
private:
/**
* Repopulates the menu from the device list.