From 490dc1e0f4d7f93e69d05f5062194a451af10e91 Mon Sep 17 00:00:00 2001 From: Nikita Bazulin Date: Fri, 22 Nov 2024 17:03:52 +0200 Subject: [PATCH] [Packages] AudioControl: multiple changes * add deamon-mode commandline parameter * fixed the bug, when "No devices" was shown falsefuly * refactoring Signed-off-by: Nikita Bazulin --- packages/ghaf-audio-control/src/app/App.cpp | 62 ++++++++++++++++--- packages/ghaf-audio-control/src/app/App.hpp | 4 +- .../src/app/DBusService.cpp | 10 ++- .../src/app/DBusService.hpp | 2 +- packages/ghaf-audio-control/src/app/main.cpp | 6 +- .../Backends/PulseAudio/Helpers.hpp | 8 +-- .../utils/ConnectionContainer.hpp | 6 ++ .../include/GhafAudioControl/utils/Logger.hpp | 32 ++++++++-- .../PulseAudio/AudioControlBackend.cpp | 14 ++--- .../lib/src/Backends/PulseAudio/Helpers.cpp | 4 +- .../src/lib/src/models/DeviceModel.cpp | 4 +- .../src/lib/src/utils/Logger.cpp | 25 ++++---- .../src/lib/src/widgets/AppList.cpp | 2 +- .../src/lib/src/widgets/AudioControl.cpp | 20 +++--- 14 files changed, 136 insertions(+), 63 deletions(-) diff --git a/packages/ghaf-audio-control/src/app/App.cpp b/packages/ghaf-audio-control/src/app/App.cpp index 5410c60..a389dfa 100644 --- a/packages/ghaf-audio-control/src/app/App.cpp +++ b/packages/ghaf-audio-control/src/app/App.cpp @@ -5,9 +5,11 @@ #include "App.hpp" +#include + #include -#include +#include using namespace ghaf::AudioControl; @@ -15,12 +17,15 @@ namespace { constexpr auto AppId = "Ghaf Audio Control"; +constexpr auto IconName = "audio-volume-high-panel"; +constexpr auto IconSize = 64; struct AppArgs { Glib::ustring pulseServerAddress; Glib::ustring indicatorIconPath; Glib::ustring appVms; + bool isDeamonMode = false; }; std::vector GetAppVmsList(const std::string& appVms) @@ -36,6 +41,18 @@ std::vector GetAppVmsList(const std::string& appVms) return result; } +std::optional GetThemeIcon() +{ + auto icon_theme = Gtk::IconTheme::get_default(); + + if (auto iconInfo = icon_theme->lookup_icon(IconName, IconSize, Gtk::ICON_LOOKUP_USE_BUILTIN)) + return iconInfo.get_filename().c_str(); + + Logger::error("App::getThemeIcon: couldn't found an icon"); + + return std::nullopt; +} + } // namespace App::AppMenu::AppMenu(App& app) @@ -51,7 +68,8 @@ App::AppMenu::AppMenu(App& app) } App::App(int argc, char** argv) - : m_menu(*this) + : Gtk::Application("org.example.MyApp", Gio::APPLICATION_HANDLES_COMMAND_LINE) + , m_menu(*this) , m_indicator(createAppIndicator()) , m_connections{m_dbusService.openSignal().connect(sigc::mem_fun(*this, &App::openWindow))} { @@ -69,10 +87,15 @@ App::App(int argc, char** argv) appVmsOption.set_long_name("app_vms"); appVmsOption.set_description("AppVMs list"); + Glib::OptionEntry deamonModeOption; + deamonModeOption.set_long_name("deamon_mode"); + deamonModeOption.set_description("Deamon mode"); + Glib::OptionGroup options("Main", "Main"); options.add_entry(pulseServerOption, appArgs.pulseServerAddress); options.add_entry(indicatorIconPathOption, appArgs.indicatorIconPath); options.add_entry(appVmsOption, appArgs.appVms); + options.add_entry(deamonModeOption, appArgs.isDeamonMode); Glib::OptionContext context("Application Options"); context.set_main_group(options); @@ -83,16 +106,28 @@ App::App(int argc, char** argv) throw std::runtime_error{"Couldn't parse the command line arguments"}; } - app_indicator_set_icon(m_indicator.get(), appArgs.indicatorIconPath.c_str()); + m_connections += signal_command_line().connect( + [this]([[maybe_unused]] const Glib::RefPtr& args) + { + hold(); + return 0; + }, + false); + + if (const auto iconPath = GetThemeIcon()) + { + Logger::info("Got icon path for the indicator: {}", iconPath->c_str()); + app_indicator_set_icon(m_indicator.get(), iconPath->filename().c_str()); + } m_audioControl = std::make_unique(std::make_unique(appArgs.pulseServerAddress), GetAppVmsList(appArgs.appVms)); } -int App::start(int argc, char** argv) +int App::start() { Logger::debug(__PRETTY_FUNCTION__); - return run(argc, argv); + return run(); } bool App::onWindowDelete([[maybe_unused]] GdkEventAny* event) @@ -105,15 +140,25 @@ bool App::onWindowDelete([[maybe_unused]] GdkEventAny* event) void App::openWindow() { - m_window->show_all(); + m_window->show(); m_window->present(); } void App::toggleWindow() { + Logger::debug(__PRETTY_FUNCTION__); + + if (m_window == nullptr) + { + on_activate(); + openWindow(); + + return; + } + auto& window = *m_window; - ghaf::AudioControl::Logger::debug(std::format("Indicator has been activated. window.is_visible: {}", window.is_visible())); + Logger::debug("Indicator has been activated. window.is_visible: {}", window.is_visible()); if (window.is_visible()) window.hide(); @@ -140,7 +185,8 @@ void App::on_activate() hold(); add_window(*m_window); - m_window->show_all(); + m_window->show(); + m_audioControl->show(); } RaiiWrap App::createAppIndicator() diff --git a/packages/ghaf-audio-control/src/app/App.hpp b/packages/ghaf-audio-control/src/app/App.hpp index be8b9e1..da51bb9 100644 --- a/packages/ghaf-audio-control/src/app/App.hpp +++ b/packages/ghaf-audio-control/src/app/App.hpp @@ -23,7 +23,7 @@ class App : public Gtk::Application class AppMenu : public Gtk::Menu { public: - AppMenu(App& app); + explicit AppMenu(App& app); ~AppMenu() override = default; private: @@ -38,7 +38,7 @@ class App : public Gtk::Application public: App(int argc, char** argv); - int start(int argc, char** argv); + int start(); [[nodiscard]] ghaf::AudioControl::RaiiWrap createAppIndicator(); diff --git a/packages/ghaf-audio-control/src/app/DBusService.cpp b/packages/ghaf-audio-control/src/app/DBusService.cpp index 1c666fa..2db3b03 100644 --- a/packages/ghaf-audio-control/src/app/DBusService.cpp +++ b/packages/ghaf-audio-control/src/app/DBusService.cpp @@ -9,9 +9,6 @@ #include -#include -#include - using namespace ghaf::AudioControl; namespace @@ -54,11 +51,12 @@ void DBusService::onNameLost(const Glib::RefPtr&, const G Logger::error("Couldn't register service for org.ghaf.Audio"); } -void DBusService::onMethodCall(const Glib::RefPtr& connection, const Glib::ustring& sender, const Glib::ustring& objectPath, - const Glib::ustring& interfaceName, const Glib::ustring& methodName, const Glib::VariantContainerBase& parameters, +void DBusService::onMethodCall([[maybe_unused]] const Glib::RefPtr& connection, [[maybe_unused]] const Glib::ustring& sender, + [[maybe_unused]] const Glib::ustring& objectPath, [[maybe_unused]] const Glib::ustring& interfaceName, + const Glib::ustring& methodName, const Glib::VariantContainerBase& parameters, const Glib::RefPtr& invocation) { - Logger::debug(std::format("Invokated method: {}", methodName.c_str())); + Logger::debug("Invokated method: {}", methodName.c_str()); if (methodName == "Open") { diff --git a/packages/ghaf-audio-control/src/app/DBusService.hpp b/packages/ghaf-audio-control/src/app/DBusService.hpp index d048b62..c9bf5dc 100644 --- a/packages/ghaf-audio-control/src/app/DBusService.hpp +++ b/packages/ghaf-audio-control/src/app/DBusService.hpp @@ -9,7 +9,7 @@ #include #include -class DBusService +class DBusService final { public: using OpenSignalSignature = sigc::signal; diff --git a/packages/ghaf-audio-control/src/app/main.cpp b/packages/ghaf-audio-control/src/app/main.cpp index 9fe20a7..e304f89 100644 --- a/packages/ghaf-audio-control/src/app/main.cpp +++ b/packages/ghaf-audio-control/src/app/main.cpp @@ -16,16 +16,16 @@ int main(int argc, char** argv) try { App app(argc, argv); - return app.start(argc, argv); + return app.start(); } catch (const Glib::Error& ex) { - Logger::error(std::format("Error: {}", ex.what().c_str())); + Logger::error("Error: {}", ex.what().c_str()); return 1; } catch (const std::exception& e) { - Logger::error(std::format("Exception: {}", e.what())); + Logger::error("Exception: {}", e.what()); return 1; } } diff --git a/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/Backends/PulseAudio/Helpers.hpp b/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/Backends/PulseAudio/Helpers.hpp index f8c2aa3..f9fc2f7 100644 --- a/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/Backends/PulseAudio/Helpers.hpp +++ b/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/Backends/PulseAudio/Helpers.hpp @@ -34,10 +34,10 @@ void ExecutePulseFuncPrivate(Fx fx, ArgsT... args) } #if defined(DEBUG) - #define ExecutePulseFunc(FX, ARGS...) \ - { \ - Logger::debug(std::format("ExecutePulseFunc: {}", #FX)); \ - ExecutePulseFuncPrivate(FX, ARGS); \ + #define ExecutePulseFunc(FX, ARGS...) \ + { \ + Logger::debug("ExecutePulseFunc: {}", #FX); \ + ExecutePulseFuncPrivate(FX, ARGS); \ } #else template diff --git a/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/ConnectionContainer.hpp b/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/ConnectionContainer.hpp index 9e5d22d..fdd7fe4 100644 --- a/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/ConnectionContainer.hpp +++ b/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/ConnectionContainer.hpp @@ -30,6 +30,12 @@ class ConnectionContainer final std::ignore = m_connections.emplace_back(std::move(connection)); } + ConnectionContainer& operator+=(sigc::connection&& connection) + { + add(std::move(connection)); + return *this; + } + ScopeExit blockGuarded(); ConnectionContainer& operator=(ConnectionContainer&) = delete; diff --git a/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/Logger.hpp b/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/Logger.hpp index 3881433..b63eb8b 100644 --- a/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/Logger.hpp +++ b/packages/ghaf-audio-control/src/lib/include/GhafAudioControl/utils/Logger.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include namespace ghaf::AudioControl @@ -12,13 +13,36 @@ namespace ghaf::AudioControl class Logger { +private: + enum class LogLevel + { + DEBUG, + ERROR, + INFO + }; + public: - static void debug(std::string_view message); - static void error(std::string_view message); - static void info(std::string_view message); + template + static void debug(std::string_view message, ArgsT... args) + { + log(std::vformat(message, std::make_format_args(args...)), LogLevel::DEBUG); + } + + template + static void error(std::string_view message, ArgsT... args) + { + log(std::vformat(message, std::make_format_args(args...)), LogLevel::ERROR); + } + + template + static void info(std::string_view message, ArgsT... args) + { + log(std::vformat(message, std::make_format_args(args...)), LogLevel::INFO); + } private: - static void log(std::string_view message, std::string_view logLevel); + static std::string logLevelToString(LogLevel logLevel); + static void log(std::string_view message, LogLevel logLevel); Logger(); }; diff --git a/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/AudioControlBackend.cpp b/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/AudioControlBackend.cpp index 2646628..76a9185 100644 --- a/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/AudioControlBackend.cpp +++ b/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/AudioControlBackend.cpp @@ -38,7 +38,7 @@ void OnPulseDeviceInfo(const InfoT& info, IAudioControlBackend::SignalMapsecond; map.update(*deviceIt, [&info](IDeviceT& device) { dynamic_cast(device).update(info); }); - Logger::debug(std::format("Updating... {}", device.toString())); + Logger::debug("Updating... {}", device.toString()); } else { @@ -51,11 +51,11 @@ void DeletePulseDevice(IAudioControlBackend::SignalMap& map, IndexT in { if (auto deviceIt = map.findByKey(index)) { - Logger::debug(std::format("AudioControlBackend::DeletePulseDevice: delete device with id: {}", index)); + Logger::debug("AudioControlBackend::DeletePulseDevice: delete device with id: {}", index); map.remove(*deviceIt, [](IDeviceT& device) { dynamic_cast(device).markDeleted(); }); } else - Logger::error(std::format("AudioControlBackend::DeletePulseDevice: no device with id: {}", index)); + Logger::error("AudioControlBackend::DeletePulseDevice: no device with id: {}", index); } std::string ToString(const pa_card_port_info& port) @@ -145,7 +145,7 @@ AudioControlBackend::AudioControlBackend(std::string pulseAudioServerAddress) void AudioControlBackend::start() { - Logger::info(std::format("PulseAudio::AudioControlBackend: starting with server: {}", m_serverAddress)); + Logger::info("PulseAudio::AudioControlBackend: starting with server: {}", m_serverAddress); m_context = InitContext(*m_mainloopApi, contextStateCallback, *this); } @@ -243,7 +243,7 @@ void AudioControlBackend::subscribeCallback(pa_context* context, pa_subscription break; default: - Logger::error(std::format("subscribeCallback: unknown eventType: {0}", static_cast(eventType))); + Logger::error("subscribeCallback: unknown eventType: {0}", static_cast(eventType)); break; }; } @@ -274,7 +274,7 @@ void AudioControlBackend::contextStateCallback(pa_context* context, void* data) break; default: - Logger::error(std::format("contextStateCb: unknown state: {0}", static_cast(state))); + Logger::error("contextStateCb: unknown state: {0}", static_cast(state)); break; } } @@ -336,7 +336,7 @@ void AudioControlBackend::cardInfoCallback(pa_context* context, const pa_card_in return; Logger::debug("###############################################"); - Logger::debug(std::format("Card. index: {}, name: {}", info->index, info->name)); + Logger::debug("Card. index: {}, name: {}", info->index, info->name); for (size_t i = 0; i < info->n_ports; ++i) Logger::info(ToString(*info->ports[i])); diff --git a/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/Helpers.cpp b/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/Helpers.cpp index c09a44b..29062d5 100644 --- a/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/Helpers.cpp +++ b/packages/ghaf-audio-control/src/lib/src/Backends/PulseAudio/Helpers.cpp @@ -16,7 +16,7 @@ bool PulseCallbackCheck(const pa_context* context, int eol, std::string_view cal { if (context == nullptr) { - Logger::error(std::format("pulseCallbackCheck: callback: {} context == nullptr", callbackName)); + Logger::error("pulseCallbackCheck: callback: {} context == nullptr", callbackName); return false; } @@ -28,7 +28,7 @@ bool PulseCallbackCheck(const pa_context* context, int eol, std::string_view cal if (error == pa_error_code::PA_ERR_NOENTITY || error == pa_error_code::PA_OK) return true; - Logger::error(std::format("pulseCallbackCheck: callback: {} failed with error: {}", callbackName, pa_strerror(error))); + Logger::error("pulseCallbackCheck: callback: {} failed with error: {}", callbackName, pa_strerror(error)); return false; } diff --git a/packages/ghaf-audio-control/src/lib/src/models/DeviceModel.cpp b/packages/ghaf-audio-control/src/lib/src/models/DeviceModel.cpp index bfecd38..f538ba3 100644 --- a/packages/ghaf-audio-control/src/lib/src/models/DeviceModel.cpp +++ b/packages/ghaf-audio-control/src/lib/src/models/DeviceModel.cpp @@ -77,13 +77,13 @@ void DeviceModel::onSoundEnabledChange() { const auto isEnabled = m_isSoundEnabled.get_value(); - Logger::debug(std::format("SoundEnabled has changed to: {0}", isEnabled)); + Logger::debug("SoundEnabled has changed to: {0}", isEnabled); m_device->setMuted(!isEnabled); } void DeviceModel::onSoundVolumeChange() { - Logger::debug(std::format("SoundVolume has changed to: {0}", m_soundVolume.get_value())); + Logger::debug("SoundVolume has changed to: {0}", m_soundVolume.get_value()); m_device->setVolume(Volume::fromPercents(m_soundVolume.get_value())); } diff --git a/packages/ghaf-audio-control/src/lib/src/utils/Logger.cpp b/packages/ghaf-audio-control/src/lib/src/utils/Logger.cpp index 9837b9b..cb58723 100644 --- a/packages/ghaf-audio-control/src/lib/src/utils/Logger.cpp +++ b/packages/ghaf-audio-control/src/lib/src/utils/Logger.cpp @@ -12,29 +12,28 @@ namespace ghaf::AudioControl { -void Logger::debug(std::string_view message) +std::string Logger::logLevelToString(LogLevel logLevel) { - log(message, "debug"); -} + if (logLevel == Logger::LogLevel::DEBUG) + return "debug"; -void Logger::error(std::string_view message) -{ - log(message, "error"); -} + if (logLevel == Logger::LogLevel::ERROR) + return "error"; -void Logger::info(std::string_view message) -{ - log(message, "info"); + if (logLevel == Logger::LogLevel::INFO) + return "info"; + + return "unknown"; } -void Logger::log(std::string_view message, std::string_view logLevel) +void Logger::log(std::string_view message, LogLevel logLevel) { const std::chrono::time_point timeNow = std::chrono::system_clock::now(); - if (logLevel == "error") + if (logLevel == Logger::LogLevel::ERROR) std::cerr << "\033[31m"; - std::cerr << std::format("[{}] [{:5}] {}", timeNow, logLevel, message) << "\033[0m" << '\n'; + std::cerr << std::format("[{}] [{:5}] {}", timeNow, logLevelToString(logLevel), message) << "\033[0m" << '\n'; } } // namespace ghaf::AudioControl diff --git a/packages/ghaf-audio-control/src/lib/src/widgets/AppList.cpp b/packages/ghaf-audio-control/src/lib/src/widgets/AppList.cpp index 11045ee..c3e572d 100644 --- a/packages/ghaf-audio-control/src/lib/src/widgets/AppList.cpp +++ b/packages/ghaf-audio-control/src/lib/src/widgets/AppList.cpp @@ -95,7 +95,7 @@ void AppList::addDevice(IAudioControlBackend::ISinkInput::Ptr device) m_appsModel->get_item(*index)->addDevice(std::move(device)); else { - Logger::info(std::format("AppList::addDevice: add new app with name: {}", appName)); + Logger::info("AppList::addDevice: add new app with name: {}", appName); auto appVmModel = DeviceListModel::create(appName, AppVmPrefix); m_appsModel->append(appVmModel); diff --git a/packages/ghaf-audio-control/src/lib/src/widgets/AudioControl.cpp b/packages/ghaf-audio-control/src/lib/src/widgets/AudioControl.cpp index a8312fb..997b815 100644 --- a/packages/ghaf-audio-control/src/lib/src/widgets/AudioControl.cpp +++ b/packages/ghaf-audio-control/src/lib/src/widgets/AudioControl.cpp @@ -55,16 +55,16 @@ void OnPulseDeviceChanged(IAudioControlBackend::EventType eventType, IndexT inde switch (eventType) { case IAudioControlBackend::EventType::Add: - Logger::debug(std::format("OnPulseDeviceChanged: ADD {}: {}", deviceType, device->toString())); + Logger::debug("OnPulseDeviceChanged: ADD {}: {}", deviceType, device->toString()); appList.addDevice(std::move(device)); break; case IAudioControlBackend::EventType::Update: - Logger::debug(std::format("OnPulseDeviceChanged: UPDATE {}: {}", deviceType, device->toString())); + Logger::debug("OnPulseDeviceChanged: UPDATE {}: {}", deviceType, device->toString()); break; case IAudioControlBackend::EventType::Delete: - Logger::debug(std::format("OnPulseDeviceChanged: DELETE {} with index: {}", deviceType, index)); + Logger::debug("OnPulseDeviceChanged: DELETE {} with index: {}", deviceType, index); break; } } @@ -94,11 +94,11 @@ void AudioControl::init() pack_start(m_sources); pack_start(m_appList); - m_connections.add(m_audioControl->onSinksChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSinksChanged))); - m_connections.add(m_audioControl->onSourcesChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSourcesChanged))); - m_connections.add(m_audioControl->onSinkInputsChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSinkInputsChanged))); - // m_connections.add(m_audioControl->onSourceOutputsChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSourcesOutputsChanged))); - m_connections.add(m_audioControl->onError().connect(sigc::mem_fun(*this, &AudioControl::onPulseError))); + m_connections += m_audioControl->onSinksChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSinksChanged)); + m_connections += m_audioControl->onSourcesChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSourcesChanged)); + m_connections += m_audioControl->onSinkInputsChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSinkInputsChanged)); + // m_connections += m_audioControl->onSourceOutputsChanged().connect(sigc::mem_fun(*this, &AudioControl::onPulseSourcesOutputsChanged)); + m_connections += m_audioControl->onError().connect(sigc::mem_fun(*this, &AudioControl::onPulseError)); show_all_children(); @@ -116,14 +116,14 @@ void AudioControl::init() style_context->add_provider_for_screen(Gdk::Screen::get_default(), cssProvider, GTK_STYLE_PROVIDER_PRIORITY_USER); } -void AudioControl::onPulseSinksChanged(IAudioControlBackend::EventType eventType, IAudioControlBackend::Sinks::IndexT extIndex, +void AudioControl::onPulseSinksChanged(IAudioControlBackend::EventType eventType, [[maybe_unused]] IAudioControlBackend::Sinks::IndexT extIndex, IAudioControlBackend::Sinks::PtrT sink) { if (eventType == IAudioControlBackend::EventType::Add) m_sinksModel->addDevice(std::move(sink)); } -void AudioControl::onPulseSourcesChanged(IAudioControlBackend::EventType eventType, IAudioControlBackend::Sources::IndexT extIndex, +void AudioControl::onPulseSourcesChanged(IAudioControlBackend::EventType eventType, [[maybe_unused]] IAudioControlBackend::Sources::IndexT extIndex, IAudioControlBackend::Sources::PtrT source) { if (eventType == IAudioControlBackend::EventType::Add)