add new sigc++2 directory
[ardour.git] / libs / glibmm2 / glib / glibmm / main.cc
1 // -*- c++ -*-
2 /* $Id: main.cc 420 2007-06-22 15:29:58Z murrayc $ */
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.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   #ifdef GLIBMM_EXCEPTIONS_ENABLED
193   try
194   {
195   #endif //GLIBMM_EXCEPTIONS_ENABLED
196     // Recreate the specific slot from the generic slot node.
197     return (*static_cast<sigc::slot<bool>*>(conn_data->get_slot()))();
198   #ifdef GLIBMM_EXCEPTIONS_ENABLED
199   }
200   catch(...)
201   {
202     Glib::exception_handlers_invoke();
203   }
204   #endif //GLIBMM_EXCEPTIONS_ENABLED
205   return 0;
206 }
207
208 static gboolean glibmm_iosource_callback(GIOChannel*, GIOCondition condition, void* data)
209 {
210   SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(data);
211   g_return_val_if_fail(callback_data->node != 0, 0);
212
213   #ifdef GLIBMM_EXCEPTIONS_ENABLED
214   try
215   {
216   #endif //GLIBMM_EXCEPTIONS_ENABLED
217     // Recreate the specific slot from the generic slot node.
218     return (*static_cast<sigc::slot<bool, Glib::IOCondition>*>(callback_data->node->get_slot()))
219                                   ((Glib::IOCondition) condition);
220   #ifdef GLIBMM_EXCEPTIONS_ENABLED
221   }
222   catch(...)
223   {
224     Glib::exception_handlers_invoke();
225   }
226   #endif //GLIBMM_EXCEPTIONS_ENABLED
227   return 0;
228 }
229
230 /* Only used by SignalChildWatch::connect().
231  * These don't use Glib::Source, to avoid the unnecessary overhead
232  * of a completely unused wrapper object.
233  */
234 static gboolean glibmm_child_watch_callback(GPid pid, gint child_status, void* data)
235 {
236   SourceConnectionNode *const conn_data = static_cast<SourceConnectionNode*>(data);
237
238   #ifdef GLIBMM_EXCEPTIONS_ENABLED
239   try {
240   #endif //GLIBMM_EXCEPTIONS_ENABLED
241     //Recreate the specific slot from the generic slot node.
242     (*static_cast<sigc::slot<void, GPid, int>*>(conn_data->get_slot()))(pid, child_status);
243   #ifdef GLIBMM_EXCEPTIONS_ENABLED
244   }
245   catch(...)
246   {
247     Glib::exception_handlers_invoke();
248   }
249   #endif //GLIBMM_EXCEPTIONS_ENABLED
250   return 0;
251 }
252
253 } // anonymous namespace
254
255
256 namespace Glib
257 {
258
259 /**** Glib::PollFD *********************************************************/
260
261 PollFD::PollFD()
262 {
263   gobject_.fd      = 0;
264   gobject_.events  = 0;
265   gobject_.revents = 0;
266 }
267
268 PollFD::PollFD(int fd)
269 {
270   gobject_.fd      = fd;
271   gobject_.events  = 0;
272   gobject_.revents = 0;
273 }
274
275 PollFD::PollFD(int fd, IOCondition events)
276 {
277   gobject_.fd      = fd;
278   gobject_.events  = events;
279   gobject_.revents = 0;
280 }
281
282
283 /**** Glib::SignalTimeout **************************************************/
284
285 inline
286 SignalTimeout::SignalTimeout(GMainContext* context)
287 :
288   context_ (context)
289 {}
290
291 /* Note that this is our equivalent of g_timeout_add(). */
292 sigc::connection SignalTimeout::connect(const sigc::slot<bool>& slot,
293                                         unsigned int interval, int priority)
294 {
295   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
296   const sigc::connection connection (*conn_node->get_slot());
297
298   GSource *const source = g_timeout_source_new(interval);
299
300   if(priority != G_PRIORITY_DEFAULT)
301     g_source_set_priority(source, priority);
302
303   g_source_set_callback(
304       source, &glibmm_source_callback, conn_node,
305       &SourceConnectionNode::destroy_notify_callback);
306
307   g_source_attach(source, context_);
308   g_source_unref(source); // GMainContext holds a reference
309
310   conn_node->install(source);
311   return connection;
312 }
313
314 /* Note that this is our equivalent of g_timeout_add_seconds(). */
315 sigc::connection SignalTimeout::connect_seconds(const sigc::slot<bool>& slot,
316                                         unsigned int interval, int priority)
317 {
318   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
319   const sigc::connection connection (*conn_node->get_slot());
320
321   GSource *const source = g_timeout_source_new_seconds(interval);
322
323   if(priority != G_PRIORITY_DEFAULT)
324     g_source_set_priority(source, priority);
325
326   g_source_set_callback(
327       source, &glibmm_source_callback, conn_node,
328       &SourceConnectionNode::destroy_notify_callback);
329
330   g_source_attach(source, context_);
331   g_source_unref(source); // GMainContext holds a reference
332
333   conn_node->install(source);
334   return connection;
335 }
336
337 SignalTimeout signal_timeout()
338 {
339   return SignalTimeout(0); // 0 means default context
340 }
341
342
343 /**** Glib::SignalIdle *****************************************************/
344
345 inline
346 SignalIdle::SignalIdle(GMainContext* context)
347 :
348   context_ (context)
349 {}
350
351 sigc::connection SignalIdle::connect(const sigc::slot<bool>& slot, int priority)
352 {
353   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
354   const sigc::connection connection (*conn_node->get_slot());
355
356   GSource *const source = g_idle_source_new();
357
358   if(priority != G_PRIORITY_DEFAULT)
359     g_source_set_priority(source, priority);
360
361   g_source_set_callback(
362       source, &glibmm_source_callback, conn_node,
363       &SourceConnectionNode::destroy_notify_callback);
364
365   g_source_attach(source, context_);
366   g_source_unref(source); // GMainContext holds a reference
367
368   conn_node->install(source);
369   return connection;
370 }
371
372 SignalIdle signal_idle()
373 {
374   return SignalIdle(0); // 0 means default context
375 }
376
377
378 /**** Glib::SignalIO *******************************************************/
379
380 inline
381 SignalIO::SignalIO(GMainContext* context)
382 :
383   context_ (context)
384 {}
385
386 sigc::connection SignalIO::connect(const sigc::slot<bool,IOCondition>& slot,
387                                    int fd, IOCondition condition, int priority)
388 {
389   const Glib::RefPtr<IOSource> source = IOSource::create(fd, condition);
390
391   if(priority != G_PRIORITY_DEFAULT)
392     source->set_priority(priority);
393
394   const sigc::connection connection = source->connect(slot);
395
396   g_source_attach(source->gobj(), context_);
397
398   return connection;
399 }
400
401 sigc::connection SignalIO::connect(const sigc::slot<bool,IOCondition>& slot,
402                                    const Glib::RefPtr<IOChannel>& channel,
403                                    IOCondition condition, int priority)
404 {
405   const Glib::RefPtr<IOSource> source = IOSource::create(channel, condition);
406
407   if(priority != G_PRIORITY_DEFAULT)
408     source->set_priority(priority);
409
410   const sigc::connection connection = source->connect(slot);
411
412   g_source_attach(source->gobj(), context_);
413
414   return connection;
415 }
416
417 SignalIO signal_io()
418 {
419   return SignalIO(0); // 0 means default context
420 }
421
422 /**** Glib::SignalChildWatch **************************************************/
423
424 inline
425 SignalChildWatch::SignalChildWatch(GMainContext* context)
426 :
427   context_ (context)
428 {}
429
430 sigc::connection SignalChildWatch::connect(const sigc::slot<void, GPid, int>& slot,
431                                         GPid pid, int priority)
432 {
433   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
434   const sigc::connection connection(*conn_node->get_slot());
435
436   GSource *const source = g_child_watch_source_new(pid);
437  
438   if(priority != G_PRIORITY_DEFAULT)
439     g_source_set_priority(source, priority);
440
441   g_source_set_callback(
442       source, (GSourceFunc)&glibmm_child_watch_callback, conn_node,
443       &SourceConnectionNode::destroy_notify_callback);
444
445   g_source_attach(source, context_);
446   g_source_unref(source); // GMainContext holds a reference
447
448   conn_node->install(source);
449   return connection;
450 }
451
452 SignalChildWatch signal_child_watch()
453 {
454   return SignalChildWatch(0); // 0 means default context
455 }
456
457 /**** Glib::MainContext ****************************************************/
458
459 // static
460 Glib::RefPtr<MainContext> MainContext::create()
461 {
462   return Glib::RefPtr<MainContext>(reinterpret_cast<MainContext*>(g_main_context_new()));
463 }
464
465 // static
466 Glib::RefPtr<MainContext> MainContext::get_default()
467 {
468   return Glib::wrap(g_main_context_default(), true);
469 }
470
471 bool MainContext::iteration(bool may_block)
472 {
473   return g_main_context_iteration(gobj(), may_block);
474 }
475
476 bool MainContext::pending()
477 {
478   return g_main_context_pending(gobj());
479 }
480
481 void MainContext::wakeup()
482 {
483   g_main_context_wakeup(gobj());
484 }
485
486 bool MainContext::acquire()
487 {
488   return g_main_context_acquire(gobj());
489 }
490
491 bool MainContext::wait(Glib::Cond& cond, Glib::Mutex& mutex)
492 {
493   return g_main_context_wait(gobj(), cond.gobj(), mutex.gobj());
494 }
495
496 void MainContext::release()
497 {
498   g_main_context_release(gobj());
499 }
500
501 bool MainContext::prepare(int& priority)
502 {
503   return g_main_context_prepare(gobj(), &priority);
504 }
505
506 bool MainContext::prepare()
507 {
508   return g_main_context_prepare(gobj(), 0);
509 }
510
511 void MainContext::query(int max_priority, int& timeout, std::vector<PollFD>& fds)
512 {
513   if(fds.empty())
514     fds.resize(8); // rather bogus number, but better than 0
515
516   for(;;)
517   {
518     const int size_before = fds.size();
519     const int size_needed = g_main_context_query(
520         gobj(), max_priority, &timeout, reinterpret_cast<GPollFD*>(&fds.front()), size_before);
521
522     fds.resize(size_needed);
523
524     if(size_needed <= size_before)
525       break;
526   }
527 }
528
529 bool MainContext::check(int max_priority, std::vector<PollFD>& fds)
530 {
531   if(!fds.empty())
532     return g_main_context_check(gobj(), max_priority, reinterpret_cast<GPollFD*>(&fds.front()), fds.size());
533   else
534     return false;
535 }
536
537 void MainContext::dispatch()
538 {
539   g_main_context_dispatch(gobj());
540 }
541
542 void MainContext::set_poll_func(GPollFunc poll_func)
543 {
544   g_main_context_set_poll_func(gobj(), poll_func);
545 }
546
547 GPollFunc MainContext::get_poll_func()
548 {
549   return g_main_context_get_poll_func(gobj());
550 }
551
552 void MainContext::add_poll(PollFD& fd, int priority)
553 {
554   g_main_context_add_poll(gobj(), fd.gobj(), priority);
555 }
556
557 void MainContext::remove_poll(PollFD& fd)
558 {
559   g_main_context_remove_poll(gobj(), fd.gobj());
560 }
561
562 SignalTimeout MainContext::signal_timeout()
563 {
564   return SignalTimeout(gobj());
565 }
566
567 SignalIdle MainContext::signal_idle()
568 {
569   return SignalIdle(gobj());
570 }
571
572 SignalIO MainContext::signal_io()
573 {
574   return SignalIO(gobj());
575 }
576
577 SignalChildWatch MainContext::signal_child_watch()
578 {
579   return SignalChildWatch(gobj());
580 }
581
582 void MainContext::reference() const
583 {
584   g_main_context_ref(reinterpret_cast<GMainContext*>(const_cast<MainContext*>(this)));
585 }
586
587 void MainContext::unreference() const
588 {
589   g_main_context_unref(reinterpret_cast<GMainContext*>(const_cast<MainContext*>(this)));
590 }
591
592 GMainContext* MainContext::gobj()
593 {
594   return reinterpret_cast<GMainContext*>(this);
595 }
596
597 const GMainContext* MainContext::gobj() const
598 {
599   return reinterpret_cast<const GMainContext*>(this);
600 }
601
602 GMainContext* MainContext::gobj_copy() const
603 {
604   reference();
605   return const_cast<GMainContext*>(gobj());
606 }
607
608 Glib::RefPtr<MainContext> wrap(GMainContext* gobject, bool take_copy)
609 {
610   if(take_copy && gobject)
611     g_main_context_ref(gobject);
612
613   return Glib::RefPtr<MainContext>(reinterpret_cast<MainContext*>(gobject));
614 }
615
616
617 /**** Glib::MainLoop *******************************************************/
618
619 Glib::RefPtr<MainLoop> MainLoop::create(bool is_running)
620 {
621   return Glib::RefPtr<MainLoop>(
622       reinterpret_cast<MainLoop*>(g_main_loop_new(0, is_running)));
623 }
624
625 Glib::RefPtr<MainLoop> MainLoop::create(const Glib::RefPtr<MainContext>& context, bool is_running)
626 {
627   return Glib::RefPtr<MainLoop>(
628       reinterpret_cast<MainLoop*>(g_main_loop_new(Glib::unwrap(context), is_running)));
629 }
630
631 void MainLoop::run()
632 {
633   g_main_loop_run(gobj());
634 }
635
636 void MainLoop::quit()
637 {
638   g_main_loop_quit(gobj());
639 }
640
641 bool MainLoop::is_running()
642 {
643   return g_main_loop_is_running(gobj());
644 }
645
646 Glib::RefPtr<MainContext> MainLoop::get_context()
647 {
648   return Glib::wrap(g_main_loop_get_context(gobj()), true);
649 }
650
651 //static:
652 int MainLoop::depth()
653 {
654   return g_main_depth();
655 }                                             
656
657 void MainLoop::reference() const
658 {
659   g_main_loop_ref(reinterpret_cast<GMainLoop*>(const_cast<MainLoop*>(this)));
660 }
661
662 void MainLoop::unreference() const
663 {
664   g_main_loop_unref(reinterpret_cast<GMainLoop*>(const_cast<MainLoop*>(this)));
665 }
666
667 GMainLoop* MainLoop::gobj()
668 {
669   return reinterpret_cast<GMainLoop*>(this);
670 }
671
672 const GMainLoop* MainLoop::gobj() const
673 {
674   return reinterpret_cast<const GMainLoop*>(this);
675 }
676
677 GMainLoop* MainLoop::gobj_copy() const
678 {
679   reference();
680   return const_cast<GMainLoop*>(gobj());
681 }
682
683 Glib::RefPtr<MainLoop> wrap(GMainLoop* gobject, bool take_copy)
684 {
685   if(take_copy && gobject)
686     g_main_loop_ref(gobject);
687
688   return Glib::RefPtr<MainLoop>(reinterpret_cast<MainLoop*>(gobject));
689 }
690
691
692 /**** Glib::Source *********************************************************/
693
694 // static
695 const GSourceFuncs Source::vfunc_table_ =
696 {
697   &Source::prepare_vfunc,
698   &Source::check_vfunc,
699   &Source::dispatch_vfunc,
700   0, // finalize_vfunc // We can't use finalize_vfunc because there is no way
701                        // to store a pointer to our wrapper anywhere in GSource so
702                        // that it persists until finalize_vfunc would be called from here.
703   0, // closure_callback
704   0, // closure_marshal
705 };
706
707 unsigned int Source::attach(const Glib::RefPtr<MainContext>& context)
708 {
709   return g_source_attach(gobject_, Glib::unwrap(context));
710 }
711
712 unsigned int Source::attach()
713 {
714   return g_source_attach(gobject_, 0);
715 }
716
717 void Source::destroy()
718 {
719   g_source_destroy(gobject_);
720 }
721
722 void Source::set_priority(int priority)
723 {
724   g_source_set_priority(gobject_, priority);
725 }
726
727 int Source::get_priority() const
728 {
729   return g_source_get_priority(gobject_);
730 }
731
732 void Source::set_can_recurse(bool can_recurse)
733 {
734   g_source_set_can_recurse(gobject_, can_recurse);
735 }
736
737 bool Source::get_can_recurse() const
738 {
739   return g_source_get_can_recurse(gobject_);
740 }
741
742 unsigned int Source::get_id() const
743 {
744   return g_source_get_id(gobject_);
745 }
746
747 Glib::RefPtr<MainContext> Source::get_context()
748 {
749   return Glib::wrap(g_source_get_context(gobject_), true);
750 }
751
752 GSource* Source::gobj_copy() const
753 {
754   return g_source_ref(gobject_);
755 }
756
757 void Source::reference() const
758 {
759   g_source_ref(gobject_);
760 }
761
762 void Source::unreference() const
763 {
764   g_source_unref(gobject_);
765 }
766
767 Source::Source()
768 :
769   gobject_ (g_source_new(const_cast<GSourceFuncs*>(&vfunc_table_), sizeof(GSource)))
770 {
771   g_source_set_callback(
772       gobject_, &glibmm_dummy_source_callback,
773       new SourceCallbackData(this), // our persistant callback data object
774       &SourceCallbackData::destroy_notify_callback);
775 }
776
777 Source::Source(GSource* cast_item, GSourceFunc callback_func)
778 :
779   gobject_ (cast_item)
780 {
781   g_source_set_callback(
782       gobject_, callback_func,
783       new SourceCallbackData(this), // our persistant callback data object
784       &SourceCallbackData::destroy_notify_callback);
785 }
786
787 Source::~Source()
788 {
789   // The dtor should be invoked by destroy_notify_callback() only, which clears
790   // gobject_ before deleting.  However, we might also get to this point if
791   // a derived ctor threw an exception, and then we need to unref manually.
792
793   if(gobject_)
794   {
795     SourceCallbackData *const data = glibmm_source_get_callback_data(gobject_);
796     data->wrapper = 0;
797
798     GSource *const tmp_gobject = gobject_;
799     gobject_ = 0;
800
801     g_source_unref(tmp_gobject);
802   }
803 }
804
805 sigc::connection Source::connect_generic(const sigc::slot_base& slot)
806 {
807   SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
808   const sigc::connection connection (*conn_node->get_slot());
809
810   // Don't override the callback data.  Reuse the existing one
811   // calling SourceCallbackData::set_node() to register conn_node.
812   SourceCallbackData *const data = glibmm_source_get_callback_data(gobject_);
813   data->set_node(conn_node);
814
815   conn_node->install(gobject_);
816   return connection;
817 }
818
819 void Source::add_poll(Glib::PollFD& poll_fd)
820 {
821   g_source_add_poll(gobject_, poll_fd.gobj());
822 }
823
824 void Source::remove_poll(Glib::PollFD& poll_fd)
825 {
826   g_source_remove_poll(gobject_, poll_fd.gobj());
827 }
828
829 void Source::get_current_time(Glib::TimeVal& current_time)
830 {
831   g_source_get_current_time(gobject_, &current_time);
832 }
833
834 inline // static
835 Source* Source::get_wrapper(GSource* source)
836 {
837   SourceCallbackData *const data = glibmm_source_get_callback_data(source);
838   return data->wrapper;
839 }
840
841 // static
842 gboolean Source::prepare_vfunc(GSource* source, int* timeout)
843 {
844   #ifdef GLIBMM_EXCEPTIONS_ENABLED
845   try
846   {
847   #endif //GLIBMM_EXCEPTIONS_ENABLED
848     Source *const self = get_wrapper(source);
849     return self->prepare(*timeout);
850   #ifdef GLIBMM_EXCEPTIONS_ENABLED
851   }
852   catch(...)
853   {
854     Glib::exception_handlers_invoke();
855   }
856   #endif //GLIBMM_EXCEPTIONS_ENABLED
857
858   return 0;
859 }
860
861 // static
862 gboolean Source::check_vfunc(GSource* source)
863 {
864   #ifdef GLIBMM_EXCEPTIONS_ENABLED
865   try
866   {
867   #endif //GLIBMM_EXCEPTIONS_ENABLED
868     Source *const self = get_wrapper(source);
869     return self->check();
870   #ifdef GLIBMM_EXCEPTIONS_ENABLED
871   }
872   catch(...)
873   {
874     Glib::exception_handlers_invoke();
875   }
876   #endif //GLIBMM_EXCEPTIONS_ENABLED
877
878   return 0;
879 }
880
881 // static
882 gboolean Source::dispatch_vfunc(GSource*, GSourceFunc callback, void* user_data)
883 {
884   SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(user_data);
885
886   g_return_val_if_fail(callback == &glibmm_dummy_source_callback, 0);
887   g_return_val_if_fail(callback_data != 0 && callback_data->node != 0, 0);
888
889   #ifdef GLIBMM_EXCEPTIONS_ENABLED
890   try
891   {
892   #endif //GLIBMM_EXCEPTIONS_ENABLED
893     Source *const self = callback_data->wrapper;
894     return self->dispatch(callback_data->node->get_slot());
895   #ifdef GLIBMM_EXCEPTIONS_ENABLED
896   }
897   catch(...)
898   {
899     Glib::exception_handlers_invoke();
900   }
901   #endif //GLIBMM_EXCEPTIONS_ENABLED
902   return 0;
903 }
904
905 // static
906 void Source::destroy_notify_callback(void* data)
907 {
908   if(data)
909   {
910     Source *const self = static_cast<Source*>(data);
911
912     // gobject_ is already invalid at this point.
913     self->gobject_ = 0;
914
915     // No exception checking: if the dtor throws, you're out of luck anyway.
916     delete self;
917   }
918 }
919
920
921 /**** Glib::TimeoutSource **************************************************/
922
923 // static
924 Glib::RefPtr<TimeoutSource> TimeoutSource::create(unsigned int interval)
925 {
926   return Glib::RefPtr<TimeoutSource>(new TimeoutSource(interval));
927 }
928
929 sigc::connection TimeoutSource::connect(const sigc::slot<bool>& slot)
930 {
931   return connect_generic(slot);
932 }
933
934 TimeoutSource::TimeoutSource(unsigned int interval)
935 :
936   interval_ (interval)
937 {
938   expiration_.assign_current_time();
939   expiration_.add_milliseconds(std::min<unsigned long>(G_MAXLONG, interval_));
940 }
941
942 TimeoutSource::~TimeoutSource()
943 {}
944
945 bool TimeoutSource::prepare(int& timeout)
946 {
947   Glib::TimeVal current_time;
948   get_current_time(current_time);
949
950   Glib::TimeVal remaining = expiration_;
951   remaining.subtract(current_time);
952
953   if(remaining.negative())
954   {
955     // Already expired.
956     timeout = 0;
957   }
958   else
959   {
960     const unsigned long milliseconds =
961         static_cast<unsigned long>(remaining.tv_sec)  * 1000U +
962         static_cast<unsigned long>(remaining.tv_usec) / 1000U;
963
964     // Set remaining milliseconds.
965     timeout = std::min<unsigned long>(G_MAXINT, milliseconds);
966
967     // Check if the system time has been set backwards. (remaining > interval)
968     remaining.add_milliseconds(- std::min<unsigned long>(G_MAXLONG, interval_) - 1);
969     if(!remaining.negative())
970     {
971       // Oh well.  Reset the expiration time to now + interval;
972       // this at least avoids hanging for long periods of time.
973       expiration_ = current_time;
974       expiration_.add_milliseconds(interval_);
975       timeout = std::min<unsigned int>(G_MAXINT, interval_);
976     }
977   }
978
979   return (timeout == 0);
980 }
981
982 bool TimeoutSource::check()
983 {
984   Glib::TimeVal current_time;
985   get_current_time(current_time);
986
987   return (expiration_ <= current_time);
988 }
989
990 bool TimeoutSource::dispatch(sigc::slot_base* slot)
991 {
992   const bool again = (*static_cast<sigc::slot<bool>*>(slot))();
993
994   if(again)
995   {
996     get_current_time(expiration_);
997     expiration_.add_milliseconds(std::min<unsigned long>(G_MAXLONG, interval_));
998   }
999
1000   return again;
1001 }
1002
1003
1004 /**** Glib::IdleSource *****************************************************/
1005
1006 // static
1007 Glib::RefPtr<IdleSource> IdleSource::create()
1008 {
1009   return Glib::RefPtr<IdleSource>(new IdleSource());
1010 }
1011
1012 sigc::connection IdleSource::connect(const sigc::slot<bool>& slot)
1013 {
1014   return connect_generic(slot);
1015 }
1016
1017 IdleSource::IdleSource()
1018 {
1019   set_priority(PRIORITY_DEFAULT_IDLE);
1020 }
1021
1022 IdleSource::~IdleSource()
1023 {}
1024
1025 bool IdleSource::prepare(int& timeout)
1026 {
1027   timeout = 0;
1028   return true;
1029 }
1030
1031 bool IdleSource::check()
1032 {
1033   return true;
1034 }
1035
1036 bool IdleSource::dispatch(sigc::slot_base* slot)
1037 {
1038   return (*static_cast<sigc::slot<bool>*>(slot))();
1039 }
1040
1041
1042 /**** Glib::IOSource *******************************************************/
1043
1044 // static
1045 Glib::RefPtr<IOSource> IOSource::create(int fd, IOCondition condition)
1046 {
1047   return Glib::RefPtr<IOSource>(new IOSource(fd, condition));
1048 }
1049
1050 Glib::RefPtr<IOSource> IOSource::create(const Glib::RefPtr<IOChannel>& channel, IOCondition condition)
1051 {
1052   return Glib::RefPtr<IOSource>(new IOSource(channel, condition));
1053 }
1054
1055 sigc::connection IOSource::connect(const sigc::slot<bool,IOCondition>& slot)
1056 {
1057   return connect_generic(slot);
1058 }
1059
1060 IOSource::IOSource(int fd, IOCondition condition)
1061 :
1062   poll_fd_ (fd, condition)
1063 {
1064   add_poll(poll_fd_);
1065 }
1066
1067 IOSource::IOSource(const Glib::RefPtr<IOChannel>& channel, IOCondition condition)
1068 :
1069   Source(g_io_create_watch(channel->gobj(), (GIOCondition) condition),
1070          (GSourceFunc) &glibmm_iosource_callback)
1071 {}
1072
1073 IOSource::~IOSource()
1074 {}
1075
1076 bool IOSource::prepare(int& timeout)
1077 {
1078   timeout = -1;
1079   return false;
1080 }
1081
1082 bool IOSource::check()
1083 {
1084   return ((poll_fd_.get_revents() & poll_fd_.get_events()) != 0);
1085 }
1086
1087 bool IOSource::dispatch(sigc::slot_base* slot)
1088 {
1089   return (*static_cast<sigc::slot<bool,IOCondition>*>(slot))
1090                                  (poll_fd_.get_revents());
1091 }
1092
1093 } // namespace Glib
1094