diff options
author | Xavi Garcia Mena <xavi.garcia.mena@canonical.com> | 2015-12-23 12:08:16 +0100 |
---|---|---|
committer | Xavi Garcia Mena <xavi.garcia.mena@canonical.com> | 2015-12-23 12:08:16 +0100 |
commit | d8d60bc83824359c6e22b9114fc0a6bde45b8eca (patch) | |
tree | 9103330b940fa63dedb8f0919c1431d266df0172 /src | |
parent | 3a75ebb5eae371de3b50ce4716a4af886d9eeac3 (diff) | |
download | ayatana-indicator-sound-d8d60bc83824359c6e22b9114fc0a6bde45b8eca.tar.gz ayatana-indicator-sound-d8d60bc83824359c6e22b9114fc0a6bde45b8eca.tar.bz2 ayatana-indicator-sound-d8d60bc83824359c6e22b9114fc0a6bde45b8eca.zip |
Reverted to release 507
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 21 | ||||
-rw-r--r-- | src/gmenuharness/CMakeLists.txt | 17 | ||||
-rw-r--r-- | src/gmenuharness/MatchResult.cpp | 187 | ||||
-rw-r--r-- | src/gmenuharness/MatchUtils.cpp | 77 | ||||
-rw-r--r-- | src/gmenuharness/MenuItemMatcher.cpp | 1008 | ||||
-rw-r--r-- | src/gmenuharness/MenuMatcher.cpp | 208 | ||||
-rw-r--r-- | src/service.vala | 407 | ||||
-rw-r--r-- | src/sound-menu.vala | 38 | ||||
-rw-r--r-- | src/volume-control-pulse.vala | 83 | ||||
-rw-r--r-- | src/volume-control.vala | 14 |
10 files changed, 75 insertions, 1985 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c621ae..194dfc9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,12 +8,12 @@ set(SYMBOLS_PATH "${CMAKE_CURRENT_BINARY_DIR}/indicator-sound-service.def") set(VAPI_PATH "${CMAKE_CURRENT_BINARY_DIR}/indicator-sound-service.vapi") vapi_gen(accounts-service - LIBRARY - accounts-service - PACKAGES - gio-2.0 - INPUT - /usr/share/gir-1.0/AccountsService-1.0.gir + LIBRARY + accounts-service + PACKAGES + gio-2.0 + INPUT + /usr/share/gir-1.0/AccountsService-1.0.gir ) vala_init(indicator-sound-service @@ -70,7 +70,7 @@ vala_add(indicator-sound-service media-player-user.vala DEPENDS media-player - accounts-service-sound-settings + accounts-service-sound-settings greeter-broadcast ) vala_add(indicator-sound-service @@ -103,7 +103,6 @@ vala_add(indicator-sound-service sound-menu.vala DEPENDS media-player - volume-control ) vala_add(indicator-sound-service accounts-service-user.vala @@ -165,8 +164,8 @@ add_definitions( ) add_library( - indicator-sound-service-lib STATIC - ${INDICATOR_SOUND_SOURCES} + indicator-sound-service-lib STATIC + ${INDICATOR_SOUND_SOURCES} ) target_link_libraries( @@ -207,5 +206,3 @@ install( RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/indicator-sound/ ) -# Disable integration tests -# add_subdirectory(gmenuharness) diff --git a/src/gmenuharness/CMakeLists.txt b/src/gmenuharness/CMakeLists.txt deleted file mode 100644 index c9e613a..0000000 --- a/src/gmenuharness/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -pkg_check_modules(UNITY_API libunity-api>=0.1.3 REQUIRED) -include_directories(${UNITY_API_INCLUDE_DIRS}) - -include_directories("${CMAKE_SOURCE_DIR}/include") - -add_library( - gmenuharness-shared SHARED - MatchResult.cpp - MatchUtils.cpp - MenuItemMatcher.cpp - MenuMatcher.cpp -) - -target_link_libraries( - gmenuharness-shared - ${GLIB_LDFLAGS} -) diff --git a/src/gmenuharness/MatchResult.cpp b/src/gmenuharness/MatchResult.cpp deleted file mode 100644 index 40629aa..0000000 --- a/src/gmenuharness/MatchResult.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright © 2014 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3, - * as published by the Free Software Foundation. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Authored by: Pete Woods <pete.woods@canonical.com> - */ - -#include <unity/gmenuharness/MatchResult.h> - -#include <chrono> -#include <map> -#include <sstream> -#include <iostream> - -using namespace std; - -namespace unity -{ - -namespace gmenuharness -{ - -namespace -{ - - -static void printLocation(ostream& ss, const vector<unsigned int>& location, bool first) -{ - for (int i : location) - { - ss << " "; - if (first) - { - ss << i; - } - else - { - ss << " "; - } - } - ss << " "; -} - -struct compare_vector -{ - bool operator()(const vector<unsigned int>& a, - const vector<unsigned int>& b) const - { - auto p1 = a.begin(); - auto p2 = b.begin(); - - while (p1 != a.end()) - { - if (p2 == b.end()) - { - return false; - } - if (*p2 > *p1) - { - return true; - } - if (*p1 > *p2) - { - return false; - } - - ++p1; - ++p2; - } - - if (p2 != b.end()) - { - return true; - } - - return false; - } -}; -} - -struct MatchResult::Priv -{ - bool m_success = true; - - map<vector<unsigned int>, vector<string>, compare_vector> m_failures; - - chrono::time_point<chrono::system_clock> m_timeout = chrono::system_clock::now() + chrono::seconds(10); -}; - -MatchResult::MatchResult() : - p(new Priv) -{ -} - -MatchResult::MatchResult(MatchResult&& other) -{ - *this = move(other); -} - -MatchResult::MatchResult(const MatchResult& other) : - p(new Priv) -{ - *this = other; -} - -MatchResult& MatchResult::operator=(const MatchResult& other) -{ - p->m_success = other.p->m_success; - p->m_failures= other.p->m_failures; - return *this; -} - -MatchResult& MatchResult::operator=(MatchResult&& other) -{ - p = move(other.p); - return *this; -} - -MatchResult MatchResult::createChild() const -{ - MatchResult child; - child.p->m_timeout = p->m_timeout; - return child; -} - -void MatchResult::failure(const vector<unsigned int>& location, const string& message) -{ - p->m_success = false; - auto it = p->m_failures.find(location); - if (it == p->m_failures.end()) - { - it = p->m_failures.insert(make_pair(location, vector<string>())).first; - } - it->second.emplace_back(message); -} - -void MatchResult::merge(const MatchResult& other) -{ - p->m_success &= other.p->m_success; - for (const auto& e : other.p->m_failures) - { - p->m_failures.insert(make_pair(e.first, e.second)); - } -} - -bool MatchResult::success() const -{ - return p->m_success; -} - -bool MatchResult::hasTimedOut() const -{ - auto now = chrono::system_clock::now(); - return (now >= p->m_timeout); -} - -string MatchResult::concat_failures() const -{ - stringstream ss; - ss << "Failed expectations:" << endl; - for (const auto& failure : p->m_failures) - { - bool first = true; - for (const string& s: failure.second) - { - printLocation(ss, failure.first, first); - first = false; - ss << s << endl; - } - } - return ss.str(); -} - -} // namespace gmenuharness - -} // namespace unity diff --git a/src/gmenuharness/MatchUtils.cpp b/src/gmenuharness/MatchUtils.cpp deleted file mode 100644 index 7b87a25..0000000 --- a/src/gmenuharness/MatchUtils.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright © 2014 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3, - * as published by the Free Software Foundation. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Authored by: Pete Woods <pete.woods@canonical.com> - */ - -#include <unity/gmenuharness/MatchUtils.h> - -#include <unity/util/ResourcePtr.h> - -using namespace std; -namespace util = unity::util; - -namespace unity -{ - -namespace gmenuharness -{ - -void waitForCore (GObject * obj, const string& signalName, unsigned int timeout) { - shared_ptr<GMainLoop> loop(g_main_loop_new(nullptr, false), &g_main_loop_unref); - - /* Our two exit criteria */ - util::ResourcePtr<gulong, function<void(gulong)>> signal( - g_signal_connect_swapped(obj, signalName.c_str(), - G_CALLBACK(g_main_loop_quit), loop.get()), - [obj](gulong s) - { - g_signal_handler_disconnect(obj, s); - }); - - util::ResourcePtr<guint, function<void(guint)>> timer(g_timeout_add(timeout, - [](gpointer user_data) -> gboolean - { - g_main_loop_quit((GMainLoop *)user_data); - return G_SOURCE_CONTINUE; - }, - loop.get()), - &g_source_remove); - - /* Wait for sync */ - g_main_loop_run(loop.get()); -} - -void menuWaitForItems(const shared_ptr<GMenuModel>& menu, unsigned int timeout) -{ - waitForCore(G_OBJECT(menu.get()), "items-changed", timeout); -} - -void g_object_deleter(gpointer object) -{ - g_clear_object(&object); -} - -void gvariant_deleter(GVariant* varptr) -{ - if (varptr != nullptr) - { - g_variant_unref(varptr); - } -} - -} // namespace gmenuharness - -} // namespace unity diff --git a/src/gmenuharness/MenuItemMatcher.cpp b/src/gmenuharness/MenuItemMatcher.cpp deleted file mode 100644 index f39acef..0000000 --- a/src/gmenuharness/MenuItemMatcher.cpp +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Copyright © 2014 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3, - * as published by the Free Software Foundation. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Authored by: Pete Woods <pete.woods@canonical.com> - */ - -#include <unity/gmenuharness/MatchResult.h> -#include <unity/gmenuharness/MatchUtils.h> -#include <unity/gmenuharness/MenuItemMatcher.h> - -#include <iostream> -#include <vector> -#include <map> - -using namespace std; - -namespace unity -{ - -namespace gmenuharness -{ - -namespace -{ - -enum class LinkType -{ - any, - section, - submenu -}; - -static string bool_to_string(bool value) -{ - return value? "true" : "false"; -} - -static shared_ptr<GVariant> get_action_group_attribute(const shared_ptr<GActionGroup>& actionGroup, const gchar* attribute) -{ - shared_ptr<GVariant> value( - g_action_group_get_action_state(actionGroup.get(), attribute), - &gvariant_deleter); - return value; -} - -static shared_ptr<GVariant> get_attribute(const shared_ptr<GMenuItem> menuItem, const gchar* attribute) -{ - shared_ptr<GVariant> value( - g_menu_item_get_attribute_value(menuItem.get(), attribute, nullptr), - &gvariant_deleter); - return value; -} - -static string get_string_attribute(const shared_ptr<GMenuItem> menuItem, const gchar* attribute) -{ - string result; - char* temp = nullptr; - if (g_menu_item_get_attribute(menuItem.get(), attribute, "s", &temp)) - { - result = temp; - g_free(temp); - } - return result; -} - -static pair<string, string> split_action(const string& action) -{ - auto index = action.find('.'); - - if (index == string::npos) - { - return make_pair(string(), action); - } - - return make_pair(action.substr(0, index), action.substr(index + 1, action.size())); -} - -static string type_to_string(MenuItemMatcher::Type type) -{ - switch(type) - { - case MenuItemMatcher::Type::plain: - return "plain"; - case MenuItemMatcher::Type::checkbox: - return "checkbox"; - case MenuItemMatcher::Type::radio: - return "radio"; - } - - return string(); -} -} - -struct MenuItemMatcher::Priv -{ - void all(MatchResult& matchResult, const vector<unsigned int>& location, - const shared_ptr<GMenuModel>& menu, - map<string, shared_ptr<GActionGroup>>& actions) - { - int count = g_menu_model_get_n_items(menu.get()); - - if (m_items.size() != (unsigned int) count) - { - matchResult.failure( - location, - "Expected " + to_string(m_items.size()) - + " children, but found " + to_string(count)); - return; - } - - for (size_t i = 0; i < m_items.size(); ++i) - { - const auto& matcher = m_items.at(i); - matcher.match(matchResult, location, menu, actions, i); - } - } - - void startsWith(MatchResult& matchResult, const vector<unsigned int>& location, - const shared_ptr<GMenuModel>& menu, - map<string, shared_ptr<GActionGroup>>& actions) - { - int count = g_menu_model_get_n_items(menu.get()); - if (m_items.size() > (unsigned int) count) - { - matchResult.failure( - location, - "Expected at least " + to_string(m_items.size()) - + " children, but found " + to_string(count)); - return; - } - - for (size_t i = 0; i < m_items.size(); ++i) - { - const auto& matcher = m_items.at(i); - matcher.match(matchResult, location, menu, actions, i); - } - } - - void endsWith(MatchResult& matchResult, const vector<unsigned int>& location, - const shared_ptr<GMenuModel>& menu, - map<string, shared_ptr<GActionGroup>>& actions) - { - int count = g_menu_model_get_n_items(menu.get()); - if (m_items.size() > (unsigned int) count) - { - matchResult.failure( - location, - "Expected at least " + to_string(m_items.size()) - + " children, but found " + to_string(count)); - return; - } - - // match the last N items - size_t j; - for (size_t i = count - m_items.size(), j = 0; i < count && j < m_items.size(); ++i, ++j) - { - const auto& matcher = m_items.at(j); - matcher.match(matchResult, location, menu, actions, i); - } - } - - Type m_type = Type::plain; - - Mode m_mode = Mode::all; - - LinkType m_linkType = LinkType::any; - - shared_ptr<size_t> m_expectedSize; - - shared_ptr<string> m_label; - - shared_ptr<string> m_icon; - - map<shared_ptr<string>, vector<std::string>> m_themed_icons; - - shared_ptr<string> m_action; - - vector<std::string> m_state_icons; - - vector<pair<string, shared_ptr<GVariant>>> m_attributes; - - vector<string> m_not_exist_attributes; - - vector<pair<string, shared_ptr<GVariant>>> m_pass_through_attributes; - - shared_ptr<bool> m_isToggled; - - vector<MenuItemMatcher> m_items; - - vector<pair<string, shared_ptr<GVariant>>> m_activations; - - vector<pair<string, shared_ptr<GVariant>>> m_setActionStates; - - double m_maxDifference = 0.0; -}; - -MenuItemMatcher MenuItemMatcher::checkbox() -{ - MenuItemMatcher matcher; - matcher.type(Type::checkbox); - return matcher; -} - -MenuItemMatcher MenuItemMatcher::radio() -{ - MenuItemMatcher matcher; - matcher.type(Type::radio); - return matcher; -} - -MenuItemMatcher::MenuItemMatcher() : - p(new Priv) -{ -} - -MenuItemMatcher::~MenuItemMatcher() -{ -} - -MenuItemMatcher::MenuItemMatcher(const MenuItemMatcher& other) : - p(new Priv) -{ - *this = other; -} - -MenuItemMatcher::MenuItemMatcher(MenuItemMatcher&& other) -{ - *this = move(other); -} - -MenuItemMatcher& MenuItemMatcher::operator=(const MenuItemMatcher& other) -{ - p->m_type = other.p->m_type; - p->m_mode = other.p->m_mode; - p->m_expectedSize = other.p->m_expectedSize; - p->m_label = other.p->m_label; - p->m_icon = other.p->m_icon; - p->m_themed_icons = other.p->m_themed_icons; - p->m_action = other.p->m_action; - p->m_state_icons = other.p->m_state_icons; - p->m_attributes = other.p->m_attributes; - p->m_not_exist_attributes = other.p->m_not_exist_attributes; - p->m_pass_through_attributes = other.p->m_pass_through_attributes; - p->m_isToggled = other.p->m_isToggled; - p->m_linkType = other.p->m_linkType; - p->m_items = other.p->m_items; - p->m_activations = other.p->m_activations; - p->m_setActionStates = other.p->m_setActionStates; - p->m_maxDifference = other.p->m_maxDifference; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::operator=(MenuItemMatcher&& other) -{ - p = move(other.p); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::type(Type type) -{ - p->m_type = type; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::label(const string& label) -{ - p->m_label = make_shared<string>(label); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::action(const string& action) -{ - p->m_action = make_shared<string>(action); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::state_icons(const std::vector<std::string>& state_icons) -{ - p->m_state_icons = state_icons; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::icon(const string& icon) -{ - p->m_icon = make_shared<string>(icon); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::themed_icon(const std::string& iconName, const std::vector<std::string>& icons) -{ - p->m_themed_icons[make_shared<string>(iconName)] = icons; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::widget(const string& widget) -{ - return string_attribute("x-canonical-type", widget); -} - -MenuItemMatcher& MenuItemMatcher::pass_through_attribute(const string& actionName, const shared_ptr<GVariant>& value) -{ - p->m_pass_through_attributes.emplace_back(actionName, value); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::pass_through_boolean_attribute(const string& actionName, bool value) -{ - return pass_through_attribute( - actionName, - shared_ptr<GVariant>(g_variant_new_boolean(value), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::pass_through_string_attribute(const string& actionName, const string& value) -{ - return pass_through_attribute( - actionName, - shared_ptr<GVariant>(g_variant_new_string(value.c_str()), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::pass_through_double_attribute(const std::string& actionName, double value) -{ - return pass_through_attribute( - actionName, - shared_ptr<GVariant>(g_variant_new_double(value), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::round_doubles(double maxDifference) -{ - p->m_maxDifference = maxDifference; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::attribute(const string& name, const shared_ptr<GVariant>& value) -{ - p->m_attributes.emplace_back(name, value); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::boolean_attribute(const string& name, bool value) -{ - return attribute( - name, - shared_ptr<GVariant>(g_variant_new_boolean(value), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::string_attribute(const string& name, const string& value) -{ - return attribute( - name, - shared_ptr<GVariant>(g_variant_new_string(value.c_str()), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::int32_attribute(const std::string& name, int value) -{ - return attribute( - name, - shared_ptr<GVariant>(g_variant_new_int32 (value), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::int64_attribute(const std::string& name, int value) -{ - return attribute( - name, - shared_ptr<GVariant>(g_variant_new_int64 (value), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::double_attribute(const std::string& name, double value) -{ - return attribute( - name, - shared_ptr<GVariant>(g_variant_new_double (value), - &gvariant_deleter)); -} - -MenuItemMatcher& MenuItemMatcher::attribute_not_set(const std::string& name) -{ - p->m_not_exist_attributes.emplace_back (name); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::toggled(bool isToggled) -{ - p->m_isToggled = make_shared<bool>(isToggled); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::mode(Mode mode) -{ - p->m_mode = mode; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::submenu() -{ - p->m_linkType = LinkType::submenu; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::section() -{ - p->m_linkType = LinkType::section; - return *this; -} - -MenuItemMatcher& MenuItemMatcher::is_empty() -{ - return has_exactly(0); -} - -MenuItemMatcher& MenuItemMatcher::has_exactly(size_t children) -{ - p->m_expectedSize = make_shared<size_t>(children); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::item(const MenuItemMatcher& item) -{ - p->m_items.emplace_back(item); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::item(MenuItemMatcher&& item) -{ - p->m_items.emplace_back(item); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::pass_through_activate(std::string const& action, const shared_ptr<GVariant>& parameter) -{ - p->m_activations.emplace_back(action, parameter); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::activate(const shared_ptr<GVariant>& parameter) -{ - p->m_activations.emplace_back(string(), parameter); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::set_pass_through_action_state(const std::string& action, const std::shared_ptr<GVariant>& state) -{ - p->m_setActionStates.emplace_back(action, state); - return *this; -} - -MenuItemMatcher& MenuItemMatcher::set_action_state(const std::shared_ptr<GVariant>& state) -{ - p->m_setActionStates.emplace_back("", state); - return *this; -} - -void MenuItemMatcher::match( - MatchResult& matchResult, - const vector<unsigned int>& parentLocation, - const shared_ptr<GMenuModel>& menu, - map<string, shared_ptr<GActionGroup>>& actions, - int index) const -{ - shared_ptr<GMenuItem> menuItem(g_menu_item_new_from_model(menu.get(), index), &g_object_deleter); - - vector<unsigned int> location(parentLocation); - location.emplace_back(index); - - string action = get_string_attribute(menuItem, G_MENU_ATTRIBUTE_ACTION); - - bool isCheckbox = false; - bool isRadio = false; - bool isToggled = false; - - pair<string, string> idPair; - shared_ptr<GActionGroup> actionGroup; - shared_ptr<GVariant> state; - - if (!action.empty()) - { - idPair = split_action(action); - actionGroup = actions[idPair.first]; - state = shared_ptr<GVariant>(g_action_group_get_action_state(actionGroup.get(), - idPair.second.c_str()), - &gvariant_deleter); - auto attributeTarget = get_attribute(menuItem, G_MENU_ATTRIBUTE_TARGET); - - if (attributeTarget && state) - { - isToggled = g_variant_equal(state.get(), attributeTarget.get()); - isRadio = true; - } - else if (state - && g_variant_is_of_type(state.get(), G_VARIANT_TYPE_BOOLEAN)) - { - isToggled = g_variant_get_boolean(state.get()); - isCheckbox = true; - } - } - - Type actualType = Type::plain; - if (isCheckbox) - { - actualType = Type::checkbox; - } - else if (isRadio) - { - actualType = Type::radio; - } - - if (actualType != p->m_type) - { - matchResult.failure( - location, - "Expected " + type_to_string(p->m_type) + ", found " - + type_to_string(actualType)); - } - - // check themed icons - map<shared_ptr<string>, vector<string>>::iterator iter; - for (iter = p->m_themed_icons.begin(); iter != p->m_themed_icons.end(); ++iter) - { - auto icon_val = g_menu_item_get_attribute_value(menuItem.get(), (*iter).first->c_str(), nullptr); - if (!icon_val) - { - matchResult.failure( - location, - "Expected themed icon " + (*(*iter).first) + " was not found"); - } - - auto gicon = g_icon_deserialize(icon_val); - if (!gicon || !G_IS_THEMED_ICON(gicon)) - { - matchResult.failure( - location, - "Expected attribute " + (*(*iter).first) + " is not a themed icon"); - } - auto iconNames = g_themed_icon_get_names(G_THEMED_ICON(gicon)); - int nb_icons = 0; - while(iconNames[nb_icons]) - { - ++nb_icons; - } - - if (nb_icons != (*iter).second.size()) - { - matchResult.failure( - location, - "Expected " + to_string((*iter).second.size()) + - " icons for themed icon [" + (*(*iter).first) + - "], but " + to_string(nb_icons) + " were found."); - } - else - { - // now compare all the icons - for (int i = 0; i < nb_icons; ++i) - { - if (string(iconNames[i]) != (*iter).second[i]) - { - matchResult.failure( - location, - "Icon at position " + to_string(i) + - " for themed icon [" + (*(*iter).first) + - "], mismatchs. Expected: " + iconNames[i] + " but found " + (*iter).second[i]); - } - } - } - g_object_unref(gicon); - } - - string label = get_string_attribute(menuItem, G_MENU_ATTRIBUTE_LABEL); - if (p->m_label && (*p->m_label) != label) - { - matchResult.failure( - location, - "Expected label '" + *p->m_label + "', but found '" + label - + "'"); - } - - string icon = get_string_attribute(menuItem, G_MENU_ATTRIBUTE_ICON); - if (p->m_icon && (*p->m_icon) != icon) - { - matchResult.failure( - location, - "Expected icon '" + *p->m_icon + "', but found '" + icon + "'"); - } - - if (p->m_action && (*p->m_action) != action) - { - matchResult.failure( - location, - "Expected action '" + *p->m_action + "', but found '" + action - + "'"); - } - - if (!p->m_state_icons.empty() && !state) - { - matchResult.failure( - location, - "Expected state icons but no state was found"); - } - else if (!p->m_state_icons.empty() && state && - !g_variant_is_of_type(state.get(), G_VARIANT_TYPE_VARDICT)) - { - matchResult.failure( - location, - "Expected state icons vardict, found " - + type_to_string(actualType)); - } - else if (!p->m_state_icons.empty() && state && - g_variant_is_of_type(state.get(), G_VARIANT_TYPE_VARDICT)) - { - std::vector<std::string> actual_state_icons; - GVariantIter it; - gchar* key; - GVariant* value; - - g_variant_iter_init(&it, state.get()); - while (g_variant_iter_loop(&it, "{sv}", &key, &value)) - { - if (std::string(key) == "icon") { - auto gicon = g_icon_deserialize(value); - if (gicon && G_IS_THEMED_ICON(gicon)) - { - auto iconNames = g_themed_icon_get_names(G_THEMED_ICON(gicon)); - // Just take the first icon in the list (there is only ever one) - actual_state_icons.push_back(iconNames[0]); - g_object_unref(gicon); - } - } - else if (std::string(key) == "icons" && g_variant_is_of_type(value, G_VARIANT_TYPE("av"))) - { - // If we find "icons" in the map, clear any icons we may have found in "icon", - // then break from the loop as we have found all icons now. - actual_state_icons.clear(); - GVariantIter icon_it; - GVariant* icon_value; - - g_variant_iter_init(&icon_it, value); - while (g_variant_iter_loop(&icon_it, "v", &icon_value)) - { - auto gicon = g_icon_deserialize(icon_value); - if (gicon && G_IS_THEMED_ICON(gicon)) - { - auto iconNames = g_themed_icon_get_names(G_THEMED_ICON(gicon)); - // Just take the first icon in the list (there is only ever one) - actual_state_icons.push_back(iconNames[0]); - g_object_unref(gicon); - } - } - // We're breaking out of g_variant_iter_loop here so clean up - g_variant_unref(value); - g_free(key); - break; - } - } - - if (p->m_state_icons != actual_state_icons) - { - std::string expected_icons; - for (unsigned int i = 0; i < p->m_state_icons.size(); ++i) - { - expected_icons += i == 0 ? p->m_state_icons[i] : ", " + p->m_state_icons[i]; - } - std::string actual_icons; - for (unsigned int i = 0; i < actual_state_icons.size(); ++i) - { - actual_icons += i == 0 ? actual_state_icons[i] : ", " + actual_state_icons[i]; - } - matchResult.failure( - location, - "Expected state_icons == {" + expected_icons - + "} but found {" + actual_icons + "}"); - } - } - - for (const auto& e: p->m_pass_through_attributes) - { - string actionName = get_string_attribute(menuItem, e.first.c_str()); - if (actionName.empty()) - { - matchResult.failure( - location, - "Could not find action name '" + e.first + "'"); - } - else - { - auto passThroughIdPair = split_action(actionName); - auto actionGroup = actions[passThroughIdPair.first]; - if (actionGroup) - { - auto value = get_action_group_attribute( - actionGroup, passThroughIdPair.second.c_str()); - if (!value) - { - matchResult.failure( - location, - "Expected pass-through attribute '" + e.first - + "' was not present"); - } - else if (!g_variant_is_of_type(e.second.get(), g_variant_get_type(value.get()))) - { - std::string expectedType = g_variant_get_type_string(e.second.get()); - std::string actualType = g_variant_get_type_string(value.get()); - matchResult.failure( - location, - "Expected pass-through attribute type '" + expectedType - + "' but found '" + actualType + "'"); - } - else if (g_variant_compare(e.second.get(), value.get())) - { - bool reportMismatch = true; - if (g_strcmp0(g_variant_get_type_string(value.get()),"d") == 0 && p->m_maxDifference) - { - auto actualDouble = g_variant_get_double(value.get()); - auto expectedDouble = g_variant_get_double(e.second.get()); - auto difference = actualDouble-expectedDouble; - if (difference < 0) difference = difference * -1.0; - if (difference <= p->m_maxDifference) - { - reportMismatch = false; - } - } - if (reportMismatch) - { - gchar* expectedString = g_variant_print(e.second.get(), true); - gchar* actualString = g_variant_print(value.get(), true); - matchResult.failure( - location, - "Expected pass-through attribute '" + e.first - + "' == " + expectedString + " but found " - + actualString); - - g_free(expectedString); - g_free(actualString); - } - } - } - else - { - matchResult.failure(location, "Could not find action group for ID '" + passThroughIdPair.first + "'"); - } - } - } - - for (const auto& e: p->m_attributes) - { - auto value = get_attribute(menuItem, e.first.c_str()); - if (!value) - { - matchResult.failure(location, - "Expected attribute '" + e.first - + "' could not be found"); - } - else if (!g_variant_is_of_type(e.second.get(), g_variant_get_type(value.get()))) - { - std::string expectedType = g_variant_get_type_string(e.second.get()); - std::string actualType = g_variant_get_type_string(value.get()); - matchResult.failure( - location, - "Expected attribute type '" + expectedType - + "' but found '" + actualType + "'"); - } - else if (g_variant_compare(e.second.get(), value.get())) - { - gchar* expectedString = g_variant_print(e.second.get(), true); - gchar* actualString = g_variant_print(value.get(), true); - matchResult.failure( - location, - "Expected attribute '" + e.first + "' == " + expectedString - + ", but found " + actualString); - g_free(expectedString); - g_free(actualString); - } - } - - for (const auto& e: p->m_not_exist_attributes) - { - auto value = get_attribute(menuItem, e.c_str()); - if (value) - { - matchResult.failure(location, - "Not expected attribute '" + e - + "' was found"); - } - } - - if (p->m_isToggled && (*p->m_isToggled) != isToggled) - { - matchResult.failure( - location, - "Expected toggled = " + bool_to_string(*p->m_isToggled) - + ", but found " + bool_to_string(isToggled)); - } - - if (!matchResult.success()) - { - return; - } - - if (!p->m_items.empty() || p->m_expectedSize) - { - shared_ptr<GMenuModel> link; - - switch (p->m_linkType) - { - case LinkType::any: - { - link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SUBMENU), &g_object_deleter); - if (!link) - { - link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SECTION), &g_object_deleter); - } - break; - } - case LinkType::submenu: - { - link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SUBMENU), &g_object_deleter); - break; - } - case LinkType::section: - { - link.reset(g_menu_model_get_item_link(menu.get(), (int) index, G_MENU_LINK_SECTION), &g_object_deleter); - break; - } - } - - - if (!link) - { - if (p->m_expectedSize) - { - matchResult.failure( - location, - "Expected " + to_string(*p->m_expectedSize) - + " children, but found none"); - } - else - { - matchResult.failure( - location, - "Expected " + to_string(p->m_items.size()) - + " children, but found none"); - } - return; - } - else - { - while (true) - { - MatchResult childMatchResult(matchResult.createChild()); - - if (p->m_expectedSize - && *p->m_expectedSize - != (unsigned int) g_menu_model_get_n_items( - link.get())) - { - childMatchResult.failure( - location, - "Expected " + to_string(*p->m_expectedSize) - + " child items, but found " - + to_string( - g_menu_model_get_n_items( - link.get()))); - } - else if (!p->m_items.empty()) - { - switch (p->m_mode) - { - case Mode::all: - p->all(childMatchResult, location, link, actions); - break; - case Mode::starts_with: - p->startsWith(childMatchResult, location, link, actions); - break; - case Mode::ends_with: - p->endsWith(childMatchResult, location, link, actions); - break; - } - } - - if (childMatchResult.success()) - { - matchResult.merge(childMatchResult); - break; - } - else - { - if (matchResult.hasTimedOut()) - { - matchResult.merge(childMatchResult); - break; - } - menuWaitForItems(link); - } - } - } - } - - - for (const auto& a: p->m_setActionStates) - { - auto stateAction = action; - auto stateIdPair = idPair; - auto stateActionGroup = actionGroup; - if (!a.first.empty()) - { - stateAction = get_string_attribute(menuItem, a.first.c_str());; - stateIdPair = split_action(stateAction); - stateActionGroup = actions[stateIdPair.first]; - } - - if (stateAction.empty()) - { - matchResult.failure( - location, - "Tried to set action state, but no action was found"); - } - else if(!stateActionGroup) - { - matchResult.failure( - location, - "Tried to set action state for action group '" + stateIdPair.first - + "', but action group wasn't found"); - } - else if (!g_action_group_has_action(stateActionGroup.get(), stateIdPair.second.c_str())) - { - matchResult.failure( - location, - "Tried to set action state for action '" + stateAction - + "', but action was not found"); - } - else - { - g_action_group_change_action_state(stateActionGroup.get(), stateIdPair.second.c_str(), - g_variant_ref(a.second.get())); - } - - // FIXME this is a dodgy way to ensure the action state change gets dispatched - menuWaitForItems(menu, 100); - } - - for (const auto& a: p->m_activations) - { - string tmpAction = action; - auto tmpIdPair = idPair; - auto tmpActionGroup = actionGroup; - if (!a.first.empty()) - { - tmpAction = get_string_attribute(menuItem, a.first.c_str()); - tmpIdPair = split_action(tmpAction); - tmpActionGroup = actions[tmpIdPair.first]; - } - - if (tmpAction.empty()) - { - matchResult.failure( - location, - "Tried to activate action, but no action was found"); - } - else if(!tmpActionGroup) - { - matchResult.failure( - location, - "Tried to activate action group '" + tmpIdPair.first - + "', but action group wasn't found"); - } - else if (!g_action_group_has_action(tmpActionGroup.get(), tmpIdPair.second.c_str())) - { - matchResult.failure( - location, - "Tried to activate action '" + tmpAction + "', but action was not found"); - } - else - { - if (a.second) - { - g_action_group_activate_action(tmpActionGroup.get(), tmpIdPair.second.c_str(), - g_variant_ref(a.second.get())); - } - else - { - g_action_group_activate_action(tmpActionGroup.get(), tmpIdPair.second.c_str(), nullptr); - } - - // FIXME this is a dodgy way to ensure the activation gets dispatched - menuWaitForItems(menu, 100); - } - } -} - -} // namepsace gmenuharness - -} // namespace unity diff --git a/src/gmenuharness/MenuMatcher.cpp b/src/gmenuharness/MenuMatcher.cpp deleted file mode 100644 index 5bb4fbd..0000000 --- a/src/gmenuharness/MenuMatcher.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright © 2014 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3, - * as published by the Free Software Foundation. - * - * This program 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * Authored by: Pete Woods <pete.woods@canonical.com> - */ - -#include <unity/gmenuharness/MenuMatcher.h> -#include <unity/gmenuharness/MatchUtils.h> - -#include <iostream> - -#include <gio/gio.h> - -using namespace std; - -namespace unity -{ - -namespace gmenuharness -{ - -namespace -{ - -static void gdbus_connection_deleter(GDBusConnection* connection) -{ -// if (!g_dbus_connection_is_closed(connection)) -// { -// g_dbus_connection_close_sync(connection, nullptr, nullptr); -// } - g_clear_object(&connection); -} -} - -struct MenuMatcher::Parameters::Priv -{ - string m_busName; - - vector<pair<string, string>> m_actions; - - string m_menuObjectPath; -}; - -MenuMatcher::Parameters::Parameters(const string& busName, - const vector<pair<string, string>>& actions, - const string& menuObjectPath) : - p(new Priv) -{ - p->m_busName = busName; - p->m_actions = actions; - p->m_menuObjectPath = menuObjectPath; -} - -MenuMatcher::Parameters::~Parameters() -{ -} - -MenuMatcher::Parameters::Parameters(const Parameters& other) : - p(new Priv) -{ - *this = other; -} - -MenuMatcher::Parameters::Parameters(Parameters&& other) -{ - *this = move(other); -} - -MenuMatcher::Parameters& MenuMatcher::Parameters::operator=(const Parameters& other) -{ - p->m_busName = other.p->m_busName; - p->m_actions = other.p->m_actions; - p->m_menuObjectPath = other.p->m_menuObjectPath; - return *this; -} - -MenuMatcher::Parameters& MenuMatcher::Parameters::operator=(Parameters&& other) -{ - p = move(other.p); - return *this; -} - -struct MenuMatcher::Priv -{ - Priv(const Parameters& parameters) : - m_parameters(parameters) - { - } - - Parameters m_parameters; - - vector<MenuItemMatcher> m_items; - - shared_ptr<GDBusConnection> m_system; - - shared_ptr<GDBusConnection> m_session; - - shared_ptr<GMenuModel> m_menu; - - map<string, shared_ptr<GActionGroup>> m_actions; -}; - -MenuMatcher::MenuMatcher(const Parameters& parameters) : - p(new Priv(parameters)) -{ - p->m_system.reset(g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr), - &gdbus_connection_deleter); - g_dbus_connection_set_exit_on_close(p->m_system.get(), false); - - p->m_session.reset(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr), - &gdbus_connection_deleter); - g_dbus_connection_set_exit_on_close(p->m_session.get(), false); - - p->m_menu.reset( - G_MENU_MODEL( - g_dbus_menu_model_get( - p->m_session.get(), - p->m_parameters.p->m_busName.c_str(), - p->m_parameters.p->m_menuObjectPath.c_str())), - &g_object_deleter); - - for (const auto& action : p->m_parameters.p->m_actions) - { - shared_ptr<GActionGroup> actionGroup( - G_ACTION_GROUP( - g_dbus_action_group_get( - p->m_session.get(), - p->m_parameters.p->m_busName.c_str(), - action.second.c_str())), - &g_object_deleter); - p->m_actions[action.first] = actionGroup; - } -} - -MenuMatcher::~MenuMatcher() -{ -} - -MenuMatcher& MenuMatcher::item(const MenuItemMatcher& item) -{ - p->m_items.emplace_back(item); - return *this; -} - -void MenuMatcher::match(MatchResult& matchResult) const -{ - vector<unsigned int> location; - - while (true) - { - MatchResult childMatchResult(matchResult.createChild()); - - int menuSize = g_menu_model_get_n_items(p->m_menu.get()); - if (p->m_items.size() > (unsigned int) menuSize) - { - childMatchResult.failure( - location, - "Row count mismatch, expected " + to_string(p->m_items.size()) - + " but found " + to_string(menuSize)); - } - else - { - for (size_t i = 0; i < p->m_items.size(); ++i) - { - const auto& matcher = p->m_items.at(i); - matcher.match(childMatchResult, location, p->m_menu, p->m_actions, i); - } - } - - if (childMatchResult.success()) - { - matchResult.merge(childMatchResult); - break; - } - else - { - if (matchResult.hasTimedOut()) - { - matchResult.merge(childMatchResult); - break; - } - menuWaitForItems(p->m_menu); - } - } -} - -MatchResult MenuMatcher::match() const -{ - MatchResult matchResult; - match(matchResult); - return matchResult; -} - -} // namespace gmenuharness - -} // namespace unity diff --git a/src/service.vala b/src/service.vala index 12e2ac2..a08edf3 100644 --- a/src/service.vala +++ b/src/service.vala @@ -43,7 +43,7 @@ public class IndicatorSound.Service: Object { warn_notification.closed.connect((n) => { n.clear_actions(); }); BusWatcher.watch_namespace (GLib.BusType.SESSION, "org.freedesktop.Notifications", - () => { debug("Notifications name appeared"); }, + () => { debug("Notifications name appeared"); notify_server_caps_checked = false; }, () => { debug("Notifications name vanshed"); notify_server_caps_checked = false; }); this.settings = new Settings ("com.canonical.indicator.sound"); @@ -52,8 +52,6 @@ public class IndicatorSound.Service: Object { this.notify["visible"].connect ( () => this.update_root_icon () ); this.volume_control = volume; - this.volume_control.active_output_changed.connect (this.update_root_icon); - this.volume_control.active_output_changed.connect (this.update_notification); this.accounts_service = accounts; /* If we're on the greeter, don't export */ @@ -92,10 +90,6 @@ public class IndicatorSound.Service: Object { this.volume_control.bind_property ("high-volume", menu, "show-high-volume-warning", BindingFlags.SYNC_CREATE); }); - this.menus.@foreach ( (profile, menu) => { - this.volume_control.active_output_changed.connect (menu.update_volume_slider); - }); - this.sync_preferred_players (); this.settings.changed["interested-media-players"].connect ( () => { this.sync_preferred_players (); @@ -251,7 +245,17 @@ public class IndicatorSound.Service: Object { void update_root_icon () { double volume = this.volume_control.volume.volume; - string icon = get_volume_root_icon (volume, this.volume_control.mute, volume_control.active_output); + string icon; + if (this.volume_control.mute || volume <= 0.0) + icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; + else if (this.accounts_service != null && this.accounts_service.silentMode) + icon = "audio-volume-muted-panel"; + else if (volume <= 0.3) + icon = "audio-volume-low-panel"; + else if (volume <= 0.7) + icon = "audio-volume-medium-panel"; + else + icon = "audio-volume-high-panel"; string accessible_name; if (this.volume_control.mute) { @@ -277,333 +281,15 @@ public class IndicatorSound.Service: Object { private bool notify_server_supports_actions = false; private bool notify_server_supports_sync = false; private bool block_info_notifications = false; - private bool waiting_user_approve_warn = false; - - private string get_volume_icon (double volume, VolumeControl.ActiveOutput active_output) - { - string icon = ""; - switch (active_output) - { - case VolumeControl.ActiveOutput.SPEAKERS: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.USB_SPEAKER: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.USB_HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.HDMI_SPEAKER: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted"; - else if (volume <= 0.3) - icon = "audio-volume-low"; - else if (volume <= 0.7) - icon = "audio-volume-medium"; - else - icon = "audio-volume-high"; - break; - } - return icon; - } - - private string get_volume_root_icon_by_volume (double volume, VolumeControl.ActiveOutput active_output) - { - string icon = ""; - switch (active_output) - { - case VolumeControl.ActiveOutput.SPEAKERS: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.USB_SPEAKER: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.USB_HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.HDMI_SPEAKER: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - if (volume <= 0.0) - icon = "audio-volume-muted-panel"; - else if (volume <= 0.3) - icon = "audio-volume-low-panel"; - else if (volume <= 0.7) - icon = "audio-volume-medium-panel"; - else - icon = "audio-volume-high-panel"; - break; - } - return icon; - } - - private string get_volume_notification_icon (double volume, bool loud, VolumeControl.ActiveOutput active_output) { - string icon = ""; - if (loud) { - switch (active_output) - { - case VolumeControl.ActiveOutput.SPEAKERS: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.HEADPHONES: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.USB_SPEAKER: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.USB_HEADPHONES: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.HDMI_SPEAKER: - icon = "audio-volume-high"; - break; - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - icon = "audio-volume-high"; - break; - } - } else { - icon = get_volume_icon (volume, active_output); - } - return icon; - } - - private string get_volume_root_icon (double volume, bool mute, VolumeControl.ActiveOutput active_output) { - string icon = ""; - switch (active_output) - { - case VolumeControl.ActiveOutput.SPEAKERS: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.HEADPHONES: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.USB_SPEAKER: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.USB_HEADPHONES: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.HDMI_SPEAKER: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - if (mute || volume <= 0.0) - icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; - else if (this.accounts_service != null && this.accounts_service.silentMode) - icon = "audio-volume-muted-panel"; - else - icon = get_volume_root_icon_by_volume (volume, active_output); - break; - } - return icon; - } - - private string get_notification_label () { - string volume_label = ""; - switch (volume_control.active_output) - { - case VolumeControl.ActiveOutput.SPEAKERS: - volume_label = _("Speakers"); - break; - case VolumeControl.ActiveOutput.HEADPHONES: - volume_label = _("Headphones"); - break; - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - volume_label = _("Bluetooth headphones"); - break; - case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER: - volume_label = _("Bluetooth speaker"); - break; - case VolumeControl.ActiveOutput.USB_SPEAKER: - volume_label = _("Usb speaker"); - break; - case VolumeControl.ActiveOutput.USB_HEADPHONES: - volume_label = _("Usb headphones"); - break; - case VolumeControl.ActiveOutput.HDMI_SPEAKER: - volume_label = _("HDMI speaker"); - break; - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - volume_label = _("HDMI headphones"); - break; - } - - return volume_label; - } private void update_notification () { - List<string> caps = Notify.get_server_caps (); - notify_server_supports_actions = caps.find_custom ("actions", strcmp) != null; - notify_server_supports_sync = caps.find_custom ("x-canonical-private-synchronous", strcmp) != null; - notify_server_caps_checked = true; + if (!notify_server_caps_checked) { + List<string> caps = Notify.get_server_caps (); + notify_server_supports_actions = caps.find_custom ("actions", strcmp) != null; + notify_server_supports_sync = caps.find_custom ("x-canonical-private-synchronous", strcmp) != null; + notify_server_caps_checked = true; + } var loud = volume_control.high_volume; var warn = loud @@ -626,36 +312,47 @@ public class IndicatorSound.Service: Object { _pre_warn_volume = null; volume_control.volume = tmp; } - waiting_user_approve_warn = false; }); warn_notification.add_action ("cancel", _("Cancel"), (n, a) => { _pre_warn_volume = null; - waiting_user_approve_warn = false; }); - waiting_user_approve_warn = true; show_notification(warn_notification); } else { - if (!waiting_user_approve_warn) { - close_notification(warn_notification); - - if (notify_server_supports_sync && !block_info_notifications) { - - /* Determine Label */ - string volume_label = get_notification_label (); - - /* Choose an icon */ - string icon = get_volume_notification_icon (volume_control.volume.volume, loud, volume_control.active_output); - - /* Reset the notification */ - var n = this.info_notification; - n.update (_("Volume"), volume_label, icon); - n.clear_hints(); - n.set_hint ("x-canonical-non-shaped-icon", "true"); - n.set_hint ("x-canonical-private-synchronous", "true"); - n.set_hint ("x-canonical-value-bar-tint", loud ? "true" : "false"); - n.set_hint ("value", (int32)Math.round(get_volume_percent() * 100.0)); - show_notification(n); + close_notification(warn_notification); + + if (notify_server_supports_sync && !block_info_notifications) { + + /* Determine Label */ + unowned string volume_label = loud + ? _("High volume can damage your hearing.") + : ""; + + /* Choose an icon */ + unowned string icon; + if (loud) { + icon = "audio-volume-high"; + } else { + var volume = volume_control.volume.volume; + + if (volume <= 0.0) + icon = "audio-volume-muted"; + else if (volume <= 0.3) + icon = "audio-volume-low"; + else if (volume <= 0.7) + icon = "audio-volume-medium"; + else + icon = "audio-volume-high"; } + + /* Reset the notification */ + var n = this.info_notification; + n.update (_("Volume"), volume_label, icon); + n.clear_hints(); + n.set_hint ("x-canonical-non-shaped-icon", "true"); + n.set_hint ("x-canonical-private-synchronous", "true"); + n.set_hint ("x-canonical-value-bar-tint", loud ? "true" : "false"); + n.set_hint ("value", (int32)Math.round(get_volume_percent() * 100.0)); + show_notification(n); } } } diff --git a/src/sound-menu.vala b/src/sound-menu.vala index 3d682e4..7a6044b 100644 --- a/src/sound-menu.vala +++ b/src/sound-menu.vala @@ -71,7 +71,6 @@ public class SoundMenu: Object this.notify_handlers = new HashTable<MediaPlayer, ulong> (direct_hash, direct_equal); this.greeter_players = (flags & DisplayFlags.GREETER_PLAYERS) != 0; - } ~SoundMenu () { @@ -194,43 +193,6 @@ public class SoundMenu: Object this.notify_handlers.remove (player); } - public void update_volume_slider (VolumeControl.ActiveOutput active_output) { - int index = find_action (this.volume_section, "indicator.volume"); - if (index != -1) { - string label = "Volume"; - switch (active_output) { - case VolumeControl.ActiveOutput.SPEAKERS: - label = _("Volume"); - break; - case VolumeControl.ActiveOutput.HEADPHONES: - label = _("Volume (Headphones)"); - break; - case VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER: - label = _("Volume (Bluetooth)"); - break; - case VolumeControl.ActiveOutput.USB_SPEAKER: - label = _("Volume (Usb)"); - break; - case VolumeControl.ActiveOutput.HDMI_SPEAKER: - label = _("Volume (HDMI)"); - break; - case VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES: - label = _("Volume (Bluetooth headphones)"); - break; - case VolumeControl.ActiveOutput.USB_HEADPHONES: - label = _("Volume (Usb headphones)"); - break; - case VolumeControl.ActiveOutput.HDMI_HEADPHONES: - label = _("Volume (HDMI headphones)"); - break; - } - this.volume_section.remove (index); - this.volume_section.insert_item (index, this.create_slider_menu_item (_(label), "indicator.volume(0)", 0.0, 1.0, 0.01, - "audio-volume-low-zero-panel", - "audio-volume-high-panel")); - } - } - public Menu root; public Menu menu; Menu volume_section; diff --git a/src/volume-control-pulse.vala b/src/volume-control-pulse.vala index 8122f26..87af258 100644 --- a/src/volume-control-pulse.vala +++ b/src/volume-control-pulse.vala @@ -87,7 +87,6 @@ public class VolumeControlPulse : VolumeControl private bool _send_next_local_volume = false; private double _account_service_volume = 0.0; private bool _active_port_headphone = false; - private VolumeControl.ActiveOutput _active_output = VolumeControl.ActiveOutput.SPEAKERS; /** true when connected to the pulse server */ public override bool ready { get; private set; } @@ -136,49 +135,6 @@ public class VolumeControlPulse : VolumeControl stop_high_volume_approved_timer(); } - private VolumeControl.ActiveOutput calculate_active_output (SinkInfo? sink) { - - VolumeControl.ActiveOutput ret_output = VolumeControl.ActiveOutput.SPEAKERS; - /* Check if the current active port is headset/headphone */ - /* There is not easy way to check if the port is a headset/headphone besides - * checking for the port name. On touch (with the pulseaudio droid element) - * the headset/headphone port is called 'output-headset' and 'output-headphone'. - * On the desktop this is usually called 'analog-output-headphones' */ - // look if it's a headset/headphones - if (sink.name == "indicator_sound_test_headphones" || - (sink.active_port != null && - (sink.active_port.name.contains("headset") || - sink.active_port.name.contains("headphone")))) { - _active_port_headphone = true; - // check if it's a bluetooth device - var device_bus = sink.proplist.gets ("device.bus"); - if (device_bus != null && device_bus == "bluetooth") { - ret_output = VolumeControl.ActiveOutput.BLUETOOTH_HEADPHONES; - } else if (device_bus != null && device_bus == "usb") { - ret_output = VolumeControl.ActiveOutput.USB_HEADPHONES; - } else if (device_bus != null && device_bus == "hdmi") { - ret_output = VolumeControl.ActiveOutput.HDMI_HEADPHONES; - } else { - ret_output = VolumeControl.ActiveOutput.HEADPHONES; - } - } else { - // speaker - _active_port_headphone = false; - var device_bus = sink.proplist.gets ("device.bus"); - if (device_bus != null && device_bus == "bluetooth") { - ret_output = VolumeControl.ActiveOutput.BLUETOOTH_SPEAKER; - } else if (device_bus != null && device_bus == "usb") { - ret_output = VolumeControl.ActiveOutput.USB_SPEAKER; - } else if (device_bus != null && device_bus == "hdmi") { - ret_output = VolumeControl.ActiveOutput.HDMI_SPEAKER; - } else { - ret_output = VolumeControl.ActiveOutput.SPEAKERS; - } - } - - return ret_output; - } - /* PulseAudio logic*/ private void context_events_cb (Context c, Context.SubscriptionEventType t, uint32 index) { @@ -245,20 +201,18 @@ public class VolumeControlPulse : VolumeControl this.notify_property ("is-playing"); } - // store the current status of the active output - VolumeControl.ActiveOutput active_output_before = active_output; - - // calculate the output - _active_output = calculate_active_output (i); - - // check if the output has changed, if so... emit a signal - VolumeControl.ActiveOutput active_output_now = active_output; - if (active_output_now != active_output_before) { - this.active_output_changed (active_output_now); - if (active_output_now == VolumeControl.ActiveOutput.SPEAKERS) { - _high_volume_approved = false; - } - update_high_volume(); + /* Check if the current active port is headset/headphone */ + /* There is not easy way to check if the port is a headset/headphone besides + * checking for the port name. On touch (with the pulseaudio droid element) + * the headset/headphone port is called 'output-headset' and 'output-headphone'. + * On the desktop this is usually called 'analog-output-headphones' */ + if (i.active_port != null && + (i.active_port.name == "output-wired_headset" || + i.active_port.name == "output-wired_headphone" || + i.active_port.name == "analog-output-headphones")) { + _active_port_headphone = true; + } else { + _active_port_headphone = false; } if (_pulse_use_stream_restore == false && @@ -524,8 +478,7 @@ public class VolumeControlPulse : VolumeControl this.context = new PulseAudio.Context (loop.get_api(), null, props); this.context.set_state_callback (context_state_callback); - var server_string = Environment.get_variable("PULSE_SERVER"); - if (context.connect(server_string, Context.Flags.NOFAIL, null) < 0) + if (context.connect(null, Context.Flags.NOFAIL, null) < 0) warning( "pa_context_connect() failed: %s\n", PulseAudio.strerror(context.errno())); } @@ -582,14 +535,6 @@ public class VolumeControlPulse : VolumeControl } } - public override VolumeControl.ActiveOutput active_output - { - get - { - return _active_output; - } - } - /* Volume operations */ private static PulseAudio.Volume double_to_volume (double vol) { @@ -765,7 +710,7 @@ public class VolumeControlPulse : VolumeControl private bool calculate_high_volume_from_volume(double volume) { return _active_port_headphone && _warning_volume_enabled - && volume > _warning_volume_norms + && volume >= _warning_volume_norms && (stream == "multimedia"); } diff --git a/src/volume-control.vala b/src/volume-control.vala index 8e615ea..6efac35 100644 --- a/src/volume-control.vala +++ b/src/volume-control.vala @@ -28,17 +28,6 @@ public abstract class VolumeControl : Object VOLUME_STREAM_CHANGE } - public enum ActiveOutput { - SPEAKERS, - HEADPHONES, - BLUETOOTH_HEADPHONES, - BLUETOOTH_SPEAKER, - USB_SPEAKER, - USB_HEADPHONES, - HDMI_SPEAKER, - HDMI_HEADPHONES - } - public class Volume : Object { public double volume; public VolumeReasons reason; @@ -50,7 +39,6 @@ public abstract class VolumeControl : Object public virtual bool high_volume { get { return false; } protected set { } } public virtual bool mute { get { return false; } } public virtual bool is_playing { get { return false; } } - public virtual VolumeControl.ActiveOutput active_output { get { return VolumeControl.ActiveOutput.SPEAKERS; } } private Volume _volume; public virtual Volume volume { get { return _volume; } set { } } public virtual double mic_volume { get { return 0.0; } set { } } @@ -68,6 +56,4 @@ public abstract class VolumeControl : Object v.reason = reason; this.volume = v; } - - public signal void active_output_changed (VolumeControl.ActiveOutput active_output); } |