[pulseaudio-commits] po/POTFILES.in src/mainwindow.cc src/mainwindow.h src/Makefile.am src/pavuapplication.cc src/pavuapplication.h src/pavucontrol.cc src/pavucontrol.h

Tanu Kaskinen tanuk at kemper.freedesktop.org
Wed Nov 1 11:44:04 UTC 2017


 po/POTFILES.in         |    1 
 src/Makefile.am        |    1 
 src/mainwindow.cc      |   16 ++++
 src/mainwindow.h       |    3 
 src/pavuapplication.cc |  181 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/pavuapplication.h  |   55 ++++++++++++++
 src/pavucontrol.cc     |  102 ++++-----------------------
 src/pavucontrol.h      |    2 
 8 files changed, 274 insertions(+), 87 deletions(-)

New commits:
commit f6ce4fb8db51489f6ab1210593695f465ccb83a0
Author: Colin Leroy <colin at colino.net>
Date:   Thu Oct 26 22:20:36 2017 +0200

    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.

diff --git a/po/POTFILES.in b/po/POTFILES.in
index c952a83..e9d0f55 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,3 +12,4 @@ src/sinkwidget.cc
 src/sourceoutputwidget.cc
 src/sourcewidget.cc
 src/streamwidget.cc
+src/pavuapplication.cc
diff --git a/src/Makefile.am b/src/Makefile.am
index 7257260..b5c0314 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,6 +37,7 @@ pavucontrol_SOURCES= \
   rolewidget.h rolewidget.cc \
   mainwindow.h mainwindow.cc \
   pavucontrol.h pavucontrol.cc \
+  pavuapplication.cc pavuapplication.h \
   i18n.h
 
 pavucontrol_LDADD=$(AM_LDADD) $(GUILIBS_LIBS) $(PULSE_LIBS)
diff --git a/src/mainwindow.cc b/src/mainwindow.cc
index 31d5695..da598fd 100644
--- a/src/mainwindow.cc
+++ b/src/mainwindow.cc
@@ -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) {
     CardWidget *w;
     bool is_new = false;
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 30e1ad0..f45bf9a 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -60,6 +60,9 @@ public:
     void removeSourceOutput(uint32_t index);
     void removeClient(uint32_t index);
 
+    void selectBestTab();
+    void selectTab(int tab_number);
+
     void removeAllWidgets();
 
     void setConnectingMessage(const char *string = NULL);
diff --git a/src/pavuapplication.cc b/src/pavuapplication.cc
new file mode 100644
index 0000000..3fc874f
--- /dev/null
+++ b/src/pavuapplication.cc
@@ -0,0 +1,181 @@
+/***
+  This file is part of pavucontrol.
+
+  Copyright 2006-2008 Lennart Poettering
+  Copyright 2008 Sjoerd Simons <sjoerd at 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);
+}
diff --git a/src/pavuapplication.h b/src/pavuapplication.h
new file mode 100644
index 0000000..8ff3f35
--- /dev/null
+++ b/src/pavuapplication.h
@@ -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
diff --git a/src/pavucontrol.cc b/src/pavucontrol.cc
index 7a95c3e..fc7499c 100644
--- a/src/pavucontrol.cc
+++ b/src/pavucontrol.cc
@@ -23,7 +23,6 @@
 #endif
 
 #include <pulse/pulseaudio.h>
-#include <pulse/glib-mainloop.h>
 #include <pulse/ext-stream-restore.h>
 #include <pulse/ext-device-manager.h>
 
@@ -45,7 +44,7 @@
 static pa_context* context = NULL;
 static pa_mainloop_api* api = NULL;
 static int n_outstanding = 0;
-static int default_tab = 0;
+static int tab_number = 0;
 static bool retry = false;
 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) {
             /* At this point all notebook pages have been populated, so
              * let's open one that isn't empty */
-            if (default_tab != -1) {
-                if (default_tab < 1 || default_tab > w->notebook->get_n_pages()) {
-                    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 {
-                    w->notebook->set_current_page(default_tab - 1);
-                }
-                default_tab = -1;
+            if (tab_number != 0) {
+                w->selectTab(tab_number);
+            } else {
+                w->selectBestTab();
             }
         }
 
@@ -636,82 +625,21 @@ gboolean connect_to_pulse(gpointer userdata) {
     return false;
 }
 
-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);
-
-
-    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);
+Gtk::Window* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool _retry, int _tab_number) {
 
-    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);
+    MainWindow* mainWindow = NULL;
 
-    bool version = false;
-    Glib::OptionEntry entry4;
-    entry4.set_long_name("version");
-    entry4.set_description(_("Show version"));
-    group.add_entry(entry4, version);
+    tab_number = _tab_number;
+    retry = _retry;
 
-    options.set_main_group(group);
+    ca_context_set_driver(ca_gtk_context_get(), "pulse");
 
-    try {
-        Gtk::Main kit(argc, argv, options);
+    mainWindow = MainWindow::create(maximize);
 
-        if (version) {
-            printf("%s\n", PACKAGE_STRING);
-            return 0;
-        }
-
-        ca_context_set_driver(ca_gtk_context_get(), "pulse");
-
-        MainWindow* 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);
-        g_assert(api);
-
-        connect_to_pulse(mainWindow);
-        if (reconnect_timeout >= 0)
-            Gtk::Main::run(*mainWindow);
+    api = pa_glib_mainloop_get_api(m);
+    g_assert(api);
 
-        if (reconnect_timeout < 0)
-            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;
-    }
+    connect_to_pulse(mainWindow);
 
-    return 0;
+    return mainWindow;
 }
diff --git a/src/pavucontrol.h b/src/pavucontrol.h
index 65cb913..31fee6b 100644
--- a/src/pavucontrol.h
+++ b/src/pavucontrol.h
@@ -29,6 +29,7 @@
 #include <gtkmm.h>
 
 #include <pulse/pulseaudio.h>
+#include <pulse/glib-mainloop.h>
 
 #ifndef GLADE_FILE
 #define GLADE_FILE "pavucontrol.glade"
@@ -71,4 +72,5 @@ enum SourceType {
 pa_context* get_context(void);
 void show_error(const char *txt);
 
+Gtk::Window* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool retry, int tab_number);
 #endif



More information about the pulseaudio-commits mailing list