1 /*
2 * Copyright (C) 2008 2009 2010, Magnus Hjorth
3 *
4 * This file is part of mhWaveEdit.
5 *
6 * mhWaveEdit is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * mhWaveEdit is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with mhWaveEdit; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21
22 #include <config.h>
23
24
25 #include <poll.h>
26 #include <gtk/gtk.h>
27 #include "mainloop.h"
28 #include "sound.h"
29 #include "statusbar.h"
30 #include "document.h"
31 #include "mainwindow.h"
32
33 gboolean idle_work_flag;
34
35 struct constant_source {
36 constsource_cb cb;
37 gpointer user_data;
38 gboolean enabled;
39 gboolean lowprio;
40 };
41
42 struct time_source {
43 timesource_cb cb;
44 gpointer user_data;
45 gboolean enabled;
46 GTimeVal call_time;
47 };
48
49 struct io_source {
50 GPollFD pfd;
51 iosource_cb cb;
52 gpointer user_data;
53 gboolean enabled;
54 };
55
56 struct io_group {
57 int nfds;
58 GPollFD *pfds;
59 int *orig_events;
60 int wdtime_ms;
61 gpointer wd;
62 iogroup_cb cb;
63 gpointer user_data;
64 gboolean enabled;
65 };
66
67 static GList *constsources = NULL, *timesources = NULL, *iosources = NULL;
68 static GList *iogroups = NULL;
69 static GList *dead_iosources = NULL;
70
in_sources(gpointer src,gpointer * sources,int n_sources)71 static gboolean in_sources(gpointer src, gpointer *sources, int n_sources)
72 {
73 int i;
74 if (sources == NULL) return TRUE;
75 for (i=0; i<n_sources; i++)
76 if (src == sources[i]) return TRUE;
77 return FALSE;
78 }
79
timesource_scan_main(GTimeVal * current_time,gboolean do_dispatch,gpointer * sources,int n_sources)80 static int timesource_scan_main(GTimeVal *current_time, gboolean do_dispatch,
81 gpointer *sources, int n_sources)
82 {
83 GList *l,*nl;
84 struct time_source *src;
85 GTimeVal tv;
86 int i,j;
87 int timeout = -1;
88 for (l=timesources; l!=NULL; l=nl) {
89 nl = l->next;
90 src = (struct time_source *)l->data;
91 if (!src->enabled || !in_sources(src,sources,n_sources)) continue;
92 i = timeval_subtract(&tv, &src->call_time, current_time);
93 if (i || (tv.tv_sec==0 && tv.tv_usec==0)) {
94 timeout = 0;
95
96 if (do_dispatch) {
97 src->enabled = FALSE;
98 j = src->cb(src, current_time, src->user_data);
99 if (j != 0) {
100 if (j > 0)
101 memcpy(&src->call_time,current_time,sizeof(GTimeVal));
102 else
103 j = -j;
104 src->call_time.tv_usec += j*1000;
105 while (src->call_time.tv_usec >= 1000000) {
106 src->call_time.tv_sec += 1;
107 src->call_time.tv_usec -= 1000000;
108 }
109 src->enabled = TRUE;
110 }
111 }
112
113 } else {
114 j = tv.tv_usec / 1000 + tv.tv_sec * 1000;
115 if (j <= 0) j=1;
116
117 if (timeout < 0 || j < timeout)
118 timeout = j;
119 }
120 }
121 return timeout;
122 }
123
timesource_scan(GTimeVal * current_time,gboolean do_dispatch)124 static int timesource_scan(GTimeVal *current_time, gboolean do_dispatch)
125 {
126 return timesource_scan_main(current_time,do_dispatch,NULL,0);
127 }
128
129
iosource_check_main(void)130 static gboolean iosource_check_main(void)
131 {
132 GList *l;
133 struct io_source *src;
134 struct io_group *grp;
135 int i;
136
137 for (l=iosources; l!=NULL; l=l->next) {
138 src = (struct io_source *)l->data;
139 if (src->enabled && src->pfd.revents != 0) return TRUE;
140 }
141 for (l=iogroups; l!=NULL; l=l->next) {
142 grp = (struct io_group *)l->data;
143 if (grp->enabled) {
144 for (i=0; i<grp->nfds; i++) {
145 if (grp->pfds[i].revents != 0) return TRUE;
146 }
147 }
148 }
149 return FALSE;
150 }
151
iosource_dispatch_main(GTimeVal * current_time)152 static gboolean iosource_dispatch_main(GTimeVal *current_time)
153 {
154 GList *l;
155 struct io_source *src;
156 struct io_group *grp;
157 int i,j,k;
158 GTimeVal tv;
159
160 for (l=iosources; l!=NULL; l=l->next) {
161 src = (struct io_source *)l->data;
162 if (src->enabled && src->pfd.revents != 0) {
163 src->cb(src,src->pfd.fd,src->pfd.revents,src->user_data);
164 src->pfd.revents = 0;
165 }
166 }
167 for (l=iogroups; l!=NULL; l=l->next) {
168 grp = (struct io_group *)l->data;
169 if (grp->enabled) {
170 j = 0;
171 for (i=0; i<grp->nfds; i++) {
172 if (j == 0 && grp->pfds[i].revents != 0) {
173 j++;
174 k = grp->cb(grp,grp->pfds[i].fd,grp->pfds[i].revents,
175 grp->user_data);
176 }
177 if (j != 0 && k == 0)
178 grp->pfds[i].events &= ~(grp->pfds[i].revents);
179 }
180 if (j != 0 && k != 0) {
181 mainloop_io_group_enable(grp,(k > 0));
182 }
183 /* Restart watchdog */
184 if (grp->wd != NULL) {
185 tv.tv_sec = current_time->tv_sec;
186 tv.tv_usec = current_time->tv_usec + grp->wdtime_ms*1000;
187 if (tv.tv_usec > 1000000) { tv.tv_sec++; tv.tv_usec-=1000000; }
188 mainloop_time_source_restart(grp->wd, &tv);
189 }
190
191 }
192 }
193 return TRUE;
194 }
195
196
197
198
199
200 #if GLIB_MAJOR_VERSION < 2
201
timesource_prepare(gpointer source_data,GTimeVal * current_time,gint * timeout,gpointer user_data)202 static gboolean timesource_prepare(gpointer source_data,
203 GTimeVal *current_time, gint *timeout,
204 gpointer user_data)
205 {
206 int i;
207 i = timesource_scan(current_time,FALSE);
208 if (i < 0)
209 return FALSE;
210 else if (i == 0)
211 return TRUE;
212 else {
213 if (*timeout < 0 || i < *timeout)
214 *timeout = i;
215 return FALSE;
216 }
217 }
218
timesource_check(gpointer source_data,GTimeVal * current_time,gpointer user_data)219 static gboolean timesource_check(gpointer source_data, GTimeVal *current_time,
220 gpointer user_data)
221 {
222 int i;
223 i = timesource_scan(current_time,FALSE);
224 return (i == 0);
225 }
226
timesource_dispatch(gpointer source_data,GTimeVal * dispatch_time,gpointer user_data)227 static gboolean timesource_dispatch(gpointer source_data,
228 GTimeVal *dispatch_time, gpointer user_data)
229 {
230 timesource_scan(dispatch_time,TRUE);
231 return TRUE;
232 }
233
234 static GSourceFuncs tsf = {
235 timesource_prepare, timesource_check, timesource_dispatch, NULL
236 };
237
mainloop_time_source_added(struct time_source * src)238 static void mainloop_time_source_added(struct time_source *src)
239 {
240 static gboolean inited = FALSE;
241 if (!inited) {
242 g_source_add(G_PRIORITY_HIGH, FALSE, &tsf, NULL, NULL, NULL);
243 inited = TRUE;
244 }
245 }
246
iosource_prepare(gpointer source_data,GTimeVal * current_time,gint * timeout,gpointer user_data)247 static gboolean iosource_prepare(gpointer source_data,
248 GTimeVal *current_time, gint *timeout,
249 gpointer user_data)
250 {
251 return FALSE;
252 }
253
iosource_check(gpointer source_data,GTimeVal * current_time,gpointer user_data)254 static gboolean iosource_check(gpointer source_data, GTimeVal *current_time,
255 gpointer user_data)
256 {
257 return iosource_check_main();
258 }
259
iosource_dispatch(gpointer source_data,GTimeVal * dispatch_time,gpointer user_data)260 static gboolean iosource_dispatch(gpointer source_data,
261 GTimeVal *dispatch_time, gpointer user_data)
262 {
263 iosource_dispatch_main(dispatch_time);
264 return TRUE;
265 }
266
267 static GSourceFuncs isf = {
268 iosource_prepare, iosource_check, iosource_dispatch, NULL
269 };
270
poll_add_main(GPollFD * pfd)271 static void poll_add_main(GPollFD *pfd)
272 {
273 static gboolean inited = FALSE;
274 if (!inited) {
275 g_source_add(G_PRIORITY_HIGH, FALSE, &isf, NULL, NULL, NULL);
276 inited = TRUE;
277 }
278 g_main_add_poll(pfd, G_PRIORITY_HIGH);
279 }
280
poll_remove_main(GPollFD * pfd)281 static void poll_remove_main(GPollFD *pfd)
282 {
283 g_main_remove_poll(pfd);
284 }
285
286
287
288
289
290 #else
291
292
293
294
295
296
timesource_prepare(GSource * source,gint * timeout)297 static gboolean timesource_prepare(GSource *source, gint *timeout)
298 {
299 GTimeVal tv;
300 int i;
301 g_source_get_current_time(source, &tv);
302 i = timesource_scan(&tv,FALSE);
303 if (i <= 0)
304 return (i == 0);
305 else {
306 if (*timeout < 0 || i < *timeout) *timeout = i;
307 return FALSE;
308 }
309 }
310
timesource_check(GSource * source)311 static gboolean timesource_check(GSource *source)
312 {
313 GTimeVal tv;
314 int i;
315 g_source_get_current_time(source, &tv);
316 i = timesource_scan(&tv,FALSE);
317 return (i == 0);
318 }
319
timesource_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)320 static gboolean timesource_dispatch(GSource *source, GSourceFunc callback,
321 gpointer user_data)
322 {
323 GTimeVal tv;
324 g_source_get_current_time(source,&tv);
325 timesource_scan(&tv,TRUE);
326 return TRUE;
327 }
328
329 static GSourceFuncs tsf2 = {
330 timesource_prepare,
331 timesource_check,
332 timesource_dispatch,
333 NULL
334 };
335
mainloop_time_source_added(struct time_source * src)336 static void mainloop_time_source_added(struct time_source *src)
337 {
338 static gboolean inited = FALSE;
339 GSource *s;
340 if (!inited) {
341 s = g_source_new(&tsf2, sizeof(*s));
342 g_source_attach(s,NULL);
343 inited = TRUE;
344 }
345 }
346
347
iosource_prepare(GSource * source,int * timeout)348 static gboolean iosource_prepare(GSource *source, int *timeout)
349 {
350 return FALSE;
351 }
352
iosource_check(GSource * source)353 static gboolean iosource_check(GSource *source)
354 {
355 return iosource_check_main();
356 }
357
358
iosource_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)359 static gboolean iosource_dispatch(GSource *source, GSourceFunc callback,
360 gpointer user_data)
361 {
362 GTimeVal tv;
363 g_source_get_current_time(source, &tv);
364 iosource_dispatch_main(&tv);
365 return TRUE;
366 }
367
368 static GSource *iosource_handle = NULL;
369
370 static GSourceFuncs isf2 = { iosource_prepare, iosource_check,
371 iosource_dispatch };
372
poll_add_main(GPollFD * pfd)373 static void poll_add_main(GPollFD *pfd)
374 {
375 if (iosource_handle == NULL) {
376 iosource_handle = g_source_new(&isf2, sizeof(GSource));
377 g_source_attach(iosource_handle,NULL);
378 }
379 g_source_add_poll(iosource_handle, pfd);
380 }
381
poll_remove_main(GPollFD * pfd)382 static void poll_remove_main(GPollFD *pfd)
383 {
384 g_source_remove_poll(iosource_handle, pfd);
385 }
386
387 #endif
388
389
390
391 /* ---------------------------------------- */
392
393 /* Note: Does not yet support io groups */
sources_poll(gpointer * sources,int n_sources)394 static void sources_poll(gpointer *sources, int n_sources)
395 {
396 int timeout,nfds,i;
397 GTimeVal tv;
398 struct pollfd *pfds;
399 GList *l;
400 struct io_source *src;
401 struct io_source **srcp;
402
403 /* puts("sources_poll"); */
404
405 g_get_current_time(&tv);
406 timeout = timesource_scan_main(&tv,TRUE,sources,n_sources);
407 if (timeout == 0) return;
408
409 pfds = g_malloc(n_sources * sizeof(struct pollfd));
410 srcp = g_malloc(n_sources * sizeof(struct io_source *));
411
412 nfds = 0;
413 for (l=iosources; l!=NULL; l=l->next) {
414 src = (struct io_source *)l->data;
415 if (in_sources(src,sources,n_sources)) {
416 srcp[nfds] = src;
417 memcpy(&pfds[nfds],&src->pfd,sizeof(pfds[0]));
418 nfds++;
419 }
420 }
421
422 if (nfds == 0 && timeout < 0) return;
423
424 /* printf("Calling poll with nfds=%d, timeout=%d (n_sources=%d)\n",
425 nfds,timeout,n_sources); */
426
427
428 i = poll(pfds,nfds,timeout);
429
430 if (i < 0) {
431 perror("poll");
432 return;
433 }
434
435 if (i > 0) {
436 for (i=0; i<nfds; i++) {
437 src = srcp[i];
438 src->pfd.revents = pfds[i].revents;
439 if (src->enabled && src->pfd.revents != 0) {
440 src->cb(src,src->pfd.fd,src->pfd.revents,src->user_data);
441 src->pfd.revents = 0;
442 }
443 }
444 }
445
446 g_free(pfds);
447 g_free(srcp);
448 }
449
mainloop_main(gpointer * sources,int n_sources)450 static void mainloop_main(gpointer *sources, int n_sources)
451 {
452 static guint const_highprio_idle_count=0;
453 struct constant_source *csrc;
454 gint i,j;
455 GList *l,*ln;
456
457 if (dead_iosources != NULL) {
458 for (l=dead_iosources; l!=NULL; l=l->next) {
459 g_free(l->data);
460 }
461 g_list_free(dead_iosources);
462 dead_iosources = NULL;
463 }
464
465 i = -1;
466 for (l=constsources; l!=NULL; l=ln) {
467 ln = l->next;
468 csrc = (struct constant_source *)l->data;
469 if (csrc->enabled && !csrc->lowprio &&
470 in_sources(csrc,sources,n_sources)) {
471 j = csrc->cb(csrc,csrc->user_data);
472 if (j > 0 || sources != NULL) return;
473 if (j > i) i = j;
474 }
475 }
476 if (i > 0) { const_highprio_idle_count=0; return; }
477 const_highprio_idle_count++;
478
479 if (sources == NULL && gtk_events_pending()) {
480 gtk_main_iteration();
481 return;
482 } else if (sources != NULL) {
483 sources_poll(sources,n_sources);
484 }
485
486 if (!idle_work_flag) {
487 idle_work_flag = TRUE;
488 return;
489 }
490
491 for (l=constsources; l!=NULL; l=ln) {
492 ln = l->next;
493 csrc = (struct constant_source *)l->data;
494 if (csrc->enabled && csrc->lowprio &&
495 in_sources(csrc,sources,n_sources)) {
496 j = csrc->cb(csrc,csrc->user_data);
497 if (j > 0) return;
498 if (j > i) i = j;
499 }
500 }
501
502 if (sources != NULL) return;
503
504 if (i < 0) {
505 gtk_main_iteration();
506 } else if (i >= 0 && const_highprio_idle_count > 10)
507 do_yield(TRUE);
508 }
509
mainloop(void)510 void mainloop(void)
511 {
512 mainloop_main(NULL,0);
513 }
514
515 /* Note: Does not (yet) support IO groups */
mainloop_recurse_on(gpointer * sources,int n_sources)516 void mainloop_recurse_on(gpointer *sources, int n_sources)
517 {
518 mainloop_main(sources, n_sources);
519 }
520
521
mainloop_constant_source_add(constsource_cb cb,gpointer user_data,gboolean low_prio)522 gpointer mainloop_constant_source_add(constsource_cb cb, gpointer user_data,
523 gboolean low_prio)
524 {
525 struct constant_source *src;
526 src = g_malloc(sizeof(*src));
527 src->cb = cb;
528 src->user_data = user_data;
529 src->enabled = TRUE;
530 src->lowprio = low_prio;
531 constsources = g_list_prepend(constsources, src);
532
533 return src;
534 }
535
mainloop_constant_source_enable(gpointer constsource,gboolean enable)536 void mainloop_constant_source_enable(gpointer constsource, gboolean enable)
537 {
538 struct constant_source *src = (struct constant_source *)constsource;
539 src->enabled = enable;
540 }
541
mainloop_constant_source_free(gpointer constsource)542 void mainloop_constant_source_free(gpointer constsource)
543 {
544 constsources = g_list_remove(constsources, constsource);
545 g_free(constsource);
546 }
547
mainloop_time_source_add(GTimeVal * tv,timesource_cb cb,gpointer user_data)548 gpointer mainloop_time_source_add(GTimeVal *tv, timesource_cb cb,
549 gpointer user_data)
550 {
551 struct time_source *src;
552
553 src = g_malloc(sizeof(*src));
554 src->cb = cb;
555 src->user_data = user_data;
556 if (tv != NULL) {
557 memcpy(&src->call_time,tv,sizeof(src->call_time));
558 src->enabled = TRUE;
559 } else {
560 src->enabled = FALSE;
561 }
562
563 timesources = g_list_append(timesources, src);
564
565 mainloop_time_source_added(src);
566
567 return src;
568 }
569
mainloop_time_source_restart(gpointer timesource,GTimeVal * new_tv)570 void mainloop_time_source_restart(gpointer timesource, GTimeVal *new_tv)
571 {
572 struct time_source *src = (struct time_source *)timesource;
573 memcpy(&(src->call_time),new_tv,sizeof(src->call_time));
574 src->enabled = TRUE;
575 }
576
mainloop_time_source_free(gpointer timesource)577 void mainloop_time_source_free(gpointer timesource)
578 {
579 timesources = g_list_remove(timesources, timesource);
580 g_free(timesource);
581 }
582
mainloop_time_source_enabled(gpointer ts)583 gboolean mainloop_time_source_enabled(gpointer ts)
584 {
585 struct time_source *src = (struct time_source *)ts;
586 return src->enabled;
587 }
588
mainloop_io_source_add(int fd,gushort events,iosource_cb cb,gpointer user_data)589 gpointer mainloop_io_source_add(int fd, gushort events, iosource_cb cb,
590 gpointer user_data)
591 {
592 struct io_source *src;
593 src = g_malloc(sizeof(*src));
594 src->pfd.fd = fd;
595 src->pfd.events = events;
596 src->pfd.revents = 0;
597 src->cb = cb;
598 src->user_data = user_data;
599 src->enabled = TRUE;
600 iosources = g_list_append(iosources, src);
601
602 poll_add_main(&(src->pfd));
603
604 return src;
605 }
606
mainloop_io_source_enable(gpointer iosource,gboolean enable)607 void mainloop_io_source_enable(gpointer iosource, gboolean enable)
608 {
609 struct io_source *src = (struct io_source *)iosource;
610 if (XOR(src->enabled,enable)) {
611 src->enabled = enable;
612 if (enable)
613 poll_add_main(&(src->pfd));
614 else
615 poll_remove_main(&(src->pfd));
616 }
617 }
618
mainloop_io_source_set_events(gpointer iosource,gushort new_events)619 void mainloop_io_source_set_events(gpointer iosource, gushort new_events)
620 {
621 struct io_source *src = (struct io_source *)iosource;
622 src->pfd.events = new_events;
623 if (new_events != 0 && !src->enabled) {
624 poll_add_main(&(src->pfd));
625 src->enabled = TRUE;
626 }
627 }
628
mainloop_io_source_free(gpointer iosource)629 void mainloop_io_source_free(gpointer iosource)
630 {
631 mainloop_io_source_enable(iosource,FALSE);
632 iosources = g_list_remove(iosources, iosource);
633 /* We can not free the IO source here, because we might be
634 * removing it from inside a callback called from sources_poll */
635 dead_iosources = g_list_append(dead_iosources, iosource);
636 }
637
mainloop_io_group_add(int nfds,GPollFD * pfds,int wdtime_ms,iogroup_cb cb,gpointer user_data)638 gpointer mainloop_io_group_add(int nfds, GPollFD *pfds, int wdtime_ms,
639 iogroup_cb cb, gpointer user_data)
640 {
641 struct io_group *grp;
642 int i;
643 grp = g_malloc(sizeof(*grp));
644 grp->nfds = nfds;
645 grp->pfds = NULL;
646 grp->orig_events = NULL;
647 if (nfds > 0) {
648 grp->pfds = g_malloc(nfds*sizeof(GPollFD));
649 memcpy(grp->pfds, pfds, nfds*sizeof(GPollFD));
650 grp->orig_events = g_malloc(nfds*sizeof(int));
651 }
652 for (i=0; i<nfds; i++) {
653 grp->orig_events[i] = pfds[i].events;
654 poll_add_main(&(grp->pfds[i]));
655 }
656 grp->wdtime_ms = wdtime_ms;
657 grp->wd = NULL;
658 grp->cb = cb;
659 grp->user_data = user_data;
660 grp->enabled = FALSE;
661
662 iogroups = g_list_append(iogroups, grp);
663
664 mainloop_io_group_enable(grp,TRUE);
665
666 return grp;
667 }
668
iogroup_watchdog_cb(gpointer timesource,GTimeVal * current_time,gpointer user_data)669 static gint iogroup_watchdog_cb(gpointer timesource, GTimeVal *current_time,
670 gpointer user_data)
671 {
672 struct io_group *grp = (struct io_group *)user_data;
673 int i,j;
674 i = grp->cb(grp, -1, 0, grp->user_data);
675 if (i > 0) {
676 for (j=0; j<grp->nfds; j++)
677 grp->pfds[j].events = grp->orig_events[j];
678 }
679 if (i >= 0)
680 return -grp->wdtime_ms;
681 else
682 return 0;
683 }
684
mainloop_io_group_enable(gpointer iogroup,gboolean enable)685 void mainloop_io_group_enable(gpointer iogroup, gboolean enable)
686 {
687 struct io_group *grp = (struct io_group *)iogroup;
688 int i;
689 GTimeVal tv;
690
691 if (XOR(grp->enabled,enable)) {
692 if (enable) {
693 if (grp->wdtime_ms > 0)
694 grp->wd = mainloop_time_source_add(NULL,iogroup_watchdog_cb,grp);
695 } else {
696 mainloop_time_source_free(grp->wd);
697 grp->wd = NULL;
698 }
699 }
700
701 if (enable && grp->wd != NULL) {
702 g_get_current_time(&tv);
703 tv.tv_sec += grp->wdtime_ms / 1000;
704 tv.tv_usec += 1000*(grp->wdtime_ms%1000);
705 if (tv.tv_usec >= 1000000) {
706 tv.tv_sec++;
707 tv.tv_usec -= 1000000;
708 }
709 mainloop_time_source_restart(grp->wd,&tv);
710 }
711
712 for (i=0; i<grp->nfds; i++) {
713 grp->pfds[i].events = enable ? grp->orig_events[i] : 0;
714 }
715
716 grp->enabled = enable;
717
718 }
719
mainloop_io_group_free(gpointer iogroup)720 void mainloop_io_group_free(gpointer iogroup)
721 {
722 struct io_group *grp = (struct io_group *)iogroup;
723 int i;
724
725 iogroups = g_list_remove(iogroups, grp);
726
727 mainloop_io_group_enable(iogroup,FALSE);
728 for (i=0; i<grp->nfds; i++) {
729 poll_remove_main(&(grp->pfds[i]));
730 }
731 g_free(grp->pfds);
732 g_free(grp->orig_events);
733 g_free(grp);
734 }
735
736
737
738 struct defer {
739 gpointer src;
740 defer_once_cb cscb;
741 gpointer user_data;
742 };
743
defer_once_cb1(gpointer csource,gpointer user_data)744 static int defer_once_cb1(gpointer csource, gpointer user_data)
745 {
746 struct defer *d = (struct defer *)user_data;
747 d->cscb(d->user_data);
748 mainloop_constant_source_free(csource);
749 g_free(d);
750 return -1;
751 }
752
defer_once_cb2(gpointer tsource,GTimeVal * tm,gpointer user_data)753 static int defer_once_cb2(gpointer tsource, GTimeVal *tm, gpointer user_data)
754 {
755 struct defer *d = (struct defer *)user_data;
756 d->cscb(d->user_data);
757 mainloop_time_source_free(tsource);
758 g_free(d);
759 return 0;
760 }
761
mainloop_defer_once(defer_once_cb cb,gint reltime,gpointer user_data)762 void mainloop_defer_once(defer_once_cb cb, gint reltime, gpointer user_data)
763 {
764 struct defer *d;
765 GTimeVal t;
766 d = g_malloc(sizeof(*d));
767 if (reltime <= 0)
768 d->src = mainloop_constant_source_add(defer_once_cb1, d, TRUE);
769 else {
770 g_get_current_time(&t);
771 t.tv_usec += reltime*1000;
772 while (t.tv_usec >= 1000000) {
773 t.tv_usec -= 1000000;
774 t.tv_sec += 1;
775 }
776 d->src = mainloop_time_source_add(&t,defer_once_cb2,d);
777 }
778
779 d->cscb = cb;
780 d->user_data = user_data;
781 }
782
783