From 433751ff258b78f23a8e82b06f54522f820d3230 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Feb 2009 02:39:07 +0100 Subject: add a module that forwards cork/uncork requests to X11 as fake pause/resume key events --- configure.ac | 2 +- src/Makefile.am | 9 +- src/daemon/start-pulseaudio-x11.in | 1 + src/modules/module-x11-cork-request.c | 189 ++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 src/modules/module-x11-cork-request.c diff --git a/configure.ac b/configure.ac index 9189dd0c..fbe134c4 100644 --- a/configure.ac +++ b/configure.ac @@ -485,7 +485,7 @@ AC_ARG_ENABLE([x11], [x11=auto]) if test "x${x11}" != xno ; then - PKG_CHECK_MODULES(X11, [ x11 ice sm ], + PKG_CHECK_MODULES(X11, [ x11 ice sm xtst ], HAVE_X11=1, [ HAVE_X11=0 diff --git a/src/Makefile.am b/src/Makefile.am index fc478037..811b1204 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -937,7 +937,8 @@ if HAVE_X11 modlibexec_LTLIBRARIES += \ module-x11-bell.la \ module-x11-publish.la \ - module-x11-xsmp.la + module-x11-xsmp.la \ + module-x11-cork-request.la endif if HAVE_OSS @@ -1059,6 +1060,7 @@ SYMDEF_FILES = \ modules/module-x11-bell-symdef.h \ modules/module-x11-publish-symdef.h \ modules/module-x11-xsmp-symdef.h \ + modules/module-x11-cork-request-symdef.h \ modules/oss/module-oss-symdef.h \ modules/alsa/module-alsa-sink-symdef.h \ modules/alsa/module-alsa-source-symdef.h \ @@ -1247,6 +1249,11 @@ module_x11_xsmp_la_CFLAGS = $(AM_CFLAGS) $(X11_CFLAGS) module_x11_xsmp_la_LDFLAGS = $(MODULE_LDFLAGS) module_x11_xsmp_la_LIBADD = $(AM_LIBADD) $(X11_LIBS) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la +module_x11_cork_request_la_SOURCES = modules/module-x11-cork-request.c +module_x11_cork_request_la_CFLAGS = $(AM_CFLAGS) $(X11_CFLAGS) +module_x11_cork_request_la_LDFLAGS = $(MODULE_LDFLAGS) +module_x11_cork_request_la_LIBADD = $(AM_LIBADD) $(X11_LIBS) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la + # OSS liboss_util_la_SOURCES = modules/oss/oss-util.c modules/oss/oss-util.h diff --git a/src/daemon/start-pulseaudio-x11.in b/src/daemon/start-pulseaudio-x11.in index 3cccc4dc..391a6d3c 100755 --- a/src/daemon/start-pulseaudio-x11.in +++ b/src/daemon/start-pulseaudio-x11.in @@ -24,6 +24,7 @@ set -e if [ x"$DISPLAY" != x ] ; then @PACTL_BINARY@ load-module module-x11-publish "display=$DISPLAY" > /dev/null + @PACTL_BINARY@ load-module module-x11-cork-request "display=$DISPLAY" > /dev/null if [ x"$SESSION_MANAGER" != x ] ; then @PACTL_BINARY@ load-module module-x11-xsmp "display=$DISPLAY session_manager=$SESSION_MANAGER" > /dev/null diff --git a/src/modules/module-x11-cork-request.c b/src/modules/module-x11-cork-request.c new file mode 100644 index 00000000..0c9aedf4 --- /dev/null +++ b/src/modules/module-x11-cork-request.c @@ -0,0 +1,189 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "module-x11-cork-request-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("Synthesize X11 media key events when cork/uncork is requested"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_USAGE("display="); + +static const char* const valid_modargs[] = { + "display", + NULL +}; + +struct userdata { + pa_module *module; + + pa_x11_wrapper *x11_wrapper; + pa_x11_client *x11_client; + + pa_hook_slot *hook_slot; +}; + +static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) { + struct userdata *u = userdata; + + pa_assert(w); + pa_assert(u); + pa_assert(u->x11_wrapper == w); + + if (u->x11_client) { + pa_x11_client_free(u->x11_client); + u->x11_client = NULL; + } + + if (u->x11_wrapper) { + pa_x11_wrapper_unref(u->x11_wrapper); + u->x11_wrapper = NULL; + } + + pa_module_unload_request(u->module, TRUE); +} + +static pa_hook_result_t sink_input_send_event_hook_cb( + pa_core *c, + pa_sink_input_send_event_hook_data *data, + struct userdata *u) { + + KeySym sym; + KeyCode code; + Display *display; + + pa_assert(c); + pa_assert(data); + pa_assert(u); + + if (pa_streq(data->event, PA_STREAM_EVENT_REQUEST_CORK)) + sym = XF86XK_AudioPause; + else if (pa_streq(data->event, PA_STREAM_EVENT_REQUEST_UNCORK)) + sym = XF86XK_AudioPlay; + else + return PA_HOOK_OK; + + pa_log_debug("Triggering X11 keysym: %s", XKeysymToString(sym)); + + display = pa_x11_wrapper_get_display(u->x11_wrapper); + code = XKeysymToKeycode(display, sym); + + XTestFakeKeyEvent(display, code, True, CurrentTime); + XSync(display, False); + + XTestFakeKeyEvent(display, code, False, CurrentTime); + XSync(display, False); + + return PA_HOOK_OK; +} + +int pa__init(pa_module *m) { + struct userdata *u; + pa_modargs *ma; + int xtest_event_base, xtest_error_base; + int major_version, minor_version; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("failed to parse module arguments"); + goto fail; + } + + m->userdata = u = pa_xnew0(struct userdata, 1); + u->module = m; + + if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL)))) + goto fail; + + if (!XTestQueryExtension( + pa_x11_wrapper_get_display(u->x11_wrapper), + &xtest_event_base, &xtest_error_base, + &major_version, &minor_version)) { + + pa_log("XTest extension not supported."); + goto fail; + } + + pa_log_debug("XTest %i.%i supported.", major_version, minor_version); + + u->x11_client = pa_x11_client_new(u->x11_wrapper, NULL, x11_kill_cb, u); + + u->hook_slot = pa_hook_connect( + &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], + PA_HOOK_NORMAL, + (pa_hook_cb_t) sink_input_send_event_hook_cb, u); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + + pa__done(m); + + return -1; +} + +void pa__done(pa_module*m) { + struct userdata*u; + + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->x11_client) + pa_x11_client_free(u->x11_client); + + if (u->x11_wrapper) + pa_x11_wrapper_unref(u->x11_wrapper); + + if (u->hook_slot) + pa_hook_slot_free(u->hook_slot); + + pa_xfree(u); +} -- cgit