7 #include <X11/XKBlib.h>
16 struct x11_source
*next
;
22 struct x11_source
*x11_sources
;
29 static const char* const valid_modargs
[] = {
36 static struct pa_sink
* get_output_sink(struct userdata
*u
) {
40 if (!(s
= pa_idxset_get_by_index(u
->core
->sinks
, u
->sink_index
)))
41 s
= pa_sink_get_default(u
->core
);
43 u
->sink_index
= s
? s
->index
: PA_IDXSET_INVALID
;
47 static int ring_bell(struct userdata
*u
, int percent
) {
51 if (!(s
= get_output_sink(u
))) {
52 fprintf(stderr
, __FILE__
": Invalid sink\n");
56 if (pa_scache_play_item(u
->core
, u
->scache_item
, s
, percent
*2) < 0) {
57 fprintf(stderr
, __FILE__
": Failed to play sample\n");
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
;
68 while (XPending(u
->display
)) {
70 XkbBellNotifyEvent
*bne
;
71 XNextEvent(u
->display
, &e
);
73 if (((XkbEvent
*) &e
)->any
.xkb_type
!= XkbBellNotify
)
76 bne
= ((XkbBellNotifyEvent
*) &e
);
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
);
85 static void new_io_source(struct userdata
*u
, int fd
) {
88 s
= malloc(sizeof(struct x11_source
));
90 s
->io_source
= u
->core
->mainloop
->source_io(u
->core
->mainloop
, fd
, PA_MAINLOOP_API_IO_EVENT_INPUT
, io_callback
, u
);
92 s
->next
= u
->x11_sources
;
96 int pa_module_init(struct pa_core
*c
, struct pa_module
*m
) {
97 struct userdata
*u
= NULL
;
98 struct pa_modargs
*ma
= NULL
;
100 unsigned int auto_ctrls
, auto_values
;
103 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
104 fprintf(stderr
, __FILE__
": failed to parse module arguments\n");
108 m
->userdata
= u
= malloc(sizeof(struct userdata
));
112 u
->x11_sources
= NULL
;
113 u
->scache_item
= strdup(pa_modargs_get_value(ma
, "sample", "bell"));
114 assert(u
->scache_item
);
116 if (pa_modargs_get_sink_index(ma
, c
, &u
->sink_index
) < 0) {
117 fprintf(stderr
, __FILE__
": Invalid sink specified\n");
121 if (!(u
->display
= XOpenDisplay(pa_modargs_get_value(ma
, "display", NULL
)))) {
122 fprintf(stderr
, __FILE__
": XOpenDisplay() failed\n");
126 new_io_source(u
, ConnectionNumber(u
->display
));
128 major
= XkbMajorVersion
;
129 minor
= XkbMinorVersion
;
131 if (!XkbLibraryVersion(&major
, &minor
)) {
132 fprintf(stderr
, __FILE__
": XkbLibraryVersion() failed\n");
136 major
= XkbMajorVersion
;
137 minor
= XkbMinorVersion
;
139 if (!XkbQueryExtension(u
->display
, NULL
, &u
->xkb_event_base
, NULL
, &major
, &minor
)) {
140 fprintf(stderr
, __FILE__
": XkbQueryExtension() failed\n");
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);
157 pa_module_done(c
, m
);
161 void pa_module_done(struct pa_core
*c
, struct pa_module
*m
) {
162 struct userdata
*u
= m
->userdata
;
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
);
172 free(u
->scache_item
);
175 XCloseDisplay(u
->display
);