Add #defines defining scale of priorities.
[platform/upstream/glib.git] / gmain.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gmain.c: Main loop abstraction, timeouts, and idle functions
5  * Copyright 1998 Owen Taylor
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /* 
24  * MT safe
25  */
26
27 #include "glib.h"
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #ifdef  GLIB_HAVE_SYS_POLL_H
31 #include <sys/poll.h>
32 #endif  /* GLIB_HAVE_SYS_POLL_H */
33 #include <unistd.h>
34 #include <errno.h>
35 #include "config.h"
36
37 /* Types */
38
39 typedef struct _GIdleData GIdleData;
40 typedef struct _GTimeoutData GTimeoutData;
41 typedef struct _GSource GSource;
42 typedef struct _GPollRec GPollRec;
43
44 typedef enum
45 {
46   G_SOURCE_READY = 1 << G_HOOK_FLAG_USER_SHIFT,
47   G_SOURCE_CAN_RECURSE = 1 << (G_HOOK_FLAG_USER_SHIFT + 1)
48 } GSourceFlags;
49
50 struct _GSource
51 {
52   GHook hook;
53   gint priority;
54   gpointer source_data;
55 };
56
57 struct _GMainLoop
58 {
59   gboolean is_running;
60 };
61
62 struct _GIdleData
63 {
64   GSourceFunc callback;
65 };
66
67 struct _GTimeoutData
68 {
69   GTimeVal    expiration;
70   gint        interval;
71   GSourceFunc callback;
72 };
73
74 struct _GPollRec
75 {
76   gint priority;
77   GPollFD *fd;
78   GPollRec *next;
79 };
80
81 /* Forward declarations */
82
83 static void     g_main_poll               (gint      timeout,
84                                            gboolean  use_priority, 
85                                            gint      priority);
86 static void     g_main_add_poll_unlocked  (gint      priority,
87                                            GPollFD  *fd);
88
89 static gboolean g_timeout_prepare      (gpointer  source_data, 
90                                         GTimeVal *current_time,
91                                         gint     *timeout);
92 static gboolean g_timeout_check        (gpointer  source_data,
93                                         GTimeVal *current_time);
94 static gboolean g_timeout_dispatch     (gpointer  source_data,
95                                         GTimeVal *current_time,
96                                         gpointer  user_data);
97 static gboolean g_idle_prepare         (gpointer  source_data, 
98                                         GTimeVal *current_time,
99                                         gint     *timeout);
100 static gboolean g_idle_check           (gpointer  source_data,
101                                         GTimeVal *current_time);
102 static gboolean g_idle_dispatch        (gpointer  source_data,
103                                         GTimeVal *current_time,
104                                         gpointer  user_data);
105
106 /* Data */
107
108 static GSList *pending_dispatches = NULL;
109 static GHookList source_list = { 0 };
110
111 /* The following lock is used for both the list of sources
112  * and the list of poll records
113  */
114 G_LOCK_DECLARE_STATIC (main_loop);
115
116 static GSourceFuncs timeout_funcs = {
117   g_timeout_prepare,
118   g_timeout_check,
119   g_timeout_dispatch,
120   (GDestroyNotify)g_free
121 };
122
123 static GSourceFuncs idle_funcs = {
124   g_idle_prepare,
125   g_idle_check,
126   g_idle_dispatch,
127   (GDestroyNotify)g_free
128 };
129
130 static GPollRec *poll_records = NULL;
131 static GPollRec *poll_free_list = NULL;
132 static GMemChunk *poll_chunk;
133 static guint n_poll_records = 0;
134
135 /* this pipe is used to wake up the main loop when a source is added.
136  */
137 static gint wake_up_pipe[2] = { -1, -1 };
138 static GPollFD wake_up_rec;
139 static gboolean poll_waiting = FALSE;
140
141 #ifdef HAVE_POLL
142 static GPollFunc poll_func = (GPollFunc) poll;
143 #else   /* !HAVE_POLL */
144
145 /* The following implementation of poll() comes from the GNU C Library.
146  * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
147  */
148
149 #include <string.h> /* for bzero on BSD systems */
150
151 #ifdef HAVE_SYS_SELECT_H
152 #include <sys/select.h>
153 #endif /* HAVE_SYS_SELECT_H_ */
154
155 #ifndef NO_FD_SET
156 #  define SELECT_MASK fd_set
157 #else   /* !NO_FD_SET */
158 #  ifndef _AIX
159 typedef long fd_mask;
160 #  endif
161 #  if defined(_IBMR2)
162 #    define SELECT_MASK void
163 #  else
164 #    define SELECT_MASK int
165 #  endif
166 #endif  /* !NO_FD_SET */
167
168 static gint 
169 g_poll (GPollFD *fds, guint nfds, gint timeout)
170 {
171   struct timeval tv;
172   SELECT_MASK rset, wset, xset;
173   GPollFD *f;
174   int ready;
175   int maxfd = 0;
176
177   FD_ZERO (&rset);
178   FD_ZERO (&wset);
179   FD_ZERO (&xset);
180
181   for (f = fds; f < &fds[nfds]; ++f)
182     if (f->fd >= 0)
183       {
184         if (f->events & G_IO_IN)
185           FD_SET (f->fd, &rset);
186         if (f->events & G_IO_OUT)
187           FD_SET (f->fd, &wset);
188         if (f->events & G_IO_PRI)
189           FD_SET (f->fd, &xset);
190         if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
191           maxfd = f->fd;
192       }
193
194   tv.tv_sec = timeout / 1000;
195   tv.tv_usec = (timeout % 1000) * 1000;
196
197   ready = select (maxfd + 1, &rset, &wset, &xset,
198                   timeout == -1 ? NULL : &tv);
199   if (ready > 0)
200     for (f = fds; f < &fds[nfds]; ++f)
201       {
202         f->revents = 0;
203         if (f->fd >= 0)
204           {
205             if (FD_ISSET (f->fd, &rset))
206               f->revents |= G_IO_IN;
207             if (FD_ISSET (f->fd, &wset))
208               f->revents |= G_IO_OUT;
209             if (FD_ISSET (f->fd, &xset))
210               f->revents |= G_IO_PRI;
211           }
212       }
213
214   return ready;
215 }
216 static GPollFunc poll_func = g_poll;
217 #endif  /* !HAVE_POLL */
218
219 /* Hooks for adding to the main loop */
220
221 /* Use knowledge of insert_sorted algorithm here to make
222  * sure we insert at the end of equal priority items
223  */
224 static gint
225 g_source_compare (GHook *a,
226                   GHook *b)
227 {
228   GSource *source_a = (GSource *)a;
229   GSource *source_b = (GSource *)b;
230
231   return (source_a->priority < source_b->priority) ? -1 : 1;
232 }
233
234 guint 
235 g_source_add (gint           priority,
236               gboolean       can_recurse,
237               GSourceFuncs  *funcs,
238               gpointer       source_data, 
239               gpointer       user_data,
240               GDestroyNotify notify)
241 {
242   guint return_val;
243   GSource *source;
244
245   G_LOCK (main_loop);
246
247   if (!source_list.is_setup)
248     g_hook_list_init (&source_list, sizeof(GSource));
249
250   source = (GSource *)g_hook_alloc (&source_list);
251   source->priority = priority;
252   source->source_data = source_data;
253   source->hook.func = funcs;
254   source->hook.data = user_data;
255   source->hook.destroy = notify;
256   
257   g_hook_insert_sorted (&source_list, 
258                         (GHook *)source, 
259                         g_source_compare);
260
261   if (can_recurse)
262     source->hook.flags |= G_SOURCE_CAN_RECURSE;
263
264   return_val = source->hook.hook_id;
265
266   /* Now wake up the main loop if it is waiting in the poll() */
267
268   if (poll_waiting)
269     {
270       poll_waiting = FALSE;
271       write (wake_up_pipe[1], "A", 1);
272     }
273
274   G_UNLOCK (main_loop);
275
276   return return_val;
277 }
278
279 void 
280 g_source_remove (guint tag)
281 {
282   GHook *hook;
283
284   G_LOCK (main_loop);
285
286   hook = g_hook_get (&source_list, tag);
287   if (hook)
288     {
289       GSource *source = (GSource *)hook;
290
291       ((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
292       g_hook_destroy_link (&source_list, hook);
293     }
294
295   G_UNLOCK (main_loop);
296 }
297
298 void 
299 g_source_remove_by_user_data (gpointer user_data)
300 {
301   GHook *hook;
302   
303   G_LOCK (main_loop);
304   
305   hook = g_hook_find_data (&source_list, TRUE, user_data);
306   if (hook)
307     {
308       GSource *source = (GSource *)hook;
309
310       ((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
311       g_hook_destroy_link (&source_list, hook);
312     }
313
314   G_UNLOCK (main_loop);
315 }
316
317 static gboolean
318 g_source_find_source_data (GHook        *hook,
319                            gpointer      data)
320 {
321   GSource *source = (GSource *)hook;
322
323   return (source->source_data == data);
324 }
325
326 void 
327 g_source_remove_by_source_data (gpointer source_data)
328 {
329   GHook *hook;
330
331   G_LOCK (main_loop);
332
333   hook = g_hook_find (&source_list, TRUE, 
334                       g_source_find_source_data, source_data);
335   if (hook)
336     {
337       GSource *source = (GSource *)hook;
338
339       ((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
340       g_hook_destroy_link (&source_list, hook);
341     }
342
343   G_UNLOCK (main_loop);
344 }
345
346 void
347 g_get_current_time (GTimeVal *result)
348 {
349   g_return_if_fail (result != NULL);
350
351   gettimeofday ((struct timeval *) result, NULL);
352 }
353
354 /* Running the main loop */
355
356 /* HOLDS: main_loop_lock */
357 static void
358 g_main_dispatch (GTimeVal *current_time)
359 {
360   while (pending_dispatches != NULL)
361     {
362       gboolean need_destroy;
363       GSource *source = pending_dispatches->data;
364       GSList *tmp_list;
365
366       tmp_list = pending_dispatches;
367       pending_dispatches = g_slist_remove_link (pending_dispatches, pending_dispatches);
368       g_slist_free_1 (tmp_list);
369
370       if (G_HOOK_IS_VALID (source))
371         {
372           gboolean was_in_call;
373           gpointer hook_data = source->hook.data;
374           gpointer source_data = source->source_data;
375           gboolean (*dispatch) (gpointer,
376                                 GTimeVal *,
377                                 gpointer);
378
379           dispatch = ((GSourceFuncs *) source->hook.func)->dispatch;
380           
381           was_in_call = G_HOOK_IN_CALL (source);
382           source->hook.flags |= G_HOOK_FLAG_IN_CALL;
383
384           G_UNLOCK (main_loop);
385           need_destroy = ! dispatch (source_data,
386                                      current_time,
387                                      hook_data);
388           G_LOCK (main_loop);
389
390           if (!was_in_call)
391             source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
392           
393           if (need_destroy && G_HOOK_IS_VALID (source))
394             {
395               ((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
396               g_hook_destroy_link (&source_list, (GHook *) source);
397             }
398         }
399
400       g_hook_unref (&source_list, (GHook *)source);
401     }
402 }
403
404 /* g_main_iterate () runs a single iteration of the mainloop, or,
405  * if !dispatch checks to see if any sources need dispatching.
406  * basic algorithm for dispatch=TRUE:
407  *
408  * 1) while the list of currently pending sources is non-empty,
409  *    we call (*dispatch) on those that are !IN_CALL or can_recurse,
410  *    removing sources from the list after each returns.
411  *    the return value of (*dispatch) determines whether the source
412  *    itself is kept alive.
413  *
414  * 2) call (*prepare) for sources that are not yet SOURCE_READY and
415  *    are !IN_CALL or can_recurse. a return value of TRUE determines
416  *    that the source would like to be dispatched immediatedly, it
417  *    is then flagged as SOURCE_READY.
418  *
419  * 3) poll with the pollfds from all sources at the priority of the
420  *    first source flagged as SOURCE_READY. if there are any sources
421  *    flagged as SOURCE_READY, we use a timeout of 0 or the minimum
422  *    of all timouts otherwise.
423  *
424  * 4) for each source !IN_CALL or can_recurse, if SOURCE_READY or
425  *    (*check) returns true, add the source to the pending list.
426  *    once one source returns true, stop after checking all sources
427  *    at that priority.
428  *
429  * 5) while the list of currently pending sources is non-empty,
430  *    call (*dispatch) on each source, removing the source
431  *    after the call.
432  *
433  */
434 static gboolean
435 g_main_iterate (gboolean block,
436                 gboolean dispatch)
437 {
438   GHook *hook;
439   GTimeVal current_time;
440   gint n_ready = 0;
441   gint current_priority = 0;
442   gint timeout;
443   gboolean retval = FALSE;
444
445   g_return_val_if_fail (!block || dispatch, FALSE);
446
447   g_get_current_time (&current_time);
448
449   G_LOCK (main_loop);
450   
451   /* If recursing, finish up current dispatch, before starting over */
452   if (pending_dispatches)
453     {
454       if (dispatch)
455         g_main_dispatch (&current_time);
456       
457       G_UNLOCK (main_loop);
458
459       return TRUE;
460     }
461
462   /* Prepare all sources */
463
464   timeout = block ? -1 : 0;
465   
466   hook = g_hook_first_valid (&source_list, TRUE);
467   while (hook)
468     {
469       GSource *source = (GSource *)hook;
470       GHook *tmp;
471       gint source_timeout;
472
473       if ((n_ready > 0) && (source->priority > current_priority))
474         break;
475       if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
476         {
477           hook = g_hook_next_valid (hook, TRUE);
478           continue;
479         }
480
481       g_hook_ref (&source_list, hook);
482       
483       if (hook->flags & G_SOURCE_READY ||
484           ((GSourceFuncs *) hook->func)->prepare (source->source_data,
485                                                   &current_time,
486                                                   &source_timeout))
487         {
488           if (!dispatch)
489             {
490               hook->flags |= G_SOURCE_READY;
491               g_hook_unref (&source_list, hook);
492               G_UNLOCK (main_loop);
493
494               return TRUE;
495             }
496           else
497             {
498               hook->flags |= G_SOURCE_READY;
499               n_ready++;
500               current_priority = source->priority;
501               timeout = 0;
502             }
503         }
504       
505       if (source_timeout >= 0)
506         {
507           if (timeout < 0)
508             timeout = source_timeout;
509           else
510             timeout = MIN (timeout, source_timeout);
511         }
512
513       tmp = g_hook_next_valid (hook, TRUE);
514       
515       g_hook_unref (&source_list, hook);
516       hook = tmp;
517     }
518
519   /* poll(), if necessary */
520
521   g_main_poll (timeout, n_ready > 0, current_priority);
522
523   /* Check to see what sources need to be dispatched */
524
525   n_ready = 0;
526   
527   hook = g_hook_first_valid (&source_list, TRUE);
528   while (hook)
529     {
530       GSource *source = (GSource *)hook;
531       GHook *tmp;
532
533       if ((n_ready > 0) && (source->priority > current_priority))
534         break;
535       if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
536         {
537           hook = g_hook_next_valid (hook, TRUE);
538           continue;
539         }
540
541       g_hook_ref (&source_list, hook);
542
543       if (hook->flags & G_SOURCE_READY ||
544           ((GSourceFuncs *) hook->func)->check (source->source_data,
545                                                 &current_time))
546         {
547           if (dispatch)
548             {
549               hook->flags &= ~G_SOURCE_READY;
550               g_hook_ref (&source_list, hook);
551               pending_dispatches = g_slist_prepend (pending_dispatches, source);
552               current_priority = source->priority;
553               n_ready++;
554             }
555           else
556             {
557               g_hook_unref (&source_list, hook);
558               G_UNLOCK (main_loop);
559
560               return TRUE;
561             }
562         }
563       
564       tmp = g_hook_next_valid (hook, TRUE);
565       
566       g_hook_unref (&source_list, hook);
567       hook = tmp;
568     }
569
570   /* Now invoke the callbacks */
571
572   if (pending_dispatches)
573     {
574       pending_dispatches = g_slist_reverse (pending_dispatches);
575       g_main_dispatch (&current_time);
576       retval = TRUE;
577     }
578
579   G_UNLOCK (main_loop);
580
581   return retval;
582 }
583
584 /* See if any events are pending
585  */
586 gboolean 
587 g_main_pending ()
588 {
589   return g_main_iterate (FALSE, FALSE);
590 }
591
592 /* Run a single iteration of the mainloop. If block is FALSE,
593  * will never block
594  */
595 gboolean
596 g_main_iteration (gboolean block)
597 {
598   return g_main_iterate (block, TRUE);
599 }
600
601 GMainLoop*
602 g_main_new (gboolean is_running)
603 {
604   GMainLoop *loop;
605
606   loop = g_new0 (GMainLoop, 1);
607   loop->is_running = is_running != FALSE;
608
609   return loop;
610 }
611
612 void 
613 g_main_run (GMainLoop *loop)
614 {
615   g_return_if_fail (loop != NULL);
616
617   loop->is_running = TRUE;
618   while (loop->is_running)
619     g_main_iterate (TRUE, TRUE);
620 }
621
622 void 
623 g_main_quit (GMainLoop *loop)
624 {
625   g_return_if_fail (loop != NULL);
626
627   loop->is_running = FALSE;
628 }
629
630 void 
631 g_main_destroy (GMainLoop *loop)
632 {
633   g_return_if_fail (loop != NULL);
634
635   g_free (loop);
636 }
637
638 gboolean
639 g_main_is_running (GMainLoop *loop)
640 {
641   g_return_val_if_fail (loop != NULL, FALSE);
642
643   return loop->is_running;
644 }
645
646 /* HOLDS: main_loop_lock */
647 static void
648 g_main_poll (gint     timeout,
649              gboolean use_priority,
650              gint     priority)
651 {
652   GPollFD *fd_array;
653   GPollRec *pollrec;
654
655   gint i;
656   gint npoll;
657
658   if (wake_up_pipe[0] < 0)
659     {
660       if (pipe (wake_up_pipe) < 0)
661         g_error ("Cannot create pipe main loop wake-up: %s\n",
662                  g_strerror (errno));
663
664       wake_up_rec.fd = wake_up_pipe[0];
665       wake_up_rec.events = G_IO_IN;
666       g_main_add_poll_unlocked (0, &wake_up_rec);
667     }
668   
669   fd_array = g_new (GPollFD, n_poll_records);
670  
671   pollrec = poll_records;
672   i = 0;
673   while (pollrec && (!use_priority || priority >= pollrec->priority))
674     {
675       fd_array[i].fd = pollrec->fd->fd;
676       fd_array[i].events = pollrec->fd->events;
677       fd_array[i].revents = 0;
678         
679       pollrec = pollrec->next;
680       i++;
681     }
682
683   poll_waiting = TRUE;
684   
685   G_UNLOCK (main_loop);
686   npoll = i;
687   (*poll_func) (fd_array, npoll, timeout);
688   G_LOCK (main_loop);
689
690   if (!poll_waiting)
691     {
692       gchar c;
693       read (wake_up_pipe[0], &c, 1);
694     }
695   else
696     poll_waiting = FALSE;
697
698   pollrec = poll_records;
699   i = 0;
700   while (i < npoll)
701     {
702       pollrec->fd->revents = fd_array[i].revents;
703       pollrec = pollrec->next;
704       i++;
705     }
706
707   g_free (fd_array);
708 }
709
710 void 
711 g_main_add_poll (GPollFD *fd,
712                  gint     priority)
713 {
714   G_LOCK (main_loop);
715   g_main_add_poll_unlocked (priority, fd);
716   G_UNLOCK (main_loop);
717 }
718
719 /* HOLDS: main_loop_lock */
720 static void 
721 g_main_add_poll_unlocked (gint     priority,
722                           GPollFD *fd)
723 {
724   GPollRec *lastrec, *pollrec, *newrec;
725
726   if (!poll_chunk)
727     poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
728
729   if (poll_free_list)
730     {
731       newrec = poll_free_list;
732       poll_free_list = newrec->next;
733     }
734   else
735     newrec = g_chunk_new (GPollRec, poll_chunk);
736
737   newrec->fd = fd;
738   newrec->priority = priority;
739
740   lastrec = NULL;
741   pollrec = poll_records;
742   while (pollrec && priority >= pollrec->priority)
743     {
744       lastrec = pollrec;
745       pollrec = pollrec->next;
746     }
747   
748   if (lastrec)
749     lastrec->next = newrec;
750   else
751     poll_records = newrec;
752
753   newrec->next = pollrec;
754
755   n_poll_records++;
756 }
757
758 void 
759 g_main_remove_poll (GPollFD *fd)
760 {
761   GPollRec *pollrec, *lastrec;
762
763   G_LOCK (main_loop);
764   
765   lastrec = NULL;
766   pollrec = poll_records;
767
768   while (pollrec)
769     {
770       if (pollrec->fd == fd)
771         {
772           if (lastrec != NULL)
773             lastrec->next = pollrec->next;
774           else
775             poll_records = pollrec->next;
776
777           pollrec->next = poll_free_list;
778           poll_free_list = pollrec;
779
780           n_poll_records--;
781           break;
782         }
783       lastrec = pollrec;
784       pollrec = pollrec->next;
785     }
786
787   G_UNLOCK (main_loop);
788 }
789
790 void 
791 g_main_set_poll_func (GPollFunc func)
792 {
793   if (func)
794     poll_func = func;
795   else
796 #ifdef HAVE_POLL
797     poll_func = (GPollFunc)poll;
798 #else
799     poll_func = (GPollFunc)g_poll;
800 #endif
801 }
802
803 /* Timeouts */
804
805 static gboolean 
806 g_timeout_prepare  (gpointer source_data, 
807                     GTimeVal *current_time,
808                     gint    *timeout)
809 {
810   glong msec;
811   GTimeoutData *data = source_data;
812
813   msec = (data->expiration.tv_sec  - current_time->tv_sec) * 1000 +
814          (data->expiration.tv_usec - current_time->tv_usec) / 1000;
815
816   *timeout = (msec <= 0) ? 0 : msec;
817
818   return (msec <= 0);
819 }
820
821 static gboolean 
822 g_timeout_check    (gpointer source_data,
823                     GTimeVal *current_time)
824 {
825   GTimeoutData *data = source_data;
826
827   return (data->expiration.tv_sec < current_time->tv_sec) ||
828          ((data->expiration.tv_sec == current_time->tv_sec) &&
829           (data->expiration.tv_usec <= current_time->tv_usec));
830 }
831
832 static gboolean
833 g_timeout_dispatch (gpointer source_data, 
834                     GTimeVal *current_time,
835                     gpointer user_data)
836 {
837   GTimeoutData *data = source_data;
838
839   if (data->callback(user_data))
840     {
841       guint seconds = data->interval / 1000;
842       guint msecs = data->interval - seconds * 1000;
843
844       data->expiration.tv_sec = current_time->tv_sec + seconds;
845       data->expiration.tv_usec = current_time->tv_usec + msecs * 1000;
846       if (data->expiration.tv_usec >= 1000000)
847         {
848           data->expiration.tv_usec -= 1000000;
849           data->expiration.tv_sec++;
850         }
851       return TRUE;
852     }
853   else
854     return FALSE;
855 }
856
857 guint 
858 g_timeout_add_full (gint           priority,
859                     guint          interval, 
860                     GSourceFunc    function,
861                     gpointer       data,
862                     GDestroyNotify notify)
863 {
864   guint seconds;
865   guint msecs;
866   GTimeoutData *timeout_data = g_new (GTimeoutData, 1);
867
868   timeout_data->interval = interval;
869   timeout_data->callback = function;
870   g_get_current_time (&timeout_data->expiration);
871
872   seconds = timeout_data->interval / 1000;
873   msecs = timeout_data->interval - seconds * 1000;
874
875   timeout_data->expiration.tv_sec += seconds;
876   timeout_data->expiration.tv_usec += msecs * 1000;
877   if (timeout_data->expiration.tv_usec >= 1000000)
878     {
879       timeout_data->expiration.tv_usec -= 1000000;
880       timeout_data->expiration.tv_sec++;
881     }
882
883   return g_source_add (priority, FALSE, &timeout_funcs, timeout_data, data, notify);
884 }
885
886 guint 
887 g_timeout_add (guint32        interval,
888                GSourceFunc    function,
889                gpointer       data)
890 {
891   return g_timeout_add_full (G_PRIORITY_DEFAULT, 
892                              interval, function, data, NULL);
893 }
894
895 /* Idle functions */
896
897 static gboolean 
898 g_idle_prepare  (gpointer source_data, 
899                  GTimeVal *current_time,
900                  gint     *timeout)
901 {
902   timeout = 0;
903   return TRUE;
904 }
905
906 static gboolean 
907 g_idle_check    (gpointer  source_data,
908                  GTimeVal *current_time)
909 {
910   return TRUE;
911 }
912
913 static gboolean
914 g_idle_dispatch (gpointer source_data, 
915                  GTimeVal *current_time,
916                  gpointer user_data)
917 {
918   GIdleData *data = source_data;
919
920   return (*data->callback)(user_data);
921 }
922
923 guint 
924 g_idle_add_full (gint          priority,
925                  GSourceFunc    function,
926                  gpointer       data,
927                  GDestroyNotify notify)
928 {
929   GIdleData *idle_data = g_new (GIdleData, 1);
930
931   idle_data->callback = function;
932
933   return g_source_add (priority, FALSE, &idle_funcs, idle_data, data, notify);
934 }
935
936 guint 
937 g_idle_add (GSourceFunc    function,
938             gpointer       data)
939 {
940   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
941 }