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