]> code.delx.au - pulseaudio/blob - polyp/module-x11-bell.c
add initial glib mainloop adapter
[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 #include "xmalloc.h"
14 #include "namereg.h"
15
16 struct x11_source {
17 struct pa_io_event *io_event;
18 struct x11_source *next;
19 };
20
21 struct userdata {
22 struct pa_core *core;
23 Display *display;
24 struct x11_source *x11_sources;
25 int xkb_event_base;
26
27 char *sink_name;
28 char *scache_item;
29 };
30
31 static const char* const valid_modargs[] = {
32 "sink",
33 "sample",
34 "display",
35 NULL
36 };
37
38 static int ring_bell(struct userdata *u, int percent) {
39 struct pa_sink *s;
40 assert(u);
41
42 if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) {
43 fprintf(stderr, __FILE__": Invalid sink\n");
44 return -1;
45 }
46
47 if (pa_scache_play_item(u->core, u->scache_item, s, percent*2) < 0) {
48 fprintf(stderr, __FILE__": Failed to play sample\n");
49 return -1;
50 }
51
52 return 0;
53 }
54
55 static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
56 struct userdata *u = userdata;
57 assert(u);
58
59 while (XPending(u->display)) {
60 XEvent e;
61 XkbBellNotifyEvent *bne;
62 XNextEvent(u->display, &e);
63
64 if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify)
65 continue;
66
67 bne = ((XkbBellNotifyEvent*) &e);
68
69 if (ring_bell(u, bne->percent) < 0) {
70 fprintf(stderr, __FILE__": Ringing bell failed, reverting to X11 device bell.\n");
71 XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent);
72 }
73 }
74 }
75
76 static void new_io_source(struct userdata *u, int fd) {
77 struct x11_source *s;
78
79 s = pa_xmalloc(sizeof(struct x11_source));
80 s->io_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, io_callback, u);
81 assert(s->io_event);
82 s->next = u->x11_sources;
83 u->x11_sources = s;
84 }
85
86 int pa_module_init(struct pa_core *c, struct pa_module*m) {
87 struct userdata *u = NULL;
88 struct pa_modargs *ma = NULL;
89 int major, minor;
90 unsigned int auto_ctrls, auto_values;
91 assert(c && m);
92
93 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
94 fprintf(stderr, __FILE__": failed to parse module arguments\n");
95 goto fail;
96 }
97
98 m->userdata = u = pa_xmalloc(sizeof(struct userdata));
99 u->core = c;
100 u->display = NULL;
101 u->x11_sources = NULL;
102 u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell"));
103 u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
104
105 if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) {
106 fprintf(stderr, __FILE__": XOpenDisplay() failed\n");
107 goto fail;
108 }
109
110 new_io_source(u, ConnectionNumber(u->display));
111
112 major = XkbMajorVersion;
113 minor = XkbMinorVersion;
114
115 if (!XkbLibraryVersion(&major, &minor)) {
116 fprintf(stderr, __FILE__": XkbLibraryVersion() failed\n");
117 goto fail;
118 }
119
120 major = XkbMajorVersion;
121 minor = XkbMinorVersion;
122
123 if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) {
124 fprintf(stderr, __FILE__": XkbQueryExtension() failed\n");
125 goto fail;
126 }
127
128 XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask);
129 auto_ctrls = auto_values = XkbAudibleBellMask;
130 XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values);
131 XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0);
132
133 pa_modargs_free(ma);
134
135 return 0;
136
137 fail:
138 if (ma)
139 pa_modargs_free(ma);
140 if (m->userdata)
141 pa_module_done(c, m);
142 return -1;
143 }
144
145 void pa_module_done(struct pa_core *c, struct pa_module*m) {
146 struct userdata *u = m->userdata;
147 assert(c && m && u);
148
149 while (u->x11_sources) {
150 struct x11_source *s = u->x11_sources;
151 u->x11_sources = u->x11_sources->next;
152 c->mainloop->io_free(s->io_event);
153 pa_xfree(s);
154 }
155
156 pa_xfree(u->scache_item);
157
158 if (u->display)
159 XCloseDisplay(u->display);
160 pa_xfree(u);
161 }