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 * gcc or clang
* pkg-config * pkg-config
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for: * 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. if they are not already installed by your distro.
Install and run from source Install and run from source

View File

@ -7,7 +7,6 @@
#include "data-types.h" #include "data-types.h"
#include <dlfcn.h> #include <dlfcn.h>
#include <canberra.h>
#define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL #define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL
#define LOAD_FUNC(handle, name) {\ #define LOAD_FUNC(handle, name) {\
@ -90,15 +89,56 @@ static PyMethodDef module_methods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */ {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 void
play_canberra_sound(const char *which_sound, const char *event_id) { 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( ca_context_play(
canberra_ctx, 0, canberra_ctx, 0,
CA_PROP_EVENT_ID, which_sound, "event.id", which_sound,
CA_PROP_EVENT_DESCRIPTION, event_id, "event.description", event_id,
NULL NULL
); );
} }
@ -109,6 +149,7 @@ finalize(void) {
libsn_handle = NULL; libsn_handle = NULL;
if (canberra_ctx) ca_context_destroy(canberra_ctx); if (canberra_ctx) ca_context_destroy(canberra_ctx);
canberra_ctx = NULL; canberra_ctx = NULL;
if (libcanberra_handle) dlclose(libcanberra_handle);
} }
bool bool

View File

@ -270,9 +270,6 @@ def kitty_env():
gl_libs = ['-framework', 'OpenGL'] if is_macos else pkg_config('gl', '--libs') gl_libs = ['-framework', 'OpenGL'] if is_macos else pkg_config('gl', '--libs')
libpng = pkg_config('libpng', '--libs') libpng = pkg_config('libpng', '--libs')
ans.ldpaths += pylib + font_libs + gl_libs + libpng 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: if is_macos:
ans.ldpaths.extend('-framework Cocoa'.split()) ans.ldpaths.extend('-framework Cocoa'.split())
else: else: