[PATCH] pavucontrol: implement single-launch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2017-10-26 at 22:28 +0200, Colin Leroy wrote:
> From 2120613fa5bd68ebbdd0e9428357030736fce013 Mon Sep 17 00:00:00 2001
> From: Colin Leroy <colin at colino.net>
> Date: Thu, 26 Oct 2017 22:20:36 +0200
> Subject: [PATCH] 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.

The division of responsibilities isn't always very clean, but I don't
have ideas for simple fixes for that. I think PavuApplication should
create the UI and an object for managing the libpulse stuff, and the
libpulse stuff shouldn't directly depend on the UI parts. Currently the
libpulse stuff is mostly handled in pavucontrol.cc, but that is very
much dependent on the UI stuff, so fixing this would be a big project.

> ---
>  po/POTFILES.in         |   1 +
>  src/Makefile.am        |   1 +
>  src/mainwindow.cc      |  18 ++++++
>  src/mainwindow.h       |   2 +
>  src/pavuapplication.cc | 151 +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/pavuapplication.h  |  51 +++++++++++++++++
>  src/pavucontrol.cc     |  98 ++++----------------------------
>  src/pavucontrol.h      |   2 +
>  8 files changed, 237 insertions(+), 87 deletions(-)
>  create mode 100644 src/pavuapplication.cc
>  create mode 100644 src/pavuapplication.h
> 
> 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..b73108f 100644
> --- a/src/mainwindow.cc
> +++ b/src/mainwindow.cc
> @@ -340,6 +340,24 @@ static void updatePorts(DeviceWidget *w, std::map<Glib::ustring, PortInfo> &port
>      }
>  }
>  
> +void MainWindow::selectBestTab(int default_tab) {
> +    if (default_tab != -1) {
> +        if (default_tab < 1 || default_tab > notebook->get_n_pages()) {
> +            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);
> +        } else {
> +            notebook->set_current_page(default_tab - 1);
> +        }
> +        default_tab = -1;
> +    }
> +}

This is a weird function. The name implies that it will select the best
tab on some heuristics, but it only does that if default_tab is 0. If
default_tab is -1, then the function does absolutely nothing. The
"default_tab = -1" assignment at the end doesn't make any sense.

I think it would be better if this function was only called when the
caller really wants to apply the heuristics.

> +
>  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..a163069 100644
> --- a/src/mainwindow.h
> +++ b/src/mainwindow.h
> @@ -60,6 +60,8 @@ public:
>      void removeSourceOutput(uint32_t index);
>      void removeClient(uint32_t index);
>  
> +    void selectBestTab(int default_tab);
> +
>      void removeAllWidgets();
>  
>      void setConnectingMessage(const char *string = NULL);
> diff --git a/src/pavuapplication.cc b/src/pavuapplication.cc
> new file mode 100644
> index 0000000..18f8d0b
> --- /dev/null
> +++ b/src/pavuapplication.cc
> @@ -0,0 +1,151 @@
> +/***
> +  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());
> +
> +}

Why does the PavuApplication need to be wrapped in a RefPtr?

> +
> +Gtk::Window* PavuApplication::create_window()
> +{
> +    m = pa_glib_mainloop_new(g_main_context_default());
> +    g_assert(m);
> +
> +    Gtk::Window* pavucontrol_window = pavucontrol_get_window(m, maximize, retry, tab);
> +    add_window(*pavucontrol_window);
> +
> +    pavucontrol_window->signal_hide().connect(
> +                     sigc::bind<Gtk::Window*>(sigc::mem_fun(*this,
> +                     &PavuApplication::on_hide_window), pavucontrol_window));
> +
> +    return pavucontrol_window;
> +}
> +
> +void PavuApplication::on_activate()
> +{
> +    Gtk::Window* pavucontrol_window = NULL;
> +
> +    auto windows = get_windows();
> +
> +    if (windows.size() > 0) {
> +        pavucontrol_window = dynamic_cast<Gtk::Window*>(windows[0]);
> +    }

This seems a bit ugly. Couldn't the main window be a member variable of
PavuApplication?

> +
> +    if (pavucontrol_window == NULL) {
> +        pavucontrol_window = create_window();
> +    } else if (tab != -1) {
> +        ((MainWindow *)pavucontrol_window)->selectBestTab(tab);
> +    }
> +
> +    pavucontrol_window->present();
> +}

This is probably part of the "switch tab if already running" logic, but
I don't understand how that works in practice. If there's already one
instance running, how does the tab index get passed from the new
process to the old one? I'm sure I could figure it out from the GLib
documentation, but there's apparently a lot of magic happening behind
the scenes, and it would be good to have a comment that explains how
the magic works.

-- 
Tanu

https://www.patreon.com/tanuk


[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux