diff --git a/src/dbus.cpp b/src/dbus.cpp index 849fe804..ec99d115 100644 --- a/src/dbus.cpp +++ b/src/dbus.cpp @@ -4,349 +4,21 @@ #include #include "dbus_info.h" #include "string_utils.h" +#include "dbus_helpers.hpp" using ms = std::chrono::milliseconds; +using namespace DBus_helpers; #define DBUS_TIMEOUT 2000 // ms struct mutexed_metadata main_metadata; -typedef std::vector> string_pair_vec; -typedef std::unordered_map string_pair_vec_map; -typedef std::unordered_map string_map; - namespace dbusmgr { dbus_manager dbus_mgr; } -template struct dbus_type_identifier{}; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_BYTE; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_UINT16; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_UINT32; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_UINT64; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_INT16; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_INT32; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_INT64; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_DOUBLE; }; -template<> struct dbus_type_identifier { const int value = DBUS_TYPE_STRING; }; - -template -const int dbus_type_identifier_v = dbus_type_identifier().value; - -class DBusMessageIter_wrap { -private: - DBusMessageIter resolve_variants() { - auto iter = m_Iter; - auto field_type = m_DBus->message_iter_get_arg_type(&m_Iter); - while(field_type == DBUS_TYPE_VARIANT){ - m_DBus->message_iter_recurse(&iter, &iter); - field_type = m_DBus->message_iter_get_arg_type(&iter); - } - return iter; - } - - DBusMessageIter m_Iter; - DBusMessageIter m_resolved_iter; - int m_type; - libdbus_loader* m_DBus; -public: - DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader) - { - m_DBus = loader; - if(msg){ - m_DBus->message_iter_init(msg, &m_Iter); - m_resolved_iter = resolve_variants(); - m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); - } - else { - m_type = DBUS_TYPE_INVALID; - } - } - - DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader) - : m_Iter(iter), m_DBus(loader) - { - m_resolved_iter = resolve_variants(); - m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); - } - - operator bool() { - return type() != DBUS_TYPE_INVALID; - } - - int type() { - return m_type; - } - - auto next() { - m_DBus->message_iter_next(&m_Iter); - // Resolve any variants - m_resolved_iter = resolve_variants(); - m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); - return *this; - } - - auto get_array_iter() { - if(not is_array()) { - std::cerr << "Not an array\n"; - return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus); - } - - DBusMessageIter ret; - m_DBus->message_iter_recurse(&m_resolved_iter, &ret); - return DBusMessageIter_wrap(ret, m_DBus); - } - - auto get_dict_entry_iter() { - if(type() != DBUS_TYPE_DICT_ENTRY){ - std::cerr << "Not a dict entry\n"; - return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus); - } - - DBusMessageIter ret; - m_DBus->message_iter_recurse(&m_resolved_iter, &ret); - return DBusMessageIter_wrap(ret, m_DBus); - } - - auto get_stringified() -> std::string; - - template - auto get_primitive() -> T; - - bool is_unsigned() { - return ( - (type() == DBUS_TYPE_BYTE) || - (type() == DBUS_TYPE_INT16) || - (type() == DBUS_TYPE_INT32) || - (type() == DBUS_TYPE_INT64) - ); - } - - bool is_signed() { - return ( - (type() == DBUS_TYPE_INT16) || - (type() == DBUS_TYPE_INT32) || - (type() == DBUS_TYPE_INT64) - ); - } - - bool is_string() { - return (type() == DBUS_TYPE_STRING); - } - - bool is_double() { - return (type() == DBUS_TYPE_DOUBLE); - } - - bool is_primitive() { - return ( - is_double() || - is_signed() || - is_unsigned() || - is_string() - ); - } - - bool is_array() { - return (type() == DBUS_TYPE_ARRAY); - } - - uint64_t get_unsigned() { - auto t = type(); - switch (t) - { - case DBUS_TYPE_BYTE: - return get_primitive(); - case DBUS_TYPE_UINT16: - return get_primitive(); - case DBUS_TYPE_UINT32: - return get_primitive(); - case DBUS_TYPE_UINT64: - return get_primitive(); - default: - return 0; - } - } - - uint64_t get_signed() { - auto t = type(); - switch (t) - { - case DBUS_TYPE_INT16: - return get_primitive(); - case DBUS_TYPE_INT32: - return get_primitive(); - case DBUS_TYPE_INT64: - return get_primitive(); - default: - return 0; - } - } -}; - -template -auto DBusMessageIter_wrap::get_primitive() -> T { - auto requested_type = dbus_type_identifier_v; - if(requested_type != type()){ - std::cerr << "Type mismatch: '" << (char) requested_type << "' vs '" << (char) type() << "'\n"; -#ifndef NDEBUG - exit(-1); -#else - return T(); -#endif - } - - T ret; - m_DBus->message_iter_get_basic(&m_resolved_iter, &ret); - return ret; -} - -template<> -auto DBusMessageIter_wrap::get_primitive() -> std::string { - return std::string(get_primitive()); -} - -auto DBusMessageIter_wrap::get_stringified() -> std::string { - if(is_string()) return get_primitive(); - if(is_unsigned()) return std::to_string(get_unsigned()); - if(is_signed()) return std::to_string(get_signed()); - if(is_double()) return std::to_string(get_primitive()); - std::cerr << "stringify failed\n"; - return std::string(); -} - -// Precondition: iter points to a dict of string -> any -// executes action(key, value_iter) for all entries -template -void string_map_for_each(DBusMessageIter_wrap iter, T action) { - iter = iter.get_array_iter(); - for(; iter; iter.next()) { - auto it = iter.get_dict_entry_iter(); - auto key = it.get_primitive(); - - it.next(); - action(key, it); - } -} - -template -void array_for_each(DBusMessageIter_wrap iter, Callable action) { - iter = iter.get_array_iter(); - for(; iter; iter.next()){ - action(iter.get_primitive()); - } -} - -template -void array_for_each_stringify(DBusMessageIter_wrap iter, Callable action) { - iter = iter.get_array_iter(); - for(; iter; iter.next()){ - action(iter.get_stringified()); - } -} - -template -void string_multimap_for_each_stringify(DBusMessageIter_wrap iter, T action) { - string_map_for_each(iter, [&](const std::string& key, DBusMessageIter_wrap it){ - if(it.is_array()){ - array_for_each_stringify(it, [&](const std::string& val){ - action(key, val); - }); - } - else if(it.is_primitive()){ - action(key, it.get_stringified()); - } - }); -} - -class DBusMessage_wrap { -public: - DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false) - : m_owning(owning), m_msg(msg), m_DBus(ldr) - {} - - ~DBusMessage_wrap(){ - free_if_owning(); - } - - DBusMessage_wrap(const DBusMessage_wrap&) = delete; - DBusMessage_wrap(DBusMessage_wrap&&) = default; - - operator bool() const { - return m_msg != nullptr; - } - - template - DBusMessage_wrap& argument(T arg) { - if(not m_msg) return *this; - if(not m_DBus->message_append_args( - m_msg, - dbus_type_identifier_v, - &arg, - DBUS_TYPE_INVALID - )){ - free_if_owning(); - } - return *this; - } - - DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn) { - if(not m_msg){ - return DBusMessage_wrap(nullptr, m_DBus); - } - DBusError err; - m_DBus->error_init(&err); - auto reply = m_DBus->connection_send_with_reply_and_block( - conn, - m_msg, - DBUS_TIMEOUT, - &err - ); - if(reply == nullptr) { - std::cerr << "MangoHud[" << __func__ << "]: " << err.message << "\n"; - free_if_owning(); - m_DBus->error_free(&err); - } - return DBusMessage_wrap(reply, m_DBus, true); - } - - DBusMessageIter_wrap iter() { - return DBusMessageIter_wrap(m_msg, m_DBus); - } - - static DBusMessage_wrap new_method_call( - const std::string& bus_name, - const std::string& path, - const std::string& iface, - const std::string& method, - libdbus_loader* loader - ){ - auto msg = loader->message_new_method_call( - (bus_name.empty()) ? nullptr : bus_name.c_str(), - path.c_str(), - (iface.empty()) ? nullptr : iface.c_str(), - method.c_str() - ); - return DBusMessage_wrap(msg, loader, true); - } -private: - void free_if_owning() { - if(m_msg and m_owning) m_DBus->message_unref(m_msg); - m_msg = nullptr; - } - bool m_owning; - DBusMessage* m_msg; - libdbus_loader* m_DBus; - std::vector m_args; -}; - -template<> -DBusMessage_wrap& DBusMessage_wrap::argument(const std::string& str) -{ - return argument(str.c_str()); -} - template static void assign_metadata_value(metadata& meta, const std::string& key, const T& value) { + std::cerr << "Assigning Metadata: " << key << " -> " << value << "\n"; if(key == "PlaybackStatus") { meta.playing = (value == "Playing"); meta.got_playback_data = true; @@ -354,14 +26,17 @@ static void assign_metadata_value(metadata& meta, const std::string& key, const else if(key == "xesam:title"){ meta.title = value; meta.got_song_data = true; + meta.valid = true; } else if(key == "xesam:artist") { meta.artists = value; meta.got_song_data = true; + meta.valid = true; } else if(key == "xesam:album") { meta.album = value; meta.got_song_data = true; + meta.valid = true; } else if(key == "mpris:artUrl"){ meta.artUrl = value; @@ -406,14 +81,14 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std:: if (not iter.is_array()) return; - std::cerr << "Parsing mpris update...\n"; + //std::cerr << "Parsing mpris update...\n"; string_map_for_each(iter, [&](std::string& key, DBusMessageIter_wrap it){ if(key == "Metadata"){ - std::cerr << "\tMetadata:\n"; + //std::cerr << "\tMetadata:\n"; string_map_for_each(it, [&](const std::string& key, DBusMessageIter_wrap it){ if(it.is_primitive()){ auto val = it.get_stringified(); - std::cerr << "\t\t" << key << " -> " << val << "\n"; + //std::cerr << "\t\t" << key << " -> " << val << "\n"; assign_metadata_value(meta, key, val); } else if(it.is_array()){ @@ -426,7 +101,7 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std:: val += ", " + str; } }); - std::cerr << "\t\t" << key << " -> " << val << "\n"; + //std::cerr << "\t\t" << key << " -> " << val << "\n"; assign_metadata_value(meta, key, val); } }); @@ -436,8 +111,6 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std:: } else if(key == "PlaybackStatus"){ auto val = it.get_stringified(); - std::cerr << "\tPlaybackStatus:\n"; - std::cerr << "\t\t" << key << " -> " << val << "\n"; assign_metadata_value(meta, key, val); } }); @@ -452,7 +125,7 @@ bool dbus_get_name_owner(dbusmgr::dbus_manager& dbus_mgr, std::string& name_owne "org.freedesktop.DBus", "GetNameOwner", &dbus_mgr.dbus() - ).argument(name).send_with_reply_and_block(dbus_mgr.get_conn()); + ).argument(name).send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); if(not reply) return false; auto iter = reply.iter(); @@ -471,7 +144,7 @@ bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta, c &dbus_mgr.dbus() ).argument("org.mpris.MediaPlayer2.Player") .argument(prop) - .send_with_reply_and_block(dbus_mgr.get_conn()); + .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); if(not reply) return false; @@ -538,11 +211,12 @@ bool dbus_manager::init(const std::string& requested_player) return true; } -bool dbus_manager::select_active_player() { +bool dbus_manager::select_active_player(metadata* store_meta) { // If the requested player is available, use it if(m_name_owners.count(m_requested_player) > 0) { m_active_player = m_requested_player; std::cerr << "Selecting requested player: " << m_requested_player << "\n"; + if(store_meta) get_media_player_metadata(*store_meta, m_active_player); return true; } @@ -554,6 +228,7 @@ bool dbus_manager::select_active_player() { if(meta.playing) { m_active_player = name; std::cerr << "Selecting fallback player: " << name << "\n"; + if(store_meta) *store_meta = meta; return true; } } @@ -561,6 +236,7 @@ bool dbus_manager::select_active_player() { // No media players are active std::cerr << "No active players\n"; m_active_player = ""; + if(store_meta) store_meta->clear(); return false; } @@ -615,11 +291,20 @@ bool dbus_manager::handle_properties_changed(DBusMessage* msg, const char* sende return false; if(m_active_player == "") { - select_active_player(); + select_active_player(&meta); } if (m_name_owners[m_active_player] == sender) { std::lock_guard lck(main_metadata.mtx); if(meta.got_song_data){ + // If the song has changed, reset the ticker + if( + main_metadata.meta.artists != meta.artists || + main_metadata.meta.album != meta.album || + main_metadata.meta.title != meta.title + ){ + main_metadata.ticker = {}; + } + main_metadata.meta = meta; main_metadata.meta.playing = true; } @@ -627,6 +312,7 @@ bool dbus_manager::handle_properties_changed(DBusMessage* msg, const char* sende main_metadata.meta.playing = meta.playing; } } + std::cerr << "Main metadata valid: " << std::boolalpha << main_metadata.meta.valid << "\n"; return true; } @@ -650,12 +336,12 @@ bool dbus_manager::handle_name_owner_changed(DBusMessage* msg, const char* sende { m_name_owners[str[0]] = str[2]; if(str[0] == m_requested_player){ - select_active_player(); metadata tmp; - get_media_player_metadata(tmp); + select_active_player(&tmp); { std::lock_guard lck(main_metadata.mtx); main_metadata.meta = tmp; + main_metadata.ticker = {}; } } } @@ -713,45 +399,27 @@ void dbus_manager::disconnect_from_signals() bool dbus_manager::dbus_list_name_to_owner() { - DBusError error; - - std::vector names; - std::string owner; - - DBusMessage * dbus_reply = nullptr; - DBusMessage * dbus_msg = nullptr; - - // dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:"org.mpris.MediaPlayer2.spotify" - if (nullptr == (dbus_msg = m_dbus_ldr.message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames"))) { - std::cerr << "MANGOHUD: " << __func__ << ": unable to allocate memory for dbus message\n"; - return false; - } + auto reply = DBusMessage_wrap::new_method_call( + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListNames", + &dbus_mgr.dbus() + ).send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); + if(not reply) return false; - m_dbus_ldr.error_init(&error); - if (nullptr == (dbus_reply = m_dbus_ldr.connection_send_with_reply_and_block(dbus_mgr.get_conn(), dbus_msg, DBUS_TIMEOUT, &error))) { - m_dbus_ldr.message_unref(dbus_msg); - std::cerr << "MANGOHUD: " << __func__ << ": "<< error.message << "\n"; - m_dbus_ldr.error_free(&error); - return false; - } + auto iter = reply.iter(); - auto iter = DBusMessageIter_wrap(dbus_reply, &m_dbus_ldr); if(not iter.is_array()) { - m_dbus_ldr.message_unref(dbus_msg); - m_dbus_ldr.message_unref(dbus_reply); - m_dbus_ldr.error_free(&error); return false; } array_for_each(iter, [&](std::string name){ if(!starts_with(name.c_str(), "org.mpris.MediaPlayer2.")) return; + std::string owner; if(dbus_get_name_owner(dbus_mgr, owner, name.c_str())){ m_name_owners[name] = owner; } }); - - m_dbus_ldr.message_unref(dbus_msg); - m_dbus_ldr.message_unref(dbus_reply); - m_dbus_ldr.error_free(&error); return true; } diff --git a/src/dbus_helpers.hpp b/src/dbus_helpers.hpp new file mode 100644 index 00000000..b64dcd5e --- /dev/null +++ b/src/dbus_helpers.hpp @@ -0,0 +1,362 @@ +#pragma once +#ifndef MANGOHUD_DBUS_HELPERS +#define MANGOHUD_DBUS_HELPERS + +#include "loaders/loader_dbus.h" + +namespace DBus_helpers{ +namespace detail{ +template struct dbus_type_identifier{}; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_BYTE; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_UINT16; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_UINT32; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_UINT64; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_INT16; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_INT32; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_INT64; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_DOUBLE; }; +template<> struct dbus_type_identifier { const int value = DBUS_TYPE_STRING; }; + +template +const int dbus_type_identifier_v = dbus_type_identifier().value; +} //namespace detail + +class DBusMessageIter_wrap { + +public: + DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader) + { + m_DBus = loader; + if(msg){ + m_DBus->message_iter_init(msg, &m_Iter); + m_resolved_iter = resolve_variants(); + m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); + } + else { + m_type = DBUS_TYPE_INVALID; + } + } + + DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader) + : m_Iter(iter), m_DBus(loader) + { + m_resolved_iter = resolve_variants(); + m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); + } + + + + int type() const noexcept { return m_type; } + bool is_unsigned() const noexcept; + bool is_signed() const noexcept; + bool is_string() const noexcept; + bool is_double() const noexcept; + bool is_primitive() const noexcept; + bool is_array() const noexcept; + operator bool() const noexcept { + return type() != DBUS_TYPE_INVALID; + } + + + template + auto get_primitive() -> T; + auto get_unsigned() -> uint64_t; + auto get_signed() -> int64_t; + auto get_stringified() -> std::string; + + auto get_array_iter() -> DBusMessageIter_wrap; + auto get_dict_entry_iter() -> DBusMessageIter_wrap; + + auto next() { + m_DBus->message_iter_next(&m_Iter); + // Resolve any variants + m_resolved_iter = resolve_variants(); + m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); + return *this; + } +private: + DBusMessageIter resolve_variants() { + auto iter = m_Iter; + auto field_type = m_DBus->message_iter_get_arg_type(&m_Iter); + while(field_type == DBUS_TYPE_VARIANT){ + m_DBus->message_iter_recurse(&iter, &iter); + field_type = m_DBus->message_iter_get_arg_type(&iter); + } + return iter; + } + + DBusMessageIter m_Iter; + DBusMessageIter m_resolved_iter; + int m_type; + libdbus_loader* m_DBus; +}; + + + +bool DBusMessageIter_wrap::is_unsigned() const noexcept { + return ( + (type() == DBUS_TYPE_BYTE) || + (type() == DBUS_TYPE_INT16) || + (type() == DBUS_TYPE_INT32) || + (type() == DBUS_TYPE_INT64) + ); +} + +bool DBusMessageIter_wrap::is_signed() const noexcept { + return ( + (type() == DBUS_TYPE_INT16) || + (type() == DBUS_TYPE_INT32) || + (type() == DBUS_TYPE_INT64) + ); +} + +bool DBusMessageIter_wrap::is_string() const noexcept { + return (type() == DBUS_TYPE_STRING); +} + +bool DBusMessageIter_wrap::is_double() const noexcept { + return (type() == DBUS_TYPE_DOUBLE); +} + +bool DBusMessageIter_wrap::is_primitive() const noexcept { + return ( + is_double() || + is_signed() || + is_unsigned() || + is_string() + ); +} + +bool DBusMessageIter_wrap::is_array() const noexcept { + return (type() == DBUS_TYPE_ARRAY); +} + + +template +auto DBusMessageIter_wrap::get_primitive() -> T { + auto requested_type = detail::dbus_type_identifier_v; + if(requested_type != type()){ + std::cerr << "Type mismatch: '" << (char) requested_type << "' vs '" << (char) type() << "'\n"; +#ifndef NDEBUG + exit(-1); +#else + return T(); +#endif + } + + T ret; + m_DBus->message_iter_get_basic(&m_resolved_iter, &ret); + return ret; +} + +template<> +auto DBusMessageIter_wrap::get_primitive() -> std::string { + return std::string(get_primitive()); +} + +uint64_t DBusMessageIter_wrap::get_unsigned() { + auto t = type(); + switch (t) + { + case DBUS_TYPE_BYTE: + return get_primitive(); + case DBUS_TYPE_UINT16: + return get_primitive(); + case DBUS_TYPE_UINT32: + return get_primitive(); + case DBUS_TYPE_UINT64: + return get_primitive(); + default: + return 0; + } +} + +int64_t DBusMessageIter_wrap::get_signed() { + auto t = type(); + switch (t) + { + case DBUS_TYPE_INT16: + return get_primitive(); + case DBUS_TYPE_INT32: + return get_primitive(); + case DBUS_TYPE_INT64: + return get_primitive(); + default: + return 0; + } +} + +auto DBusMessageIter_wrap::get_stringified() -> std::string { + if(is_string()) return get_primitive(); + if(is_unsigned()) return std::to_string(get_unsigned()); + if(is_signed()) return std::to_string(get_signed()); + if(is_double()) return std::to_string(get_primitive()); + std::cerr << "stringify failed\n"; + return std::string(); +} + +auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap { + if(not is_array()) { + std::cerr << "Not an array\n"; + return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus); + } + + DBusMessageIter ret; + m_DBus->message_iter_recurse(&m_resolved_iter, &ret); + return DBusMessageIter_wrap(ret, m_DBus); +} + +auto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap { + if(type() != DBUS_TYPE_DICT_ENTRY){ + std::cerr << "Not a dict entry\n"; + return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus); + } + + DBusMessageIter ret; + m_DBus->message_iter_recurse(&m_resolved_iter, &ret); + return DBusMessageIter_wrap(ret, m_DBus); +} + + + + + + +// Precondition: iter points to a dict of string -> any +// executes action(key, value_iter) for all entries +template +void string_map_for_each(DBusMessageIter_wrap iter, T action) { + iter = iter.get_array_iter(); + for(; iter; iter.next()) { + auto it = iter.get_dict_entry_iter(); + auto key = it.get_primitive(); + + it.next(); + action(key, it); + } +} + +template +void array_for_each(DBusMessageIter_wrap iter, Callable action) { + iter = iter.get_array_iter(); + for(; iter; iter.next()){ + action(iter.get_primitive()); + } +} + +template +void array_for_each_stringify(DBusMessageIter_wrap iter, Callable action) { + iter = iter.get_array_iter(); + for(; iter; iter.next()){ + action(iter.get_stringified()); + } +} + +template +void string_multimap_for_each_stringify(DBusMessageIter_wrap iter, T action) { + string_map_for_each(iter, [&](const std::string& key, DBusMessageIter_wrap it){ + if(it.is_array()){ + array_for_each_stringify(it, [&](const std::string& val){ + action(key, val); + }); + } + else if(it.is_primitive()){ + action(key, it.get_stringified()); + } + }); +} + + + +class DBusMessage_wrap { +public: + DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false) + : m_owning(owning), m_msg(msg), m_DBus(ldr) + {} + + ~DBusMessage_wrap(){ + free_if_owning(); + } + + DBusMessage_wrap(const DBusMessage_wrap&) = delete; + DBusMessage_wrap(DBusMessage_wrap&&) = default; + + operator bool() const { + return m_msg != nullptr; + } + + template + DBusMessage_wrap& argument(T arg) { + if(not m_msg) return *this; + if(not m_DBus->message_append_args( + m_msg, + detail::dbus_type_identifier_v, + &arg, + DBUS_TYPE_INVALID + )){ + free_if_owning(); + } + return *this; + } + + DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn, int timeout) { + if(not m_msg){ + return DBusMessage_wrap(nullptr, m_DBus); + } + DBusError err; + m_DBus->error_init(&err); + auto reply = m_DBus->connection_send_with_reply_and_block( + conn, + m_msg, + timeout, + &err + ); + if(reply == nullptr) { + std::cerr << "MangoHud[" << __func__ << "]: " << err.message << "\n"; + free_if_owning(); + m_DBus->error_free(&err); + } + return DBusMessage_wrap(reply, m_DBus, true); + } + + DBusMessageIter_wrap iter() { + return DBusMessageIter_wrap(m_msg, m_DBus); + } + + static DBusMessage_wrap new_method_call( + const std::string& bus_name, + const std::string& path, + const std::string& iface, + const std::string& method, + libdbus_loader* loader + ){ + auto msg = loader->message_new_method_call( + (bus_name.empty()) ? nullptr : bus_name.c_str(), + path.c_str(), + (iface.empty()) ? nullptr : iface.c_str(), + method.c_str() + ); + return DBusMessage_wrap(msg, loader, true); + } +private: + void free_if_owning() { + if(m_msg and m_owning) { + m_DBus->message_unref(m_msg); + } + m_msg = nullptr; + } + bool m_owning; + DBusMessage* m_msg; + libdbus_loader* m_DBus; + std::vector m_args; +}; + +template<> +DBusMessage_wrap& DBusMessage_wrap::argument(const std::string& str) +{ + return argument(str.c_str()); +} +} //namespace DBus_helpers + + +#endif //MANGOHUD_DBUS_HELPERS \ No newline at end of file diff --git a/src/dbus_info.h b/src/dbus_info.h index d0963631..eaca8612 100644 --- a/src/dbus_info.h +++ b/src/dbus_info.h @@ -13,8 +13,6 @@ #include #include "loaders/loader_dbus.h" -typedef std::unordered_map string_map; - struct metadata { //std::vector artists; std::string artists; // pre-concatenate @@ -23,17 +21,7 @@ struct metadata { std::string something; std::string artUrl; bool playing = false; - struct { - float pos; - float longest; - int dir = -1; - bool needs_recalc; - - float tw0; - float tw1; - float tw2; - } ticker; - + bool valid = false; bool got_song_data = false; bool got_playback_data = false; @@ -44,8 +32,6 @@ struct metadata { title.clear(); album.clear(); artUrl.clear(); - ticker = {}; - ticker.dir = -1; valid = false; } }; @@ -53,6 +39,16 @@ struct metadata { struct mutexed_metadata { std::mutex mtx; metadata meta; + struct { + float pos; + float longest; + int dir = -1; + bool needs_recalc = true; + + float tw0; + float tw1; + float tw2; + } ticker; }; enum SignalType @@ -114,7 +110,7 @@ namespace dbusmgr { void dbus_thread(); bool dbus_list_name_to_owner(); - bool select_active_player(); + bool select_active_player(metadata* meta = nullptr); static DBusHandlerResult filter_signals(DBusConnection*, DBusMessage*, void*); diff --git a/src/overlay.cpp b/src/overlay.cpp index 4e4f1aed..c8e5ed19 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -971,18 +971,18 @@ float get_ticker_limited_pos(float pos, float tw, float& left_limit, float& righ } #ifdef HAVE_DBUS -static void render_mpris_metadata(struct overlay_params& params, metadata& meta, uint64_t frame_timing, bool is_main) +static void render_mpris_metadata(struct overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing, bool is_main) { - if (meta.valid) { + if (meta.meta.valid) { auto color = ImGui::ColorConvertU32ToFloat4(params.media_player_color); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8,0)); ImGui::Dummy(ImVec2(0.0f, 20.0f)); //ImGui::PushFont(data.font1); if (meta.ticker.needs_recalc) { - meta.ticker.tw0 = ImGui::CalcTextSize(meta.title.c_str()).x; - meta.ticker.tw1 = ImGui::CalcTextSize(meta.artists.c_str()).x; - meta.ticker.tw2 = ImGui::CalcTextSize(meta.album.c_str()).x; + meta.ticker.tw0 = ImGui::CalcTextSize(meta.meta.title.c_str()).x; + meta.ticker.tw1 = ImGui::CalcTextSize(meta.meta.artists.c_str()).x; + meta.ticker.tw2 = ImGui::CalcTextSize(meta.meta.album.c_str()).x; meta.ticker.longest = std::max(std::max( meta.ticker.tw0, meta.ticker.tw1), @@ -1009,23 +1009,23 @@ static void render_mpris_metadata(struct overlay_params& params, metadata& meta, { new_pos = get_ticker_limited_pos(meta.ticker.pos, meta.ticker.tw0, left_limit, right_limit); ImGui::SetCursorPosX(new_pos); - ImGui::TextColored(color, "%s", meta.title.c_str()); + ImGui::TextColored(color, "%s", meta.meta.title.c_str()); } break; case MP_ORDER_ARTIST: { new_pos = get_ticker_limited_pos(meta.ticker.pos, meta.ticker.tw1, left_limit, right_limit); ImGui::SetCursorPosX(new_pos); - ImGui::TextColored(color, "%s", meta.artists.c_str()); + ImGui::TextColored(color, "%s", meta.meta.artists.c_str()); } break; case MP_ORDER_ALBUM: { //ImGui::NewLine(); - if (!meta.album.empty()) { + if (!meta.meta.album.empty()) { new_pos = get_ticker_limited_pos(meta.ticker.pos, meta.ticker.tw2, left_limit, right_limit); ImGui::SetCursorPosX(new_pos); - ImGui::TextColored(color, "%s", meta.album.c_str()); + ImGui::TextColored(color, "%s", meta.meta.album.c_str()); } } break; @@ -1033,7 +1033,7 @@ static void render_mpris_metadata(struct overlay_params& params, metadata& meta, } } - if (!meta.playing) { + if (!meta.meta.playing) { ImGui::TextColored(color, "(paused)"); } @@ -1385,7 +1385,7 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& ImGui::PushFont(&scaled_font); { std::lock_guard lck(main_metadata.mtx); - render_mpris_metadata(params, main_metadata.meta, frame_timing, true); + render_mpris_metadata(params, main_metadata, frame_timing, true); } //render_mpris_metadata(params, generic_mpris, frame_timing, false); ImGui::PopFont();