Install ardour as a binary, a script and a set of shared
[ardour.git] / libs / gtkmm2 / gtk / gtkmm / main.cc
1 // Generated by gtkmmproc -- DO NOT MODIFY!
2
3 #include <gtkmm/main.h>
4 #include <gtkmm/private/main_p.h>
5
6 // -*- c++ -*-
7 /* $Id$ */
8
9 /* 
10  *
11  * Copyright 1998-2002 The gtkmm Development Team
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public
24  * License along with this library; if not, write to the Free
25  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  */
27
28 #include <glib.h>
29 #include <gtkmmconfig.h>
30 #include <gtkmm/main.h>
31 #include <gtkmm/window.h>
32 #include <glibmm/init.h>
33 #include <pangomm/wrap_init.h>
34 #include <atkmm/wrap_init.h>
35 #include <gdkmm/wrap_init.h>
36 #include <gtkmm/wrap_init.h>
37
38 namespace
39 {
40
41 /* This class tells sigc++ how to break GTK+ main signal connections.  Since
42  * the gtk_*_remove() functions have the same signature, all main signals can
43  * be handled by a single class.  Special handling is needed for signals that
44  * don't support destroy notification; see the comment on connection_list_.
45  */
46 class GtkMainConnectionNode
47 {
48 public:
49   // A function taking a connection id, e.g. gtk_timeout_remove().
50   typedef void (*RemoveFunc) (guint);
51
52   explicit GtkMainConnectionNode(const sigc::slot_base& slot);
53
54   static void* notify(void* data);
55   static void destroy_notify_handler(void* data);
56
57   // Call this after installing the GTK+ callback.
58   void install(guint conn_id, RemoveFunc remove_func, bool has_destroy_notify);
59
60   inline sigc::slot_base* get_slot();
61
62   static bool list_remove(GtkMainConnectionNode* conn_node);
63   static void list_notify_all();
64
65 private:
66   sigc::slot_base slot_;
67   static GSList*  connection_list_;
68
69   guint           conn_id_;
70   RemoveFunc      remove_func_;
71   bool            has_destroy_notify_;
72   bool            destroyed_;
73 };
74
75
76 /* The global connection_list_ is needed to deal with GTK+ main signals
77  * that don't support destroy notification.  This applies only to
78  * gtk_key_snooper_install() and gtk_init_add().
79  *
80  * The list is static and not a member of Gtk::Main, in order to support
81  * connection to Gtk::Main::signal_run() before Gtk::Main is instantiated.
82  * Thus, it's possible to install initialization hooks in global constructors,
83  * for instance.
84  */
85 // static
86 GSList* GtkMainConnectionNode::connection_list_ = 0;
87
88 GtkMainConnectionNode::GtkMainConnectionNode(const sigc::slot_base& slot)
89 :
90   slot_(slot),
91   conn_id_             (0),
92   remove_func_         (0),
93   has_destroy_notify_          (false),
94   destroyed_           (false)
95 {
96   slot_.set_parent(this, &GtkMainConnectionNode::notify);
97 }
98
99 //static:
100 void* GtkMainConnectionNode::notify(void* data)
101 {
102   // notification from the sigc++ side ...
103
104   GtkMainConnectionNode *const self = static_cast<GtkMainConnectionNode*>(data);
105
106   // this call might be triggered from destroy_notify_handler().
107   if(!self->destroyed_)
108   {
109     // during (*remove_func_)() destroy_notify_handler() might get called.
110     // This must not lead to the destruction of the object!
111     self->destroyed_ = true;
112
113     // disconnect from the gtk+ side.
114     (*(self->remove_func_))(self->conn_id_);
115
116     // remove self from global list.
117     if (!self->has_destroy_notify_)
118       list_remove(self);
119
120     // destruction of slot_ notifies all objects referring to it.
121     delete self;
122   }
123
124   return 0;
125 }
126
127 // static
128 void GtkMainConnectionNode::destroy_notify_handler(void* data)
129 {
130   // notification from the gtk+ side ...
131
132   GtkMainConnectionNode *const self = static_cast<GtkMainConnectionNode*>(data);
133
134   // this call might be triggered from notify().
135   if(!self->destroyed_)
136   {
137     self->destroyed_ = true;
138
139     // The GTK+ side is disconnected now, thus the ID is no longer valid.
140     self->conn_id_ = 0;
141
142     // remove self from global list.
143     if (!self->has_destroy_notify_)
144       list_remove(self);
145
146     // destruction of slot_ notifies all objects referring to it.
147     delete self;
148   }
149 }
150
151 void GtkMainConnectionNode::install(
152     guint conn_id, GtkMainConnectionNode::RemoveFunc remove_func, bool has_destroy_notify)
153 {
154   conn_id_     = conn_id;
155   remove_func_ = remove_func;
156   has_destroy_notify_  = has_destroy_notify;
157
158   if (!has_destroy_notify_)
159     connection_list_ = g_slist_prepend(connection_list_, this);
160 }
161
162 inline
163 sigc::slot_base* GtkMainConnectionNode::get_slot()
164 {
165   return &slot_;
166 }
167
168 // static
169 bool GtkMainConnectionNode::list_remove(GtkMainConnectionNode* conn_node)
170 {
171   // The conn_node pointer is only valid if we still hold
172   // a reference of the ConnectionNode in our global list.
173   //
174   if(GSList *const link = g_slist_find(connection_list_, conn_node))
175   {
176     connection_list_ = g_slist_delete_link(connection_list_, link);
177     return true;
178   }
179
180   return false;
181 }
182
183 /* Cleanup function to be called by the Gtk::Main destructor.  The elements
184  * are removed prior to notification, in order to avoid invalid elements in
185  * the container.
186  */
187 // static
188 void GtkMainConnectionNode::list_notify_all()
189 {
190   while(connection_list_ != 0)
191   {
192     GtkMainConnectionNode *const conn_node =
193         static_cast<GtkMainConnectionNode*>(connection_list_->data);
194
195     connection_list_ = g_slist_delete_link(connection_list_, connection_list_);
196
197     // no need to search the list in notify().
198     conn_node->has_destroy_notify_ = true;
199
200     // conn_node gets destroyed from notify().
201     notify(conn_node);
202   }
203 }
204
205 } // anonymous namespace
206
207
208 namespace Gtk
209 {
210
211 /**** Gtk::RunSig **********************************************************/
212
213 sigc::connection RunSig::connect(const RunSig::SlotType& slot)
214 {
215   GtkMainConnectionNode *const conn_node = new GtkMainConnectionNode(slot);
216   const sigc::connection connection(*conn_node->get_slot());
217
218   // The callback will be invoked the next time gtk_main() is called.
219   gtk_init_add(&RunSig::gtk_callback, conn_node);
220
221   conn_node->install(0, 0, false); // there's no gtk_init_remove()
222   return connection;
223 }
224
225 // static
226 gboolean RunSig::gtk_callback(gpointer data)
227 {
228   GtkMainConnectionNode *const conn_node =
229       static_cast<GtkMainConnectionNode*>(data);
230
231   if(GtkMainConnectionNode::list_remove(conn_node))
232   {
233     try
234     {
235       // Recreate the specific SlotType from the generic slot_base.
236       SlotType* pSlot = static_cast<SlotType*>(conn_node->get_slot());
237       (*pSlot)();
238     }
239     catch(...)
240     {
241       Glib::exception_handlers_invoke();
242     }
243
244     // We don't need it anymore, since RunSig is a one-shot signal.
245     GtkMainConnectionNode::destroy_notify_handler(conn_node);
246   }
247
248   return 0;
249 }
250
251
252 /**** Gtk::QuitSig *********************************************************/
253
254 sigc::connection QuitSig::connect(const QuitSig::SlotType& slot, guint main_level)
255 {
256   GtkMainConnectionNode *const conn_node = new GtkMainConnectionNode(slot);
257   const sigc::connection connection(*conn_node->get_slot());
258
259   const guint conn_id = gtk_quit_add_full(
260       main_level, &QuitSig::gtk_callback, 0 /* marshaller */,
261       conn_node, &GtkMainConnectionNode::destroy_notify_handler);
262
263   conn_node->install(conn_id, &gtk_quit_remove, true);
264   return connection;
265 }
266
267 // static
268 gboolean QuitSig::gtk_callback(gpointer data)
269 {
270   try
271   {
272     // Call the slot:
273     GtkMainConnectionNode* node = static_cast<GtkMainConnectionNode*>(data);
274     SlotType* pSlot = static_cast<SlotType*>(node->get_slot());
275     (*pSlot)();
276   }
277   catch(...)
278   {
279     Glib::exception_handlers_invoke();
280   }
281   return 0;
282 }
283
284
285 /**** Gtk::KeySnooperSig ***************************************************/
286
287 sigc::connection KeySnooperSig::connect(const KeySnooperSig::SlotType& slot)
288 {
289   GtkMainConnectionNode *const conn_node = new GtkMainConnectionNode(slot);
290   const sigc::connection connection(*conn_node->get_slot());
291
292   const guint conn_id = gtk_key_snooper_install(&KeySnooperSig::gtk_callback, conn_node);
293
294   conn_node->install(conn_id, &gtk_key_snooper_remove, false);
295   return connection;
296 }
297
298 // static
299 gint KeySnooperSig::gtk_callback(GtkWidget* widget, GdkEventKey* event, gpointer data)
300 {
301   try
302   {
303     // Recreate the specific SlotType from the generic slot node.
304     GtkMainConnectionNode* conn_node = static_cast<GtkMainConnectionNode*>(data);
305     SlotType* pSlot = static_cast<SlotType*>(conn_node->get_slot());
306     return (*pSlot)(Glib::wrap(widget), event);
307   }
308   catch(...)
309   {
310     Glib::exception_handlers_invoke();
311   }
312   return 0;
313 }
314
315
316 /**** Gtk::Main -- static data *********************************************/
317
318 RunSig        Main::signal_run_;
319 QuitSig       Main::signal_quit_;
320 KeySnooperSig Main::signal_key_snooper_;
321 Main*         Main::instance_ = 0;
322
323
324 /**** Gtk::Main -- construction/destruction ********************************/
325
326 Main::Main(int& argc, char**& argv, bool set_locale)
327 {
328   init(&argc, &argv, set_locale);
329 }
330
331 Main::Main(int* argc, char*** argv, bool set_locale)
332 {
333   init(argc, argv, set_locale);
334 }
335
336 /*Main::Main(int* argc, char*** argv, const std::string& parameter_string, const Glib::ArrayHandle<const Glib::OptionEntry&>& entries, const std::string& translation_domain)
337 {
338   init(argc, argv, parameter_string, entries, translation_domain);
339 }*/
340
341 // Default ctor only used by subclasses:
342 Main::Main()
343 {
344   if(instance_ == 0)
345   {
346     init_gtkmm_internals();
347     instance_ = this;
348   }
349   else
350   {
351     g_warning("Gtk::Main instantiated twice");
352   }
353 }
354
355 Main::~Main()
356 {
357   // A second Gtk::Main will produce a warning, but
358   // Main::~Main would still run. So this prevents the crash.
359   if(instance_ == this)
360   {
361     instance_ = 0;
362     GtkMainConnectionNode::list_notify_all();
363
364     Glib::init();
365   }
366 }
367
368 // protected
369 void Main::init(int* argc, char*** argv, bool set_locale)
370 {
371   if(instance_)
372   {
373     g_warning("Gtk::Main::init() called twice");
374   }
375   else
376   {
377     if(!set_locale)
378       gtk_disable_setlocale();
379
380     //TODO: Add support for gtk_init_check().
381     gtk_init(argc, argv);
382
383     init_gtkmm_internals();
384     instance_ = this;
385   }
386 }
387
388 Main::Main(int& argc, char**& argv, Glib::OptionContext& option_context)
389 {
390   if(instance_)
391   {
392     g_warning("Gtk::Main::init() called twice");
393   }
394   else
395   {
396     init_gtkmm_internals();
397     instance_ = this;
398
399     //This reimplements some stuff from gtk_init_with_options(),
400     //without calling check_setugid(), because that is not public API.
401
402     add_gtk_option_group(option_context);
403     option_context.parse(argc, argv);
404   }
405 }
406
407 // This is a static method so that it can be used before Main is instantiated,
408 // for instance in Gnome::canvas_init().  But if you use this method, you
409 // _must_ have a Gtk::Main, so that Main::~Main() is called to clean this up
410 // later.  Of course I can't imagine any situation in which you wouldn't have
411 // a Gtk::Main.
412 //
413 void Main::init_gtkmm_internals()
414 {
415   static bool init_done = false;
416
417   if(!init_done)
418   {
419     Glib::init();
420
421     // Populate the map of GTypes to C++ wrap_new() functions.
422     Pango::wrap_init();
423     Atk::wrap_init();
424     Gdk::wrap_init();
425     Gtk::wrap_init();
426
427     init_done = true;
428   }
429 }
430
431 void Main::add_gtk_option_group(Glib::OptionContext& option_context, bool open_default_display)
432 {
433   //Get the option group:
434   Glib::OptionGroup gtkgroup( gtk_get_option_group(open_default_display) ); //Takes ownership of the GOptionGroup.
435
436   //Give it to the option_context, which will also then own the underlying GOptionGroup, deleting it when necessary:
437   option_context.add_group(gtkgroup);
438 }
439
440
441 /**** Gtk::Main -- static forwarder methods ********************************/
442
443 Main* Main::instance()
444 {
445   return instance_;
446 }
447
448 void Main::run()
449 {
450   instance_->run_impl();
451 }
452
453 void Main::run(Gtk::Window& window)
454 {
455   window.show();
456   window.signal_hide().connect(sigc::mem_fun(*instance_, &Main::on_window_hide));
457   instance_->run_impl();
458 }
459
460 void Main::quit()
461 {
462   instance_->quit_impl();
463 }
464
465 guint Main::level()
466 {
467   return instance_->level_impl();
468 }
469
470 bool Main::iteration(bool blocking)
471 {
472   return instance_->iteration_impl(blocking);
473 }
474
475 bool Main::events_pending()
476 {
477   return instance_->events_pending_impl();
478 }
479
480
481 /**** Gtk::Main -- static signal accessors *********************************/
482
483 RunSig& Main::signal_run()
484 {
485   return signal_run_;
486 }
487
488 QuitSig& Main::signal_quit()
489 {
490   return signal_quit_;
491 }
492
493 KeySnooperSig& Main::signal_key_snooper()
494 {
495   return signal_key_snooper_;
496 }
497
498
499 /**** Gtk::Main -- protected virtuals **************************************/
500
501 void Main::run_impl()
502 {
503   gtk_main();
504 }
505
506 void Main::quit_impl()
507 {
508   gtk_main_quit();
509 }
510
511 guint Main::level_impl()
512 {
513   return gtk_main_level();
514 }
515
516 bool Main::iteration_impl(bool blocking)
517 {
518   return gtk_main_iteration_do(blocking);
519 }
520
521 bool Main::events_pending_impl()
522 {
523   return gtk_events_pending();
524 }
525
526 void Main::on_window_hide()
527 {
528   quit_impl();
529 }
530
531 } /* namespace Gtk */
532
533
534 namespace
535 {
536 } // anonymous namespace
537
538