45e1e0d68420400ff7534ab2df950ac58d468a9a
[ardour.git] / libs / glibmm2 / glibmm / main.cc
1 // -*- c++ -*-
2 /* $Id$ */
3
4 /* Copyright (C) 2002 The gtkmm Development Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <glibmm/main.h>
22 #include <glibmm/exceptionhandler.h>
23 #include <glibmm/thread.h>
24 #include <glibmm/wrap.h>
25 #include <glibmm/iochannel.h>
26
27 #include <glib/gmessages.h>
28 #include <algorithm>
29
30 GLIBMM_USING_STD(min)
31
32
33 namespace
34 {
35
36 class SourceConnectionNode
37 {
38 public:
39   explicit inline SourceConnectionNode(const sigc::slot_base& slot);
40
41   static void* notify(void* data);
42   static void  destroy_notify_callback(void* data);
43
44   inline void install(GSource* source);
45   inline sigc::slot_base* get_slot();
46
47 private:
48   sigc::slot_base slot_;
49   GSource* source_;
50 };
51
52 inline
53 SourceConnectionNode::SourceConnectionNode(const sigc::slot_base& slot)
54 :
55   slot_ (slot),
56   source_ (0)
57 {
58   slot_.set_parent(this, &SourceConnectionNode::notify);
59 }
60
61 void* SourceConnectionNode::notify(void* data)
62 {
63   SourceConnectionNode *const self = static_cast<SourceConnectionNode*>(data);
64
65   // if there is no object, this call was triggered from destroy_notify_handler(),
66   // because we set self->source_ to 0 there:
67   if (self->source_)
68   {
69     GSource* s = self->source_;  
70     self->source_ = 0;
71     g_source_destroy(s);
72
73     // Destroying the object triggers execution of destroy_notify_handler(),
74     // eiter immediately or later, so we leave that to do the deletion.
75   }
76
77   return 0;
78 }
79
80 // static
81 void SourceConnectionNode::destroy_notify_callback(void* data)
82 {
83   SourceConnectionNode *const self = static_cast<SourceConnectionNode*>(data);
84
85   if (self)
86   {
87     // The GLib side is disconnected now, thus the GSource* is no longer valid.
88     self->source_ = 0;
89
90     delete self;
91   }
92 }
93
94 inline
95 void SourceConnectionNode::install(GSource* source)
96 {
97   source_ = source;
98 }
99
100 inline
101 sigc::slot_base* SourceConnectionNode::get_slot()
102 {
103   return &slot_;
104 }
105
106
107 /* We use the callback data member of GSource to store both a pointer to our
108  * wrapper and a pointer to the connection node that is currently being used.
109  * The one and only SourceCallbackData object of a Glib::Source is constructed
110  * in the ctor of Glib::Source and destroyed after the GSource object when the
111  * reference counter of the GSource object reaches zero!
112  */
113 struct SourceCallbackData
114 {
115   explicit inline SourceCallbackData(Glib::Source* wrapper_);
116
117   void set_node(SourceConnectionNode* node_);
118
119   static void destroy_notify_callback(void* data);
120
121   Glib::Source* wrapper;
122   SourceConnectionNode* node;
123 };
124
125 inline
126 SourceCallbackData::SourceCallbackData(Glib::Source* wrapper_)
127 :
128   wrapper (wrapper_),
129   node    (0)
130 {}
131
132 void SourceCallbackData::set_node(SourceConnectionNode* node_)
133 {
134   if(node)
135     SourceConnectionNode::destroy_notify_callback(node);
136
137   node = node_;
138 }
139
140 // static
141 void SourceCallbackData::destroy_notify_callback(void* data)
142 {
143   SourceCallbackData *const self = static_cast<SourceCallbackData*>(data);
144
145   if(self->node)
146     SourceConnectionNode::destroy_notify_callback(self->node);
147
148   if(self->wrapper)
149     Glib::Source::destroy_notify_callback(self->wrapper);
150
151   delete self;
152 }
153
154
155 /* Retrieve the callback data from a wrapped GSource object.
156  */
157 static SourceCallbackData* glibmm_source_get_callback_data(GSource* source)
158 {
159   g_return_val_if_fail(source->callback_funcs->get != 0, 0);
160
161   GSourceFunc func;
162   void* user_data = 0;
163
164   // Retrieve the callback function and data.
165   (*source->callback_funcs->get)(source->callback_data, source, &func, &user_data);
166
167   return static_cast<SourceCallbackData*>(user_data);
168 }
169
170 /* Glib::Source doesn't use the callback function installed with
171  * g_source_set_callback().  Instead, it invokes the sigc++ slot
172  * directly from dispatch_vfunc(), which is both simpler and more
173  * efficient.
174  * For correctness, provide a pointer to this dummy callback rather
175  * than some random pointer.  That also allows for sanity checks
176  * here as well as in Source::dispatch_vfunc().
177  */
178 static gboolean glibmm_dummy_source_callback(void*)
179 {
180   g_assert_not_reached();
181   return 0;
182 }
183
184 /* Only used by SignalTimeout::connect() and SignalIdle::connect().
185  * These don't use Glib::Source, to avoid the unnecessary overhead
186  * of a completely unused wrapper object.
187  */
188 static gboolean glibmm_source_callback(void* data)
189 {
190   SourceConnectionNode *const conn_data = static_cast<SourceConnectionNode*>(data);
191
192   try
193   {
194     // Recreate the specific slot from the generic slot node.
195     return (*static_cast<sigc::slot<bool>*>(conn_data->get_slot()))();
196   }
197   catch(...)
198   {
199     Glib::exception_handlers_invoke();
200   }
201   return 0;
202 }
203
204 static gboolean glibmm_iosource_callback(GIOChannel*, GIOCondition condition, void* data)
205 {
206   SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(data);
207   g_return_val_if_fail(callback_data->node != 0, 0);
208
209   try
210   {
211     // Recreate the specific slot from the generic slot node.
212     return (*static_cast<sigc::slot<bool,Glib::IOCondition>*>(callback_data->node->get_slot()))
213                                   ((Glib::IOCondition) condition);
214   }
215   catch(...)
216   {
217     Glib::exception_handlers_invoke();
218   }
219   return 0;
220 }
221
222 } // anonymous namespace
223
224
225 namespace Glib
226 {
227
228 /**** Glib::PollFD *********************************************************/
229
230 PollFD::PollFD()
231 {
232   gobject_.fd      = 0;
233   gobject_.events  = 0;
234   gobject_.revents = 0;
235 }
236
237 PollFD::PollFD(int fd)
238 {
239   gobject_.fd      = fd;
240   gobject_.events  = 0;
241   gobject_.revents = 0;
242 }
243
244 PollFD::PollFD(int fd, IOCondition events)
245 {
246   gobject_.fd      = fd;
247   gobject_.events  = events;
248   gobject_.revents = 0;
249 }
250
251
252 /**** Glib::SignalTimeout **************************************************/
253
254 inline
255 SignalTimeout::SignalTimeout(GMainContext* context)
256 :
257   context_ (context)
258 {}
259
260 sigc::connection SignalTimeout::connect(const sigc::slot<bool>& slot,
261                                         unsigned int interval, int priority)
262 {
263   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
264   const sigc::connection connection (*conn_node->get_slot());
265
266   GSource *const source = g_timeout_source_new(interval);
267
268   if(priority != G_PRIORITY_DEFAULT)
269     g_source_set_priority(source, priority);
270
271   g_source_set_callback(
272       source, &glibmm_source_callback, conn_node,
273       &SourceConnectionNode::destroy_notify_callback);
274
275   g_source_attach(source, context_);
276   g_source_unref(source); // GMainContext holds a reference
277
278   conn_node->install(source);
279   return connection;
280 }
281
282 SignalTimeout signal_timeout()
283 {
284   return SignalTimeout(0); // 0 means default context
285 }
286
287
288 /**** Glib::SignalIdle *****************************************************/
289
290 inline
291 SignalIdle::SignalIdle(GMainContext* context)
292 :
293   context_ (context)
294 {}
295
296 sigc::connection SignalIdle::connect(const sigc::slot<bool>& slot, int priority)
297 {
298   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
299   const sigc::connection connection (*conn_node->get_slot());
300
301   GSource *const source = g_idle_source_new();
302
303   if(priority != G_PRIORITY_DEFAULT)
304     g_source_set_priority(source, priority);
305
306   g_source_set_callback(
307       source, &glibmm_source_callback, conn_node,
308       &SourceConnectionNode::destroy_notify_callback);
309
310   g_source_attach(source, context_);
311   g_source_unref(source); // GMainContext holds a reference
312
313   conn_node->install(source);
314   return connection;
315 }
316
317 SignalIdle signal_idle()
318 {
319   return SignalIdle(0); // 0 means default context
320 }
321
322
323 /**** Glib::SignalIO *******************************************************/
324
325 inline
326 SignalIO::SignalIO(GMainContext* context)
327 :
328   context_ (context)
329 {}
330
331 sigc::connection SignalIO::connect(const sigc::slot<bool,IOCondition>& slot,
332                                    int fd, IOCondition condition, int priority)
333 {
334   const Glib::RefPtr<IOSource> source = IOSource::create(fd, condition);
335
336   if(priority != G_PRIORITY_DEFAULT)
337     source->set_priority(priority);
338
339   const sigc::connection connection = source->connect(slot);
340
341   g_source_attach(source->gobj(), context_);
342
343   return connection;
344 }
345
346 sigc::connection SignalIO::connect(const sigc::slot<bool,IOCondition>& slot,
347                                    const Glib::RefPtr<IOChannel>& channel,
348                                    IOCondition condition, int priority)
349 {
350   const Glib::RefPtr<IOSource> source = IOSource::create(channel, condition);
351
352   if(priority != G_PRIORITY_DEFAULT)
353     source->set_priority(priority);
354
355   const sigc::connection connection = source->connect(slot);
356
357   g_source_attach(source->gobj(), context_);
358
359   return connection;
360 }
361
362 SignalIO signal_io()
363 {
364   return SignalIO(0); // 0 means default context
365 }
366
367
368 /**** Glib::MainContext ****************************************************/
369
370 // static
371 Glib::RefPtr<MainContext> MainContext::create()
372 {
373   return Glib::RefPtr<MainContext>(reinterpret_cast<MainContext*>(g_main_context_new()));
374 }
375
376 // static
377 Glib::RefPtr<MainContext> MainContext::get_default()
378 {
379   return Glib::wrap(g_main_context_default(), true);
380 }
381
382 bool MainContext::iteration(bool may_block)
383 {
384   return g_main_context_iteration(gobj(), may_block);
385 }
386
387 bool MainContext::pending()
388 {
389   return g_main_context_pending(gobj());
390 }
391
392 void MainContext::wakeup()
393 {
394   g_main_context_wakeup(gobj());
395 }
396
397 bool MainContext::acquire()
398 {
399   return g_main_context_acquire(gobj());
400 }
401
402 bool MainContext::wait(Glib::Cond& cond, Glib::Mutex& mutex)
403 {
404   return g_main_context_wait(gobj(), cond.gobj(), mutex.gobj());
405 }
406
407 void MainContext::release()
408 {
409   g_main_context_release(gobj());
410 }
411
412 bool MainContext::prepare(int& priority)
413 {
414   return g_main_context_prepare(gobj(), &priority);
415 }
416
417 bool MainContext::prepare()
418 {
419   return g_main_context_prepare(gobj(), 0);
420 }
421
422 void MainContext::query(int max_priority, int& timeout, std::vector<PollFD>& fds)
423 {
424   if(fds.empty())
425     fds.resize(8); // rather bogus number, but better than 0
426
427   for(;;)
428   {
429     const int size_before = fds.size();
430     const int size_needed = g_main_context_query(
431         gobj(), max_priority, &timeout, reinterpret_cast<GPollFD*>(&fds.front()), size_before);
432
433     fds.resize(size_needed);
434
435     if(size_needed <= size_before)
436       break;
437   }
438 }
439
440 bool MainContext::check(int max_priority, std::vector<PollFD>& fds)
441 {
442   if(!fds.empty())
443     return g_main_context_check(gobj(), max_priority, reinterpret_cast<GPollFD*>(&fds.front()), fds.size());
444   else
445     return false;
446 }
447
448 void MainContext::dispatch()
449 {
450   g_main_context_dispatch(gobj());
451 }
452
453 void MainContext::set_poll_func(GPollFunc poll_func)
454 {
455   g_main_context_set_poll_func(gobj(), poll_func);
456 }
457
458 GPollFunc MainContext::get_poll_func()
459 {
460   return g_main_context_get_poll_func(gobj());
461 }
462
463 void MainContext::add_poll(PollFD& fd, int priority)
464 {
465   g_main_context_add_poll(gobj(), fd.gobj(), priority);
466 }
467
468 void MainContext::remove_poll(PollFD& fd)
469 {
470   g_main_context_remove_poll(gobj(), fd.gobj());
471 }
472
473 SignalTimeout MainContext::signal_timeout()
474 {
475   return SignalTimeout(gobj());
476 }
477
478 SignalIdle MainContext::signal_idle()
479 {
480   return SignalIdle(gobj());
481 }
482
483 SignalIO MainContext::signal_io()
484 {
485   return SignalIO(gobj());
486 }
487
488 void MainContext::reference() const
489 {
490   g_main_context_ref(reinterpret_cast<GMainContext*>(const_cast<MainContext*>(this)));
491 }
492
493 void MainContext::unreference() const
494 {
495   g_main_context_unref(reinterpret_cast<GMainContext*>(const_cast<MainContext*>(this)));
496 }
497
498 GMainContext* MainContext::gobj()
499 {
500   return reinterpret_cast<GMainContext*>(this);
501 }
502
503 const GMainContext* MainContext::gobj() const
504 {
505   return reinterpret_cast<const GMainContext*>(this);
506 }
507
508 GMainContext* MainContext::gobj_copy() const
509 {
510   reference();
511   return const_cast<GMainContext*>(gobj());
512 }
513
514 Glib::RefPtr<MainContext> wrap(GMainContext* gobject, bool take_copy)
515 {
516   if(take_copy && gobject)
517     g_main_context_ref(gobject);
518
519   return Glib::RefPtr<MainContext>(reinterpret_cast<MainContext*>(gobject));
520 }
521
522
523 /**** Glib::MainLoop *******************************************************/
524
525 Glib::RefPtr<MainLoop> MainLoop::create(bool is_running)
526 {
527   return Glib::RefPtr<MainLoop>(
528       reinterpret_cast<MainLoop*>(g_main_loop_new(0, is_running)));
529 }
530
531 Glib::RefPtr<MainLoop> MainLoop::create(const Glib::RefPtr<MainContext>& context, bool is_running)
532 {
533   return Glib::RefPtr<MainLoop>(
534       reinterpret_cast<MainLoop*>(g_main_loop_new(Glib::unwrap(context), is_running)));
535 }
536
537 void MainLoop::run()
538 {
539   g_main_loop_run(gobj());
540 }
541
542 void MainLoop::quit()
543 {
544   g_main_loop_quit(gobj());
545 }
546
547 bool MainLoop::is_running()
548 {
549   return g_main_loop_is_running(gobj());
550 }
551
552 Glib::RefPtr<MainContext> MainLoop::get_context()
553 {
554   return Glib::wrap(g_main_loop_get_context(gobj()), true);
555 }
556
557 //static:
558 int MainLoop::depth()
559 {
560   return g_main_depth();
561 }                                             
562
563 void MainLoop::reference() const
564 {
565   g_main_loop_ref(reinterpret_cast<GMainLoop*>(const_cast<MainLoop*>(this)));
566 }
567
568 void MainLoop::unreference() const
569 {
570   g_main_loop_unref(reinterpret_cast<GMainLoop*>(const_cast<MainLoop*>(this)));
571 }
572
573 GMainLoop* MainLoop::gobj()
574 {
575   return reinterpret_cast<GMainLoop*>(this);
576 }
577
578 const GMainLoop* MainLoop::gobj() const
579 {
580   return reinterpret_cast<const GMainLoop*>(this);
581 }
582
583 GMainLoop* MainLoop::gobj_copy() const
584 {
585   reference();
586   return const_cast<GMainLoop*>(gobj());
587 }
588
589 Glib::RefPtr<MainLoop> wrap(GMainLoop* gobject, bool take_copy)
590 {
591   if(take_copy && gobject)
592     g_main_loop_ref(gobject);
593
594   return Glib::RefPtr<MainLoop>(reinterpret_cast<MainLoop*>(gobject));
595 }
596
597
598 /**** Glib::Source *********************************************************/
599
600 // static
601 const GSourceFuncs Source::vfunc_table_ =
602 {
603   &Source::prepare_vfunc,
604   &Source::check_vfunc,
605   &Source::dispatch_vfunc,
606   0, // finalize_vfunc // We can't use finalize_vfunc because there is no way
607                        // to store a pointer to our wrapper anywhere in GSource so
608                        // that it persists until finalize_vfunc would be called from here.
609   0, // closure_callback
610   0, // closure_marshal
611 };
612
613 unsigned int Source::attach(const Glib::RefPtr<MainContext>& context)
614 {
615   return g_source_attach(gobject_, Glib::unwrap(context));
616 }
617
618 unsigned int Source::attach()
619 {
620   return g_source_attach(gobject_, 0);
621 }
622
623 void Source::destroy()
624 {
625   g_source_destroy(gobject_);
626 }
627
628 void Source::set_priority(int priority)
629 {
630   g_source_set_priority(gobject_, priority);
631 }
632
633 int Source::get_priority() const
634 {
635   return g_source_get_priority(gobject_);
636 }
637
638 void Source::set_can_recurse(bool can_recurse)
639 {
640   g_source_set_can_recurse(gobject_, can_recurse);
641 }
642
643 bool Source::get_can_recurse() const
644 {
645   return g_source_get_can_recurse(gobject_);
646 }
647
648 unsigned int Source::get_id() const
649 {
650   return g_source_get_id(gobject_);
651 }
652
653 Glib::RefPtr<MainContext> Source::get_context()
654 {
655   return Glib::wrap(g_source_get_context(gobject_), true);
656 }
657
658 GSource* Source::gobj_copy() const
659 {
660   return g_source_ref(gobject_);
661 }
662
663 void Source::reference() const
664 {
665   g_source_ref(gobject_);
666 }
667
668 void Source::unreference() const
669 {
670   g_source_unref(gobject_);
671 }
672
673 Source::Source()
674 :
675   gobject_ (g_source_new(const_cast<GSourceFuncs*>(&vfunc_table_), sizeof(GSource)))
676 {
677   g_source_set_callback(
678       gobject_, &glibmm_dummy_source_callback,
679       new SourceCallbackData(this), // our persistant callback data object
680       &SourceCallbackData::destroy_notify_callback);
681 }
682
683 Source::Source(GSource* cast_item, GSourceFunc callback_func)
684 :
685   gobject_ (cast_item)
686 {
687   g_source_set_callback(
688       gobject_, callback_func,
689       new SourceCallbackData(this), // our persistant callback data object
690       &SourceCallbackData::destroy_notify_callback);
691 }
692
693 Source::~Source()
694 {
695   // The dtor should be invoked by destroy_notify_callback() only, which clears
696   // gobject_ before deleting.  However, we might also get to this point if
697   // a derived ctor threw an exception, and then we need to unref manually.
698
699   if(gobject_)
700   {
701     SourceCallbackData *const data = glibmm_source_get_callback_data(gobject_);
702     data->wrapper = 0;
703
704     GSource *const tmp_gobject = gobject_;
705     gobject_ = 0;
706
707     g_source_unref(tmp_gobject);
708   }
709 }
710
711 sigc::connection Source::connect_generic(const sigc::slot_base& slot)
712 {
713   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
714   const sigc::connection connection (*conn_node->get_slot());
715
716   // Don't override the callback data.  Reuse the existing one
717   // calling SourceCallbackData::set_node() to register conn_node.
718   SourceCallbackData *const data = glibmm_source_get_callback_data(gobject_);
719   data->set_node(conn_node);
720
721   conn_node->install(gobject_);
722   return connection;
723 }
724
725 void Source::add_poll(Glib::PollFD& poll_fd)
726 {
727   g_source_add_poll(gobject_, poll_fd.gobj());
728 }
729
730 void Source::remove_poll(Glib::PollFD& poll_fd)
731 {
732   g_source_remove_poll(gobject_, poll_fd.gobj());
733 }
734
735 void Source::get_current_time(Glib::TimeVal& current_time)
736 {
737   g_source_get_current_time(gobject_, &current_time);
738 }
739
740 inline // static
741 Source* Source::get_wrapper(GSource* source)
742 {
743   SourceCallbackData *const data = glibmm_source_get_callback_data(source);
744   return data->wrapper;
745 }
746
747 // static
748 gboolean Source::prepare_vfunc(GSource* source, int* timeout)
749 {
750   try
751   {
752     Source *const self = get_wrapper(source);
753     return self->prepare(*timeout);
754   }
755   catch(...)
756   {
757     Glib::exception_handlers_invoke();
758   }
759   return 0;
760 }
761
762 // static
763 gboolean Source::check_vfunc(GSource* source)
764 {
765   try
766   {
767     Source *const self = get_wrapper(source);
768     return self->check();
769   }
770   catch(...)
771   {
772     Glib::exception_handlers_invoke();
773   }
774   return 0;
775 }
776
777 // static
778 gboolean Source::dispatch_vfunc(GSource*, GSourceFunc callback, void* user_data)
779 {
780   SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(user_data);
781
782   g_return_val_if_fail(callback == &glibmm_dummy_source_callback, 0);
783   g_return_val_if_fail(callback_data != 0 && callback_data->node != 0, 0);
784
785   try
786   {
787     Source *const self = callback_data->wrapper;
788     return self->dispatch(callback_data->node->get_slot());
789   }
790   catch(...)
791   {
792     Glib::exception_handlers_invoke();
793   }
794   return 0;
795 }
796
797 // static
798 void Source::destroy_notify_callback(void* data)
799 {
800   if(data)
801   {
802     Source *const self = static_cast<Source*>(data);
803
804     // gobject_ is already invalid at this point.
805     self->gobject_ = 0;
806
807     // No exception checking: if the dtor throws, you're out of luck anyway.
808     delete self;
809   }
810 }
811
812
813 /**** Glib::TimeoutSource **************************************************/
814
815 // static
816 Glib::RefPtr<TimeoutSource> TimeoutSource::create(unsigned int interval)
817 {
818   return Glib::RefPtr<TimeoutSource>(new TimeoutSource(interval));
819 }
820
821 sigc::connection TimeoutSource::connect(const sigc::slot<bool>& slot)
822 {
823   return connect_generic(slot);
824 }
825
826 TimeoutSource::TimeoutSource(unsigned int interval)
827 :
828   interval_ (interval)
829 {
830   expiration_.assign_current_time();
831   expiration_.add_milliseconds(std::min<unsigned long>(G_MAXLONG, interval_));
832 }
833
834 TimeoutSource::~TimeoutSource()
835 {}
836
837 bool TimeoutSource::prepare(int& timeout)
838 {
839   Glib::TimeVal current_time;
840   get_current_time(current_time);
841
842   Glib::TimeVal remaining = expiration_;
843   remaining.subtract(current_time);
844
845   if(remaining.negative())
846   {
847     // Already expired.
848     timeout = 0;
849   }
850   else
851   {
852     const unsigned long milliseconds =
853         static_cast<unsigned long>(remaining.tv_sec)  * 1000U +
854         static_cast<unsigned long>(remaining.tv_usec) / 1000U;
855
856     // Set remaining milliseconds.
857     timeout = std::min<unsigned long>(G_MAXINT, milliseconds);
858
859     // Check if the system time has been set backwards. (remaining > interval)
860     remaining.add_milliseconds(- std::min<unsigned long>(G_MAXLONG, interval_) - 1);
861     if(!remaining.negative())
862     {
863       // Oh well.  Reset the expiration time to now + interval;
864       // this at least avoids hanging for long periods of time.
865       expiration_ = current_time;
866       expiration_.add_milliseconds(interval_);
867       timeout = std::min<unsigned int>(G_MAXINT, interval_);
868     }
869   }
870
871   return (timeout == 0);
872 }
873
874 bool TimeoutSource::check()
875 {
876   Glib::TimeVal current_time;
877   get_current_time(current_time);
878
879   return (expiration_ <= current_time);
880 }
881
882 bool TimeoutSource::dispatch(sigc::slot_base* slot)
883 {
884   const bool again = (*static_cast<sigc::slot<bool>*>(slot))();
885
886   if(again)
887   {
888     get_current_time(expiration_);
889     expiration_.add_milliseconds(std::min<unsigned long>(G_MAXLONG, interval_));
890   }
891
892   return again;
893 }
894
895
896 /**** Glib::IdleSource *****************************************************/
897
898 // static
899 Glib::RefPtr<IdleSource> IdleSource::create()
900 {
901   return Glib::RefPtr<IdleSource>(new IdleSource());
902 }
903
904 sigc::connection IdleSource::connect(const sigc::slot<bool>& slot)
905 {
906   return connect_generic(slot);
907 }
908
909 IdleSource::IdleSource()
910 {
911   set_priority(PRIORITY_DEFAULT_IDLE);
912 }
913
914 IdleSource::~IdleSource()
915 {}
916
917 bool IdleSource::prepare(int& timeout)
918 {
919   timeout = 0;
920   return true;
921 }
922
923 bool IdleSource::check()
924 {
925   return true;
926 }
927
928 bool IdleSource::dispatch(sigc::slot_base* slot)
929 {
930   return (*static_cast<sigc::slot<bool>*>(slot))();
931 }
932
933
934 /**** Glib::IOSource *******************************************************/
935
936 // static
937 Glib::RefPtr<IOSource> IOSource::create(int fd, IOCondition condition)
938 {
939   return Glib::RefPtr<IOSource>(new IOSource(fd, condition));
940 }
941
942 Glib::RefPtr<IOSource> IOSource::create(const Glib::RefPtr<IOChannel>& channel, IOCondition condition)
943 {
944   return Glib::RefPtr<IOSource>(new IOSource(channel, condition));
945 }
946
947 sigc::connection IOSource::connect(const sigc::slot<bool,IOCondition>& slot)
948 {
949   return connect_generic(slot);
950 }
951
952 IOSource::IOSource(int fd, IOCondition condition)
953 :
954   poll_fd_ (fd, condition)
955 {
956   add_poll(poll_fd_);
957 }
958
959 IOSource::IOSource(const Glib::RefPtr<IOChannel>& channel, IOCondition condition)
960 :
961   Source(g_io_create_watch(channel->gobj(), (GIOCondition) condition),
962          (GSourceFunc) &glibmm_iosource_callback)
963 {}
964
965 IOSource::~IOSource()
966 {}
967
968 bool IOSource::prepare(int& timeout)
969 {
970   timeout = -1;
971   return false;
972 }
973
974 bool IOSource::check()
975 {
976   return ((poll_fd_.get_revents() & poll_fd_.get_events()) != 0);
977 }
978
979 bool IOSource::dispatch(sigc::slot_base* slot)
980 {
981   return (*static_cast<sigc::slot<bool,IOCondition>*>(slot))
982                                  (poll_fd_.get_revents());
983 }
984
985 } // namespace Glib
986