Load libcanberra dynamically at runtime, as needed

Fixes #2089
This commit is contained in:
Kovid Goyal 2019-10-24 09:03:52 +05:30
parent 54ad1d103a
commit 8184ba246a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 47 additions and 9 deletions

View File

@ -29,7 +29,7 @@ Build-time dependencies:
* gcc or clang
* pkg-config
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, ``libcanberra-dev`` and ``libpython-dev``.
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, and ``libpython-dev``,
if they are not already installed by your distro.
Install and run from source

View File

@ -7,7 +7,6 @@
#include "data-types.h"
#include <dlfcn.h>
#include <canberra.h>
#define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL
#define LOAD_FUNC(handle, name) {\
@ -90,15 +89,56 @@ static PyMethodDef module_methods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */
};
static ca_context *canberra_ctx = NULL;
static void* libcanberra_handle = NULL;
static void *canberra_ctx = NULL;
FUNC(ca_context_create, int, void**);
FUNC(ca_context_destroy, int, void*);
typedef int (*ca_context_play_func)(void*, uint32_t, ...); static ca_context_play_func ca_context_play = NULL;
static PyObject*
load_libcanberra_functions(void) {
LOAD_FUNC(libcanberra_handle, ca_context_create);
LOAD_FUNC(libcanberra_handle, ca_context_play);
LOAD_FUNC(libcanberra_handle, ca_context_destroy);
return NULL;
}
static void
load_libcanberra(void) {
static const char* libname = "libcanberra.so";
// some installs are missing the .so symlink, so try the full name
static const char* libname2 = "libcanberra.so.0";
static const char* libname3 = "libcanberra.so.0.2.5";
static bool done = false;
if (done) return;
done = true;
libcanberra_handle = dlopen(libname, RTLD_LAZY);
if (libcanberra_handle == NULL) libsn_handle = dlopen(libname2, RTLD_LAZY);
if (libcanberra_handle == NULL) libsn_handle = dlopen(libname3, RTLD_LAZY);
if (libcanberra_handle == NULL) {
fprintf(stderr, "Failed to load %s, cannot play beep sound, with error: %s\n", libname, dlerror());
return;
}
load_libcanberra_functions();
if (PyErr_Occurred()) {
PyErr_Print();
dlclose(libcanberra_handle); libcanberra_handle = NULL;
}
if (ca_context_create(&canberra_ctx) != 0) {
fprintf(stderr, "Failed to create libcanberra context, cannot play beep sound\n");
ca_context_destroy(canberra_ctx); canberra_ctx = NULL;
dlclose(libcanberra_handle); libcanberra_handle = NULL;
}
}
void
play_canberra_sound(const char *which_sound, const char *event_id) {
if (canberra_ctx == NULL) ca_context_create(&canberra_ctx);
load_libcanberra();
if (libcanberra_handle == NULL || canberra_ctx == NULL) return;
ca_context_play(
canberra_ctx, 0,
CA_PROP_EVENT_ID, which_sound,
CA_PROP_EVENT_DESCRIPTION, event_id,
"event.id", which_sound,
"event.description", event_id,
NULL
);
}
@ -109,6 +149,7 @@ finalize(void) {
libsn_handle = NULL;
if (canberra_ctx) ca_context_destroy(canberra_ctx);
canberra_ctx = NULL;
if (libcanberra_handle) dlclose(libcanberra_handle);
}
bool

View File

@ -270,9 +270,6 @@ def kitty_env():
gl_libs = ['-framework', 'OpenGL'] if is_macos else pkg_config('gl', '--libs')
libpng = pkg_config('libpng', '--libs')
ans.ldpaths += pylib + font_libs + gl_libs + libpng
if not is_macos:
cflags.extend(pkg_config('libcanberra', '--cflags-only-I'))
ans.ldpaths += pkg_config('libcanberra', '--libs')
if is_macos:
ans.ldpaths.extend('-framework Cocoa'.split())
else: