mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-06 19:40:10 +02:00
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:
@@ -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')
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
chainloader_deps = [
|
||||
configuration_dep,
|
||||
|
||||
dbus_dep,
|
||||
dl_dep,
|
||||
ghc_filesystem_dep,
|
||||
rt_dep,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user