Connect to the session message bus using libdbus-1

This is the first step of migrating the desktop notifications over to
pure DBus.
This commit is contained in:
Robbert van der Helm
2022-10-28 16:01:43 +02:00
parent d94d7e886b
commit d1b3de5fc0
5 changed files with 112 additions and 1 deletions
+4
View File
@@ -240,6 +240,10 @@ else
# version now.
bitsery_dep = dependency('bitsery', version : '>=5.2.0')
endif
# The DBus headers are also only accessed through the include path. We don't
# link to libdbus-1 to make soname changes don't completely break yabridge.
dbus_dep = dependency('dbus-1').partial_dependency(compile_args : true, includes : true)
function2_dep = dependency('function2', version : '>=4.0.0')
ghc_filesystem_dep = dependency('ghc_filesystem', modules : 'ghcFilesystem::ghc_filesystem', version : '>=1.5.0')
threads_dep = dependency('threads')
+1
View File
@@ -4,6 +4,7 @@
chainloader_deps = [
configuration_dep,
dbus_dep,
dl_dep,
ghc_filesystem_dep,
rt_dep,
+102 -1
View File
@@ -16,14 +16,115 @@
#include "notifications.h"
#include <sstream>
#include <atomic>
#include <cassert>
#include <iostream>
#include <dbus/dbus.h>
#include <dlfcn.h>
#include "logging/common.h"
#include "process.h"
#include "utils.h"
constexpr char libdbus_library_name[] = "libdbus-1.so";
std::atomic<void*> libdbus_handle = nullptr;
std::mutex libdbus_mutex;
// We'll fetch all of these functions at runtime when send a first notification
decltype(dbus_connection_unref)* libdbus_connection_unref = nullptr;
decltype(dbus_bus_get)* libdbus_bus_get = nullptr;
decltype(dbus_error_free)* libdbus_error_free = nullptr;
decltype(dbus_error_init)* libdbus_error_init = nullptr;
decltype(dbus_error_is_set)* libdbus_error_is_set = nullptr;
decltype(dbus_connection_set_exit_on_disconnect)*
libdbus_connection_set_exit_on_disconnect = nullptr;
std::unique_ptr<DBusConnection, void (*)(DBusConnection*)> libdbus_connection(
nullptr,
libdbus_connection_unref);
/**
* Try to set up DBus. Returns `false` if a function could not be resolved or if
* we could not connect to the DBus session.
*/
bool setup_libdbus() {
// If this function is called from two threads at the same time, then we can
// skip this. `libdbus_handle` is only set at the very end of this function
// once every function pointer has been resolved
std::lock_guard lock(libdbus_mutex);
if (libdbus_handle) {
return true;
}
Logger logger = Logger::create_exception_logger();
void* handle = dlopen(libdbus_library_name, RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
logger.log("Could not load '" + std::string(libdbus_library_name) +
"', not sending desktop notifications");
return false;
}
#define LOAD_FUNCTION(name) \
do { \
lib##name = \
reinterpret_cast<decltype(lib##name)>(dlsym(handle, #name)); \
if (!(name)) { \
logger.log("Could not find '" + std::string(#name) + "' in '" + \
std::string(libdbus_library_name) + \
"', not sending desktop notifications"); \
return false; \
} \
} while (false)
LOAD_FUNCTION(dbus_connection_unref);
LOAD_FUNCTION(dbus_bus_get);
LOAD_FUNCTION(dbus_error_free);
LOAD_FUNCTION(dbus_error_init);
LOAD_FUNCTION(dbus_error_is_set);
LOAD_FUNCTION(dbus_connection_set_exit_on_disconnect);
#undef LOAD_FUNCTION
// With every function ready, we can try connecting to the DBus interface
DBusError error;
libdbus_error_init(&error);
libdbus_connection.reset(
libdbus_bus_get(DBusBusType::DBUS_BUS_SESSION, &error));
if (libdbus_error_is_set(&error)) {
assert(error.message);
logger.log("Could not connect to DBus session bus: " +
std::string(error.message));
libdbus_error_free(&error);
return false;
}
assert(libdbus_connection);
// While the connection should not be closed while this plugin is alive,
// this does sound extremely dangerous and why is it enabled by default?
libdbus_connection_set_exit_on_disconnect(libdbus_connection.get(), false);
// This is only set at the very end since this indicates that everything
// has been initialized properly
libdbus_handle.store(handle);
return true;
}
bool send_notification(const std::string& title,
const std::string body,
std::optional<ghc::filesystem::path> origin) {
// The first time this function is called we'll need to set up the DBus
// interface. Previously yabridge relied on notify-send, but some distros
// don't install that by default.
if (!libdbus_handle && !setup_libdbus()) {
return false;
}
// I think there's a zero chance that we're going to call this function with
// anything that even somewhat resembles HTML, but we should still do a
// basic XML escape anyways.
+3
View File
@@ -7,6 +7,7 @@ vst2_plugin_deps = [
asio_dep,
bitsery_dep,
dbus_dep,
dl_dep,
ghc_filesystem_dep,
rt_dep,
@@ -21,6 +22,7 @@ if with_clap
asio_dep,
bitsery_dep,
clap_dep,
dbus_dep,
dl_dep,
function2_dep,
ghc_filesystem_dep,
@@ -36,6 +38,7 @@ if with_vst3
asio_dep,
bitsery_dep,
dbus_dep,
dl_dep,
function2_dep,
ghc_filesystem_dep,
+2
View File
@@ -8,6 +8,7 @@ if is_64bit_system
asio_dep,
bitsery_dep,
dbus_dep,
function2_dep,
ghc_filesystem_dep,
rt_dep,
@@ -37,6 +38,7 @@ if with_bitbridge
asio_dep,
ghc_filesystem_dep,
bitsery_dep,
dbus_dep,
function2_dep,
rt_dep,
tomlplusplus_dep,