diff --git a/meson.build b/meson.build index 0d72ca1..d6e410d 100644 --- a/meson.build +++ b/meson.build @@ -1,16 +1,16 @@ project('pavucontrol', 'cpp', version : '5.0', meson_version : '>= 0.50.0', - default_options : [ 'c_std=gnu11', 'cpp_std=c++11' ] + default_options : [ 'c_std=gnu11', 'cpp_std=c++17' ] ) with_lynx = get_option('lynx') cpp = meson.get_compiler('cpp') -gtkmm_dep = dependency('gtkmm-3.0', version : '>= 3.0', required : true) +gtkmm_dep = dependency('gtkmm-4.0', version : '>= 4.0', required : true) sigcpp_dep = dependency('sigc++-2.0', required : true) -canberragtk_dep = dependency('libcanberra-gtk3', version : '>= 0.16', required : true) +canberragtk_dep = dependency('libcanberra', version : '>= 0.16', required : true) libpulse_dep = dependency('libpulse', version : '>= 5.0', required : true) libpulsemlglib_dep = dependency('libpulse-mainloop-glib', version : '>= 0.9.16', required : true) diff --git a/src/cardwidget.cc b/src/cardwidget.cc index d751fd2..bdacdaa 100644 --- a/src/cardwidget.cc +++ b/src/cardwidget.cc @@ -28,14 +28,14 @@ /*** CardWidget ***/ CardWidget::CardWidget(BaseObjectType* cobject, const Glib::RefPtr& x) : - Gtk::VBox(cobject) { + Gtk::Box(cobject) { - x->get_widget("cardNameLabel", nameLabel); - x->get_widget("profileList", profileList); - x->get_widget("cardIconImage", iconImage); - x->get_widget("codecBox", codecBox); - x->get_widget("codecList", codecList); - x->get_widget("profileLockToggleButton", profileLockToggleButton); + nameLabel = x->get_widget("cardNameLabel"); + profileList = x->get_widget("profileList"); + iconImage = x->get_widget("cardIconImage"); + codecBox = x->get_widget("codecBox"); + codecList = x->get_widget("codecList"); + profileLockToggleButton = x->get_widget("profileLockToggleButton"); profileListStore = Gtk::ListStore::create(profileModel); profileList->set_model(profileListStore); @@ -61,7 +61,7 @@ CardWidget::CardWidget(BaseObjectType* cobject, const Glib::RefPtr CardWidget* CardWidget::create() { CardWidget* w; Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "cardWidget"); - x->get_widget_derived("cardWidget", w); + w = Gtk::Builder::get_widget_derived(x, "cardWidget"); w->reference(); return w; } @@ -123,7 +123,7 @@ void CardWidget::onProfileChange() { Glib::ustring profile = row[profileModel.name]; if (!(o = pa_context_set_card_profile_by_index(get_context(), index, profile.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_card_profile_by_index() failed")); + show_error(this, _("pa_context_set_card_profile_by_index() failed")); return; } diff --git a/src/cardwidget.h b/src/cardwidget.h index 3c86659..fcaacdd 100644 --- a/src/cardwidget.h +++ b/src/cardwidget.h @@ -34,13 +34,12 @@ public: std::vector profiles; }; -class CardWidget : public Gtk::VBox { +class CardWidget : public Gtk::Box { public: CardWidget(BaseObjectType* cobject, const Glib::RefPtr& x); static CardWidget* create(); Gtk::Label *nameLabel; - Gtk::Menu menu; Gtk::Image *iconImage; Glib::ustring name; std::string pulse_card_name; diff --git a/src/channelwidget.cc b/src/channelwidget.cc index f141009..87c494b 100644 --- a/src/channelwidget.cc +++ b/src/channelwidget.cc @@ -30,14 +30,14 @@ /*** ChannelWidget ***/ ChannelWidget::ChannelWidget(BaseObjectType* cobject, const Glib::RefPtr& x) : - Gtk::EventBox(cobject), + Gtk::Widget(cobject), can_decibel(false), volumeScaleEnabled(true), last(false) { - x->get_widget("channelLabel", channelLabel); - x->get_widget("volumeLabel", volumeLabel); - x->get_widget("volumeScale", volumeScale); + channelLabel = x->get_widget("channelLabel"); + volumeLabel = x->get_widget("volumeLabel"); + volumeScale = x->get_widget("volumeScale"); volumeScale->set_range((double)PA_VOLUME_MUTED, (double)PA_VOLUME_UI_MAX); volumeScale->set_value((double)PA_VOLUME_NORM); @@ -52,7 +52,7 @@ ChannelWidget* ChannelWidget::createOne(MinimalStreamWidget *owner, int channelI Glib::RefPtr x = Gtk::Builder::create(); x->add_from_file(GLADE_FILE, "adjustment1"); x->add_from_file(GLADE_FILE, "channelWidget"); - x->get_widget_derived("channelWidget", w); + w = Gtk::Builder::get_widget_derived(x, "channelWidget"); w->reference(); w->channel = channelIndex; @@ -75,8 +75,8 @@ void ChannelWidget::create(MinimalStreamWidget *owner, const pa_channel_map &m, Gtk::Requisition minimumSize; Gtk::Requisition naturalSize; widgets[i]->channelLabel->get_preferred_size(minimumSize, naturalSize); - if (naturalSize.width > maxLabelWidth) - maxLabelWidth = naturalSize.width; + if (naturalSize.get_width() > maxLabelWidth) + maxLabelWidth = naturalSize.get_width(); } widgets[m.channels - 1]->last = true; @@ -108,6 +108,7 @@ void ChannelWidget::setVolume(pa_volume_t volume) { volumeScaleEnabled = false; volumeScale->set_value(volume > PA_VOLUME_UI_MAX ? PA_VOLUME_UI_MAX : volume); + currentVolume = volumeScale->get_value(); volumeScaleEnabled = true; } @@ -120,11 +121,12 @@ void ChannelWidget::onVolumeScaleValueChanged() { return; pa_volume_t volume = (pa_volume_t) volumeScale->get_value(); - minimalStreamWidget->updateChannelVolume(channel, volume); + if (volume != currentVolume) + minimalStreamWidget->updateChannelVolume(channel, volume); } void ChannelWidget::set_sensitive(bool enabled) { - Gtk::EventBox::set_sensitive(enabled); + Gtk::Widget::set_sensitive(enabled); channelLabel->set_sensitive(enabled); volumeLabel->set_sensitive(enabled); diff --git a/src/channelwidget.h b/src/channelwidget.h index 6216b74..d09c6ec 100644 --- a/src/channelwidget.h +++ b/src/channelwidget.h @@ -25,7 +25,7 @@ class MinimalStreamWidget; -class ChannelWidget : public Gtk::EventBox { +class ChannelWidget : public Gtk::Widget { public: ChannelWidget(BaseObjectType* cobject, const Glib::RefPtr& x); @@ -53,6 +53,7 @@ public: virtual void setBaseVolume(pa_volume_t); private: + pa_volume_t currentVolume; static ChannelWidget *createOne(MinimalStreamWidget *owner, int channelIndex, pa_channel_position channelPosition, bool can_decibel); }; diff --git a/src/devicewidget.cc b/src/devicewidget.cc index e86cd20..d03450f 100644 --- a/src/devicewidget.cc +++ b/src/devicewidget.cc @@ -37,29 +37,45 @@ DeviceWidget::DeviceWidget(BaseObjectType* cobject, const Glib::RefPtrget_widget("deviceChannelsVBox", channelsVBox); - x->get_widget("deviceNameLabel", nameLabel); - x->get_widget("deviceBoldNameLabel", boldNameLabel); - x->get_widget("deviceIconImage", iconImage); + channelsVBox = x->get_widget("deviceChannelsVBox"); + nameLabel = x->get_widget("deviceNameLabel"); + boldNameLabel = x->get_widget("deviceBoldNameLabel"); + iconImage= x->get_widget("deviceIconImage"); - x->get_widget("deviceLockToggleButton", lockToggleButton); - x->get_widget("deviceMuteToggleButton", muteToggleButton); - x->get_widget("defaultToggleButton", defaultToggleButton); - x->get_widget("portSelect", portSelect); - x->get_widget("portList", portList); - x->get_widget("advancedOptions", advancedOptions); - x->get_widget("offsetSelect", offsetSelect); - x->get_widget("offsetButton", offsetButton); + lockToggleButton = x->get_widget("deviceLockToggleButton"); + muteToggleButton = x->get_widget("deviceMuteToggleButton"); + defaultToggleButton= x->get_widget("defaultToggleButton"); + portSelect = x->get_widget("portSelect"); + portList = x->get_widget("portList"); + advancedOptions = x->get_widget("advancedOptions"); + offsetSelect = x->get_widget("offsetSelect"); + offsetButton = x->get_widget("offsetButton"); - this->signal_button_press_event().connect(sigc::mem_fun(*this, &DeviceWidget::onContextTriggerEvent)); muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &DeviceWidget::onMuteToggleButton)); lockToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &DeviceWidget::onLockToggleButton)); defaultToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &DeviceWidget::onDefaultToggleButton)); - rename.set_label(_("Rename Device...")); - rename.signal_activate().connect(sigc::mem_fun(*this, &DeviceWidget::renamePopup)); - contextMenu.append(rename); - contextMenu.show_all(); + auto gesture = Gtk::GestureClick::create(); + gesture->set_button(3); + gesture->set_exclusive(true); + gesture->signal_pressed().connect(sigc::mem_fun(*this, &DeviceWidget::onContextTriggerEvent)); + this->add_controller(gesture); + + const std::string actionName = "rename", groupName="devicewidget"; + auto action = Gio::SimpleAction::create(actionName); + action->set_enabled(true); + action->signal_activate().connect(sigc::mem_fun(*this, &DeviceWidget::openRenamePopup)); + + auto group = Gio::SimpleActionGroup::create(); + group->add_action(action); + + insert_action_group(groupName, group); + + auto menuModel = Gio::Menu::create(); + menuModel->append(_("Rename Device..."), groupName + "." + actionName); + contextMenu.set_menu_model(menuModel); + contextMenu.set_parent(*this); + treeModel = Gtk::ListStore::create(portModel); portList->set_model(treeModel); @@ -88,7 +104,7 @@ void DeviceWidget::setChannelMap(const pa_channel_map &m, bool can_decibel) { for (int i = 0; i < m.channels; i++) { ChannelWidget *cw = channelWidgets[i]; - channelsVBox->pack_start(*cw, false, false, 0); + channelsVBox->prepend(*cw); cw->unreference(); } @@ -160,7 +176,7 @@ void DeviceWidget::onOffsetChange() { if (!(o = pa_context_set_port_latency_offset(get_context(), card_name.c_str(), activePort.c_str(), offset, NULL, NULL))) { - show_error(_("pa_context_set_port_latency_offset() failed")); + show_error(this, _("pa_context_set_port_latency_offset() failed")); return; } pa_operation_unref(o); @@ -225,55 +241,64 @@ void DeviceWidget::prepareMenu() { updateAdvancedOptionsVisibility(); } -bool DeviceWidget::onContextTriggerEvent(GdkEventButton* event) { - if (GDK_BUTTON_PRESS == event->type && 3 == event->button) { - contextMenu.popup_at_pointer((GdkEvent*)event); - return true; - } - return false; +void DeviceWidget::onContextTriggerEvent(gint n_press, gdouble x, gdouble y) { + if (n_press == 1) { + contextMenu.set_pointing_to(Gdk::Rectangle {(int) x, (int) y, 0 , 0}); + contextMenu.popup(); + } } -void DeviceWidget::renamePopup() { +void DeviceWidget::openRenamePopup(const Glib::VariantBase& parameter) { if (updating) return; if (!mpMainWindow->canRenameDevices) { - Gtk::MessageDialog dialog( - *mpMainWindow, - _("Sorry, but device renaming is not supported."), - false, - Gtk::MESSAGE_WARNING, - Gtk::BUTTONS_OK, - true); - dialog.set_secondary_text(_("You need to load module-device-manager in the PulseAudio server in order to rename devices")); - dialog.run(); + auto dialog = Gtk::AlertDialog::create(_("Sorry, but device renaming is not supported.")); + dialog->set_modal(true); + dialog->set_detail(_("You need to load module-device-manager in the PulseAudio server in order to rename devices")); + dialog->show(*mpMainWindow); return; } - Gtk::Dialog* dialog; - Gtk::Entry* renameText; - Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "renameDialog"); - x->get_widget("renameDialog", dialog); - x->get_widget("renameText", renameText); + gchar *key = g_markup_printf_escaped("%s:%s", mDeviceType.c_str(), name.c_str()); + RenameWindow* renameDialog = Gtk::Builder::get_widget_derived(x, "renameDialog", description.c_str(), key); + renameDialog->set_transient_for(*mpMainWindow); - renameText->set_text(description); - dialog->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); - dialog->add_button(_("_OK"), Gtk::RESPONSE_OK); - dialog->set_default_response(Gtk::RESPONSE_OK); - if (Gtk::RESPONSE_OK == dialog->run()) { - pa_operation* o; - gchar *key = g_markup_printf_escaped("%s:%s", mDeviceType.c_str(), name.c_str()); + renameDialog->present(); +} - if (!(o = pa_ext_device_manager_set_device_description(get_context(), key, renameText->get_text().c_str(), NULL, NULL))) { - show_error(_("pa_ext_device_manager_write() failed")); - return; - } - pa_operation_unref(o); - g_free(key); +RenameWindow::RenameWindow(BaseObjectType* cobject, const Glib::RefPtr& x, const gchar* name, const gchar* key) : + Gtk::ApplicationWindow(cobject), + deviceKey(key){ + + renameText = x->get_widget("renameText"); + renameText->set_text(name); + + Gtk::Button* renameButton = x->get_widget("renameButton"); + set_default_widget(*renameButton); + + auto renameAction = Gio::SimpleAction::create("rename"); + renameAction->set_enabled(true); + renameAction->signal_activate().connect(sigc::mem_fun(*this, &RenameWindow::renamePopup)); + + add_action(renameAction); +} + + + +void RenameWindow::renamePopup(const Glib::VariantBase& parameter){ + pa_operation* o; + auto name = renameText->get_text(); + + if (!(o = pa_ext_device_manager_set_device_description(get_context(), deviceKey, name.c_str(), NULL, NULL))) { + show_error(this, _("pa_ext_device_manager_write() failed")); + return; } - delete dialog; + pa_operation_unref(o); + g_free((char*)deviceKey); + delete this; } void DeviceWidget::updateAdvancedOptionsVisibility() { diff --git a/src/devicewidget.h b/src/devicewidget.h index cb13b61..d229fe2 100644 --- a/src/devicewidget.h +++ b/src/devicewidget.h @@ -57,7 +57,7 @@ public: virtual void onLockToggleButton(); virtual void onDefaultToggleButton(); virtual void setDefault(bool isDefault); - virtual bool onContextTriggerEvent(GdkEventButton*); + virtual void onContextTriggerEvent(gint n_press, gdouble x, gdouble y); virtual void setLatencyOffset(int64_t offset); void onOffsetChange(); @@ -73,7 +73,7 @@ public: void prepareMenu(); - void renamePopup(); + void openRenamePopup(const Glib::VariantBase& parameter); protected: MainWindow *mpMainWindow; @@ -85,8 +85,7 @@ protected: virtual void onPortChange() = 0; - Gtk::Menu contextMenu; - Gtk::MenuItem rename; + Gtk::PopoverMenu contextMenu; /* Tree model columns */ class ModelColumns : public Gtk::TreeModel::ColumnRecord @@ -103,7 +102,7 @@ protected: ModelColumns portModel; Gtk::Expander *advancedOptions; - Gtk::HBox *portSelect, *offsetSelect; + Gtk::Box *portSelect, *offsetSelect; Gtk::ComboBox *portList; Glib::RefPtr treeModel; Glib::RefPtr offsetAdjustment; @@ -114,7 +113,15 @@ protected: private: Glib::ustring mDeviceType; +}; +class RenameWindow : public Gtk::ApplicationWindow { +public: + RenameWindow(BaseObjectType* cobject, const Glib::RefPtr& x, const gchar* name, const gchar* key); + Gtk::Entry* renameText; + const gchar* deviceKey; +private: + void renamePopup(const Glib::VariantBase& parameter); }; #endif diff --git a/src/mainwindow.cc b/src/mainwindow.cc index 4199a37..6c0964e 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -76,30 +76,26 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr canRenameDevices(false), m_connected(false), m_config_filename(NULL) { + ca_context_create (&canberraContext); + ca_context_set_driver(canberraContext, "pulse"); - x->get_widget("cardsVBox", cardsVBox); - x->get_widget("streamsVBox", streamsVBox); - x->get_widget("recsVBox", recsVBox); - x->get_widget("sinksVBox", sinksVBox); - x->get_widget("sourcesVBox", sourcesVBox); - x->get_widget("noCardsLabel", noCardsLabel); - x->get_widget("noStreamsLabel", noStreamsLabel); - x->get_widget("noRecsLabel", noRecsLabel); - x->get_widget("noSinksLabel", noSinksLabel); - x->get_widget("noSourcesLabel", noSourcesLabel); - x->get_widget("connectingLabel", connectingLabel); - x->get_widget("sinkInputTypeComboBox", sinkInputTypeComboBox); - x->get_widget("sourceOutputTypeComboBox", sourceOutputTypeComboBox); - x->get_widget("sinkTypeComboBox", sinkTypeComboBox); - x->get_widget("sourceTypeComboBox", sourceTypeComboBox); - x->get_widget("notebook", notebook); - x->get_widget("showVolumeMetersCheckButton", showVolumeMetersCheckButton); - - sourcesVBox->signal_size_allocate().connect([this](Gdk::Rectangle _unused){ sourcesVBox->queue_draw(); }); - cardsVBox->signal_size_allocate().connect([this](Gdk::Rectangle _unused){ cardsVBox->queue_draw(); }); - streamsVBox->signal_size_allocate().connect([this](Gdk::Rectangle _unused){ streamsVBox->queue_draw(); }); - recsVBox->signal_size_allocate().connect([this](Gdk::Rectangle _unused){ recsVBox->queue_draw(); }); - sinksVBox->signal_size_allocate().connect([this](Gdk::Rectangle _unused){ sinksVBox->queue_draw(); }); + cardsVBox = x->get_widget("cardsVBox"); + streamsVBox = x->get_widget("streamsVBox"); + recsVBox = x->get_widget("recsVBox"); + sinksVBox = x->get_widget("sinksVBox"); + sourcesVBox = x->get_widget("sourcesVBox"); + noCardsLabel = x->get_widget("noCardsLabel"); + noStreamsLabel = x->get_widget("noStreamsLabel"); + noRecsLabel = x->get_widget("noRecsLabel"); + noSinksLabel = x->get_widget("noSinksLabel"); + noSourcesLabel = x->get_widget("noSourcesLabel"); + connectingLabel = x->get_widget("connectingLabel"); + sinkInputTypeComboBox = x->get_widget("sinkInputTypeComboBox"); + sourceOutputTypeComboBox = x->get_widget("sourceOutputTypeComboBox"); + sinkTypeComboBox = x->get_widget("sinkTypeComboBox"); + sourceTypeComboBox = x->get_widget("sourceTypeComboBox"); + notebook = x->get_widget("notebook"); + showVolumeMetersCheckButton = x->get_widget("showVolumeMetersCheckButton"); sinkInputTypeComboBox->set_active((int) showSinkInputType); sourceOutputTypeComboBox->set_active((int) showSourceOutputType); @@ -112,6 +108,9 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr sourceTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceTypeComboBoxChanged)); showVolumeMetersCheckButton->signal_toggled().connect(sigc::mem_fun(*this, &MainWindow::onShowVolumeMetersCheckButtonToggled)); + auto event_controller_key = Gtk::EventControllerKey::create(); + event_controller_key->signal_key_pressed().connect(sigc::mem_fun(*this, &MainWindow::on_key_press_event), false); + this->add_controller(event_controller_key); GKeyFile* config = g_key_file_new(); g_assert(config); @@ -134,7 +133,7 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr int default_width, default_height; get_default_size(default_width, default_height); if (width >= default_width && height >= default_height) - resize(width, height); + set_default_size(width, height); int sinkInputTypeSelection = g_key_file_get_integer(config, "window", "sinkInputType", &err); if (err == NULL) @@ -187,7 +186,7 @@ MainWindow* MainWindow::create(bool maximize) { x->add_from_file(GLADE_FILE, "liststore3"); x->add_from_file(GLADE_FILE, "liststore4"); x->add_from_file(GLADE_FILE, "mainWindow"); - x->get_widget_derived("mainWindow", w); + w = Gtk::Builder::get_widget_derived(x, "mainWindow"); w->get_style_context()->add_class("pavucontrol-window"); if (w && maximize) w->maximize(); @@ -197,26 +196,26 @@ MainWindow* MainWindow::create(bool maximize) { void MainWindow::on_realize() { Gtk::Window::on_realize(); - get_window()->set_cursor(Gdk::Cursor::create(Gdk::WATCH)); + set_cursor(Gdk::Cursor::create("wait")); } -bool MainWindow::on_key_press_event(GdkEventKey* event) { +bool MainWindow::on_key_press_event(guint keyval, guint keycode, Gdk::ModifierType state) { - if (event->state & GDK_CONTROL_MASK) { - switch (event->keyval) { + if ((state & Gdk::ModifierType::CONTROL_MASK) == Gdk::ModifierType::CONTROL_MASK) { + switch (keyval) { case GDK_KEY_KP_1: case GDK_KEY_KP_2: case GDK_KEY_KP_3: case GDK_KEY_KP_4: case GDK_KEY_KP_5: - notebook->set_current_page(event->keyval - GDK_KEY_KP_1); + notebook->set_current_page(keyval - GDK_KEY_KP_1); return true; case GDK_KEY_1: case GDK_KEY_2: case GDK_KEY_3: case GDK_KEY_4: case GDK_KEY_5: - notebook->set_current_page(event->keyval - GDK_KEY_1); + notebook->set_current_page(keyval - GDK_KEY_1); return true; case GDK_KEY_W: case GDK_KEY_Q: @@ -226,7 +225,7 @@ bool MainWindow::on_key_press_event(GdkEventKey* event) { return true; } } - return Gtk::Window::on_key_press_event(event); + return false; } MainWindow::~MainWindow() { @@ -234,7 +233,7 @@ MainWindow::~MainWindow() { g_assert(config); int width, height; - get_size(width, height); + get_default_size(width, height); g_key_file_set_integer(config, "window", "width", width); g_key_file_set_integer(config, "window", "height", height); g_key_file_set_integer(config, "window", "sinkInputType", sinkInputTypeComboBox->get_active_row_number()); @@ -247,7 +246,7 @@ MainWindow::~MainWindow() { GError *err = NULL; gchar *filedata = g_key_file_to_data(config, &filelen, &err); if (err) { - show_error(_("Error saving preferences")); + show_error(this, _("Error saving preferences")); g_error_free(err); goto finish; } @@ -256,7 +255,7 @@ MainWindow::~MainWindow() { g_free(filedata); if (err) { gchar* msg = g_strconcat(_("Error writing config file %s"), m_config_filename, NULL); - show_error(msg); + show_error(this, msg); g_free(msg); g_error_free(err); goto finish; @@ -274,34 +273,20 @@ finish: } } -static void set_icon_name_default(Gtk::Image *i, const char *name, Gtk::IconSize size) { +static void set_icon_name_default(Gtk::Image *i, const char *name) { + /* We emulate the behavior of the GTK_ICON_LOOKUP_GENERIC_FALLBACK flag from Gtk3 */ Glib::RefPtr theme; - Glib::RefPtr pixbuf; - gint width = 24, height = 24; - - Gtk::IconSize::lookup(size, width, height); - theme = Gtk::IconTheme::get_default(); - - try { - pixbuf = theme->load_icon(name, width, Gtk::ICON_LOOKUP_GENERIC_FALLBACK | Gtk::ICON_LOOKUP_FORCE_SIZE); - } catch (Glib::Error &e) { - /* Ignore errors. */ - } - - if (!pixbuf) { - try { - pixbuf = Gdk::Pixbuf::create_from_file(name); - } catch (Glib::FileError &e) { - /* Ignore errors. */ - } catch (Gdk::PixbufError &e) { - /* Ignore errors. */ + theme = Gtk::IconTheme::get_for_display(Gdk::Display::get_default()); + std::string iconName(name); + while (!theme->has_icon(iconName.c_str())) { + size_t lastDashIndex = iconName.find_last_of("-"); + if (lastDashIndex == std::string::npos) { + iconName = "gtk-missing-image"; + break; } + iconName = iconName.substr(0,lastDashIndex); } - - if (pixbuf) { - pixbuf = pixbuf->scale_simple(width, height, Gdk::INTERP_BILINEAR); - i->set(pixbuf); - } + i->set_from_icon_name(iconName.c_str()); } static void updatePorts(DeviceWidget *w, std::map &ports) { @@ -365,7 +350,7 @@ void MainWindow::updateCard(const pa_card_info &info) { w = cardWidgets[info.index]; else { cardWidgets[info.index] = w = CardWidget::create(); - cardsVBox->pack_start(*w, false, false, 0); + cardsVBox->append(*w); w->unreference(); w->index = info.index; is_new = true; @@ -382,7 +367,7 @@ void MainWindow::updateCard(const pa_card_info &info) { g_free(txt); icon = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_ICON_NAME); - set_icon_name_default(w->iconImage, icon ? icon : "audio-card", Gtk::ICON_SIZE_SMALL_TOOLBAR); + set_icon_name_default(w->iconImage, icon ? icon : "audio-card"); w->hasSinks = w->hasSources = false; profile_priorities.clear(); @@ -556,7 +541,7 @@ bool MainWindow::updateSink(const pa_sink_info &info) { else { sinkWidgets[info.index] = w = SinkWidget::create(this); w->setChannelMap(info.channel_map, !!(info.flags & PA_SINK_DECIBEL_VOLUME)); - sinksVBox->pack_start(*w, false, false, 0); + sinksVBox->append(*w); w->unreference(); w->index = info.index; w->monitor_index = info.monitor_source; @@ -580,7 +565,7 @@ bool MainWindow::updateSink(const pa_sink_info &info) { g_free(txt); icon = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_ICON_NAME); - set_icon_name_default(w->iconImage, icon ? icon : "audio-card", Gtk::ICON_SIZE_SMALL_TOOLBAR); + set_icon_name_default(w->iconImage, icon ? icon : "audio-card"); w->setVolume(info.volume); w->muteToggleButton->set_active(info.mute); @@ -630,7 +615,7 @@ static void read_callback(pa_stream *s, size_t length, void *userdata) { double v; if (pa_stream_peek(s, &data, &length) < 0) { - show_error(_("Failed to read data from stream")); + show_error(w, _("Failed to read data from stream")); return; } @@ -675,7 +660,7 @@ pa_stream* MainWindow::createMonitorStreamForSource(uint32_t source_idx, uint32_ snprintf(t, sizeof(t), "%u", source_idx); if (!(s = pa_stream_new(get_context(), _("Peak detect"), &ss, NULL))) { - show_error(_("Failed to create monitoring stream")); + show_error(this, _("Failed to create monitoring stream")); return NULL; } @@ -690,7 +675,7 @@ pa_stream* MainWindow::createMonitorStreamForSource(uint32_t source_idx, uint32_ (!showVolumeMetersCheckButton->get_active() ? PA_STREAM_START_CORKED : PA_STREAM_NOFLAGS)); if (pa_stream_connect_record(s, t, &attr, flags) < 0) { - show_error(_("Failed to connect monitoring stream")); + show_error(this, _("Failed to connect monitoring stream")); pa_stream_unref(s); return NULL; } @@ -722,7 +707,7 @@ void MainWindow::updateSource(const pa_source_info &info) { else { sourceWidgets[info.index] = w = SourceWidget::create(this); w->setChannelMap(info.channel_map, !!(info.flags & PA_SOURCE_DECIBEL_VOLUME)); - sourcesVBox->pack_start(*w, false, false, 0); + sourcesVBox->append(*w); w->unreference(); w->index = info.index; is_new = true; @@ -748,7 +733,7 @@ void MainWindow::updateSource(const pa_source_info &info) { g_free(txt); icon = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_ICON_NAME); - set_icon_name_default(w->iconImage, icon ? icon : "audio-input-microphone", Gtk::ICON_SIZE_SMALL_TOOLBAR); + set_icon_name_default(w->iconImage, icon ? icon : "audio-input-microphone"); w->setVolume(info.volume); w->muteToggleButton->set_active(info.mute); @@ -817,7 +802,7 @@ void MainWindow::setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const cha finish: - set_icon_name_default(icon, t, Gtk::ICON_SIZE_SMALL_TOOLBAR); + set_icon_name_default(icon, t); } void MainWindow::updateSinkInput(const pa_sink_input_info &info) { @@ -840,7 +825,7 @@ void MainWindow::updateSinkInput(const pa_sink_input_info &info) { } else { sinkInputWidgets[info.index] = w = SinkInputWidget::create(this); w->setChannelMap(info.channel_map, true); - streamsVBox->pack_start(*w, false, false, 0); + streamsVBox->append(*w); w->unreference(); w->index = info.index; w->clientIndex = info.client; @@ -899,7 +884,7 @@ void MainWindow::updateSourceOutput(const pa_source_output_info &info) { #if HAVE_SOURCE_OUTPUT_VOLUMES w->setChannelMap(info.channel_map, true); #endif - recsVBox->pack_start(*w, false, false, 0); + recsVBox->append(*w); w->unreference(); w->index = info.index; w->clientIndex = info.client; @@ -996,7 +981,7 @@ bool MainWindow::createEventRoleWidget() { }; eventRoleWidget = RoleWidget::create(); - streamsVBox->pack_start(*eventRoleWidget, false, false, 0); + streamsVBox->append(*eventRoleWidget); eventRoleWidget->unreference(); eventRoleWidget->role = "sink-input-by-media-role:event"; eventRoleWidget->setChannelMap(cm, true); @@ -1004,7 +989,7 @@ bool MainWindow::createEventRoleWidget() { eventRoleWidget->boldNameLabel->set_text(""); eventRoleWidget->nameLabel->set_label(_("System Sounds")); - eventRoleWidget->iconImage->set_from_icon_name("multimedia-volume-control", Gtk::ICON_SIZE_SMALL_TOOLBAR); + eventRoleWidget->iconImage->set_from_icon_name("multimedia-volume-control"); eventRoleWidget->device = ""; @@ -1292,7 +1277,7 @@ void MainWindow::removeSink(uint32_t index) { if (!sinkWidgets.count(index)) return; - delete sinkWidgets[index]; + sinksVBox->remove(*sinkWidgets[index]); sinkWidgets.erase(index); updateDeviceVisibility(); } @@ -1301,7 +1286,7 @@ void MainWindow::removeSource(uint32_t index) { if (!sourceWidgets.count(index)) return; - delete sourceWidgets[index]; + sourcesVBox->remove(*sourceWidgets[index]); sourceWidgets.erase(index); updateDeviceVisibility(); } @@ -1310,7 +1295,7 @@ void MainWindow::removeSinkInput(uint32_t index) { if (!sinkInputWidgets.count(index)) return; - delete sinkInputWidgets[index]; + streamsVBox->remove(*sinkInputWidgets[index]); sinkInputWidgets.erase(index); updateDeviceVisibility(); } @@ -1319,7 +1304,7 @@ void MainWindow::removeSourceOutput(uint32_t index) { if (!sourceOutputWidgets.count(index)) return; - delete sourceOutputWidgets[index]; + recsVBox->remove(*sourceOutputWidgets[index]); sourceOutputWidgets.erase(index); updateDeviceVisibility(); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 5015144..ca40a7b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -29,6 +29,8 @@ class MainWindow; # include #endif +#include + #include class CardWidget; @@ -76,7 +78,7 @@ public: void setConnectingMessage(const char *string = NULL); Gtk::Notebook *notebook; - Gtk::VBox *streamsVBox, *recsVBox, *sinksVBox, *sourcesVBox, *cardsVBox; + Gtk::Box *streamsVBox, *recsVBox, *sinksVBox, *sourcesVBox, *cardsVBox; Gtk::Label *noStreamsLabel, *noRecsLabel, *noSinksLabel, *noSourcesLabel, *noCardsLabel, *connectingLabel; Gtk::ComboBox *sinkInputTypeComboBox, *sourceOutputTypeComboBox, *sinkTypeComboBox, *sourceTypeComboBox; Gtk::CheckButton *showVolumeMetersCheckButton; @@ -116,9 +118,11 @@ public: bool canRenameDevices; + ca_context *canberraContext; + protected: virtual void on_realize(); - virtual bool on_key_press_event(GdkEventKey* event); + virtual bool on_key_press_event(guint keyval, guint keycode, Gdk::ModifierType state); private: gboolean m_connected; diff --git a/src/meson.build b/src/meson.build index f8a4b81..97eeb00 100644 --- a/src/meson.build +++ b/src/meson.build @@ -33,8 +33,8 @@ executable('pavucontrol', install_data('pavucontrol.glade') desktop_file = i18n.merge_file( - input : 'pavucontrol.desktop.in', - output : 'pavucontrol.desktop', + input : 'org.pulseaudio.pavucontrol.desktop.in', + output : 'org.pulseaudio.pavucontrol.desktop', po_dir : po_dir, type : 'desktop', install : true, diff --git a/src/minimalstreamwidget.cc b/src/minimalstreamwidget.cc index 09b34b8..92e5f08 100644 --- a/src/minimalstreamwidget.cc +++ b/src/minimalstreamwidget.cc @@ -26,7 +26,7 @@ /*** MinimalStreamWidget ***/ MinimalStreamWidget::MinimalStreamWidget(BaseObjectType* cobject) : - Gtk::VBox(cobject), + Gtk::Box(cobject), channelsVBox(NULL), nameLabel(NULL), boldNameLabel(NULL), @@ -53,7 +53,7 @@ void MinimalStreamWidget::init() { * in the constructor. */ peakProgressBar.set_size_request(-1, 10); - channelsVBox->pack_end(peakProgressBar, false, false); + channelsVBox->append(peakProgressBar); /* XXX: Why is the peak meter hidden by default? Maybe the idea is that if * setting up the monitoring stream fails for whatever reason, then we @@ -64,20 +64,19 @@ void MinimalStreamWidget::init() { #define DECAY_STEP (1.0 / PEAKS_RATE) void MinimalStreamWidget::updatePeak(double v) { - if (lastPeak >= DECAY_STEP) if (v < lastPeak - DECAY_STEP) v = lastPeak - DECAY_STEP; lastPeak = v; - if (v >= 0) { - peakProgressBar.set_sensitive(TRUE); - peakProgressBar.set_fraction(v); - } else { - peakProgressBar.set_sensitive(FALSE); - peakProgressBar.set_fraction(0); - } + if (v >= 0) { + peakProgressBar.set_sensitive(TRUE); + peakProgressBar.set_fraction(v); + } else { + peakProgressBar.set_sensitive(FALSE); + peakProgressBar.set_fraction(0); + } enableVolumeMeter(); } diff --git a/src/minimalstreamwidget.h b/src/minimalstreamwidget.h index 24f2f6a..78671a5 100644 --- a/src/minimalstreamwidget.h +++ b/src/minimalstreamwidget.h @@ -25,7 +25,7 @@ #define PEAKS_RATE 144 -class MinimalStreamWidget : public Gtk::VBox { +class MinimalStreamWidget : public Gtk::Box { public: MinimalStreamWidget(BaseObjectType* cobject); virtual ~MinimalStreamWidget(); @@ -33,7 +33,7 @@ public: /* Subclass constructors are expected to initialize these variables. * MinimalStreamWidget can't initialize these, because the glade object * id's depend on the subclass type. */ - Gtk::VBox *channelsVBox; + Gtk::Box *channelsVBox; Gtk::Label *nameLabel, *boldNameLabel; Gtk::Image *iconImage; diff --git a/src/pavucontrol.desktop.in b/src/org.pulseaudio.pavucontrol.desktop.in similarity index 100% rename from src/pavucontrol.desktop.in rename to src/org.pulseaudio.pavucontrol.desktop.in diff --git a/src/pavuapplication.cc b/src/pavuapplication.cc index 6773b53..f4ad11a 100644 --- a/src/pavuapplication.cc +++ b/src/pavuapplication.cc @@ -24,8 +24,6 @@ #include "i18n.h" -#include - #include "pavuapplication.h" #include "pavucontrol.h" #include "mainwindow.h" @@ -39,7 +37,7 @@ PavuApplication::get_instance() } PavuApplication::PavuApplication() : - Gtk::Application("org.pulseaudio.pavucontrol", Gio::ApplicationFlags::APPLICATION_HANDLES_COMMAND_LINE), + Gtk::Application("org.pulseaudio.pavucontrol", Gio::Application::Flags::HANDLES_COMMAND_LINE), mainWindow(NULL), retry(false), maximize(false), @@ -59,9 +57,8 @@ MainWindow* PavuApplication::create_window() MainWindow* pavucontrol_window = pavucontrol_get_window(m, maximize, retry, tab); - pavucontrol_window->signal_hide().connect( - sigc::bind(sigc::mem_fun(*this, - &PavuApplication::on_hide_window), pavucontrol_window)); + pavucontrol_window->signal_close_request().connect(sigc::mem_fun(*this, + &PavuApplication::on_close_window), true); return pavucontrol_window; } @@ -94,9 +91,9 @@ void PavuApplication::on_activate() * exiting : when the last registered window of Gtk::Application is closed, * the application's run() function returns. */ -void PavuApplication::on_hide_window(Gtk::Window* window) +bool PavuApplication::on_close_window() { - delete window; + delete mainWindow; mainWindow = NULL; if (get_context()) { @@ -104,6 +101,7 @@ void PavuApplication::on_hide_window(Gtk::Window* window) } pa_glib_mainloop_free(m); m = NULL; + return true; } template @@ -155,23 +153,23 @@ int main(int argc, char *argv[]) { /* Add command-line options */ globalInstance.add_main_option_entry( - Gio::Application::OptionType::OPTION_TYPE_INT, + Gio::Application::OptionType::INT, "tab", 't', _("Select a specific tab on load."), _("number")); globalInstance.add_main_option_entry( - Gio::Application::OptionType::OPTION_TYPE_BOOL, + Gio::Application::OptionType::BOOL, "retry", 'r', _("Retry forever if pa quits (every 5 seconds).")); globalInstance.add_main_option_entry( - Gio::Application::OptionType::OPTION_TYPE_BOOL, + Gio::Application::OptionType::BOOL, "maximize", 'm', _("Maximize the window.")); globalInstance.add_main_option_entry( - Gio::Application::OptionType::OPTION_TYPE_BOOL, + Gio::Application::OptionType::BOOL, "version", 'v', _("Show version.")); diff --git a/src/pavuapplication.h b/src/pavuapplication.h index d2a1f5a..53cc0e3 100644 --- a/src/pavuapplication.h +++ b/src/pavuapplication.h @@ -45,7 +45,8 @@ protected: private: MainWindow* create_window(); - void on_hide_window(Gtk::Window* window); + void on_hide_window(); + bool on_close_window(); pa_glib_mainloop *m; }; diff --git a/src/pavucontrol.cc b/src/pavucontrol.cc index 18d5400..62a6499 100644 --- a/src/pavucontrol.cc +++ b/src/pavucontrol.cc @@ -29,8 +29,6 @@ #include #endif -#include - #include "pavucontrol.h" #include "i18n.h" #include "minimalstreamwidget.h" @@ -58,15 +56,27 @@ static int tab_number = 0; static bool retry = false; static int reconnect_timeout = 1; -void show_error(const char *txt) { +void show_error_finish (const Glib::RefPtr& result) { + PavuApplication::get_instance().quit(); +} + +void show_error(Gtk::Widget* widget, const char *txt) { + Gtk::Root *root = widget->get_root(); char buf[256]; snprintf(buf, sizeof(buf), "%s: %s", txt, pa_strerror(pa_context_errno(context))); - Gtk::MessageDialog dialog(buf, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE, true); - dialog.run(); - - PavuApplication::get_instance().quit(); + auto dialog = Gtk::AlertDialog::create(buf); + dialog->set_modal(true); + if (GTK_IS_WINDOW(root->gobj())) { + GtkWindow* w = (GtkWindow*) root->gobj(); + Gtk::Window* window = Glib::wrap(w); + window->present(); + dialog->choose(*window, sigc::ptr_fun(show_error_finish)); + } + else { + dialog->choose(sigc::ptr_fun(show_error_finish)); + } } static void dec_outstanding(MainWindow *w) { @@ -74,7 +84,7 @@ static void dec_outstanding(MainWindow *w) { return; if (--n_outstanding <= 0) { - w->get_window()->set_cursor(); + w->set_cursor(Gdk::Cursor::create("default"));; w->setConnectionState(true); } } @@ -355,7 +365,7 @@ void card_cb(pa_context *c, const pa_card_info *i, int eol, void *userdata) { if (pa_context_errno(context) == PA_ERR_NOENTITY) return; - show_error(_("Card callback failure")); + show_error(w, _("Card callback failure")); return; } @@ -383,7 +393,7 @@ void sink_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) { if (pa_context_errno(context) == PA_ERR_NOENTITY) return; - show_error(_("Sink callback failure")); + show_error(w, _("Sink callback failure")); return; } @@ -407,7 +417,7 @@ void source_cb(pa_context *, const pa_source_info *i, int eol, void *userdata) { if (pa_context_errno(context) == PA_ERR_NOENTITY) return; - show_error(_("Source callback failure")); + show_error(w, _("Source callback failure")); return; } @@ -426,7 +436,7 @@ void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *use if (pa_context_errno(context) == PA_ERR_NOENTITY) return; - show_error(_("Sink input callback failure")); + show_error(w, _("Sink input callback failure")); return; } @@ -445,7 +455,7 @@ void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, voi if (pa_context_errno(context) == PA_ERR_NOENTITY) return; - show_error(_("Source output callback failure")); + show_error(w, _("Source output callback failure")); return; } @@ -475,7 +485,7 @@ void client_cb(pa_context *, const pa_client_info *i, int eol, void *userdata) { if (pa_context_errno(context) == PA_ERR_NOENTITY) return; - show_error(_("Client callback failure")); + show_error(w, _("Client callback failure")); return; } @@ -491,7 +501,7 @@ void server_info_cb(pa_context *, const pa_server_info *i, void *userdata) { MainWindow *w = static_cast(userdata); if (!i) { - show_error(_("Server info callback failure")); + show_error(w, _("Server info callback failure")); return; } @@ -527,7 +537,7 @@ static void ext_stream_restore_subscribe_cb(pa_context *c, void *userdata) { pa_operation *o; if (!(o = pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, w))) { - show_error(_("pa_ext_stream_restore_read() failed")); + show_error(w, _("pa_ext_stream_restore_read() failed")); return; } @@ -566,7 +576,7 @@ static void ext_device_restore_subscribe_cb(pa_context *c, pa_device_type_t type return; if (!(o = pa_ext_device_restore_read_formats(c, type, idx, ext_device_restore_read_cb, w))) { - show_error(_("pa_ext_device_restore_read_sink_formats() failed")); + show_error(w, _("pa_ext_device_restore_read_sink_formats() failed")); return; } @@ -603,7 +613,7 @@ static void ext_device_manager_subscribe_cb(pa_context *c, void *userdata) { pa_operation *o; if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, w))) { - show_error(_("pa_ext_device_manager_read() failed")); + show_error(w, _("pa_ext_device_manager_read() failed")); return; } @@ -620,7 +630,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, else { pa_operation *o; if (!(o = pa_context_get_sink_info_by_index(c, index, sink_cb, w))) { - show_error(_("pa_context_get_sink_info_by_index() failed")); + show_error(w, _("pa_context_get_sink_info_by_index() failed")); return; } pa_operation_unref(o); @@ -633,7 +643,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, else { pa_operation *o; if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, w))) { - show_error(_("pa_context_get_source_info_by_index() failed")); + show_error(w, _("pa_context_get_source_info_by_index() failed")); return; } pa_operation_unref(o); @@ -646,7 +656,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, else { pa_operation *o; if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, w))) { - show_error(_("pa_context_get_sink_input_info() failed")); + show_error(w, _("pa_context_get_sink_input_info() failed")); return; } pa_operation_unref(o); @@ -659,7 +669,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, else { pa_operation *o; if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, w))) { - show_error(_("pa_context_get_sink_input_info() failed")); + show_error(w, _("pa_context_get_sink_input_info() failed")); return; } pa_operation_unref(o); @@ -672,7 +682,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, else { pa_operation *o; if (!(o = pa_context_get_client_info(c, index, client_cb, w))) { - show_error(_("pa_context_get_client_info() failed")); + show_error(w, _("pa_context_get_client_info() failed")); return; } pa_operation_unref(o); @@ -682,7 +692,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, case PA_SUBSCRIPTION_EVENT_SERVER: { pa_operation *o; if (!(o = pa_context_get_server_info(c, server_info_cb, w))) { - show_error(_("pa_context_get_server_info() failed")); + show_error(w, _("pa_context_get_server_info() failed")); return; } pa_operation_unref(o); @@ -695,7 +705,7 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index, else { pa_operation *o; if (!(o = pa_context_get_card_info_by_index(c, index, card_cb, w))) { - show_error(_("pa_context_get_card_info_by_index() failed")); + show_error(w, _("pa_context_get_card_info_by_index() failed")); return; } pa_operation_unref(o); @@ -738,7 +748,7 @@ void context_state_callback(pa_context *c, void *userdata) { PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SERVER| PA_SUBSCRIPTION_MASK_CARD), NULL, NULL))) { - show_error(_("pa_context_subscribe() failed")); + show_error(w, _("pa_context_subscribe() failed")); return; } pa_operation_unref(o); @@ -747,49 +757,49 @@ void context_state_callback(pa_context *c, void *userdata) { n_outstanding = 0; if (!(o = pa_context_get_server_info(c, server_info_cb, w))) { - show_error(_("pa_context_get_server_info() failed")); + show_error(w, _("pa_context_get_server_info() failed")); return; } pa_operation_unref(o); n_outstanding++; if (!(o = pa_context_get_client_info_list(c, client_cb, w))) { - show_error(_("pa_context_client_info_list() failed")); + show_error(w, _("pa_context_client_info_list() failed")); return; } pa_operation_unref(o); n_outstanding++; if (!(o = pa_context_get_card_info_list(c, card_cb, w))) { - show_error(_("pa_context_get_card_info_list() failed")); + show_error(w, _("pa_context_get_card_info_list() failed")); return; } pa_operation_unref(o); n_outstanding++; if (!(o = pa_context_get_sink_info_list(c, sink_cb, w))) { - show_error(_("pa_context_get_sink_info_list() failed")); + show_error(w, _("pa_context_get_sink_info_list() failed")); return; } pa_operation_unref(o); n_outstanding++; if (!(o = pa_context_get_source_info_list(c, source_cb, w))) { - show_error(_("pa_context_get_source_info_list() failed")); + show_error(w, _("pa_context_get_source_info_list() failed")); return; } pa_operation_unref(o); n_outstanding++; if (!(o = pa_context_get_sink_input_info_list(c, sink_input_cb, w))) { - show_error(_("pa_context_get_sink_input_info_list() failed")); + show_error(w, _("pa_context_get_sink_input_info_list() failed")); return; } pa_operation_unref(o); n_outstanding++; if (!(o = pa_context_get_source_output_info_list(c, source_output_cb, w))) { - show_error(_("pa_context_get_source_output_info_list() failed")); + show_error(w, _("pa_context_get_source_output_info_list() failed")); return; } pa_operation_unref(o); @@ -916,8 +926,6 @@ MainWindow* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool _ret tab_number = _tab_number; retry = _retry; - ca_context_set_driver(ca_gtk_context_get(), "pulse"); - mainWindow = MainWindow::create(maximize); api = pa_glib_mainloop_get_api(m); diff --git a/src/pavucontrol.glade b/src/pavucontrol.glade index b9155fb..25591fd 100644 --- a/src/pavucontrol.glade +++ b/src/pavucontrol.glade @@ -1,714 +1,430 @@ - + 100 44.2408370972 5 - True - False - window2 + 1 + window2 - - - True - False + + 6 - True - False - <b>left-front</b> - True + center + <b>left-front</b> + 1 1 0 - - False - False - 0 - - - True - True + + 1 + 1 adjustment1 0 - False - - True - True - 1 - - True - False - 8 - <small>50%</small> - True + center + 8 + 8 + <small>50%</small> + 1 right 12 1 0 - - False - False - 2 - - + - True - False - window1 + 1 + window1 - - - True - False - False + + + vertical - - True - False + + center + vertical + 6 + 12 + 12 + 12 + 12 - - True - False - 12 + + center 6 - - True - False - 6 - - - True - False - 0 - gtk-missing-image - - - False - True - 0 - - - - - True - False - - - True - False - Card Name - True - middle - 0 - - - True - True - 0 - - - - - True - True - 1 - - - - - True - False - 3 - - - True - True - False - Lock card to this profile - none - True - - - True - False - changes-prevent - 1 - - - - - False - False - 1 - - - - - False - True - 2 - - + + gtk-missing-image - - False - False - 0 - - - True - False - 6 + + 1 - - True - False - <b>Profile:</b> - True + + 1 + Card Name + 1 + middle 0 - - False - True - 0 - - - - - True - False - - - True - True - 1 - - - - - True - False - 6 - - - True - False - <b>Codec:</b> - True - 0 - - - False - True - 0 - - - - - True - False - - - True - True - 1 - - - - - False - False - 2 - - - False - False - 1 - + + + + 3 + + + center + 1 + Lock card to this profile + 0 + 1 + + + changes-prevent + normal + + + + + - - False - False - 0 - - - True - False + + center + 6 + + + <b>Profile:</b> + 1 + 0 + + + + + 1 + + + + + center + 6 + + + <b>Codec:</b> + 1 + 0 + + + + + 1 + + + + - - False - False - 1 - + + + center + + - + - True - False - window1 + 1 + window1 - - - True - False - False + + + vertical - - True - False + + center + vertical + 6 + 12 + 12 + 12 + 12 - - True - False - 12 + + center 6 - - True - False - 6 - - - True - False - gtk-missing-image - - - False - True - 0 - - - - - True - False - - - True - False - True - - - False - True - 0 - - - - - True - False - Device Title - True - end - 0 - - - False - True - 1 - - - - - True - True - 1 - - - - - True - False - 3 - - - True - True - False - Mute audio - none - - - True - False - audio-volume-muted - 1 - - - - - False - False - 0 - - - - - True - True - False - Lock channels together - none - True - - - True - False - changes-prevent - 1 - - - - - False - False - 1 - - - - - True - True - False - Set as default - - - True - False - emblem-default - - - - - False - False - 2 - - - - - False - True - 2 - - + + gtk-missing-image - - False - False - 0 - - - True - False - 6 + + 1 - - True - False - <b>Port:</b> - True + + 1 + + + + + Device Title + 1 + end 0 - - False - True - 0 - - - - - True - False - - - True - True - 1 - - - False - False - 1 - - - True - False - 6 + + 3 - - - - - - - - False - False - 2 - - - - - True - - - True - False + + center + 1 + Mute audio + 0 - - False - True - True - - - PCM - True - False - True - False - True - True - - - 0 - 0 - - - - - AC-3 - True - True - False - True - - - 1 - 0 - - - - - DTS - True - True - False - True - - - 2 - 0 - - - - - E-AC-3 - True - True - False - True - - - 0 - 1 - - - - - MPEG - True - True - False - True - - - 1 - 1 - - - - - AAC - True - True - False - True - - - 2 - 1 - - - - - TrueHD - True - True - False - True - - - 0 - 2 - - - - - DTS-HD - True - True - False - True - - - 1 - 2 - - + + audio-volume-muted + normal - - False - False - 0 - - - - - True - False - 6 - - - True - False - <b>Latency offset:</b> - True - 0 - - - False - True - 0 - - - - - True - True - - False - False - - - True - True - 1 - - - - - True - False - ms - True - - - False - True - 2 - - - - - False - False - 1 - - - - True - False - Advanced + + + center + 1 + Lock channels together + 0 + 1 + + + changes-prevent + normal + + + + + + + center + 1 + Set as default + + + emblem-default + + - - False - False - 3 - - - False - False - 0 - - - True - False + + center + 6 + + + <b>Port:</b> + 1 + 0 + + + + + 1 + + + + + + + center + vertical + 6 + + + + + + + + + + + center + 0 + 1 + + + vertical + + + center + 0 + 1 + 1 + + + PCM + 0 + 1 + 1 + + 0 + 0 + + + + + + AC-3 + 1 + + 1 + 0 + + + + + + DTS + 1 + + 2 + 0 + + + + + + E-AC-3 + 1 + + 0 + 1 + + + + + + MPEG + 1 + + 1 + 1 + + + + + + AAC + 1 + + 2 + 1 + + + + + + TrueHD + 1 + + 0 + 2 + + + + + + DTS-HD + 1 + + 1 + 2 + + + + + + + + center + 6 + + + <b>Latency offset:</b> + 1 + 0 + + + + + 1 + 1 + + + + + ms + 1 + + + + + + + + + Advanced + + - - False - False - 1 - + + + center + + - + - @@ -725,7 +441,6 @@ - @@ -742,7 +457,6 @@ - @@ -759,7 +473,6 @@ - @@ -781,113 +494,76 @@ - False - Volume Control + Volume Control 500 400 multimedia-volume-control - - - True - False + + + vertical 12 - True - True - False - True + 1 + 1 + 0 + 1 - - True - False - - - True - True - 0 + + + + vertical - - True - False - none - - - True - False - - - True - False - False - 16 - 16 - <i>No application is currently playing audio.</i> - True + + 1 + 1 + + + + + vertical + + + 1 + 0 + <i>No application is currently playing audio.</i> + 1 + + - - True - True - 0 - - + - + - - - True - True - 0 - - - - - True - False - - - False - False - 1 - - - - - True - False - 12 - 12 - 12 - 12 - - True - False + + center + + + + 6 + 12 + 12 + 12 + 12 + center - True - False - <b>_Show:</b> - True - True + 1 + <b>_Show:</b> + 1 + 1 1 - - True - True - 0 - - True - False + 1 liststore1 @@ -896,122 +572,72 @@ - - True - True - 1 - - - False - False - 2 - - + + + + _Playback + 1 + + - - - True - False - _Playback - True - - - False - - - - True - False - - - True - True - 0 + + + + vertical - - True - False - none - - - True - False - - - True - False - False - 16 - 16 - <i>No application is currently recording audio.</i> - True + + 1 + 1 + + + + + vertical + + + 1 + 0 + <i>No application is currently recording audio.</i> + 1 + + - - True - True - 0 - - + - + - - - True - True - 0 - - - - - True - False - - - False - False - 1 - - - - - True - False - 12 - 12 - 12 - 12 - - True - False + + center + + + + 6 + 12 + 12 + 12 + 12 + center - True - False - <b>_Show:</b> - True - True + 1 + <b>_Show:</b> + 1 + 1 1 - - True - True - 0 - - True - False + 1 liststore2 @@ -1020,127 +646,73 @@ - - True - True - 1 - - - False - False - 2 - - + + + + _Recording + 1 + + - - 1 - - - - - True - False - _Recording - True - - - 1 - False - - - True - False - - - True - True - 0 + + + + vertical - - True - False - none - - - True - False - - - True - False - False - 16 - 16 - <i>No output devices available</i> - True + + 1 + 1 + + + + + vertical + + + 1 + 0 + <i>No output devices available</i> + 1 + + - - True - True - 0 - - + - + - - - True - True - 0 - - - - - True - False - - - False - False - 1 - - - - - True - False - 12 - 12 - 12 - 12 - - True - False + + center + + + + 6 + 12 + 12 + 12 + 12 + center - True - False - <b>S_how:</b> - True - True + 1 + <b>S_how:</b> + 1 + 1 sinkTypeComboBox 1 - - True - True - 0 - - True - False + 1 liststore3 @@ -1149,128 +721,73 @@ - - True - True - 1 - - - False - True - 2 - - + + + + _Output Devices + 1 + + - - 2 - - - - - True - False - _Output Devices - True - - - 2 - False - - - True - False - - - True - True - 0 + + + + vertical - - True - False - queue - none - - - True - False - - - True - False - False - 16 - 16 - <i>No input devices available</i> - True + + 1 + 1 + + + + + vertical + + + 1 + 0 + <i>No input devices available</i> + 1 + + - - True - True - 0 - - + - + - - - True - True - 0 - - - - - True - False - - - False - False - 1 - - - - - True - False - 12 - 12 - 12 - 12 - - True - False + + center + + + + 6 + 12 + 12 + 12 + 12 + center - True - False - <b>Sho_w:</b> - True - True + 1 + <b>Sho_w:</b> + 1 + 1 sourceTypeComboBox 1 - - True - True - 0 - - True - False + 1 liststore4 @@ -1279,442 +796,263 @@ - - True - True - 1 - - - False - True - 2 - - + + + + _Input Devices + 1 + + - - 3 - - - - - True - False - _Input Devices - True - - - 3 - False - - - True - False - - - True - True - 0 + + + + vertical - - True - False - none - - - True - False - - - True - False + + 1 + 1 + + + + + vertical - - True - False - False - 16 - 16 - <i>No cards available for configuration</i> - True + + 1 + vertical + + + 1 + 0 + <i>No cards available for configuration</i> + 1 + + + + + + + vertical + 1 + + + + + + Show volume meters + 1 + 1 + + - - True - True - 0 - - - True - True - 0 - - - - - True - False - - - True - False - - - False - True - 0 - - - - - Show volume meters - True - True - False - True - True - - - True - True - 1 - - - - - False - True - 1 - - + - + - - True - True - 0 - - + + + + _Configuration + 1 + + - - 4 - - - - - True - False - _Configuration - True - - - 4 - False - - - True - True - 0 - - False + 1 + 0 ... - True + 1 - - True - True - 1 - - + - - False - 5 - normal + + 1 - - - - True - False + vertical 2 - - - True - False - end - - - - - - - - - False - True - end - 0 - - + 5 + 5 + 5 + 5 - True - False - <b>Rename device to:</b> - True + 1 + <b>Rename device to:</b> + 1 0 - - True - True - 1 - - True - True + 1 + 1 - True + 1 60 - False - False - - True - True - 2 - + + + + bottom + GTK_ALIGN_END + 1 + + + _Cancel + 1 + 1 + window.close + + + + + _Ok + 1 + 1 + win.rename + + + - True - False - window1 + 1 + window1 - - - True - False - False + + + vertical - - True - False + + center + vertical + 6 + 12 + 12 + 12 + 12 - - True - False - 12 + + center 6 - - True - False - 6 - - - True - False - gtk-missing-image - - - False - True - 0 - - - - - True - False - 2 - - - True - False - True - - - False - True - 0 - - - - - True - False - Stream Title - True - end - 0 - - - False - True - 1 - - - - - True - False - 4 - direction - True - 0 - - - False - True - 2 - - - - - True - False - - - False - True - end - 3 - - - - - True - True - 1 - - - - - True - False - 3 - - - True - True - False - Mute audio - none - - - True - False - audio-volume-muted - 1 - - - - - False - False - 0 - - - - - True - True - False - Lock channels together - none - True - - - True - False - changes-prevent - 1 - - - - - False - False - 1 - - - - - False - True - 2 - - + + gtk-missing-image - - False - False - 0 - - - True - False - 6 + + 1 + 2 - + + 1 + - + + Stream Title + 1 + end + 0 + + + + + 4 + 4 + direction + 1 + 0 + + + + + GTK_ALIGN_END + 1 + + + + + + + 3 + + + center + 1 + Mute audio + 0 + + + audio-volume-muted + normal + + + + + + + center + 1 + Lock channels together + 0 + 1 + + + changes-prevent + normal + + + - - False - False - 1 - - - False - False - 0 - - - True - False + + center + vertical + 6 + + + + + + - - False - False - 1 - + + + center + + - + diff --git a/src/pavucontrol.h b/src/pavucontrol.h index c8696e6..e6282d7 100644 --- a/src/pavucontrol.h +++ b/src/pavucontrol.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -74,7 +75,7 @@ enum SourceType { #include "mainwindow.h" pa_context* get_context(void); -void show_error(const char *txt); +void show_error(Gtk::Widget *w, const char *txt); MainWindow* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool retry, int tab_number); diff --git a/src/rolewidget.cc b/src/rolewidget.cc index 7f755aa..cff0880 100644 --- a/src/rolewidget.cc +++ b/src/rolewidget.cc @@ -39,15 +39,11 @@ RoleWidget::RoleWidget(BaseObjectType* cobject, const Glib::RefPtr RoleWidget* RoleWidget::create() { RoleWidget* w; Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); + w = Gtk::Builder::get_widget_derived(x, "streamWidget"); w->reference(); return w; } -bool RoleWidget::onContextTriggerEvent(GdkEventButton*) { - return false; -} - void RoleWidget::onMuteToggleButton() { StreamWidget::onMuteToggleButton(); @@ -69,7 +65,7 @@ void RoleWidget::executeVolumeUpdate() { pa_operation* o; if (!(o = pa_ext_stream_restore_write(get_context(), PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL))) { - show_error(_("pa_ext_stream_restore_write() failed")); + show_error(this, _("pa_ext_stream_restore_write() failed")); return; } diff --git a/src/rolewidget.h b/src/rolewidget.h index 1d008f2..3dc2861 100644 --- a/src/rolewidget.h +++ b/src/rolewidget.h @@ -35,7 +35,6 @@ public: virtual void onMuteToggleButton(); virtual void executeVolumeUpdate(); - virtual bool onContextTriggerEvent(GdkEventButton*); }; #endif diff --git a/src/sinkinputwidget.cc b/src/sinkinputwidget.cc index ff086d6..732205f 100644 --- a/src/sinkinputwidget.cc +++ b/src/sinkinputwidget.cc @@ -35,13 +35,13 @@ SinkInputWidget::SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtrset_label(txt = g_markup_printf_escaped("%s", _("on"))); g_free(txt); - terminate.set_label(_("Terminate Playback")); + addKillMenu(_("Terminate Playback")); } SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) { SinkInputWidget* w; Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); + w = Gtk::Builder::get_widget_derived(x, "streamWidget"); w->init(mainWindow); w->reference(); @@ -84,7 +84,7 @@ void SinkInputWidget::executeVolumeUpdate() { pa_operation* o; if (!(o = pa_context_set_sink_input_volume(get_context(), index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_sink_input_volume() failed")); + show_error(this, _("pa_context_set_sink_input_volume() failed")); return; } @@ -99,17 +99,17 @@ void SinkInputWidget::onMuteToggleButton() { pa_operation* o; if (!(o = pa_context_set_sink_input_mute(get_context(), index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_sink_input_mute() failed")); + show_error(this, _("pa_context_set_sink_input_mute() failed")); return; } pa_operation_unref(o); } -void SinkInputWidget::onKill() { +void SinkInputWidget::onKill(const Glib::VariantBase& parameter) { pa_operation* o; if (!(o = pa_context_kill_sink_input(get_context(), index, NULL, NULL))) { - show_error(_("pa_context_kill_sink_input() failed")); + show_error(this, _("pa_context_kill_sink_input() failed")); return; } diff --git a/src/sinkinputwidget.h b/src/sinkinputwidget.h index af40d03..acd8cc1 100644 --- a/src/sinkinputwidget.h +++ b/src/sinkinputwidget.h @@ -41,7 +41,7 @@ public: void updateDeviceComboBox(); virtual void executeVolumeUpdate(); virtual void onMuteToggleButton(); - virtual void onKill(); + virtual void onKill(const Glib::VariantBase& parameter); virtual void onDeviceComboBoxChanged(); private: diff --git a/src/sinkwidget.cc b/src/sinkwidget.cc index f30bd37..1cbc1c3 100644 --- a/src/sinkwidget.cc +++ b/src/sinkwidget.cc @@ -24,7 +24,7 @@ #include "sinkwidget.h" -#include +#include #if HAVE_EXT_DEVICE_RESTORE_API # include # include @@ -37,35 +37,35 @@ SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr #if HAVE_EXT_DEVICE_RESTORE_API uint8_t i = 0; - x->get_widget("encodingSelect", encodingSelect); + encodingSelect = x->get_widget("encodingSelect"); encodings[i].encoding = PA_ENCODING_PCM; - x->get_widget("encodingFormatPCM", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatPCM"); encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange)); ++i; encodings[i].encoding = PA_ENCODING_AC3_IEC61937; - x->get_widget("encodingFormatAC3", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatAC3"); encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange)); ++i; encodings[i].encoding = PA_ENCODING_EAC3_IEC61937; - x->get_widget("encodingFormatEAC3", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatEAC3"); encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange)); ++i; encodings[i].encoding = PA_ENCODING_MPEG_IEC61937; - x->get_widget("encodingFormatMPEG", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatMPEG"); encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange)); ++i; encodings[i].encoding = PA_ENCODING_DTS_IEC61937; - x->get_widget("encodingFormatDTS", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatDTS"); encodings[i].widget->signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onEncodingsChange)); ++i; encodings[i].encoding = PA_ENCODING_INVALID; - x->get_widget("encodingFormatAAC", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatAAC"); encodings[i].widget->set_sensitive(false); #ifdef PA_ENCODING_MPEG2_AAC_IEC61937 if (pa_context_get_server_protocol_version(get_context()) >= 28) { @@ -76,7 +76,7 @@ SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr #endif ++i; encodings[i].encoding = PA_ENCODING_INVALID; - x->get_widget("encodingFormatTRUEHD", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatTRUEHD"); encodings[i].widget->set_sensitive(false); #ifdef PA_ENCODING_TRUEHD_IEC61937 if (pa_context_get_server_protocol_version(get_context()) >= 33) { @@ -87,7 +87,7 @@ SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr #endif ++i; encodings[i].encoding = PA_ENCODING_INVALID; - x->get_widget("encodingFormatDTSHD", encodings[i].widget); + encodings[i].widget = x->get_widget("encodingFormatDTSHD"); encodings[i].widget->set_sensitive(false); #ifdef PA_ENCODING_DTSHD_IEC61937 if (pa_context_get_server_protocol_version(get_context()) >= 33) { @@ -102,7 +102,7 @@ SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr SinkWidget* SinkWidget::create(MainWindow* mainWindow) { SinkWidget* w; Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "deviceWidget"); - x->get_widget_derived("deviceWidget", w); + w = Gtk::Builder::get_widget_derived(x, "deviceWidget"); w->init(mainWindow, "sink"); w->reference(); return w; @@ -114,28 +114,29 @@ void SinkWidget::executeVolumeUpdate() { int playing = 0; if (!(o = pa_context_set_sink_volume_by_index(get_context(), index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_sink_volume_by_index() failed")); + show_error(this, _("pa_context_set_sink_volume_by_index() failed")); return; } pa_operation_unref(o); - ca_context_playing(ca_gtk_context_get(), 2, &playing); + snprintf(dev, sizeof(dev), "%lu", (unsigned long) index); + + ca_context_playing(mpMainWindow->canberraContext, 2, &playing); if (playing) return; - snprintf(dev, sizeof(dev), "%lu", (unsigned long) index); - ca_context_change_device(ca_gtk_context_get(), dev); + ca_context_change_device(mpMainWindow->canberraContext, dev); - ca_gtk_play_for_widget(GTK_WIDGET(gobj()), - 2, - CA_PROP_EVENT_DESCRIPTION, _("Volume Control Feedback Sound"), - CA_PROP_EVENT_ID, "audio-volume-change", - CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", - CA_PROP_CANBERRA_ENABLE, "1", - NULL); + ca_context_play(mpMainWindow->canberraContext, + 2, + CA_PROP_EVENT_DESCRIPTION, _("Volume Control Feedback Sound"), + CA_PROP_EVENT_ID, "audio-volume-change", + CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", + CA_PROP_CANBERRA_ENABLE, "1", + NULL); - ca_context_change_device(ca_gtk_context_get(), NULL); + ca_context_change_device(mpMainWindow->canberraContext, NULL); } void SinkWidget::onMuteToggleButton() { @@ -146,7 +147,7 @@ void SinkWidget::onMuteToggleButton() { pa_operation* o; if (!(o = pa_context_set_sink_mute_by_index(get_context(), index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_sink_mute_by_index() failed")); + show_error(this, _("pa_context_set_sink_mute_by_index() failed")); return; } @@ -160,7 +161,7 @@ void SinkWidget::onDefaultToggleButton() { return; if (!(o = pa_context_set_default_sink(get_context(), name.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_default_sink() failed")); + show_error(this, _("pa_context_set_default_sink() failed")); return; } pa_operation_unref(o); @@ -180,7 +181,7 @@ void SinkWidget::onPortChange() { Glib::ustring port = row[portModel.name]; if (!(o = pa_context_set_sink_port_by_index(get_context(), index, port.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_sink_port_by_index() failed")); + show_error(this, _("pa_context_set_sink_port_by_index() failed")); return; } @@ -222,7 +223,7 @@ void SinkWidget::onEncodingsChange() { } if (!(o = pa_ext_device_restore_save_formats(get_context(), PA_DEVICE_TYPE_SINK, index, n_formats, formats, NULL, NULL))) { - show_error(_("pa_ext_device_restore_save_sink_formats() failed")); + show_error(this, _("pa_ext_device_restore_save_sink_formats() failed")); free(formats); return; } diff --git a/src/sourceoutputwidget.cc b/src/sourceoutputwidget.cc index 1c2e762..d164552 100644 --- a/src/sourceoutputwidget.cc +++ b/src/sourceoutputwidget.cc @@ -35,7 +35,7 @@ SourceOutputWidget::SourceOutputWidget(BaseObjectType* cobject, const Glib::RefP directionLabel->set_label(txt = g_markup_printf_escaped("%s", _("from"))); g_free(txt); - terminate.set_label(_("Terminate Recording")); + addKillMenu(_("Terminate Recording")); #if !HAVE_SOURCE_OUTPUT_VOLUMES /* Source Outputs do not have volume controls in versions of PA < 1.0 */ @@ -47,7 +47,7 @@ SourceOutputWidget::SourceOutputWidget(BaseObjectType* cobject, const Glib::RefP SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) { SourceOutputWidget* w; Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); + w = Gtk::Builder::get_widget_derived(x, "streamWidget"); w->init(mainWindow); w->reference(); return w; @@ -90,7 +90,7 @@ void SourceOutputWidget::executeVolumeUpdate() { pa_operation* o; if (!(o = pa_context_set_source_output_volume(get_context(), index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_source_output_volume() failed")); + show_error(this, _("pa_context_set_source_output_volume() failed")); return; } @@ -105,7 +105,7 @@ void SourceOutputWidget::onMuteToggleButton() { pa_operation* o; if (!(o = pa_context_set_source_output_mute(get_context(), index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_source_output_mute() failed")); + show_error(this, _("pa_context_set_source_output_mute() failed")); return; } @@ -113,10 +113,10 @@ void SourceOutputWidget::onMuteToggleButton() { } #endif -void SourceOutputWidget::onKill() { +void SourceOutputWidget::onKill(const Glib::VariantBase& parameter) { pa_operation* o; if (!(o = pa_context_kill_source_output(get_context(), index, NULL, NULL))) { - show_error(_("pa_context_kill_source_output() failed")); + show_error(this, _("pa_context_kill_source_output() failed")); return; } diff --git a/src/sourceoutputwidget.h b/src/sourceoutputwidget.h index 5edd438..a670c65 100644 --- a/src/sourceoutputwidget.h +++ b/src/sourceoutputwidget.h @@ -43,7 +43,7 @@ public: virtual void executeVolumeUpdate(); virtual void onMuteToggleButton(); #endif - virtual void onKill(); + virtual void onKill(const Glib::VariantBase& parameter); virtual void onDeviceComboBoxChanged(); private: diff --git a/src/sourcewidget.cc b/src/sourcewidget.cc index fde5333..ebcf7fb 100644 --- a/src/sourcewidget.cc +++ b/src/sourcewidget.cc @@ -33,7 +33,7 @@ SourceWidget::SourceWidget(BaseObjectType* cobject, const Glib::RefPtr x = Gtk::Builder::create_from_file(GLADE_FILE, "deviceWidget"); - x->get_widget_derived("deviceWidget", w); + w = Gtk::Builder::get_widget_derived(x, "deviceWidget"); w->init(mainWindow, "source"); w->reference(); return w; @@ -43,7 +43,7 @@ void SourceWidget::executeVolumeUpdate() { pa_operation* o; if (!(o = pa_context_set_source_volume_by_index(get_context(), index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_source_volume_by_index() failed")); + show_error(this, _("pa_context_set_source_volume_by_index() failed")); return; } @@ -58,7 +58,7 @@ void SourceWidget::onMuteToggleButton() { pa_operation* o; if (!(o = pa_context_set_source_mute_by_index(get_context(), index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_source_mute_by_index() failed")); + show_error(this, _("pa_context_set_source_mute_by_index() failed")); return; } @@ -72,7 +72,7 @@ void SourceWidget::onDefaultToggleButton() { return; if (!(o = pa_context_set_default_source(get_context(), name.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_default_source() failed")); + show_error(this, _("pa_context_set_default_source() failed")); return; } pa_operation_unref(o); @@ -94,7 +94,7 @@ void SourceWidget::onPortChange() { Glib::ustring port = row[portModel.name]; if (!(o = pa_context_set_source_port_by_index(get_context(), index, port.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_source_port_by_index() failed")); + show_error(this, _("pa_context_set_source_port_by_index() failed")); return; } diff --git a/src/streamwidget.cc b/src/streamwidget.cc index d203b20..499fbb2 100644 --- a/src/streamwidget.cc +++ b/src/streamwidget.cc @@ -34,26 +34,20 @@ StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtrget_widget("streamChannelsVBox", channelsVBox); - x->get_widget("streamNameLabel", nameLabel); - x->get_widget("streamBoldNameLabel", boldNameLabel); - x->get_widget("streamIconImage", iconImage); + channelsVBox = x->get_widget("streamChannelsVBox"); + nameLabel = x->get_widget("streamNameLabel"); + boldNameLabel = x->get_widget("streamBoldNameLabel"); + iconImage = x->get_widget("streamIconImage"); - x->get_widget("streamLockToggleButton", lockToggleButton); - x->get_widget("streamMuteToggleButton", muteToggleButton); - x->get_widget("directionLabel", directionLabel); - x->get_widget("deviceComboBox", deviceComboBox); + lockToggleButton = x->get_widget("streamLockToggleButton"); + muteToggleButton = x->get_widget("streamMuteToggleButton"); + directionLabel = x->get_widget("directionLabel"); + deviceComboBox = x->get_widget("deviceComboBox"); - this->signal_button_press_event().connect(sigc::mem_fun(*this, &StreamWidget::onContextTriggerEvent)); muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onMuteToggleButton)); lockToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onLockToggleButton)); deviceComboBox->signal_changed().connect(sigc::mem_fun(*this, &StreamWidget::onDeviceComboBoxChanged)); - terminate.set_label(_("Terminate")); - terminate.signal_activate().connect(sigc::mem_fun(*this, &StreamWidget::onKill)); - contextMenu.append(terminate); - contextMenu.show_all(); - for (unsigned i = 0; i < PA_CHANNELS_MAX; i++) channelWidgets[i] = NULL; } @@ -64,12 +58,35 @@ void StreamWidget::init(MainWindow* mainWindow) { MinimalStreamWidget::init(); } -bool StreamWidget::onContextTriggerEvent(GdkEventButton* event) { - if (GDK_BUTTON_PRESS == event->type && 3 == event->button) { - contextMenu.popup_at_pointer((GdkEvent*)event); - return true; +void StreamWidget::addKillMenu(const char* killLabel) { + auto gesture = Gtk::GestureClick::create(); + gesture->set_button(3); + gesture->set_exclusive(true); + gesture->signal_pressed().connect(sigc::mem_fun(*this, &StreamWidget::onContextTriggerEvent)); + this->add_controller(gesture); + + const std::string actionName = "kill", groupName="streamwidget"; + auto action = Gio::SimpleAction::create(actionName); + action->set_enabled(true); + action->signal_activate().connect(sigc::mem_fun(*this, &StreamWidget::onKill)); + + auto group = Gio::SimpleActionGroup::create(); + group->add_action(action); + + insert_action_group(groupName, group); + + auto menuModel = Gio::Menu::create(); + menuModel->append(killLabel, groupName + "." + actionName); + contextMenu.set_menu_model(menuModel); + contextMenu.set_parent(*this); +} + + +void StreamWidget::onContextTriggerEvent(gint n_press, gdouble x, gdouble y) { + if (n_press == 1) { + contextMenu.set_pointing_to(Gdk::Rectangle {(int) x, (int) y, 0 , 0}); + contextMenu.popup(); } - return false; } void StreamWidget::setChannelMap(const pa_channel_map &m, bool can_decibel) { @@ -79,7 +96,7 @@ void StreamWidget::setChannelMap(const pa_channel_map &m, bool can_decibel) { for (int i = 0; i < m.channels; i++) { ChannelWidget *cw = channelWidgets[i]; - channelsVBox->pack_start(*cw, false, false, 0); + channelsVBox->prepend(*cw); cw->unreference(); } @@ -144,7 +161,7 @@ bool StreamWidget::timeoutEvent() { void StreamWidget::executeVolumeUpdate() { } -void StreamWidget::onKill() { +void StreamWidget::onKill(const Glib::VariantBase& parameter) { } void StreamWidget::onDeviceComboBoxChanged() { diff --git a/src/streamwidget.h b/src/streamwidget.h index c1a79da..048fbb9 100644 --- a/src/streamwidget.h +++ b/src/streamwidget.h @@ -53,21 +53,21 @@ public: virtual void onMuteToggleButton(); virtual void onLockToggleButton(); - virtual bool onContextTriggerEvent(GdkEventButton*); + virtual void onContextTriggerEvent(gint n_press, gdouble x, gdouble y); sigc::connection timeoutConnection; bool timeoutEvent(); virtual void executeVolumeUpdate(); - virtual void onKill(); + virtual void onKill(const Glib::VariantBase& parameter); virtual void onDeviceComboBoxChanged(); protected: MainWindow* mpMainWindow; - Gtk::Menu contextMenu; - Gtk::MenuItem terminate; + Gtk::PopoverMenu contextMenu; + void addKillMenu(const char* killLabel); }; #endif