The libcanberra calls use libtool, which can not be called from multiple
threads at the same time. Use a global lock to serialize these calls in
the x11-bell module.
This is only a problem when multiple libcanberra calls are made in the
same process, such when you load the x11-bell module twice. There is no
guarantee that other libcanberra calls will not interfere but for now
we only use libcanberra here.
Fixes#2834
Make the XOpenDiplay call failure print an info message instead of a
warning. We usually ignore this error in the config file. Add a
suggestion for how to fix this issue in the info log.
Fixes#2918
Unfortunately, libX11 has global error and I/O error handlers,
which make it inconvenient to use them from library code.
Since libX11 1.7.0, there is a per-display "exit_handler" which
is called from `_XIOError()`, however, the global I/O error
handler is still called before that, and that - by default -
calls `exit(1)` in `_XDefaultIOError()` after printing the error
to stderr.
To avoid exiting, custom handlers will be registered when
libpipewire-module-x11-bell.so is loaded given that at
that moment the default handlers are installed.
When the shared object is unloaded, the handlers will
be reset to the default ones given that the currently
registered handlers are the ones that were registered
when the module was loaded.
The logic only works correctly if there are no concurrent
calls to `XSet{IO}ErrorHandler()` while `{set,restore}_x11_handlers()`
is running. Since module-x11-bell is probably mostly going to
be loaded in `pipewire-pulse`, this seems like a reasonable
assumption to make.
`x11_close()` is no longer needed since X11 errors
are now considered fatal, so `module_destroy()` will
be called if `x11_connect()` fails, which means that
the code from `x11_close()` can be moved there.