Add DBus loader, combined ticker for Spotify metadata

pull/131/head
jackun 4 years ago
parent d975278396
commit 8024736253
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

@ -115,7 +115,7 @@ inc_common = [
dep_vulkan = dependency('vulkan', required: get_option('use_system_vulkan')) dep_vulkan = dependency('vulkan', required: get_option('use_system_vulkan'))
dep_pthread = dependency('threads') dep_pthread = dependency('threads')
dep_dbus = dependency('dbus-1') dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true)
# Check for generic C arguments # Check for generic C arguments
c_args = [] c_args = []

@ -6,3 +6,4 @@ option('include_doc', type : 'boolean', value : true, description: 'Include the
option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support') option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support')
option('with_x11', type : 'feature', value : 'enabled') option('with_x11', type : 'feature', value : 'enabled')
option('with_wayland', type : 'feature', value : 'disabled') option('with_wayland', type : 'feature', value : 'disabled')
option('with_dbus', type : 'feature', value : 'enabled')

@ -17,104 +17,107 @@ std::string format_signal(const DBusSignal& s)
return ss.str(); return ss.str();
} }
static bool check_msg_arg(libdbus_loader& dbus, DBusMessageIter *iter, int type)
static bool check_msg_arg(DBusMessageIter *iter, int type)
{ {
int curr_type = DBUS_TYPE_INVALID; int curr_type = DBUS_TYPE_INVALID;
if ((curr_type = dbus_message_iter_get_arg_type (iter)) != type) { if ((curr_type = dbus.message_iter_get_arg_type (iter)) != type) {
#ifndef NDEBUG
std::cerr << "Argument is not of type '" << (char)type << "' != '" << (char) curr_type << "'" << std::endl; std::cerr << "Argument is not of type '" << (char)type << "' != '" << (char) curr_type << "'" << std::endl;
#endif
return false; return false;
} }
return true; return true;
} }
bool get_string_array(DBusMessageIter *iter_, std::vector<std::string>& entries) bool get_string_array(libdbus_loader& dbus, DBusMessageIter *iter_, std::vector<std::string>& entries)
{ {
DBusMessageIter iter = *iter_; DBusMessageIter iter = *iter_;
DBusMessageIter subiter; DBusMessageIter subiter;
int current_type = DBUS_TYPE_INVALID; int current_type = DBUS_TYPE_INVALID;
current_type = dbus_message_iter_get_arg_type (&iter); current_type = dbus.message_iter_get_arg_type (&iter);
if (current_type == DBUS_TYPE_VARIANT) { if (current_type == DBUS_TYPE_VARIANT) {
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
current_type = dbus_message_iter_get_arg_type (&iter); current_type = dbus.message_iter_get_arg_type (&iter);
} }
if (current_type != DBUS_TYPE_ARRAY) { if (current_type != DBUS_TYPE_ARRAY) {
#ifndef NDEBUG
std::cerr << "Not an array: '" << (char)current_type << "'" << std::endl; std::cerr << "Not an array: '" << (char)current_type << "'" << std::endl;
#endif
return false; return false;
} }
char *val = nullptr; char *val = nullptr;
dbus_message_iter_recurse (&iter, &subiter); dbus.message_iter_recurse (&iter, &subiter);
entries.clear(); entries.clear();
while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) { while ((current_type = dbus.message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) {
if (current_type == DBUS_TYPE_STRING) if (current_type == DBUS_TYPE_STRING)
{ {
dbus_message_iter_get_basic (&subiter, &val); dbus.message_iter_get_basic (&subiter, &val);
entries.push_back(val); entries.push_back(val);
} }
dbus_message_iter_next (&subiter); dbus.message_iter_next (&subiter);
} }
return true; return true;
} }
static bool get_variant_string(DBusMessageIter *iter_, std::string &val, bool key_or_value = false) static bool get_variant_string(libdbus_loader& dbus, DBusMessageIter *iter_, std::string &val, bool key_or_value = false)
{ {
DBusMessageIter iter = *iter_; DBusMessageIter iter = *iter_;
char *str = nullptr; char *str = nullptr;
int type = dbus_message_iter_get_arg_type (&iter); int type = dbus.message_iter_get_arg_type (&iter);
if (type != DBUS_TYPE_VARIANT && type != DBUS_TYPE_DICT_ENTRY) if (type != DBUS_TYPE_VARIANT && type != DBUS_TYPE_DICT_ENTRY)
return false; return false;
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
if (key_or_value) { if (key_or_value) {
dbus_message_iter_next (&iter); dbus.message_iter_next (&iter);
if (!check_msg_arg (&iter, DBUS_TYPE_VARIANT)) if (!check_msg_arg (dbus, &iter, DBUS_TYPE_VARIANT))
return false; return false;
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
} }
if (!check_msg_arg (&iter, DBUS_TYPE_STRING)) if (!check_msg_arg (dbus, &iter, DBUS_TYPE_STRING))
return false; return false;
dbus_message_iter_get_basic(&iter, &str); dbus.message_iter_get_basic(&iter, &str);
val = str; val = str;
return true; return true;
} }
static bool get_variant_string(DBusMessage *msg, std::string &val, bool key_or_value = false) static bool get_variant_string(libdbus_loader& dbus, DBusMessage *msg, std::string &val, bool key_or_value = false)
{ {
DBusMessageIter iter; DBusMessageIter iter;
dbus_message_iter_init (msg, &iter); dbus.message_iter_init (msg, &iter);
return get_variant_string(&iter, val, key_or_value); return get_variant_string(dbus, &iter, val, key_or_value);
} }
static void parse_mpris_metadata(DBusMessageIter *iter_, string_pair_vec& entries) static void parse_mpris_metadata(libdbus_loader& dbus, DBusMessageIter *iter_, string_pair_vec& entries)
{ {
DBusMessageIter subiter, iter = *iter_; DBusMessageIter subiter, iter = *iter_;
std::string key, val; std::string key, val;
std::vector<std::string> list; std::vector<std::string> list;
while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) while (dbus.message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
{ {
dbus_message_iter_next (&iter); dbus.message_iter_next (&iter);
//std::cerr << "\ttype: " << (char)dbus_message_iter_get_arg_type(&iter) << std::endl; //std::cerr << "\ttype: " << (char)dbus.message_iter_get_arg_type(&iter) << std::endl;
if (!get_variant_string(&iter, key)) if (!get_variant_string(dbus, &iter, key))
return; return;
dbus_message_iter_recurse (&iter, &subiter); dbus.message_iter_recurse (&iter, &subiter);
dbus_message_iter_next (&subiter); dbus.message_iter_next (&subiter);
//std::cerr << "\tkey: " << key << std::endl; //std::cerr << "\tkey: " << key << std::endl;
if (get_variant_string(&subiter, val)) { if (get_variant_string(dbus, &subiter, val)) {
//std::cerr << "\t\t" << val << std::endl; //std::cerr << "\t\t" << val << std::endl;
entries.push_back({key, val}); entries.push_back({key, val});
} }
else if (get_string_array(&subiter, list)) { else if (get_string_array(dbus, &subiter, list)) {
for (auto& s : list) { for (auto& s : list) {
//std::cerr << "\t\t" << s << std::endl; //std::cerr << "\t\t" << s << std::endl;
entries.push_back({key, s}); entries.push_back({key, s});
@ -123,7 +126,7 @@ static void parse_mpris_metadata(DBusMessageIter *iter_, string_pair_vec& entrie
} }
} }
static void parse_mpris_properties(DBusMessage *msg, std::string& source, string_pair_vec& entries) static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::string& source, string_pair_vec& entries)
{ {
const char *val_char = nullptr; const char *val_char = nullptr;
DBusMessageIter iter; DBusMessageIter iter;
@ -132,30 +135,30 @@ static void parse_mpris_properties(DBusMessage *msg, std::string& source, string
std::vector<DBusMessageIter> stack; std::vector<DBusMessageIter> stack;
stack.push_back({}); stack.push_back({});
dbus_message_iter_init (msg, &stack.back()); dbus.message_iter_init (msg, &stack.back());
// Should be 'org.mpris.MediaPlayer2.Player' // Should be 'org.mpris.MediaPlayer2.Player'
if (!check_msg_arg(&stack.back(), DBUS_TYPE_STRING)) if (!check_msg_arg(dbus, &stack.back(), DBUS_TYPE_STRING))
return; return;
dbus_message_iter_get_basic(&stack.back(), &val_char); dbus.message_iter_get_basic(&stack.back(), &val_char);
source = val_char; source = val_char;
if (source != "org.mpris.MediaPlayer2.Player") if (source != "org.mpris.MediaPlayer2.Player")
return; return;
dbus_message_iter_next (&stack.back()); dbus.message_iter_next (&stack.back());
//std::cerr << "type: " << (char)dbus_message_iter_get_arg_type(&stack.back()) << std::endl; //std::cerr << "type: " << (char)dbus.message_iter_get_arg_type(&stack.back()) << std::endl;
if (!check_msg_arg(&stack.back(), DBUS_TYPE_ARRAY)) if (!check_msg_arg(dbus, &stack.back(), DBUS_TYPE_ARRAY))
return; return;
dbus_message_iter_recurse (&stack.back(), &iter); dbus.message_iter_recurse (&stack.back(), &iter);
stack.push_back(iter); stack.push_back(iter);
while (dbus_message_iter_get_arg_type(&stack.back()) != DBUS_TYPE_INVALID) while (dbus.message_iter_get_arg_type(&stack.back()) != DBUS_TYPE_INVALID)
{ {
if (!get_variant_string(&stack.back(), key)) { if (!get_variant_string(dbus, &stack.back(), key)) {
dbus_message_iter_next (&stack.back()); dbus.message_iter_next (&stack.back());
continue; continue;
} }
@ -165,33 +168,33 @@ static void parse_mpris_properties(DBusMessage *msg, std::string& source, string
#endif #endif
// dive into Metadata // dive into Metadata
dbus_message_iter_recurse (&stack.back(), &iter); dbus.message_iter_recurse (&stack.back(), &iter);
// get the array of entries // get the array of entries
dbus_message_iter_next (&iter); dbus.message_iter_next (&iter);
if (!check_msg_arg(&iter, DBUS_TYPE_VARIANT)) if (!check_msg_arg(dbus, &iter, DBUS_TYPE_VARIANT))
continue; continue;
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
if (!check_msg_arg(&iter, DBUS_TYPE_ARRAY)) if (!check_msg_arg(dbus, &iter, DBUS_TYPE_ARRAY))
continue; continue;
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
parse_mpris_metadata(&iter, entries); parse_mpris_metadata(dbus, &iter, entries);
} }
else if (key == "PlaybackStatus") { else if (key == "PlaybackStatus") {
dbus_message_iter_recurse (&stack.back(), &iter); dbus.message_iter_recurse (&stack.back(), &iter);
dbus_message_iter_next (&iter); dbus.message_iter_next (&iter);
if (get_variant_string(&iter, val)) if (get_variant_string(dbus, &iter, val))
entries.push_back({key, val}); entries.push_back({key, val});
} }
dbus_message_iter_next (&stack.back()); dbus.message_iter_next (&stack.back());
} }
} }
static void parse_property_changed(DBusMessage *msg, std::string& source, string_pair_vec& entries) static void parse_property_changed(libdbus_loader& dbus, DBusMessage *msg, std::string& source, string_pair_vec& entries)
{ {
char *name = nullptr; char *name = nullptr;
int i; int i;
@ -202,20 +205,22 @@ static void parse_property_changed(DBusMessage *msg, std::string& source, string
stack.push_back({}); stack.push_back({});
#ifndef NDEBUG #ifndef NDEBUG
std::vector<char> tabs; std::vector<char> padding;
tabs.push_back('\0'); padding.push_back('\0');
#endif #endif
dbus_message_iter_init (msg, &stack.back()); dbus.message_iter_init (msg, &stack.back());
int type, prev_type = 0; int type, prev_type = 0;
type = dbus_message_iter_get_arg_type (&stack.back()); type = dbus.message_iter_get_arg_type (&stack.back());
if (type != DBUS_TYPE_STRING) { if (type != DBUS_TYPE_STRING) {
#ifndef NDEBUG
std::cerr << __func__ << "First element is not a string" << std::endl; std::cerr << __func__ << "First element is not a string" << std::endl;
#endif
return; return;
} }
dbus_message_iter_get_basic(&stack.back(), &name); dbus.message_iter_get_basic(&stack.back(), &name);
source = name; source = name;
#ifndef NDEBUG #ifndef NDEBUG
std::cout << name << std::endl; std::cout << name << std::endl;
@ -223,17 +228,18 @@ static void parse_property_changed(DBusMessage *msg, std::string& source, string
std::pair<std::string, std::string> kv; std::pair<std::string, std::string> kv;
dbus_message_iter_next (&stack.back()); dbus.message_iter_next (&stack.back());
while ((type = dbus_message_iter_get_arg_type (&stack.back())) != DBUS_TYPE_INVALID) { // the loop should be able parse the whole message if used for generic use-cases
while ((type = dbus.message_iter_get_arg_type (&stack.back())) != DBUS_TYPE_INVALID) {
#ifndef NDEBUG #ifndef NDEBUG
tabs.back() = ' '; padding.back() = ' ';
tabs.resize(stack.size() + 1, ' '); padding.resize(stack.size() + 1, ' ');
tabs.back() = '\0'; padding.back() = '\0';
std::cout << tabs.data() << "Type: " << (char)type; std::cout << padding.data() << "Type: " << (char)type;
#endif #endif
if (type == DBUS_TYPE_STRING) { if (type == DBUS_TYPE_STRING) {
dbus_message_iter_get_basic(&stack.back(), &name); dbus.message_iter_get_basic(&stack.back(), &name);
#ifndef NDEBUG #ifndef NDEBUG
std::cout << "=" << name << std::endl; std::cout << "=" << name << std::endl;
#endif #endif
@ -245,19 +251,19 @@ static void parse_property_changed(DBusMessage *msg, std::string& source, string
} }
} }
else if (type == DBUS_TYPE_INT32) { else if (type == DBUS_TYPE_INT32) {
dbus_message_iter_get_basic(&stack.back(), &i); dbus.message_iter_get_basic(&stack.back(), &i);
#ifndef NDEBUG #ifndef NDEBUG
std::cout << "=" << i << std::endl; std::cout << "=" << i << std::endl;
#endif #endif
} }
else if (type == DBUS_TYPE_UINT64) { else if (type == DBUS_TYPE_UINT64) {
dbus_message_iter_get_basic(&stack.back(), &u64); dbus.message_iter_get_basic(&stack.back(), &u64);
#ifndef NDEBUG #ifndef NDEBUG
std::cout << "=" << u64 << std::endl; std::cout << "=" << u64 << std::endl;
#endif #endif
} }
else if (type == DBUS_TYPE_DOUBLE) { else if (type == DBUS_TYPE_DOUBLE) {
dbus_message_iter_get_basic(&stack.back(), &d); dbus.message_iter_get_basic(&stack.back(), &d);
#ifndef NDEBUG #ifndef NDEBUG
std::cout << "=" << d << std::endl; std::cout << "=" << d << std::endl;
#endif #endif
@ -268,8 +274,8 @@ static void parse_property_changed(DBusMessage *msg, std::string& source, string
#endif #endif
prev_type = type; prev_type = type;
DBusMessageIter iter; DBusMessageIter iter;
dbus_message_iter_recurse (&stack.back(), &iter); dbus.message_iter_recurse (&stack.back(), &iter);
if (dbus_message_iter_get_arg_type (&stack.back()) != DBUS_TYPE_INVALID) if (dbus.message_iter_get_arg_type (&stack.back()) != DBUS_TYPE_INVALID)
stack.push_back(iter); stack.push_back(iter);
continue; continue;
} else { } else {
@ -278,67 +284,69 @@ static void parse_property_changed(DBusMessage *msg, std::string& source, string
#endif #endif
} }
while(FALSE == dbus_message_iter_next (&stack.back()) && stack.size() > 1) { while(FALSE == dbus.message_iter_next (&stack.back()) && stack.size() > 1) {
stack.pop_back(); stack.pop_back();
prev_type = 0; prev_type = 0;
} }
} }
} }
bool get_dict_string_array(DBusMessage *msg, string_pair_vec& entries) bool get_dict_string_array(libdbus_loader& dbus, DBusMessage *msg, string_pair_vec& entries)
{ {
DBusMessageIter iter, outer_iter; DBusMessageIter iter, outer_iter;
dbus_message_iter_init (msg, &outer_iter); dbus.message_iter_init (msg, &outer_iter);
int current_type = DBUS_TYPE_INVALID; int current_type = DBUS_TYPE_INVALID;
current_type = dbus_message_iter_get_arg_type (&outer_iter); current_type = dbus.message_iter_get_arg_type (&outer_iter);
if (current_type == DBUS_TYPE_VARIANT) { if (current_type == DBUS_TYPE_VARIANT) {
dbus_message_iter_recurse (&outer_iter, &outer_iter); dbus.message_iter_recurse (&outer_iter, &outer_iter);
current_type = dbus_message_iter_get_arg_type (&outer_iter); current_type = dbus.message_iter_get_arg_type (&outer_iter);
} }
if (current_type != DBUS_TYPE_ARRAY) { if (current_type != DBUS_TYPE_ARRAY) {
#ifndef NDEBUG
std::cerr << "Not an array " << (char)current_type << std::endl; std::cerr << "Not an array " << (char)current_type << std::endl;
#endif
return false; return false;
} }
char *val_key = nullptr, *val_value = nullptr; char *val_key = nullptr, *val_value = nullptr;
dbus_message_iter_recurse (&outer_iter, &outer_iter); dbus.message_iter_recurse (&outer_iter, &outer_iter);
while ((current_type = dbus_message_iter_get_arg_type (&outer_iter)) != DBUS_TYPE_INVALID) { while ((current_type = dbus.message_iter_get_arg_type (&outer_iter)) != DBUS_TYPE_INVALID) {
// printf("type: %d\n", current_type); // printf("type: %d\n", current_type);
if (current_type == DBUS_TYPE_DICT_ENTRY) if (current_type == DBUS_TYPE_DICT_ENTRY)
{ {
dbus_message_iter_recurse (&outer_iter, &iter); dbus.message_iter_recurse (&outer_iter, &iter);
// dict entry key // dict entry key
//printf("\tentry: {%c, ", dbus_message_iter_get_arg_type (&iter)); //printf("\tentry: {%c, ", dbus.message_iter_get_arg_type (&iter));
dbus_message_iter_get_basic (&iter, &val_key); dbus.message_iter_get_basic (&iter, &val_key);
std::string key = val_key; std::string key = val_key;
// dict entry value // dict entry value
dbus_message_iter_next (&iter); dbus.message_iter_next (&iter);
if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT) if (dbus.message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY) { if (dbus.message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY) {
dbus_message_iter_recurse (&iter, &iter); dbus.message_iter_recurse (&iter, &iter);
if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) { if (dbus.message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) {
//printf("%c}\n", dbus_message_iter_get_arg_type (&iter)); //printf("%c}\n", dbus.message_iter_get_arg_type (&iter));
dbus_message_iter_get_basic (&iter, &val_value); dbus.message_iter_get_basic (&iter, &val_value);
entries.push_back({val_key, val_value}); entries.push_back({val_key, val_value});
} }
} }
else if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) { else if (dbus.message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) {
//printf("%c}\n", dbus_message_iter_get_arg_type (&iter)); //printf("%c}\n", dbus.message_iter_get_arg_type (&iter));
dbus_message_iter_get_basic (&iter, &val_value); dbus.message_iter_get_basic (&iter, &val_value);
entries.push_back({val_key, val_value}); entries.push_back({val_key, val_value});
} }
} }
dbus_message_iter_next (&outer_iter); dbus.message_iter_next (&outer_iter);
} }
return true; return true;
} }
@ -346,18 +354,14 @@ bool get_dict_string_array(DBusMessage *msg, string_pair_vec& entries)
static void assign_metadata(metadata& meta, string_pair_vec& entries) static void assign_metadata(metadata& meta, string_pair_vec& entries)
{ {
std::lock_guard<std::mutex> lk(meta.mutex); std::lock_guard<std::mutex> lk(meta.mutex);
std::vector<std::string> artists;
meta.valid = false; meta.valid = false;
bool artists_cleared = false;
for (auto& kv : entries) { for (auto& kv : entries) {
#ifndef NDEBUG #ifndef NDEBUG
std::cerr << kv.first << " = " << kv.second << std::endl; std::cerr << kv.first << " = " << kv.second << std::endl;
#endif #endif
if (kv.first == "xesam:artist") { if (kv.first == "xesam:artist") {
if (!artists_cleared) { artists.push_back(kv.second);
artists_cleared = true;
meta.artists.clear();
}
meta.artists.push_back(kv.second);
} }
else if (kv.first == "xesam:title") else if (kv.first == "xesam:title")
meta.title = kv.second; meta.title = kv.second;
@ -369,20 +373,34 @@ static void assign_metadata(metadata& meta, string_pair_vec& entries)
meta.playing = (kv.second == "Playing"); meta.playing = (kv.second == "Playing");
} }
// XXX Spotify only sends one artist anyway
meta.artists.clear();
for (auto p = artists.begin(); p != artists.end(); p++) {
meta.artists += *p;
if (p != artists.end() - 1)
meta.artists += ", ";
}
if (meta.artists.size() || !meta.title.empty()) if (meta.artists.size() || !meta.title.empty())
meta.valid = meta.playing; meta.valid = meta.playing;
meta.ticker.needs_recalc = true;
meta.ticker.pos = 0;
meta.ticker.longest = 0;
meta.ticker.dir = -1;
} }
void dbus_get_spotify_property(dbusmgr::dbus_manager& dbus, string_pair_vec& entries, const char * prop) void dbus_get_spotify_property(dbusmgr::dbus_manager& dbus_mgr, string_pair_vec& entries, const char * prop)
{ {
auto& dbus = dbus_mgr.dbus();
DBusError error; DBusError error;
::dbus_error_init(&error); dbus.error_init(&error);
DBusMessage * dbus_reply = nullptr; DBusMessage * dbus_reply = nullptr;
DBusMessage * dbus_msg = nullptr; DBusMessage * dbus_msg = nullptr;
// dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata' // dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata'
if (nullptr == (dbus_msg = ::dbus_message_new_method_call("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"))) { if (nullptr == (dbus_msg = dbus.message_new_method_call("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"))) {
throw std::runtime_error("unable to allocate memory for dbus message"); throw std::runtime_error("unable to allocate memory for dbus message");
} }
@ -391,26 +409,26 @@ void dbus_get_spotify_property(dbusmgr::dbus_manager& dbus, string_pair_vec& ent
}; };
std::cerr << __func__ << ": " << prop << std::endl; std::cerr << __func__ << ": " << prop << std::endl;
if (!dbus_message_append_args (dbus_msg, DBUS_TYPE_STRING, &v_STRINGS[0], DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID)) { if (!dbus.message_append_args (dbus_msg, DBUS_TYPE_STRING, &v_STRINGS[0], DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID)) {
::dbus_message_unref(dbus_msg); dbus.message_unref(dbus_msg);
throw std::runtime_error(error.message); throw std::runtime_error(error.message);
} }
if (nullptr == (dbus_reply = ::dbus_connection_send_with_reply_and_block(dbus.get_conn(), dbus_msg, DBUS_TIMEOUT_USE_DEFAULT, &error))) { if (nullptr == (dbus_reply = dbus.connection_send_with_reply_and_block(dbus_mgr.get_conn(), dbus_msg, DBUS_TIMEOUT_USE_DEFAULT, &error))) {
::dbus_message_unref(dbus_msg); dbus.message_unref(dbus_msg);
throw dbusmgr::dbus_error(&error); throw dbusmgr::dbus_error(dbus, &error);
} }
std::string entry; std::string entry;
if (get_dict_string_array(dbus_reply, entries)) { if (get_dict_string_array(dbus, dbus_reply, entries)) {
// nothing // nothing
} else if (get_variant_string(dbus_reply, entry)) { } else if (get_variant_string(dbus, dbus_reply, entry)) {
entries.push_back({prop, entry}); entries.push_back({prop, entry});
} }
::dbus_message_unref(dbus_msg); dbus.message_unref(dbus_msg);
::dbus_message_unref(dbus_reply); dbus.message_unref(dbus_reply);
::dbus_error_free(&error); dbus.error_free(&error);
} }
void get_spotify_metadata(dbusmgr::dbus_manager& dbus, metadata& meta) void get_spotify_metadata(dbusmgr::dbus_manager& dbus, metadata& meta)
@ -425,12 +443,17 @@ void get_spotify_metadata(dbusmgr::dbus_manager& dbus, metadata& meta)
namespace dbusmgr { namespace dbusmgr {
void dbus_manager::init() void dbus_manager::init()
{ {
::dbus_threads_init_default(); if (!m_dbus_ldr.Load("libdbus-1.so.3"))
throw std::runtime_error("Could not load libdbus-1.so.3");
m_dbus_ldr.error_init(&m_error);
if ( nullptr == (m_dbus_conn = ::dbus_bus_get(DBUS_BUS_SESSION, &m_error)) ) { m_dbus_ldr.threads_init_default();
throw dbus_error(&m_error);
if ( nullptr == (m_dbus_conn = m_dbus_ldr.bus_get(DBUS_BUS_SESSION, &m_error)) ) {
throw dbus_error(m_dbus_ldr, &m_error);
} }
std::cout << "Connected to D-Bus as \"" << ::dbus_bus_get_unique_name(m_dbus_conn) << "\"." << std::endl; std::cout << "Connected to D-Bus as \"" << m_dbus_ldr.bus_get_unique_name(m_dbus_conn) << "\"." << std::endl;
connect_to_signals(); connect_to_signals();
m_inited = true; m_inited = true;
@ -441,21 +464,21 @@ dbus_manager::~dbus_manager()
// unreference system bus connection instead of closing it // unreference system bus connection instead of closing it
if (m_dbus_conn) { if (m_dbus_conn) {
disconnect_from_signals(); disconnect_from_signals();
::dbus_connection_unref(m_dbus_conn); m_dbus_ldr.connection_unref(m_dbus_conn);
m_dbus_conn = nullptr; m_dbus_conn = nullptr;
} }
::dbus_error_free(&m_error); m_dbus_ldr.error_free(&m_error);
} }
void dbus_manager::connect_to_signals() void dbus_manager::connect_to_signals()
{ {
for (auto kv : m_signals) { for (auto kv : m_signals) {
auto signal = format_signal(kv); auto signal = format_signal(kv);
::dbus_bus_add_match(m_dbus_conn, signal.c_str(), &m_error); m_dbus_ldr.bus_add_match(m_dbus_conn, signal.c_str(), &m_error);
if (::dbus_error_is_set(&m_error)) { if (m_dbus_ldr.error_is_set(&m_error)) {
::perror(m_error.name); ::perror(m_error.name);
::perror(m_error.message); ::perror(m_error.message);
::dbus_error_free(&m_error); m_dbus_ldr.error_free(&m_error);
//return; //return;
} }
} }
@ -467,11 +490,11 @@ void dbus_manager::disconnect_from_signals()
{ {
for (auto kv : m_signals) { for (auto kv : m_signals) {
auto signal = format_signal(kv); auto signal = format_signal(kv);
::dbus_bus_remove_match(m_dbus_conn, signal.c_str(), &m_error); m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error);
if (dbus_error_is_set(&m_error)) { if (m_dbus_ldr.error_is_set(&m_error)) {
::perror(m_error.name); ::perror(m_error.name);
::perror(m_error.message); ::perror(m_error.message);
::dbus_error_free(&m_error); m_dbus_ldr.error_free(&m_error);
} }
} }
@ -499,19 +522,18 @@ void dbus_manager::start_thread()
void dbus_manager::dbus_thread(dbus_manager *pmgr) void dbus_manager::dbus_thread(dbus_manager *pmgr)
{ {
DBusError error; (void)parse_property_changed;
DBusMessage *msg = nullptr; DBusMessage *msg = nullptr;
auto& dbus = pmgr->dbus();
::dbus_error_init(&error);
// loop listening for signals being emmitted // loop listening for signals being emmitted
while (!pmgr->m_quit) { while (!pmgr->m_quit) {
// non blocking read of the next available message // non blocking read of the next available message
if (!::dbus_connection_read_write(pmgr->m_dbus_conn, 0)) if (!dbus.connection_read_write(pmgr->m_dbus_conn, 0))
return; // connection closed return; // connection closed
msg = ::dbus_connection_pop_message(pmgr->m_dbus_conn); msg = dbus.connection_pop_message(pmgr->m_dbus_conn);
// loop again if we haven't read a message // loop again if we haven't read a message
if (nullptr == msg) { if (nullptr == msg) {
@ -520,7 +542,7 @@ void dbus_manager::dbus_thread(dbus_manager *pmgr)
} }
for (auto& sig : pmgr->m_signals) { for (auto& sig : pmgr->m_signals) {
if (::dbus_message_is_signal(msg, sig.intf, sig.signal)) if (dbus.message_is_signal(msg, sig.intf, sig.signal))
{ {
#ifndef NDEBUG #ifndef NDEBUG
@ -534,7 +556,7 @@ void dbus_manager::dbus_thread(dbus_manager *pmgr)
std::vector<std::pair<std::string, std::string>> entries; std::vector<std::pair<std::string, std::string>> entries;
//parse_property_changed(msg, source, entries); //parse_property_changed(msg, source, entries);
parse_mpris_properties(msg, source, entries); parse_mpris_properties(dbus, msg, source, entries);
#ifndef NDEBUG #ifndef NDEBUG
std::cerr << "Source: " << source << std::endl; std::cerr << "Source: " << source << std::endl;
#endif #endif
@ -546,14 +568,14 @@ void dbus_manager::dbus_thread(dbus_manager *pmgr)
case ST_NAMEOWNERCHANGED: case ST_NAMEOWNERCHANGED:
{ {
DBusMessageIter iter; DBusMessageIter iter;
dbus_message_iter_init (msg, &iter); dbus.message_iter_init (msg, &iter);
std::vector<std::string> str; std::vector<std::string> str;
const char *value = nullptr; const char *value = nullptr;
while (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) { while (dbus.message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) {
dbus_message_iter_get_basic (&iter, &value); dbus.message_iter_get_basic (&iter, &value);
str.push_back(value); str.push_back(value);
dbus_message_iter_next (&iter); dbus.message_iter_next (&iter);
} }
// did spotify quit? // did spotify quit?
@ -569,15 +591,11 @@ void dbus_manager::dbus_thread(dbus_manager *pmgr)
default: default:
break; break;
} }
if (dbus_error_is_set(&error)) {
std::cerr << error.message << std::endl;
dbus_error_free(&error);
}
} }
} }
// free the message // free the message
dbus_message_unref(msg); dbus.message_unref(msg);
} }
} }

@ -1,5 +1,4 @@
#pragma once #pragma once
#include <dbus/dbus.h>
#include <stdexcept> #include <stdexcept>
#include <thread> #include <thread>
#include <functional> #include <functional>
@ -7,14 +6,26 @@
#include <string> #include <string>
#include <map> #include <map>
#include <mutex> #include <mutex>
#include "loaders/loader_dbus.h"
struct metadata { struct metadata {
std::vector<std::string> artists; //std::vector<std::string> artists;
std::string artists; // pre-concatenate
std::string title; std::string title;
std::string album; std::string album;
std::string something; std::string something;
std::string artUrl; std::string artUrl;
bool playing = false; 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 valid = false;
std::mutex mutex; std::mutex mutex;
@ -47,14 +58,16 @@ namespace dbusmgr {
class dbus_error : public std::runtime_error class dbus_error : public std::runtime_error
{ {
public: public:
dbus_error(DBusError *src) : std::runtime_error(src->message) dbus_error(libdbus_loader& dbus_, DBusError *src) : std::runtime_error(src->message)
{ {
dbus_error_init(&error); dbus = &dbus_;
dbus_move_error (src, &error); dbus->error_init(&error);
dbus->move_error (src, &error);
} }
virtual ~dbus_error() { dbus_error_free (&error); } virtual ~dbus_error() { dbus->error_free (&error); }
private: private:
DBusError error; DBusError error;
libdbus_loader *dbus;
}; };
class dbus_manager class dbus_manager
@ -62,7 +75,6 @@ namespace dbusmgr {
public: public:
dbus_manager() dbus_manager()
{ {
::dbus_error_init(&m_error);
} }
~dbus_manager(); ~dbus_manager();
@ -75,6 +87,11 @@ namespace dbusmgr {
return m_dbus_conn; return m_dbus_conn;
} }
libdbus_loader& dbus() {
return m_dbus_ldr;
}
protected: protected:
void stop_thread(); void stop_thread();
void start_thread(); void start_thread();
@ -88,6 +105,7 @@ namespace dbusmgr {
bool m_inited = false; bool m_inited = false;
std::thread m_thread; std::thread m_thread;
std::map<CBENUM, callback_func> m_callbacks; std::map<CBENUM, callback_func> m_callbacks;
libdbus_loader m_dbus_ldr;
const std::array<DBusSignal, 2> m_signals {{ const std::array<DBusSignal, 2> m_signals {{
{ "org.freedesktop.DBus", "NameOwnerChanged", ST_NAMEOWNERCHANGED }, { "org.freedesktop.DBus", "NameOwnerChanged", ST_NAMEOWNERCHANGED },

@ -3,7 +3,10 @@
#include <thread> #include <thread>
#include <iostream> #include <iostream>
#include "imgui_hud_shared.h" #include "imgui_hud_shared.h"
#ifdef HAVE_DBUS
#include "dbus_info.h" #include "dbus_info.h"
#endif
namespace MangoHud { namespace GL { namespace MangoHud { namespace GL {
@ -28,6 +31,8 @@ void imgui_init()
init_system_info(); init_system_info();
cfg_inited = true; cfg_inited = true;
init_cpu_stats(params); init_cpu_stats(params);
#ifdef HAVE_DBUS
if (params.enabled[OVERLAY_PARAM_ENABLED_media_player]) { if (params.enabled[OVERLAY_PARAM_ENABLED_media_player]) {
try { try {
dbusmgr::dbus_mgr.init(); dbusmgr::dbus_mgr.init();
@ -36,6 +41,7 @@ void imgui_init()
std::cerr << "Failed to get initial Spotify metadata: " << e.what() << std::endl; std::cerr << "Failed to get initial Spotify metadata: " << e.what() << std::endl;
} }
} }
#endif
} }
}} // namespaces }} // namespaces

@ -0,0 +1,270 @@
#include "loaders/loader_dbus.h"
// Put these sanity checks here so that they fire at most once
// (to avoid cluttering the build output).
#if !defined(LIBRARY_LOADER_DBUS_H_DLOPEN) && !defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED)
#error neither LIBRARY_LOADER_DBUS_H_DLOPEN nor LIBRARY_LOADER_DBUS_H_DT_NEEDED defined
#endif
#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN) && defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED)
#error both LIBRARY_LOADER_DBUS_H_DLOPEN and LIBRARY_LOADER_DBUS_H_DT_NEEDED defined
#endif
libdbus_loader::libdbus_loader() : loaded_(false) {
}
libdbus_loader::~libdbus_loader() {
CleanUp(loaded_);
}
bool libdbus_loader::Load(const std::string& library_name) {
if (loaded_) {
return false;
}
#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)
library_ = dlopen(library_name.c_str(), RTLD_LAZY);
if (!library_)
return false;
bus_add_match =
reinterpret_cast<decltype(this->bus_add_match)>(
dlsym(library_, "dbus_bus_add_match"));
if (!bus_add_match) {
CleanUp(true);
return false;
}
bus_get =
reinterpret_cast<decltype(this->bus_get)>(
dlsym(library_, "dbus_bus_get"));
if (!bus_get) {
CleanUp(true);
return false;
}
bus_get_unique_name =
reinterpret_cast<decltype(this->bus_get_unique_name)>(
dlsym(library_, "dbus_bus_get_unique_name"));
if (!bus_get_unique_name) {
CleanUp(true);
return false;
}
bus_remove_match =
reinterpret_cast<decltype(this->bus_remove_match)>(
dlsym(library_, "dbus_bus_remove_match"));
if (!bus_remove_match) {
CleanUp(true);
return false;
}
connection_pop_message =
reinterpret_cast<decltype(this->connection_pop_message)>(
dlsym(library_, "dbus_connection_pop_message"));
if (!connection_pop_message) {
CleanUp(true);
return false;
}
connection_read_write =
reinterpret_cast<decltype(this->connection_read_write)>(
dlsym(library_, "dbus_connection_read_write"));
if (!connection_read_write) {
CleanUp(true);
return false;
}
connection_send_with_reply_and_block =
reinterpret_cast<decltype(this->connection_send_with_reply_and_block)>(
dlsym(library_, "dbus_connection_send_with_reply_and_block"));
if (!connection_send_with_reply_and_block) {
CleanUp(true);
return false;
}
connection_unref =
reinterpret_cast<decltype(this->connection_unref)>(
dlsym(library_, "dbus_connection_unref"));
if (!connection_unref) {
CleanUp(true);
return false;
}
error_free =
reinterpret_cast<decltype(this->error_free)>(
dlsym(library_, "dbus_error_free"));
if (!error_free) {
CleanUp(true);
return false;
}
error_init =
reinterpret_cast<decltype(this->error_init)>(
dlsym(library_, "dbus_error_init"));
if (!error_init) {
CleanUp(true);
return false;
}
error_is_set =
reinterpret_cast<decltype(this->error_is_set)>(
dlsym(library_, "dbus_error_is_set"));
if (!error_is_set) {
CleanUp(true);
return false;
}
message_append_args =
reinterpret_cast<decltype(this->message_append_args)>(
dlsym(library_, "dbus_message_append_args"));
if (!message_append_args) {
CleanUp(true);
return false;
}
message_is_signal =
reinterpret_cast<decltype(this->message_is_signal)>(
dlsym(library_, "dbus_message_is_signal"));
if (!message_is_signal) {
CleanUp(true);
return false;
}
message_iter_get_arg_type =
reinterpret_cast<decltype(this->message_iter_get_arg_type)>(
dlsym(library_, "dbus_message_iter_get_arg_type"));
if (!message_iter_get_arg_type) {
CleanUp(true);
return false;
}
message_iter_get_basic =
reinterpret_cast<decltype(this->message_iter_get_basic)>(
dlsym(library_, "dbus_message_iter_get_basic"));
if (!message_iter_get_basic) {
CleanUp(true);
return false;
}
message_iter_init =
reinterpret_cast<decltype(this->message_iter_init)>(
dlsym(library_, "dbus_message_iter_init"));
if (!message_iter_init) {
CleanUp(true);
return false;
}
message_iter_next =
reinterpret_cast<decltype(this->message_iter_next)>(
dlsym(library_, "dbus_message_iter_next"));
if (!message_iter_next) {
CleanUp(true);
return false;
}
message_iter_recurse =
reinterpret_cast<decltype(this->message_iter_recurse)>(
dlsym(library_, "dbus_message_iter_recurse"));
if (!message_iter_recurse) {
CleanUp(true);
return false;
}
message_new_method_call =
reinterpret_cast<decltype(this->message_new_method_call)>(
dlsym(library_, "dbus_message_new_method_call"));
if (!message_new_method_call) {
CleanUp(true);
return false;
}
message_unref =
reinterpret_cast<decltype(this->message_unref)>(
dlsym(library_, "dbus_message_unref"));
if (!message_unref) {
CleanUp(true);
return false;
}
move_error =
reinterpret_cast<decltype(this->move_error)>(
dlsym(library_, "dbus_move_error"));
if (!move_error) {
CleanUp(true);
return false;
}
threads_init_default =
reinterpret_cast<decltype(this->threads_init_default)>(
dlsym(library_, "dbus_threads_init_default"));
if (!threads_init_default) {
CleanUp(true);
return false;
}
#endif
#if defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED)
bus_add_match = &::dbus_bus_add_match;
bus_get = &::dbus_bus_get;
bus_get_unique_name = &::dbus_bus_get_unique_name;
bus_remove_match = &::dbus_bus_remove_match;
connection_pop_message = &::dbus_connection_pop_message;
connection_read_write = &::dbus_connection_read_write;
connection_send_with_reply_and_block = &::dbus_connection_send_with_reply_and_block;
connection_unref = &::dbus_connection_unref;
error_free = &::dbus_error_free;
error_init = &::dbus_error_init;
error_is_set = &::dbus_error_is_set;
message_append_args = &::dbus_message_append_args;
message_is_signal = &::dbus_message_is_signal;
message_iter_get_arg_type = &::dbus_message_iter_get_arg_type;
message_iter_get_basic = &::dbus_message_iter_get_basic;
message_iter_init = &::dbus_message_iter_init;
message_iter_next = &::dbus_message_iter_next;
message_iter_recurse = &::dbus_message_iter_recurse;
message_new_method_call = &::dbus_message_new_method_call;
message_unref = &::dbus_message_unref;
move_error = &::dbus_move_error;
threads_init_default = &::dbus_threads_init_default;
#endif
loaded_ = true;
return true;
}
void libdbus_loader::CleanUp(bool unload) {
#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)
if (unload) {
dlclose(library_);
library_ = NULL;
}
#endif
loaded_ = false;
bus_add_match = NULL;
bus_get = NULL;
bus_get_unique_name = NULL;
bus_remove_match = NULL;
connection_pop_message = NULL;
connection_read_write = NULL;
connection_send_with_reply_and_block = NULL;
connection_unref = NULL;
error_free = NULL;
error_init = NULL;
error_is_set = NULL;
message_append_args = NULL;
message_is_signal = NULL;
message_iter_get_arg_type = NULL;
message_iter_get_basic = NULL;
message_iter_init = NULL;
message_iter_next = NULL;
message_iter_recurse = NULL;
message_new_method_call = NULL;
message_unref = NULL;
move_error = NULL;
threads_init_default = NULL;
}

@ -0,0 +1,61 @@
#ifndef LIBRARY_LOADER_DBUS_H
#define LIBRARY_LOADER_DBUS_H
#include <dbus/dbus.h>
#define LIBRARY_LOADER_DBUS_H_DLOPEN
#include <string>
#include <dlfcn.h>
class libdbus_loader {
public:
libdbus_loader();
libdbus_loader(const std::string& library_name) : libdbus_loader() {
Load(library_name);
}
~libdbus_loader();
bool Load(const std::string& library_name);
bool IsLoaded() { return loaded_; }
decltype(&::dbus_bus_add_match) bus_add_match;
decltype(&::dbus_bus_get) bus_get;
decltype(&::dbus_bus_get_unique_name) bus_get_unique_name;
decltype(&::dbus_bus_remove_match) bus_remove_match;
decltype(&::dbus_connection_pop_message) connection_pop_message;
decltype(&::dbus_connection_read_write) connection_read_write;
decltype(&::dbus_connection_send_with_reply_and_block) connection_send_with_reply_and_block;
decltype(&::dbus_connection_unref) connection_unref;
decltype(&::dbus_error_free) error_free;
decltype(&::dbus_error_init) error_init;
decltype(&::dbus_error_is_set) error_is_set;
decltype(&::dbus_message_append_args) message_append_args;
decltype(&::dbus_message_is_signal) message_is_signal;
decltype(&::dbus_message_iter_get_arg_type) message_iter_get_arg_type;
decltype(&::dbus_message_iter_get_basic) message_iter_get_basic;
decltype(&::dbus_message_iter_init) message_iter_init;
decltype(&::dbus_message_iter_next) message_iter_next;
decltype(&::dbus_message_iter_recurse) message_iter_recurse;
decltype(&::dbus_message_new_method_call) message_new_method_call;
decltype(&::dbus_message_unref) message_unref;
decltype(&::dbus_move_error) move_error;
decltype(&::dbus_threads_init_default) threads_init_default;
private:
void CleanUp(bool unload);
#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)
void* library_;
#endif
bool loaded_;
// Disallow copy constructor and assignment operator.
libdbus_loader(const libdbus_loader&);
void operator=(const libdbus_loader&);
};
#endif // LIBRARY_LOADER_DBUS_H

@ -53,7 +53,6 @@ vklayer_files = files(
'notify.cpp', 'notify.cpp',
'elfhacks.cpp', 'elfhacks.cpp',
'real_dlsym.cpp', 'real_dlsym.cpp',
'dbus.cpp',
) )
opengl_files = files( opengl_files = files(
@ -152,6 +151,14 @@ if false
endif endif
if dbus_dep.found() and get_option('with_dbus').enabled()
pre_args += '-DHAVE_DBUS'
vklayer_files += files(
'dbus.cpp',
'loaders/loader_dbus.cpp',
)
endif
vklayer_mesa_overlay = shared_library( vklayer_mesa_overlay = shared_library(
'MangoHud', 'MangoHud',
util_files, util_files,
@ -176,9 +183,9 @@ vklayer_mesa_overlay = shared_library(
libimgui_core_dep, libimgui_core_dep,
glimgui_glx_dep, glimgui_glx_dep,
glimgui_egl_dep, glimgui_egl_dep,
dbus_dep,
dep_dl, dep_dl,
dep_pthread, dep_pthread,
dep_dbus,
dep_vulkan], dep_vulkan],
include_directories : [inc_common, inc_opengl], include_directories : [inc_common, inc_opengl],
link_args : cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro']), link_args : cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro']),

@ -57,12 +57,15 @@
#include "loaders/loader_nvml.h" #include "loaders/loader_nvml.h"
#include "memory.h" #include "memory.h"
#include "notify.h" #include "notify.h"
#ifdef HAVE_DBUS
#include "dbus_info.h" #include "dbus_info.h"
float g_overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */;
#endif
bool open = false; bool open = false;
string gpuString; string gpuString;
float offset_x, offset_y, hudSpacing; float offset_x, offset_y, hudSpacing;
float hudTicker = 50.f, overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */;
int hudFirstRow, hudSecondRow; int hudFirstRow, hudSecondRow;
struct amdGpu amdgpu; struct amdGpu amdgpu;
struct fps_limit fps_limit_stats; struct fps_limit fps_limit_stats;
@ -1000,6 +1003,26 @@ static void right_aligned_text(float off_x, const char *fmt, ...)
ImGui::Text("%s", buffer); ImGui::Text("%s", buffer);
} }
float get_ticker_limited_pos(float pos, float tw, float& left_limit, float& right_limit)
{
float cw = ImGui::GetContentRegionAvailWidth();
float new_pos_x = ImGui::GetCursorPosX();
left_limit = cw - tw + new_pos_x;
right_limit = new_pos_x;
if (cw < tw) {
new_pos_x += pos;
// acts as a delay before it starts scrolling again
if (new_pos_x < left_limit)
return left_limit;
else if (new_pos_x > right_limit)
return right_limit;
else
return new_pos_x;
}
return new_pos_x;
}
void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan) void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan)
{ {
uint32_t f_idx = (data.n_frames - 1) % ARRAY_SIZE(data.frames_stats); uint32_t f_idx = (data.n_frames - 1) % ARRAY_SIZE(data.frames_stats);
@ -1220,6 +1243,7 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
ImGui::PopFont(); ImGui::PopFont();
} }
#ifdef HAVE_DBUS
{ {
scoped_lock lk(spotify.mutex); scoped_lock lk(spotify.mutex);
if (spotify.valid) { if (spotify.valid) {
@ -1227,60 +1251,48 @@ void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2&
ImGui::Dummy(ImVec2(0.0f, 20.0f)); ImGui::Dummy(ImVec2(0.0f, 20.0f));
ImGui::PushFont(data.font1); ImGui::PushFont(data.font1);
float tw = ImGui::CalcTextSize(spotify.title.c_str()).x; if (spotify.ticker.needs_recalc) {
float cw = ImGui::GetContentRegionAvailWidth(); spotify.ticker.tw0 = ImGui::CalcTextSize(spotify.title.c_str()).x;
//if (hudTicker < -tw) spotify.ticker.tw1 = ImGui::CalcTextSize(spotify.artists.c_str()).x;
// hudTicker = cw; spotify.ticker.tw2 = ImGui::CalcTextSize(spotify.album.c_str()).x;
spotify.ticker.longest = std::max(std::max(
static int dir = 1; spotify.ticker.tw0,
float limited_pos, new_pos_x = ImGui::GetCursorPosX(); spotify.ticker.tw1),
float left_limit = cw - tw + new_pos_x; spotify.ticker.tw2);
float right_limit = ImGui::GetCursorPosX(); spotify.ticker.needs_recalc = false;
}
if (cw < tw) {
if (hudTicker < left_limit - overflow * .25f - new_pos_x) { float new_pos, left_limit = 0, right_limit = 0;
dir = -1; get_ticker_limited_pos(spotify.ticker.pos, spotify.ticker.longest, left_limit, right_limit);
hudTicker = (left_limit - overflow * .25f) + 1.f - new_pos_x;
} else if (hudTicker > right_limit + overflow - new_pos_x) {
dir = 1;
hudTicker = (right_limit + overflow) - 1.f - new_pos_x;
}
hudTicker -= .5f * (frame_timing / 16666.7f) * dir;
new_pos_x += hudTicker;
// acts as a delay before it starts scrolling again
if (new_pos_x < left_limit)
limited_pos = left_limit;
else if (new_pos_x > right_limit)
limited_pos = right_limit;
else
limited_pos = new_pos_x;
} else { if (spotify.ticker.pos < left_limit - g_overflow * .5f) {
limited_pos = new_pos_x; spotify.ticker.dir = -1;
hudTicker = overflow; spotify.ticker.pos = (left_limit - g_overflow * .5f) + 1.f /* random */;
} else if (spotify.ticker.pos > right_limit + g_overflow) {
spotify.ticker.dir = 1;
spotify.ticker.pos = (right_limit + g_overflow) - 1.f /* random */;
} }
ImGui::SetCursorPosX(limited_pos); spotify.ticker.pos -= .5f * (frame_timing / 16666.7f) * spotify.ticker.dir;
new_pos = get_ticker_limited_pos(spotify.ticker.pos, spotify.ticker.tw0, left_limit, right_limit);
ImGui::SetCursorPosX(new_pos);
ImGui::Text("%s", spotify.title.c_str()); ImGui::Text("%s", spotify.title.c_str());
//std::cerr << "ticker: " << hudTicker << ", " << left_limit << "<>" << right_limit << ", " << dir << std::endl;
new_pos = get_ticker_limited_pos(spotify.ticker.pos, spotify.ticker.tw1, left_limit, right_limit);
for (size_t i = 0; i < spotify.artists.size(); i++) { ImGui::SetCursorPosX(new_pos);
ImGui::Text("%s", spotify.artists[i].c_str()); ImGui::Text("%s", spotify.artists.c_str());
if (i < spotify.artists.size() - 1) {
ImGui::SameLine(0, 1.0f);
ImGui::Text(",");
ImGui::SameLine(0, 1.0f);
}
}
//ImGui::NewLine(); //ImGui::NewLine();
if (!spotify.album.empty()) if (!spotify.album.empty()) {
new_pos = get_ticker_limited_pos(spotify.ticker.pos, spotify.ticker.tw2, left_limit, right_limit);
ImGui::SetCursorPosX(new_pos);
ImGui::Text("%s", spotify.album.c_str()); ImGui::Text("%s", spotify.album.c_str());
}
ImGui::PopFont(); ImGui::PopFont();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
} }
#endif
window_size = ImVec2(window_size.x, ImGui::GetCursorPosY() + 10.0f); window_size = ImVec2(window_size.x, ImGui::GetCursorPosY() + 10.0f);
ImGui::End(); ImGui::End();
@ -2519,6 +2531,7 @@ static VkResult overlay_CreateInstance(
init_cpu_stats(instance_data->params); init_cpu_stats(instance_data->params);
#ifdef HAVE_DBUS
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_media_player]) { if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_media_player]) {
try { try {
dbusmgr::dbus_mgr.init(); dbusmgr::dbus_mgr.init();
@ -2527,6 +2540,7 @@ static VkResult overlay_CreateInstance(
std::cerr << "Failed to get initial Spotify metadata: " << e.what() << std::endl; std::cerr << "Failed to get initial Spotify metadata: " << e.what() << std::endl;
} }
} }
#endif
// Adjust height for DXVK/VKD3D version number // Adjust height for DXVK/VKD3D version number
if (engineName == "DXVK" || engineName == "VKD3D"){ if (engineName == "DXVK" || engineName == "VKD3D"){

Loading…
Cancel
Save