]> code.delx.au - pulseaudio/commitdiff
add a module that forwards cork/uncork requests to X11 as fake pause/resume key events
authorLennart Poettering <lennart@poettering.net>
Fri, 13 Feb 2009 01:39:07 +0000 (02:39 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 13 Feb 2009 01:39:07 +0000 (02:39 +0100)
configure.ac
src/Makefile.am
src/daemon/start-pulseaudio-x11.in
src/modules/module-x11-cork-request.c [new file with mode: 0644]

index 9189dd0cda144119bacdebdfb67f8d117dff76d2..fbe134c445bd2cd595861c90dba24d561de64c3e 100644 (file)
@@ -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
index fc4780370ee41e7613ec6f5f854f33d60606eade..811b120416074a69efc52d9a67cb67fd5e0fc47f 100644 (file)
@@ -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
index 3cccc4dc88c20ad4ccc555448502e295cd12110f..391a6d3ce6e049c5d20fe50191392877aa4dc557 100755 (executable)
@@ -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 (file)
index 0000000..0c9aedf
--- /dev/null
@@ -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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XTest.h>
+#include <X11/XF86keysym.h>
+#include <X11/keysym.h>
+
+#include <pulse/util.h>
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/module.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/log.h>
+#include <pulsecore/x11wrap.h>
+#include <pulsecore/core-util.h>
+
+#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=<X11 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);
+}