don't cast to timeval since timeval is for some reason not always a struct
[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   struct timeval r;
350   g_return_if_fail (result != NULL);
351
352   /*this is required on alpha, there the timeval structs are int's
353     not longs and a cast only would fail horribly*/
354   gettimeofday (&r, NULL);
355   result->tv_sec = r.tv_sec;
356   result->tv_usec = r.tv_usec;
357 }
358
359 /* Running the main loop */
360
361 /* HOLDS: main_loop_lock */
362 static void
363 g_main_dispatch (GTimeVal *current_time)
364 {
365   while (pending_dispatches != NULL)
366     {
367       gboolean need_destroy;
368       GSource *source = pending_dispatches->data;
369       GSList *tmp_list;
370
371       tmp_list = pending_dispatches;
372       pending_dispatches = g_slist_remove_link (pending_dispatches, pending_dispatches);
373       g_slist_free_1 (tmp_list);
374
375       if (G_HOOK_IS_VALID (source))
376         {
377           gboolean was_in_call;
378           gpointer hook_data = source->hook.data;
379           gpointer source_data = source->source_data;
380           gboolean (*dispatch) (gpointer,
381                                 GTimeVal *,
382                                 gpointer);
383
384           dispatch = ((GSourceFuncs *) source->hook.func)->dispatch;
385           
386           was_in_call = G_HOOK_IN_CALL (source);
387           source->hook.flags |= G_HOOK_FLAG_IN_CALL;
388
389           G_UNLOCK (main_loop);
390           need_destroy = ! dispatch (source_data,
391                                      current_time,
392                                      hook_data);
393           G_LOCK (main_loop);
394
395           if (!was_in_call)
396             source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
397           
398           if (need_destroy && G_HOOK_IS_VALID (source))
399             {
400               ((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
401               g_hook_destroy_link (&source_list, (GHook *) source);
402             }
403         }
404
405       g_hook_unref (&source_list, (GHook *)source);
406     }
407 }
408
409 /* g_main_iterate () runs a single iteration of the mainloop, or,
410  * if !dispatch checks to see if any sources need dispatching.
411  * basic algorithm for dispatch=TRUE:
412  *
413  * 1) while the list of currently pending sources is non-empty,
414  *    we call (*dispatch) on those that are !IN_CALL or can_recurse,
415  *    removing sources from the list after each returns.
416  *    the return value of (*dispatch) determines whether the source
417  *    itself is kept alive.
418  *
419  * 2) call (*prepare) for sources that are not yet SOURCE_READY and
420  *    are !IN_CALL or can_recurse. a return value of TRUE determines
421  *    that the source would like to be dispatched immediatedly, it
422  *    is then flagged as SOURCE_READY.
423  *
424  * 3) poll with the pollfds from all sources at the priority of the
425  *    first source flagged as SOURCE_READY. if there are any sources
426  *    flagged as SOURCE_READY, we use a timeout of 0 or the minimum
427  *    of all timouts otherwise.
428  *
429  * 4) for each source !IN_CALL or can_recurse, if SOURCE_READY or
430  *    (*check) returns true, add the source to the pending list.
431  *    once one source returns true, stop after checking all sources
432  *    at that priority.
433  *
434  * 5) while the list of currently pending sources is non-empty,
435  *    call (*dispatch) on each source, removing the source
436  *    after the call.
437  *
438  */
439 static gboolean
440 g_main_iterate (gboolean block,
441                 gboolean dispatch)
442 {
443   GHook *hook;
444   GTimeVal current_time  ={ 0, 0 };
445   gint n_ready = 0;
446   gint current_priority = 0;
447   gint timeout;
448   gboolean retval = FALSE;
449
450   g_return_val_if_fail (!block || dispatch, FALSE);
451
452   g_get_current_time (&current_time);
453
454   G_LOCK (main_loop);
455   
456   /* If recursing, finish up current dispatch, before starting over */
457   if (pending_dispatches)
458     {
459       if (dispatch)
460         g_main_dispatch (&current_time);
461       
462       G_UNLOCK (main_loop);
463
464       return TRUE;
465     }
466
467   /* Prepare all sources */
468
469   timeout = block ? -1 : 0;
470   
471   hook = g_hook_first_valid (&source_list, TRUE);
472   while (hook)
473     {
474       GSource *source = (GSource *)hook;
475       GHook *tmp;
476       gint source_timeout = -1;
477
478       if ((n_ready > 0) && (source->priority > current_priority))
479         break;
480       if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
481         {
482           hook = g_hook_next_valid (&source_list, hook, TRUE);
483           continue;
484         }
485
486       g_hook_ref (&source_list, hook);
487       
488       if (hook->flags & G_SOURCE_READY ||
489           ((GSourceFuncs *) hook->func)->prepare (source->source_data,
490                                                   &current_time,
491                                                   &source_timeout))
492         {
493           if (!dispatch)
494             {
495               hook->flags |= G_SOURCE_READY;
496               g_hook_unref (&source_list, hook);
497               G_UNLOCK (main_loop);
498
499               return TRUE;
500             }
501           else
502             {
503               hook->flags |= G_SOURCE_READY;
504               n_ready++;
505               current_priority = source->priority;
506               timeout = 0;
507             }
508         }
509       
510       if (source_timeout >= 0)
511         {
512           if (timeout < 0)
513             timeout = source_timeout;
514           else
515             timeout = MIN (timeout, source_timeout);
516         }
517
518       tmp = g_hook_next_valid (&source_list, hook, TRUE);
519       
520       g_hook_unref (&source_list, hook);
521       hook = tmp;
522     }
523
524   /* poll(), if necessary */
525
526   g_main_poll (timeout, n_ready > 0, current_priority);
527
528   /* Check to see what sources need to be dispatched */
529
530   n_ready = 0;
531   
532   hook = g_hook_first_valid (&source_list, TRUE);
533   while (hook)
534     {
535       GSource *source = (GSource *)hook;
536       GHook *tmp;
537
538       if ((n_ready > 0) && (source->priority > current_priority))
539         break;
540       if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
541         {
542           hook = g_hook_next_valid (&source_list, hook, TRUE);
543           continue;
544         }
545
546       g_hook_ref (&source_list, hook);
547
548       if (hook->flags & G_SOURCE_READY ||
549           ((GSourceFuncs *) hook->func)->check (source->source_data,
550                                                 &current_time))
551         {
552           if (dispatch)
553             {
554               hook->flags &= ~G_SOURCE_READY;
555               g_hook_ref (&source_list, hook);
556               pending_dispatches = g_slist_prepend (pending_dispatches, source);
557               current_priority = source->priority;
558               n_ready++;
559             }
560           else
561             {
562               g_hook_unref (&source_list, hook);
563               G_UNLOCK (main_loop);
564
565               return TRUE;
566             }
567         }
568       
569       tmp = g_hook_next_valid (&source_list, hook, TRUE);
570       
571       g_hook_unref (&source_list, hook);
572       hook = tmp;
573     }
574
575   /* Now invoke the callbacks */
576
577   if (pending_dispatches)
578     {
579       pending_dispatches = g_slist_reverse (pending_dispatches);
580       g_main_dispatch (&current_time);
581       retval = TRUE;
582     }
583
584   G_UNLOCK (main_loop);
585
586   return retval;
587 }
588
589 /* See if any events are pending
590  */
591 gboolean 
592 g_main_pending ()
593 {
594   return g_main_iterate (FALSE, FALSE);
595 }
596
597 /* Run a single iteration of the mainloop. If block is FALSE,
598  * will never block
599  */
600 gboolean
601 g_main_iteration (gboolean block)
602 {
603   return g_main_iterate (block, TRUE);
604 }
605
606 GMainLoop*
607 g_main_new (gboolean is_running)
608 {
609   GMainLoop *loop;
610
611   loop = g_new0 (GMainLoop, 1);
612   loop->is_running = is_running != FALSE;
613
614   return loop;
615 }
616
617 void 
618 g_main_run (GMainLoop *loop)
619 {
620   g_return_if_fail (loop != NULL);
621
622   loop->is_running = TRUE;
623   while (loop->is_running)
624     g_main_iterate (TRUE, TRUE);
625 }
626
627 void 
628 g_main_quit (GMainLoop *loop)
629 {
630   g_return_if_fail (loop != NULL);
631
632   loop->is_running = FALSE;
633 }
634
635 void 
636 g_main_destroy (GMainLoop *loop)
637 {
638   g_return_if_fail (loop != NULL);
639
640   g_free (loop);
641 }
642
643 gboolean
644 g_main_is_running (GMainLoop *loop)
645 {
646   g_return_val_if_fail (loop != NULL, FALSE);
647
648   return loop->is_running;
649 }
650
651 /* HOLDS: main_loop_lock */
652 static void
653 g_main_poll (gint     timeout,
654              gboolean use_priority,
655              gint     priority)
656 {
657   GPollFD *fd_array;
658   GPollRec *pollrec;
659
660   gint i;
661   gint npoll;
662
663   if (wake_up_pipe[0] < 0)
664     {
665       if (pipe (wake_up_pipe) < 0)
666         g_error ("Cannot create pipe main loop wake-up: %s\n",
667                  g_strerror (errno));
668
669       wake_up_rec.fd = wake_up_pipe[0];
670       wake_up_rec.events = G_IO_IN;
671       g_main_add_poll_unlocked (0, &wake_up_rec);
672     }
673   
674   fd_array = g_new (GPollFD, n_poll_records);
675  
676   pollrec = poll_records;
677   i = 0;
678   while (pollrec && (!use_priority || priority >= pollrec->priority))
679     {
680       fd_array[i].fd = pollrec->fd->fd;
681       fd_array[i].events = pollrec->fd->events;
682       fd_array[i].revents = 0;
683         
684       pollrec = pollrec->next;
685       i++;
686     }
687
688   poll_waiting = TRUE;
689   
690   G_UNLOCK (main_loop);
691   npoll = i;
692   (*poll_func) (fd_array, npoll, timeout);
693   G_LOCK (main_loop);
694
695   if (!poll_waiting)
696     {
697       gchar c;
698       read (wake_up_pipe[0], &c, 1);
699     }
700   else
701     poll_waiting = FALSE;
702
703   pollrec = poll_records;
704   i = 0;
705   while (i < npoll)
706     {
707       pollrec->fd->revents = fd_array[i].revents;
708       pollrec = pollrec->next;
709       i++;
710     }
711
712   g_free (fd_array);
713 }
714
715 void 
716 g_main_add_poll (GPollFD *fd,
717                  gint     priority)
718 {
719   G_LOCK (main_loop);
720   g_main_add_poll_unlocked (priority, fd);
721   G_UNLOCK (main_loop);
722 }
723
724 /* HOLDS: main_loop_lock */
725 static void 
726 g_main_add_poll_unlocked (gint     priority,
727                           GPollFD *fd)
728 {
729   GPollRec *lastrec, *pollrec, *newrec;
730
731   if (!poll_chunk)
732     poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
733
734   if (poll_free_list)
735     {
736       newrec = poll_free_list;
737       poll_free_list = newrec->next;
738     }
739   else
740     newrec = g_chunk_new (GPollRec, poll_chunk);
741
742   newrec->fd = fd;
743   newrec->priority = priority;
744
745   lastrec = NULL;
746   pollrec = poll_records;
747   while (pollrec && priority >= pollrec->priority)
748     {
749       lastrec = pollrec;
750       pollrec = pollrec->next;
751     }
752   
753   if (lastrec)
754     lastrec->next = newrec;
755   else
756     poll_records = newrec;
757
758   newrec->next = pollrec;
759
760   n_poll_records++;
761 }
762
763 void 
764 g_main_remove_poll (GPollFD *fd)
765 {
766   GPollRec *pollrec, *lastrec;
767
768   G_LOCK (main_loop);
769   
770   lastrec = NULL;
771   pollrec = poll_records;
772
773   while (pollrec)
774     {
775       if (pollrec->fd == fd)
776         {
777           if (lastrec != NULL)
778             lastrec->next = pollrec->next;
779           else
780             poll_records = pollrec->next;
781
782           pollrec->next = poll_free_list;
783           poll_free_list = pollrec;
784
785           n_poll_records--;
786           break;
787         }
788       lastrec = pollrec;
789       pollrec = pollrec->next;
790     }
791
792   G_UNLOCK (main_loop);
793 }
794
795 void 
796 g_main_set_poll_func (GPollFunc func)
797 {
798   if (func)
799     poll_func = func;
800   else
801 #ifdef HAVE_POLL
802     poll_func = (GPollFunc)poll;
803 #else
804     poll_func = (GPollFunc)g_poll;
805 #endif
806 }
807
808 /* Timeouts */
809
810 static gboolean 
811 g_timeout_prepare  (gpointer source_data, 
812                     GTimeVal *current_time,
813                     gint    *timeout)
814 {
815   glong msec;
816   GTimeoutData *data = source_data;
817
818   msec = (data->expiration.tv_sec  - current_time->tv_sec) * 1000 +
819          (data->expiration.tv_usec - current_time->tv_usec) / 1000;
820
821   *timeout = (msec <= 0) ? 0 : msec;
822
823   return (msec <= 0);
824 }
825
826 static gboolean 
827 g_timeout_check    (gpointer source_data,
828                     GTimeVal *current_time)
829 {
830   GTimeoutData *data = source_data;
831
832   return (data->expiration.tv_sec < current_time->tv_sec) ||
833          ((data->expiration.tv_sec == current_time->tv_sec) &&
834           (data->expiration.tv_usec <= current_time->tv_usec));
835 }
836
837 static gboolean
838 g_timeout_dispatch (gpointer source_data, 
839                     GTimeVal *current_time,
840                     gpointer user_data)
841 {
842   GTimeoutData *data = source_data;
843
844   if (data->callback(user_data))
845     {
846       guint seconds = data->interval / 1000;
847       guint msecs = data->interval - seconds * 1000;
848
849       data->expiration.tv_sec = current_time->tv_sec + seconds;
850       data->expiration.tv_usec = current_time->tv_usec + msecs * 1000;
851       if (data->expiration.tv_usec >= 1000000)
852         {
853           data->expiration.tv_usec -= 1000000;
854           data->expiration.tv_sec++;
855         }
856       return TRUE;
857     }
858   else
859     return FALSE;
860 }
861
862 guint 
863 g_timeout_add_full (gint           priority,
864                     guint          interval, 
865                     GSourceFunc    function,
866                     gpointer       data,
867                     GDestroyNotify notify)
868 {
869   guint seconds;
870   guint msecs;
871   GTimeoutData *timeout_data = g_new (GTimeoutData, 1);
872
873   timeout_data->interval = interval;
874   timeout_data->callback = function;
875   g_get_current_time (&timeout_data->expiration);
876
877   seconds = timeout_data->interval / 1000;
878   msecs = timeout_data->interval - seconds * 1000;
879
880   timeout_data->expiration.tv_sec += seconds;
881   timeout_data->expiration.tv_usec += msecs * 1000;
882   if (timeout_data->expiration.tv_usec >= 1000000)
883     {
884       timeout_data->expiration.tv_usec -= 1000000;
885       timeout_data->expiration.tv_sec++;
886     }
887
888   return g_source_add (priority, FALSE, &timeout_funcs, timeout_data, data, notify);
889 }
890
891 guint 
892 g_timeout_add (guint32        interval,
893                GSourceFunc    function,
894                gpointer       data)
895 {
896   return g_timeout_add_full (G_PRIORITY_DEFAULT, 
897                              interval, function, data, NULL);
898 }
899
900 /* Idle functions */
901
902 static gboolean 
903 g_idle_prepare  (gpointer source_data, 
904                  GTimeVal *current_time,
905                  gint     *timeout)
906 {
907   timeout = 0;
908   return TRUE;
909 }
910
911 static gboolean 
912 g_idle_check    (gpointer  source_data,
913                  GTimeVal *current_time)
914 {
915   return TRUE;
916 }
917
918 static gboolean
919 g_idle_dispatch (gpointer source_data, 
920                  GTimeVal *current_time,
921                  gpointer user_data)
922 {
923   GIdleData *data = source_data;
924
925   return (*data->callback)(user_data);
926 }
927
928 guint 
929 g_idle_add_full (gint          priority,
930                  GSourceFunc    function,
931                  gpointer       data,
932                  GDestroyNotify notify)
933 {
934   GIdleData *idle_data = g_new (GIdleData, 1);
935
936   idle_data->callback = function;
937
938   return g_source_add (priority, FALSE, &idle_funcs, idle_data, data, notify);
939 }
940
941 guint 
942 g_idle_add (GSourceFunc    function,
943             gpointer       data)
944 {
945   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
946 }