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