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