/***
This file is part of pavucontrol.
Copyright 2006-2008 Lennart Poettering
Copyright 2009 Colin Guthrie
pavucontrol is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
pavucontrol is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with pavucontrol. If not, see .
***/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "mainwindow.h"
#include "devicewidget.h"
#include "channel.h"
#include
#include
#include
#include
#include
/*** DeviceWidget ***/
DeviceWidget::DeviceWidget(MainWindow* parent, QByteArray deviceType) :
MinimalStreamWidget(parent),
offsetButtonEnabled(false),
mpMainWindow(parent),
rename{new QAction{tr("Rename device..."), this}},
mDeviceType(deviceType) {
setupUi(this);
advancedWidget->hide();
initPeakProgressBar(channelsGrid);
timeout.setSingleShot(true);
timeout.setInterval(100);
connect(&timeout, &QTimer::timeout, this, &DeviceWidget::timeoutEvent);
connect(muteToggleButton, &QToolButton::toggled, this, &DeviceWidget::onMuteToggleButton);
connect(lockToggleButton, &QToolButton::toggled, this, &DeviceWidget::onLockToggleButton);
connect(defaultToggleButton, &QToolButton::toggled, this, &DeviceWidget::onDefaultToggleButton);
connect(rename, &QAction::triggered, this, &DeviceWidget::renamePopup);
addAction(rename);
setContextMenuPolicy(Qt::ActionsContextMenu);
connect(portList, static_cast(&QComboBox::currentIndexChanged), this, &DeviceWidget::onPortChange);
connect(offsetButton, static_cast(&QSpinBox::valueChanged), this, &DeviceWidget::onOffsetChange);
for (auto & channel : channels)
channel = nullptr;
// FIXME:
// offsetAdjustment = Gtk::Adjustment::create(0.0, -2000.0, 2000.0, 10.0, 50.0, 0.0);
// offsetButton->configure(offsetAdjustment, 0, 2);
}
void DeviceWidget::setChannelMap(const pa_channel_map &m, bool can_decibel) {
channelMap = m;
for (int i = 0; i < m.channels; i++) {
Channel *ch = channels[i] = new Channel(channelsGrid);
ch->channel = i;
ch->can_decibel = can_decibel;
ch->minimalStreamWidget = this;
char text[64];
snprintf(text, sizeof(text), "%s", pa_channel_position_to_pretty_string(m.map[i]));
ch->channelLabel->setText(QString::fromUtf8(text));
}
channels[m.channels-1]->last = true;
lockToggleButton->setEnabled(m.channels > 1);
hideLockedChannels(lockToggleButton->isChecked());
}
void DeviceWidget::setVolume(const pa_cvolume &v, bool force) {
g_assert(v.channels == channelMap.channels);
volume = v;
if (!timeout.isActive() || force) { /* do not update the volume when a volume change is still in flux */
for (int i = 0; i < volume.channels; i++)
channels[i]->setVolume(volume.values[i]);
}
}
void DeviceWidget::updateChannelVolume(int channel, pa_volume_t v) {
pa_cvolume n;
g_assert(channel < volume.channels);
n = volume;
if (lockToggleButton->isChecked())
pa_cvolume_set(&n, n.channels, v);
else
n.values[channel] = v;
setVolume(n, true);
if (!timeout.isActive()) {
timeout.start();
}
}
void DeviceWidget::hideLockedChannels(bool hide) {
for (int i = 0; i < channelMap.channels - 1; i++)
channels[i]->setVisible(!hide);
channels[channelMap.channels - 1]->channelLabel->setVisible(!hide);
}
void DeviceWidget::onMuteToggleButton() {
lockToggleButton->setEnabled(!muteToggleButton->isChecked());
for (int i = 0; i < channelMap.channels; i++)
channels[i]->setEnabled(!muteToggleButton->isChecked());
}
void DeviceWidget::onLockToggleButton() {
hideLockedChannels(lockToggleButton->isChecked());
}
void DeviceWidget::onDefaultToggleButton() {
}
void DeviceWidget::onOffsetChange() {
pa_operation *o;
int64_t offset;
std::ostringstream card_stream;
QByteArray card_name;
if (!offsetButtonEnabled)
return;
offset = offsetButton->value() * 1000.0;
card_stream << card_index;
card_name = QByteArray::fromStdString(card_stream.str());
if (!(o = pa_context_set_port_latency_offset(get_context(),
card_name.constData(), activePort.constData(), offset, nullptr, nullptr))) {
show_error(tr("pa_context_set_port_latency_offset() failed").toUtf8().constData());
return;
}
pa_operation_unref(o);
}
void DeviceWidget::setDefault(bool isDefault) {
defaultToggleButton->setChecked(isDefault);
/*defaultToggleButton->setEnabled(!isDefault);*/
}
bool DeviceWidget::timeoutEvent() {
executeVolumeUpdate();
return false;
}
void DeviceWidget::executeVolumeUpdate() {
}
void DeviceWidget::setLatencyOffset(int64_t offset) {
offsetButtonEnabled = false;
offsetButton->setValue(offset / 1000.0);
offsetButtonEnabled = true;
}
void DeviceWidget::setBaseVolume(pa_volume_t v) {
for (int i = 0; i < channelMap.channels; i++)
channels[i]->setBaseVolume(v);
}
void DeviceWidget::prepareMenu() {
int idx = 0;
int active_idx = -1;
portList->clear();
/* Fill the ComboBox's Model */
for (auto & port : ports) {
QByteArray name = port.first;
QString desc = QString::fromUtf8(port.second);
portList->addItem(desc, name);
if (port.first == activePort)
active_idx = idx;
idx++;
}
if (active_idx >= 0)
portList->setCurrentIndex(active_idx);
if (!ports.empty()) {
portSelect->show();
if (pa_context_get_server_protocol_version(get_context()) >= 27) {
offsetSelect->show();
advancedOptions->setEnabled(true);
} else {
/* advancedOptions has sensitive=false by default */
offsetSelect->hide();
}
} else {
portSelect->hide();
advancedOptions->setEnabled(false);
offsetSelect->hide();
}
}
void DeviceWidget::renamePopup() {
if (updating)
return;
if (!mpMainWindow->canRenameDevices) {
QMessageBox::warning(this, tr("Sorry, but device renaming is not supported.")
, tr("You need to load module-device-manager in the PulseAudio server in order to rename devices"));
return;
}
const QString old_name = QString::fromUtf8(description);
bool ok;
const QString new_name = QInputDialog::getText(this, QCoreApplication::organizationName(), tr("Rename device %1 to:").arg(old_name)
, QLineEdit::Normal, old_name, &ok);
if (ok && new_name != old_name) {
pa_operation* o;
gchar *key = g_markup_printf_escaped("%s:%s", mDeviceType.constData(), name.constData());
if (!(o = pa_ext_device_manager_set_device_description(get_context(), key, new_name.toUtf8().constData(), nullptr, nullptr)))
show_error(tr("pa_ext_device_manager_set_device_description() failed").toUtf8().constData());
else
pa_operation_unref(o);
g_free(key);
}
}