Git init
[framework/multimedia/pulseaudio.git] / src / modules / x11 / module-x11-bell.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5
6   PulseAudio 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.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio 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 PulseAudio; 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 <stdlib.h>
28 #include <string.h>
29
30 #include <X11/Xlib.h>
31 #include <X11/XKBlib.h>
32
33 #include <pulse/xmalloc.h>
34
35 #include <pulsecore/iochannel.h>
36 #include <pulsecore/sink.h>
37 #include <pulsecore/core-scache.h>
38 #include <pulsecore/modargs.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/x11wrap.h>
42
43 #include "module-x11-bell-symdef.h"
44
45 PA_MODULE_AUTHOR("Lennart Poettering");
46 PA_MODULE_DESCRIPTION("X11 bell interceptor");
47 PA_MODULE_VERSION(PACKAGE_VERSION);
48 PA_MODULE_LOAD_ONCE(FALSE);
49 PA_MODULE_USAGE("sink=<sink to connect to> sample=<sample name> display=<X11 display>");
50
51 static const char* const valid_modargs[] = {
52     "sink",
53     "sample",
54     "display",
55     NULL
56 };
57
58 struct userdata {
59     pa_core *core;
60     pa_module *module;
61
62     int xkb_event_base;
63
64     char *sink_name;
65     char *scache_item;
66
67     pa_x11_wrapper *x11_wrapper;
68     pa_x11_client *x11_client;
69 };
70
71 static int x11_event_cb(pa_x11_wrapper *w, XEvent *e, void *userdata) {
72     XkbBellNotifyEvent *bne;
73     struct userdata *u = userdata;
74
75     pa_assert(w);
76     pa_assert(e);
77     pa_assert(u);
78     pa_assert(u->x11_wrapper == w);
79
80     if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify)
81         return 0;
82
83     bne = (XkbBellNotifyEvent*) e;
84
85     if (pa_scache_play_item_by_name(u->core, u->scache_item, u->sink_name, ((pa_volume_t) bne->percent*PA_VOLUME_NORM)/100U, NULL, NULL) < 0) {
86         pa_log_info("Ringing bell failed, reverting to X11 device bell.");
87         XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent);
88     }
89
90     return 1;
91 }
92
93 static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) {
94     struct userdata *u = userdata;
95
96     pa_assert(w);
97     pa_assert(u);
98     pa_assert(u->x11_wrapper == w);
99
100     if (u->x11_client)
101         pa_x11_client_free(u->x11_client);
102
103     if (u->x11_wrapper)
104         pa_x11_wrapper_unref(u->x11_wrapper);
105
106     u->x11_client = NULL;
107     u->x11_wrapper = NULL;
108
109     pa_module_unload_request(u->module, TRUE);
110 }
111
112 int pa__init(pa_module*m) {
113
114     struct userdata *u = NULL;
115     pa_modargs *ma = NULL;
116     int major, minor;
117     unsigned int auto_ctrls, auto_values;
118
119     pa_assert(m);
120
121     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
122         pa_log("Failed to parse module arguments");
123         goto fail;
124     }
125
126     m->userdata = u = pa_xnew(struct userdata, 1);
127     u->core = m->core;
128     u->module = m;
129     u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "bell-window-system"));
130     u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
131     u->x11_client = NULL;
132
133     if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
134         goto fail;
135
136     major = XkbMajorVersion;
137     minor = XkbMinorVersion;
138
139     if (!XkbLibraryVersion(&major, &minor)) {
140         pa_log("XkbLibraryVersion() failed");
141         goto fail;
142     }
143
144     major = XkbMajorVersion;
145     minor = XkbMinorVersion;
146
147     if (!XkbQueryExtension(pa_x11_wrapper_get_display(u->x11_wrapper), NULL, &u->xkb_event_base, NULL, &major, &minor)) {
148         pa_log("XkbQueryExtension() failed");
149         goto fail;
150     }
151
152     XkbSelectEvents(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask);
153     auto_ctrls = auto_values = XkbAudibleBellMask;
154     XkbSetAutoResetControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbAudibleBellMask, &auto_ctrls, &auto_values);
155     XkbChangeEnabledControls(pa_x11_wrapper_get_display(u->x11_wrapper), XkbUseCoreKbd, XkbAudibleBellMask, 0);
156
157     u->x11_client = pa_x11_client_new(u->x11_wrapper, x11_event_cb, x11_kill_cb, u);
158
159     pa_modargs_free(ma);
160
161     return 0;
162
163 fail:
164     if (ma)
165         pa_modargs_free(ma);
166
167     pa__done(m);
168
169     return -1;
170 }
171
172 void pa__done(pa_module*m) {
173     struct userdata *u;
174
175     pa_assert(m);
176
177     if (!(u = m->userdata))
178         return;
179
180     pa_xfree(u->scache_item);
181     pa_xfree(u->sink_name);
182
183     if (u->x11_client)
184         pa_x11_client_free(u->x11_client);
185
186     if (u->x11_wrapper)
187         pa_x11_wrapper_unref(u->x11_wrapper);
188
189     pa_xfree(u);
190 }