4 This file is part of polypaudio.
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.
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.
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
28 #include "glib-mainloop.h"
33 struct pa_glib_mainloop
*mainloop
;
35 GIOChannel
*io_channel
;
37 GIOCondition io_condition
;
39 void (*callback
) (struct pa_mainloop_api
*m
, struct pa_io_event
*e
, int fd
, enum pa_io_event_flags f
, void *userdata
);
41 void (*destroy_callback
) (struct pa_mainloop_api
*m
, struct pa_io_event
*e
, void *userdata
);
42 struct pa_io_event
*next
, *prev
;
45 struct pa_time_event
{
46 struct pa_glib_mainloop
*mainloop
;
49 struct timeval timeval
;
50 void (*callback
) (struct pa_mainloop_api
*m
, struct pa_time_event
*e
, const struct timeval
*tv
, void *userdata
);
52 void (*destroy_callback
) (struct pa_mainloop_api
*m
, struct pa_time_event
*e
, void *userdata
);
53 struct pa_time_event
*next
, *prev
;
56 struct pa_defer_event
{
57 struct pa_glib_mainloop
*mainloop
;
60 void (*callback
) (struct pa_mainloop_api
*m
, struct pa_defer_event
*e
, void *userdata
);
62 void (*destroy_callback
) (struct pa_mainloop_api
*m
, struct pa_defer_event
*e
, void *userdata
);
63 struct pa_defer_event
*next
, *prev
;
66 struct pa_glib_mainloop
{
67 struct pa_mainloop_api api
;
69 struct pa_io_event
*io_events
, *dead_io_events
;
70 struct pa_time_event
*time_events
, *dead_time_events
;
71 struct pa_defer_event
*defer_events
, *dead_defer_events
;
74 static void schedule_free_dead_events(struct pa_glib_mainloop
*g
);
76 static void glib_io_enable(struct pa_io_event
*e
, enum pa_io_event_flags f
);
78 static struct pa_io_event
* glib_io_new(struct pa_mainloop_api
*m
, int fd
, enum pa_io_event_flags f
, void (*callback
) (struct pa_mainloop_api
*m
, struct pa_io_event
*e
, int fd
, enum pa_io_event_flags f
, void *userdata
), void *userdata
) {
79 struct pa_io_event
*e
;
80 struct pa_glib_mainloop
*g
;
82 assert(m
&& m
->userdata
&& fd
>= 0 && callback
);
85 e
= pa_xmalloc(sizeof(struct pa_io_event
));
86 e
->mainloop
= m
->userdata
;
89 e
->callback
= callback
;
90 e
->userdata
= userdata
;
91 e
->destroy_callback
= NULL
;
93 e
->io_channel
= g_io_channel_unix_new(e
->fd
);
94 assert(e
->io_channel
);
95 e
->source
= (guint
) -1;
100 e
->next
= g
->io_events
;
101 if (e
->next
) e
->next
->prev
= e
;
108 static gboolean
io_cb(GIOChannel
*source
, GIOCondition condition
, gpointer data
) {
109 struct pa_io_event
*e
= data
;
110 enum pa_io_event_flags f
;
111 assert(source
&& e
&& e
->io_channel
== source
);
113 f
= (condition
& G_IO_IN
? PA_IO_EVENT_INPUT
: 0) |
114 (condition
& G_IO_OUT
? PA_IO_EVENT_OUTPUT
: 0) |
115 (condition
& G_IO_ERR
? PA_IO_EVENT_ERROR
: 0) |
116 (condition
& G_IO_HUP
? PA_IO_EVENT_HANGUP
: 0);
118 e
->callback(&e
->mainloop
->api
, e
, e
->fd
, f
, e
->userdata
);
122 static void glib_io_enable(struct pa_io_event
*e
, enum pa_io_event_flags f
) {
124 assert(e
&& !e
->dead
);
126 c
= (f
& PA_IO_EVENT_INPUT
? G_IO_IN
: 0) | (f
& PA_IO_EVENT_OUTPUT
? G_IO_OUT
: 0);
128 if (c
== e
->io_condition
)
131 if (e
->source
!= (guint
) -1)
132 g_source_remove(e
->source
);
134 e
->source
= g_io_add_watch_full(e
->io_channel
, G_PRIORITY_DEFAULT
, c
| G_IO_ERR
| G_IO_HUP
, io_cb
, e
, NULL
);
135 assert(e
->source
!= (guint
) -1);
139 static void glib_io_free(struct pa_io_event
*e
) {
140 assert(e
&& !e
->dead
);
142 if (e
->source
!= (guint
) -1) {
143 g_source_remove(e
->source
);
144 e
->source
= (guint
) -1;
148 e
->prev
->next
= e
->next
;
150 e
->mainloop
->io_events
= e
->next
;
153 e
->next
->prev
= e
->prev
;
155 if ((e
->next
= e
->mainloop
->dead_io_events
))
158 e
->mainloop
->dead_io_events
= e
;
162 schedule_free_dead_events(e
->mainloop
);
165 static void glib_io_set_destroy(struct pa_io_event
*e
, void (*callback
)(struct pa_mainloop_api
*m
, struct pa_io_event
*e
, void *userdata
)) {
167 e
->destroy_callback
= callback
;
172 static void glib_time_restart(struct pa_time_event
*e
, const struct timeval
*tv
);
174 static struct pa_time_event
* glib_time_new(struct pa_mainloop_api
*m
, const struct timeval
*tv
, void (*callback
) (struct pa_mainloop_api
*m
, struct pa_time_event
*e
, const struct timeval
*tv
, void *userdata
), void *userdata
) {
175 struct pa_glib_mainloop
*g
;
176 struct pa_time_event
*e
;
178 assert(m
&& m
->userdata
&& tv
&& callback
);
181 e
= pa_xmalloc(sizeof(struct pa_time_event
));
184 e
->callback
= callback
;
185 e
->userdata
= userdata
;
186 e
->destroy_callback
= NULL
;
187 e
->source
= (guint
) -1;
189 glib_time_restart(e
, tv
);
191 e
->next
= g
->time_events
;
192 if (e
->next
) e
->next
->prev
= e
;
199 static guint
msec_diff(const struct timeval
*a
, const struct timeval
*b
) {
203 if (a
->tv_sec
< b
->tv_sec
)
206 if (a
->tv_sec
== b
->tv_sec
&& a
->tv_sec
<= b
->tv_sec
)
209 r
= (a
->tv_sec
-b
->tv_sec
)*1000;
211 if (a
->tv_usec
>= b
->tv_usec
)
212 r
+= (a
->tv_usec
- b
->tv_usec
) / 1000;
214 r
-= (b
->tv_usec
- a
->tv_usec
) / 1000;
219 static gboolean
time_cb(gpointer data
) {
220 struct pa_time_event
* e
= data
;
221 assert(e
&& e
->mainloop
&& e
->source
!= (guint
) -1);
223 g_source_remove(e
->source
);
224 e
->source
= (guint
) -1;
226 e
->callback(&e
->mainloop
->api
, e
, &e
->timeval
, e
->userdata
);
230 static void glib_time_restart(struct pa_time_event
*e
, const struct timeval
*tv
) {
232 assert(e
&& e
->mainloop
&& !e
->dead
);
234 gettimeofday(&now
, NULL
);
235 if (e
->source
!= (guint
) -1)
236 g_source_remove(e
->source
);
240 e
->source
= g_timeout_add_full(G_PRIORITY_DEFAULT
, msec_diff(tv
, &now
), time_cb
, e
, NULL
);
241 assert(e
->source
!= (guint
) -1);
243 e
->source
= (guint
) -1;
246 static void glib_time_free(struct pa_time_event
*e
) {
247 assert(e
&& e
->mainloop
&& !e
->dead
);
249 if (e
->source
!= (guint
) -1) {
250 g_source_remove(e
->source
);
251 e
->source
= (guint
) -1;
255 e
->prev
->next
= e
->next
;
257 e
->mainloop
->time_events
= e
->next
;
260 e
->next
->prev
= e
->prev
;
262 if ((e
->next
= e
->mainloop
->dead_time_events
))
265 e
->mainloop
->dead_time_events
= e
;
269 schedule_free_dead_events(e
->mainloop
);
272 static void glib_time_set_destroy(struct pa_time_event
*e
, void (*callback
)(struct pa_mainloop_api
*m
, struct pa_time_event
*e
, void *userdata
)) {
274 e
->destroy_callback
= callback
;
277 /* Deferred sources */
279 static void glib_defer_enable(struct pa_defer_event
*e
, int b
);
281 static struct pa_defer_event
* glib_defer_new(struct pa_mainloop_api
*m
, void (*callback
) (struct pa_mainloop_api
*m
, struct pa_defer_event
*e
, void *userdata
), void *userdata
) {
282 struct pa_defer_event
*e
;
283 struct pa_glib_mainloop
*g
;
285 assert(m
&& m
->userdata
&& callback
);
288 e
= pa_xmalloc(sizeof(struct pa_defer_event
));
291 e
->callback
= callback
;
292 e
->userdata
= userdata
;
293 e
->destroy_callback
= NULL
;
294 e
->source
= (guint
) -1;
296 glib_defer_enable(e
, 1);
298 e
->next
= g
->defer_events
;
299 if (e
->next
) e
->next
->prev
= e
;
305 static gboolean
idle_cb(gpointer data
) {
306 struct pa_defer_event
* e
= data
;
307 assert(e
&& e
->mainloop
&& e
->source
!= (guint
) -1);
309 e
->callback(&e
->mainloop
->api
, e
, e
->userdata
);
313 static void glib_defer_enable(struct pa_defer_event
*e
, int b
) {
314 assert(e
&& e
->mainloop
);
316 if (e
->source
!= (guint
) -1 && !b
) {
317 g_source_remove(e
->source
);
318 e
->source
= (guint
) -1;
319 } else if (e
->source
== (guint
) -1 && b
) {
320 e
->source
= g_idle_add_full(G_PRIORITY_HIGH
, idle_cb
, e
, NULL
);
321 assert(e
->source
!= (guint
) -1);
325 static void glib_defer_free(struct pa_defer_event
*e
) {
326 assert(e
&& e
->mainloop
&& !e
->dead
);
328 if (e
->source
!= (guint
) -1) {
329 g_source_remove(e
->source
);
330 e
->source
= (guint
) -1;
334 e
->prev
->next
= e
->next
;
336 e
->mainloop
->defer_events
= e
->next
;
339 e
->next
->prev
= e
->prev
;
341 if ((e
->next
= e
->mainloop
->dead_defer_events
))
344 e
->mainloop
->dead_defer_events
= e
;
348 schedule_free_dead_events(e
->mainloop
);
351 static void glib_defer_set_destroy(struct pa_defer_event
*e
, void (*callback
)(struct pa_mainloop_api
*m
, struct pa_defer_event
*e
, void *userdata
)) {
353 e
->destroy_callback
= callback
;
358 static void glib_quit(struct pa_mainloop_api
*a
, int retval
) {
359 struct pa_glib_mainloop
*g
;
360 assert(a
&& a
->userdata
);
366 static const struct pa_mainloop_api vtable
= {
369 .io_new
= glib_io_new
,
370 .io_enable
= glib_io_enable
,
371 .io_free
= glib_io_free
,
372 .io_set_destroy
= glib_io_set_destroy
,
374 .time_new
= glib_time_new
,
375 .time_restart
= glib_time_restart
,
376 .time_free
= glib_time_free
,
377 .time_set_destroy
= glib_time_set_destroy
,
379 .defer_new
= glib_defer_new
,
380 .defer_enable
= glib_defer_enable
,
381 .defer_free
= glib_defer_free
,
382 .defer_set_destroy
= glib_defer_set_destroy
,
387 struct pa_glib_mainloop
*pa_glib_mainloop_new(void) {
388 struct pa_glib_mainloop
*g
;
390 g
= pa_xmalloc(sizeof(struct pa_glib_mainloop
));
395 g
->io_events
= g
->dead_io_events
= NULL
;
396 g
->time_events
= g
->dead_time_events
= NULL
;
397 g
->defer_events
= g
->dead_defer_events
= NULL
;
399 g
->cleanup_source
= (guint
) -1;
403 static void free_io_events(struct pa_io_event
*e
) {
405 struct pa_io_event
*r
= e
;
408 if (r
->source
!= (guint
) -1)
409 g_source_remove(r
->source
);
412 g_io_channel_unref(r
->io_channel
);
414 if (r
->destroy_callback
)
415 r
->destroy_callback(&r
->mainloop
->api
, r
, r
->userdata
);
421 static void free_time_events(struct pa_time_event
*e
) {
423 struct pa_time_event
*r
= e
;
426 if (r
->source
!= (guint
) -1)
427 g_source_remove(r
->source
);
429 if (r
->destroy_callback
)
430 r
->destroy_callback(&r
->mainloop
->api
, r
, r
->userdata
);
436 static void free_defer_events(struct pa_defer_event
*e
) {
438 struct pa_defer_event
*r
= e
;
441 if (r
->source
!= (guint
) -1)
442 g_source_remove(r
->source
);
444 if (r
->destroy_callback
)
445 r
->destroy_callback(&r
->mainloop
->api
, r
, r
->userdata
);
451 void pa_glib_mainloop_free(struct pa_glib_mainloop
* g
) {
454 free_io_events(g
->io_events
);
455 free_io_events(g
->dead_io_events
);
456 free_defer_events(g
->defer_events
);
457 free_defer_events(g
->dead_defer_events
);
458 free_time_events(g
->time_events
);
459 free_time_events(g
->dead_time_events
);
461 if (g
->cleanup_source
!= (guint
) -1)
462 g_source_remove(g
->cleanup_source
);
467 struct pa_mainloop_api
* pa_glib_mainloop_get_api(struct pa_glib_mainloop
*g
) {
472 static gboolean
free_dead_events(gpointer p
) {
473 struct pa_glib_mainloop
*g
= p
;
476 free_io_events(g
->dead_io_events
);
477 free_defer_events(g
->dead_defer_events
);
478 free_time_events(g
->dead_time_events
);
480 g
->dead_io_events
= NULL
;
481 g
->dead_defer_events
= NULL
;
482 g
->dead_time_events
= NULL
;
484 g_source_remove(g
->cleanup_source
);
485 g
->cleanup_source
= (guint
) -1;
490 static void schedule_free_dead_events(struct pa_glib_mainloop
*g
) {
493 if (g
->cleanup_source
!= (guint
) -1)
496 g
->cleanup_source
= g_idle_add_full(G_PRIORITY_HIGH
, free_dead_events
, g
, NULL
);