Implement single-launch with Gtk::Application
This introduces a new file for clarity. Options handling changes so that --tab changes the tab if the window is already opened. Other options are only used at start time.
This commit is contained in:
parent
335c26c57c
commit
f6ce4fb8db
|
@ -12,3 +12,4 @@ src/sinkwidget.cc
|
||||||
src/sourceoutputwidget.cc
|
src/sourceoutputwidget.cc
|
||||||
src/sourcewidget.cc
|
src/sourcewidget.cc
|
||||||
src/streamwidget.cc
|
src/streamwidget.cc
|
||||||
|
src/pavuapplication.cc
|
||||||
|
|
|
@ -37,6 +37,7 @@ pavucontrol_SOURCES= \
|
||||||
rolewidget.h rolewidget.cc \
|
rolewidget.h rolewidget.cc \
|
||||||
mainwindow.h mainwindow.cc \
|
mainwindow.h mainwindow.cc \
|
||||||
pavucontrol.h pavucontrol.cc \
|
pavucontrol.h pavucontrol.cc \
|
||||||
|
pavuapplication.cc pavuapplication.h \
|
||||||
i18n.h
|
i18n.h
|
||||||
|
|
||||||
pavucontrol_LDADD=$(AM_LDADD) $(GUILIBS_LIBS) $(PULSE_LIBS)
|
pavucontrol_LDADD=$(AM_LDADD) $(GUILIBS_LIBS) $(PULSE_LIBS)
|
||||||
|
|
|
@ -340,6 +340,22 @@ static void updatePorts(DeviceWidget *w, std::map<Glib::ustring, PortInfo> &port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::selectBestTab() {
|
||||||
|
if (sinkInputWidgets.size() > 0)
|
||||||
|
notebook->set_current_page(0);
|
||||||
|
else if (sourceOutputWidgets.size() > 0)
|
||||||
|
notebook->set_current_page(1);
|
||||||
|
else if (sourceWidgets.size() > 0 && sinkWidgets.size() == 0)
|
||||||
|
notebook->set_current_page(3);
|
||||||
|
else
|
||||||
|
notebook->set_current_page(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::selectTab(int tab_number) {
|
||||||
|
if (tab_number > 0 && tab_number <= notebook->get_n_pages())
|
||||||
|
notebook->set_current_page(tab_number - 1);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateCard(const pa_card_info &info) {
|
void MainWindow::updateCard(const pa_card_info &info) {
|
||||||
CardWidget *w;
|
CardWidget *w;
|
||||||
bool is_new = false;
|
bool is_new = false;
|
||||||
|
|
|
@ -60,6 +60,9 @@ public:
|
||||||
void removeSourceOutput(uint32_t index);
|
void removeSourceOutput(uint32_t index);
|
||||||
void removeClient(uint32_t index);
|
void removeClient(uint32_t index);
|
||||||
|
|
||||||
|
void selectBestTab();
|
||||||
|
void selectTab(int tab_number);
|
||||||
|
|
||||||
void removeAllWidgets();
|
void removeAllWidgets();
|
||||||
|
|
||||||
void setConnectingMessage(const char *string = NULL);
|
void setConnectingMessage(const char *string = NULL);
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
/***
|
||||||
|
This file is part of pavucontrol.
|
||||||
|
|
||||||
|
Copyright 2006-2008 Lennart Poettering
|
||||||
|
Copyright 2008 Sjoerd Simons <sjoerd@luon.net>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
#include <canberra-gtk.h>
|
||||||
|
|
||||||
|
#include "pavuapplication.h"
|
||||||
|
#include "pavucontrol.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
PavuApplication::PavuApplication() : Gtk::Application("org.pulseaudio.pavucontrol", Gio::ApplicationFlags::APPLICATION_HANDLES_COMMAND_LINE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<PavuApplication> PavuApplication::create() {
|
||||||
|
return Glib::RefPtr<PavuApplication>(new PavuApplication());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the main window and connect its "on_hide_window" signal to our cleanup
|
||||||
|
* function
|
||||||
|
*/
|
||||||
|
MainWindow* PavuApplication::create_window()
|
||||||
|
{
|
||||||
|
m = pa_glib_mainloop_new(g_main_context_default());
|
||||||
|
g_assert(m);
|
||||||
|
|
||||||
|
MainWindow* pavucontrol_window = (MainWindow *)pavucontrol_get_window(m, maximize, retry, tab);
|
||||||
|
|
||||||
|
pavucontrol_window->signal_hide().connect(
|
||||||
|
sigc::bind<Gtk::Window*>(sigc::mem_fun(*this,
|
||||||
|
&PavuApplication::on_hide_window), pavucontrol_window));
|
||||||
|
|
||||||
|
return pavucontrol_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "on_activate" signal handler
|
||||||
|
* This is fired via the Gtk::Application framework either directly from the
|
||||||
|
* run() function, or manually from the on_command_line signal handler.
|
||||||
|
* This is always executed in the first-running process.
|
||||||
|
*/
|
||||||
|
void PavuApplication::on_activate()
|
||||||
|
{
|
||||||
|
/* See if we are already running */
|
||||||
|
if (mainWindow == NULL) {
|
||||||
|
/* We aren't. Create the main window */
|
||||||
|
mainWindow = create_window();
|
||||||
|
|
||||||
|
/* and register it in the Gtk::Application */
|
||||||
|
add_window(*mainWindow);
|
||||||
|
} else if (tab != -1) {
|
||||||
|
/* We are, and a specific tab has been requested. Select it. */
|
||||||
|
mainWindow->selectTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Present the main window. */
|
||||||
|
mainWindow->present();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "on_hide_window" signal handler
|
||||||
|
* This is executed in the first-running process and performs cleanup before
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
delete window;
|
||||||
|
mainWindow = NULL;
|
||||||
|
|
||||||
|
if (get_context()) {
|
||||||
|
pa_context_unref(get_context());
|
||||||
|
}
|
||||||
|
pa_glib_mainloop_free(m);
|
||||||
|
m = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T_ArgType>
|
||||||
|
static bool get_arg_value(const Glib::RefPtr<Glib::VariantDict>& options, const Glib::ustring& arg_name, T_ArgType& arg_value)
|
||||||
|
{
|
||||||
|
arg_value = T_ArgType();
|
||||||
|
if (options->lookup_value(arg_name, arg_value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "on_command_line" signal handler
|
||||||
|
* This is executed in the first-running process.
|
||||||
|
*/
|
||||||
|
int on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine>& command_line,
|
||||||
|
Glib::RefPtr<PavuApplication>& app)
|
||||||
|
{
|
||||||
|
const auto options = command_line->get_options_dict();
|
||||||
|
|
||||||
|
get_arg_value(options, "tab", app->tab);
|
||||||
|
get_arg_value(options, "retry", app->retry);
|
||||||
|
get_arg_value(options, "maximize", app->maximize);
|
||||||
|
get_arg_value(options, "version", app->version);
|
||||||
|
|
||||||
|
if (app->version) {
|
||||||
|
printf("%s\n", PACKAGE_STRING);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
app->activate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
/* Initialize the i18n stuff */
|
||||||
|
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
||||||
|
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
||||||
|
textdomain(GETTEXT_PACKAGE);
|
||||||
|
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
/* Create the application */
|
||||||
|
auto app = PavuApplication::create();
|
||||||
|
|
||||||
|
/* Add command-line options */
|
||||||
|
app->add_main_option_entry(
|
||||||
|
Gio::Application::OptionType::OPTION_TYPE_INT,
|
||||||
|
"tab", 't',
|
||||||
|
_("Select a specific tab on load."),
|
||||||
|
_("number"));
|
||||||
|
|
||||||
|
app->add_main_option_entry(
|
||||||
|
Gio::Application::OptionType::OPTION_TYPE_BOOL,
|
||||||
|
"retry", 'r',
|
||||||
|
_("Retry forever if pa quits (every 5 seconds)."));
|
||||||
|
|
||||||
|
app->add_main_option_entry(
|
||||||
|
Gio::Application::OptionType::OPTION_TYPE_BOOL,
|
||||||
|
"maximize", 'm',
|
||||||
|
_("Maximize the window."));
|
||||||
|
|
||||||
|
app->add_main_option_entry(
|
||||||
|
Gio::Application::OptionType::OPTION_TYPE_BOOL,
|
||||||
|
"version", 'v',
|
||||||
|
_("Show version."));
|
||||||
|
|
||||||
|
/* Connect to the "on_command_line" signal which is fired
|
||||||
|
* when the application receives command-line arguments
|
||||||
|
*/
|
||||||
|
app->signal_command_line().connect(sigc::bind(sigc::ptr_fun(&on_command_line), app), false);
|
||||||
|
|
||||||
|
/* Run the application.
|
||||||
|
* In the first launched instance, this will return when its window is
|
||||||
|
* closed. In subsequently launches instances, this will only signal the
|
||||||
|
* first instance to handle a new request, and exit immediately.
|
||||||
|
* Handling a new request consists of presenting the existing window (and
|
||||||
|
* optionally, select a tab).
|
||||||
|
*/
|
||||||
|
return app->run(argc, argv);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/***
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifndef pavuapplication_h
|
||||||
|
#define pavuapplication_h
|
||||||
|
|
||||||
|
#include "pavucontrol.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
class PavuApplication : public Gtk::Application {
|
||||||
|
protected:
|
||||||
|
PavuApplication();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Glib::RefPtr<PavuApplication> create();
|
||||||
|
|
||||||
|
/* Main window */
|
||||||
|
MainWindow *mainWindow;
|
||||||
|
|
||||||
|
/* options */
|
||||||
|
bool retry;
|
||||||
|
bool maximize;
|
||||||
|
gint32 tab;
|
||||||
|
bool version;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Override default signal handlers:
|
||||||
|
void on_activate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MainWindow* create_window();
|
||||||
|
void on_hide_window(Gtk::Window* window);
|
||||||
|
|
||||||
|
pa_glib_mainloop *m = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,7 +23,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
#include <pulse/glib-mainloop.h>
|
|
||||||
#include <pulse/ext-stream-restore.h>
|
#include <pulse/ext-stream-restore.h>
|
||||||
#include <pulse/ext-device-manager.h>
|
#include <pulse/ext-device-manager.h>
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@
|
||||||
static pa_context* context = NULL;
|
static pa_context* context = NULL;
|
||||||
static pa_mainloop_api* api = NULL;
|
static pa_mainloop_api* api = NULL;
|
||||||
static int n_outstanding = 0;
|
static int n_outstanding = 0;
|
||||||
static int default_tab = 0;
|
static int tab_number = 0;
|
||||||
static bool retry = false;
|
static bool retry = false;
|
||||||
static int reconnect_timeout = 1;
|
static int reconnect_timeout = 1;
|
||||||
|
|
||||||
|
@ -171,20 +170,10 @@ void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, voi
|
||||||
if (n_outstanding > 0) {
|
if (n_outstanding > 0) {
|
||||||
/* At this point all notebook pages have been populated, so
|
/* At this point all notebook pages have been populated, so
|
||||||
* let's open one that isn't empty */
|
* let's open one that isn't empty */
|
||||||
if (default_tab != -1) {
|
if (tab_number != 0) {
|
||||||
if (default_tab < 1 || default_tab > w->notebook->get_n_pages()) {
|
w->selectTab(tab_number);
|
||||||
if (w->sinkInputWidgets.size() > 0)
|
|
||||||
w->notebook->set_current_page(0);
|
|
||||||
else if (w->sourceOutputWidgets.size() > 0)
|
|
||||||
w->notebook->set_current_page(1);
|
|
||||||
else if (w->sourceWidgets.size() > 0 && w->sinkWidgets.size() == 0)
|
|
||||||
w->notebook->set_current_page(3);
|
|
||||||
else
|
|
||||||
w->notebook->set_current_page(2);
|
|
||||||
} else {
|
} else {
|
||||||
w->notebook->set_current_page(default_tab - 1);
|
w->selectBestTab();
|
||||||
}
|
|
||||||
default_tab = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,82 +625,21 @@ gboolean connect_to_pulse(gpointer userdata) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
Gtk::Window* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool _retry, int _tab_number) {
|
||||||
|
|
||||||
/* Initialize the i18n stuff */
|
MainWindow* mainWindow = NULL;
|
||||||
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
|
|
||||||
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
|
||||||
textdomain(GETTEXT_PACKAGE);
|
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
tab_number = _tab_number;
|
||||||
|
retry = _retry;
|
||||||
|
|
||||||
Glib::OptionContext options;
|
|
||||||
options.set_summary("PulseAudio Volume Control");
|
|
||||||
options.set_help_enabled();
|
|
||||||
|
|
||||||
Glib::OptionGroup group("pulseaudio", "PAVUControl");
|
|
||||||
|
|
||||||
Glib::OptionEntry entry;
|
|
||||||
entry.set_long_name("tab");
|
|
||||||
entry.set_short_name('t');
|
|
||||||
entry.set_description(_("Select a specific tab on load."));
|
|
||||||
group.add_entry(entry, default_tab);
|
|
||||||
|
|
||||||
Glib::OptionEntry entry2;
|
|
||||||
entry2.set_long_name("retry");
|
|
||||||
entry2.set_short_name('r');
|
|
||||||
entry2.set_description(_("Retry forever if pa quits (every 5 seconds)."));
|
|
||||||
group.add_entry(entry2, retry);
|
|
||||||
|
|
||||||
bool maximize = false;
|
|
||||||
Glib::OptionEntry entry3;
|
|
||||||
entry3.set_long_name("maximize");
|
|
||||||
entry3.set_short_name('m');
|
|
||||||
entry3.set_description(_("Maximize the window."));
|
|
||||||
group.add_entry(entry3, maximize);
|
|
||||||
|
|
||||||
bool version = false;
|
|
||||||
Glib::OptionEntry entry4;
|
|
||||||
entry4.set_long_name("version");
|
|
||||||
entry4.set_description(_("Show version"));
|
|
||||||
group.add_entry(entry4, version);
|
|
||||||
|
|
||||||
options.set_main_group(group);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Gtk::Main kit(argc, argv, options);
|
|
||||||
|
|
||||||
if (version) {
|
|
||||||
printf("%s\n", PACKAGE_STRING);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ca_context_set_driver(ca_gtk_context_get(), "pulse");
|
ca_context_set_driver(ca_gtk_context_get(), "pulse");
|
||||||
|
|
||||||
MainWindow* mainWindow = MainWindow::create(maximize);
|
mainWindow = MainWindow::create(maximize);
|
||||||
|
|
||||||
pa_glib_mainloop *m = pa_glib_mainloop_new(g_main_context_default());
|
|
||||||
g_assert(m);
|
|
||||||
api = pa_glib_mainloop_get_api(m);
|
api = pa_glib_mainloop_get_api(m);
|
||||||
g_assert(api);
|
g_assert(api);
|
||||||
|
|
||||||
connect_to_pulse(mainWindow);
|
connect_to_pulse(mainWindow);
|
||||||
if (reconnect_timeout >= 0)
|
|
||||||
Gtk::Main::run(*mainWindow);
|
|
||||||
|
|
||||||
if (reconnect_timeout < 0)
|
return mainWindow;
|
||||||
show_error(_("Fatal Error: Unable to connect to PulseAudio"));
|
|
||||||
|
|
||||||
delete mainWindow;
|
|
||||||
|
|
||||||
if (context)
|
|
||||||
pa_context_unref(context);
|
|
||||||
pa_glib_mainloop_free(m);
|
|
||||||
} catch ( const Glib::OptionError & e ) {
|
|
||||||
fprintf(stderr, "%s", options.get_help().c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
|
#include <pulse/glib-mainloop.h>
|
||||||
|
|
||||||
#ifndef GLADE_FILE
|
#ifndef GLADE_FILE
|
||||||
#define GLADE_FILE "pavucontrol.glade"
|
#define GLADE_FILE "pavucontrol.glade"
|
||||||
|
@ -71,4 +72,5 @@ enum SourceType {
|
||||||
pa_context* get_context(void);
|
pa_context* get_context(void);
|
||||||
void show_error(const char *txt);
|
void show_error(const char *txt);
|
||||||
|
|
||||||
|
Gtk::Window* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool retry, int tab_number);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue