]> code.delx.au - pulseaudio/blob - polyp/module-x11-bell.c
add new module "module-x11-bell"
[pulseaudio] / polyp / module-x11-bell.c
1 #include <stdio.h>
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include <X11/Xlib.h>
7 #include <X11/XKBlib.h>
8
9 #include "module.h"
10 #include "sink.h"
11 #include "scache.h"
12 #include "modargs.h"
13
14 struct x11_source {
15 void *io_source;
16 struct x11_source *next;
17 };
18
19 struct userdata {
20 struct pa_core *core;
21 Display *display;
22 struct x11_source *x11_sources;
23 int xkb_event_base;
24
25 int sink_index;
26 char *scache_item;
27 };
28
29 static const char* const valid_modargs[] = {
30 "sink",
31 "sample",
32 "display",
33 NULL
34 };
35
36 static struct pa_sink* get_output_sink(struct userdata *u) {
37 struct pa_sink *s;
38 assert(u);
39
40 if (!(s = pa_idxset_get_by_index(u->core->sinks, u->sink_index)))
41 s = pa_sink_get_default(u->core);
42
43 u->sink_index = s ? s->index : PA_IDXSET_INVALID;
44 return s;
45 }
46
47 static int ring_bell(struct userdata *u, int percent) {
48 struct pa_sink *s;
49 assert(u);
50
51 if (!(s = get_output_sink(u))) {
52 fprintf(stderr, __FILE__": Invalid sink\n");
53 return -1;
54 }
55
56 if (pa_scache_play_item(u->core, u->scache_item, s, percent*2) < 0) {
57 fprintf(stderr, __FILE__": Failed to play sample\n");
58 return -1;
59 }
60
61 return 0;
62 }
63
64 static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) {
65 struct userdata *u = userdata;
66 assert(u);
67
68 while (XPending(u->display)) {
69 XEvent e;
70 XkbBellNotifyEvent *bne;
71 XNextEvent(u->display, &e);
72
73 if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify)
74 continue;
75
76 bne = ((XkbBellNotifyEvent*) &e);
77
78 if (ring_bell(u, bne->percent) < 0) {
79 fprintf(stderr, __FILE__": Ringing bell failed, reverting to X11 device bell.\n");
80 XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent);
81 }
82 }
83 }
84
85 static void new_io_source(struct userdata *u, int fd) {
86 struct x11_source *s;
87
88 s = malloc(sizeof(struct x11_source));
89 assert(s);
90 s->io_source = u->core->mainloop->source_io(u->core->mainloop, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, io_callback, u);
91 assert(s->io_source);
92 s->next = u->x11_sources;
93 u->x11_sources = s;
94 }
95
96 int pa_module_init(struct pa_core *c, struct pa_module*m) {
97 struct userdata *u = NULL;
98 struct pa_modargs *ma = NULL;
99 int major, minor;
100 unsigned int auto_ctrls, auto_values;
101 assert(c && m);
102
103 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
104 fprintf(stderr, __FILE__": failed to parse module arguments\n");
105 goto fail;
106 }
107
108 m->userdata = u = malloc(sizeof(struct userdata));
109 assert(u);
110 u->core = c;
111 u->display = NULL;
112 u->x11_sources = NULL;
113 u->scache_item = strdup(pa_modargs_get_value(ma, "sample", "bell"));
114 assert(u->scache_item);
115
116 if (pa_modargs_get_sink_index(ma, c, &u->sink_index) < 0) {
117 fprintf(stderr, __FILE__": Invalid sink specified\n");
118 goto fail;
119 }
120
121 if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) {
122 fprintf(stderr, __FILE__": XOpenDisplay() failed\n");
123 goto fail;
124 }
125
126 new_io_source(u, ConnectionNumber(u->display));
127
128 major = XkbMajorVersion;
129 minor = XkbMinorVersion;
130
131 if (!XkbLibraryVersion(&major, &minor)) {
132 fprintf(stderr, __FILE__": XkbLibraryVersion() failed\n");
133 goto fail;
134 }
135
136 major = XkbMajorVersion;
137 minor = XkbMinorVersion;
138
139 if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) {
140 fprintf(stderr, __FILE__": XkbQueryExtension() failed\n");
141 goto fail;
142 }
143
144 XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask);
145 auto_ctrls = auto_values = XkbAudibleBellMask;
146 XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values);
147 XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0);
148
149 pa_modargs_free(ma);
150
151 return 0;
152
153 fail:
154 if (ma)
155 pa_modargs_free(ma);
156 if (m->userdata)
157 pa_module_done(c, m);
158 return -1;
159 }
160
161 void pa_module_done(struct pa_core *c, struct pa_module*m) {
162 struct userdata *u = m->userdata;
163 assert(c && m && u);
164
165 while (u->x11_sources) {
166 struct x11_source *s = u->x11_sources;
167 u->x11_sources = u->x11_sources->next;
168 c->mainloop->cancel_io(c->mainloop, s->io_source);
169 free(s);
170 }
171
172 free(u->scache_item);
173
174 if (u->display)
175 XCloseDisplay(u->display);
176 free(u);
177 }