]> code.delx.au - pulseaudio/blob - src/modules/module-x11-bell.c
2b891bc12dc56955cd5378cbc173a96de8ba3461
[pulseaudio] / src / modules / module-x11-bell.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <X11/Xlib.h>
32 #include <X11/XKBlib.h>
33
34 #include <polyp/xmalloc.h>
35
36 #include <polypcore/iochannel.h>
37 #include <polypcore/sink.h>
38 #include <polypcore/core-scache.h>
39 #include <polypcore/modargs.h>
40 #include <polypcore/namereg.h>
41 #include <polypcore/log.h>
42 #include <polypcore/x11wrap.h>
43
44 #include "module-x11-bell-symdef.h"
45
46 PA_MODULE_AUTHOR("Lennart Poettering")
47 PA_MODULE_DESCRIPTION("X11 Bell interceptor")
48 PA_MODULE_VERSION(PACKAGE_VERSION)
49 PA_MODULE_USAGE("sink=<sink to connect to> sample=<sample name> display=<X11 display>")
50
51 struct userdata {
52 pa_core *core;
53 int xkb_event_base;
54 char *sink_name;
55 char *scache_item;
56
57 pa_x11_wrapper *x11_wrapper;
58 pa_x11_client *x11_client;
59 };
60
61 static const char* const valid_modargs[] = {
62 "sink",
63 "sample",
64 "display",
65 NULL
66 };
67
68 static int ring_bell(struct userdata *u, int percent) {
69 pa_sink *s;
70 assert(u);
71
72 if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) {
73 pa_log(__FILE__": Invalid sink: %s", u->sink_name);
74 return -1;
75 }
76
77 pa_scache_play_item(u->core, u->scache_item, s, (percent*PA_VOLUME_NORM)/100);
78 return 0;
79 }
80
81 static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) {
82 XkbBellNotifyEvent *bne;
83 struct userdata *u = userdata;
84 assert(w && e && u && u->x11_wrapper == w);
85
86 if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify)
87 return 0;
88
89 bne = (XkbBellNotifyEvent*) e;
90
91 if (ring_bell(u, bne->percent) < 0) {
92 pa_log_info(__FILE__": Ringing bell failed, reverting to X11 device bell.");
93 XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent);
94 }
95
96 return 1;
97 }
98
99 int pa__init(pa_core *c, pa_module*m) {
100 struct userdata *u = NULL;
101 pa_modargs *ma = NULL;
102 int major, minor;
103 unsigned int auto_ctrls, auto_values;
104 assert(c && m);
105
106 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
107 pa_log(__FILE__": failed to parse module arguments");
108 goto fail;
109 }
110
111 m->userdata = u = pa_xmalloc(sizeof(struct userdata));
112 u->core = c;
113 u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell"));
114 u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
115 u->x11_client = NULL;
116
117 if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL))))
118 goto fail;
119
120 major = XkbMajorVersion;
121 minor = XkbMinorVersion;
122
123 if (!XkbLibraryVersion(&major, &minor)) {
124 pa_log(__FILE__": XkbLibraryVersion() failed");
125 goto fail;
126 }
127
128 major = XkbMajorVersion;
129 minor = XkbMinorVersion;
130
131
132 if (!XkbQueryExtension(pa_x11_wrapper_get_display(u->x11_wrapper), NULL, &u->xkb_event_base, NULL, &major, &minor)) {
133 pa_log(__FILE__": XkbQueryExtension() failed");
134 goto fail;
135 }
136
137 XkbSelectEvents(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask);
138 auto_ctrls = auto_values = XkbAudibleBellMask;
139 XkbSetAutoResetControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbAudibleBellMask, &auto_ctrls, &auto_values);
140 XkbChangeEnabledControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbAudibleBellMask, 0);
141
142 u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_callback, u);
143
144 pa_modargs_free(ma);
145
146 return 0;
147
148 fail:
149 if (ma)
150 pa_modargs_free(ma);
151 if (m->userdata)
152 pa__done(c, m);
153 return -1;
154 }
155
156 void pa__done(pa_core *c, pa_module*m) {
157 struct userdata *u = m->userdata;
158 assert(c && m && u);
159
160 pa_xfree(u->scache_item);
161 pa_xfree(u->sink_name);
162
163 if (u->x11_client)
164 pa_x11_client_free(u->x11_client);
165
166 if (u->x11_wrapper)
167 pa_x11_wrapper_unref(u->x11_wrapper);
168
169 pa_xfree(u);
170 }