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 --- src/modules/module-x11-cork-request.c | 189 ++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/modules/module-x11-cork-request.c (limited to 'src/modules') 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