~ubuntu-branches/ubuntu/precise/gtkmm3.0/precise

« back to all changes in this revision

Viewing changes to gtk/src/main.ccg

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2011-06-17 00:12:44 UTC
  • Revision ID: james.westby@ubuntu.com-20110617001244-9hl5an15hiaaahi6
Tags: upstream-3.0.1
ImportĀ upstreamĀ versionĀ 3.0.1

Show diffs side-by-side

added added

removed removed

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