c++-gtk-utils
window.h
Go to the documentation of this file.
1 /* Copyright (C) 2005 to 2011 and 2013 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 */
24 
25 #ifndef CGU_WINDOW_H
26 #define CGU_WINDOW_H
27 
29 
30 #ifdef CGU_USE_GTK
31 #include <gtk/gtk.h>
32 #endif
33 
34 /**
35  * @class Cgu::WinBase window.h c++-gtk-utils/window.h
36  * @brief This is a class for managing the lifetime of top level
37  * widgets.
38  * @sa MainWidgetBase Application
39  *
40  * This class provides a base class for lifetime management of top
41  * level windows which can make GTK+ exception safe. It would be
42  * possible to use GTK+ to control the lifetime of the contained GTK+
43  * window object, through the delete event handler and the destroy
44  * signal. However in the case of a blocking window (say a dialog)
45  * this would result in an invalid object remaining in scope. It is
46  * better to use the C++ lifetime handling mechanisms to control
47  * object status, and this class does that. Where a Cgu::WinBase
48  * object is created as an auto (local) object its contained GTK+ top
49  * level window object will be valid while it remains in scope. For a
50  * Cgu::WinBase object which is not blocking (on which exec() is not
51  * called) and which is therefore created on free store the WinBase
52  * class will delete its own memory and destroy its contained GTK+ top
53  * level window object when it is closed (see below about the close()
54  * function).
55  *
56  * If a NULL pointer is passed as the last argument of its
57  * constructor, a new window object will be created with
58  * gtk_window_new(GTK_WINDOW_TOPLEVEL). However, alternatively a
59  * pre-formed object deriving from GtkWindow (such as a GtkDialog or
60  * GtkMessageDialog object) can be passed as that argument, in which
61  * case the class will manage that object.
62  *
63  * A window will block with a call to exec(), which returns an int
64  * value. The exec() method obtains its return value by calling the
65  * virtual protected function get_exec_val(), which by default returns
66  * 0 but can be overridden to return something more meaningful. If
67  * something other than an int needs to be returned, it will be
68  * necessary for a derived class to provide an extractor function to
69  * obtain the data from the object after exec() has returned.
70  *
71  * A convenience virtual protected on_delete_event() method is
72  * provided for any derived class which needs to respond to that
73  * signal. It does not return a value (it does not cause a destroy
74  * event to be emitted as in the case of a GTK+ delete event handler
75  * returning false).
76  *
77  * If the class is constructed on free store and exec() has not been
78  * called on it, it self-destroys and any memory allocated to it freed
79  * by calling the protected close() function. If exec() has been
80  * called for an object, a call to close() will only terminate the
81  * window event loop (that is, cause exec() to unblock), which is
82  * correct for an auto (local) object as it will destroy itself when
83  * it goes out of scope. By default (that is, if not overridden by
84  * any derived classes) on_delete_event() calls close().
85  *
86  * No special memory management for GTK+ widgets contained in the
87  * WinBase object (or in an object of a class derived from WinBase) is
88  * needed. The GTK+ object system takes care of that, and they will
89  * be released when the life of the WinBase object finishes. For this
90  * reason, the WinBase class can be used to make GTK+ exception safe:
91  * as its constructor does not throw, exceptions thrown in the
92  * constructors of classes derived from it will be correctly dealt
93  * with without causing GTK+ to leak memory if a widget is put into
94  * its container in the derived class's constructor immediately after
95  * creation on a "top down" basis, or it is placed in another widget
96  * class derived from MainWidgetBase.
97  *
98  * If a C string is passed to the caption argument of the constructor,
99  * then the window will display that text as its caption. A NULL
100  * pointer can be passed if no caption is required. Likewise if a
101  * pointer to a GdkPixbuf object is passed as the second parameter, it
102  * will be used to set a window icon in the window bar (if the user's
103  * window manager supports this).
104  *
105  * The constructor of WinBase does not call gtk_widget_show() because
106  * the constructor of a derived class may want to do things which
107  * require the window not to be visible. Accordingly the constructor
108  * of the derived class (or the library user) should call the
109  * WinBase::show_all() method(), or call
110  * gtk_widget_show()/gtk_widget_show_all() via WinBase::get_win().
111  *
112  * See @ref Threading for particulars about GTK+ thread safety (and so
113  * WinBase thread safety).
114  *
115  * WinBase objects can be used with widget heirarchies or top level
116  * windows created using GtkBuilder. See @ref GtkBuilder for
117  * particulars about that.
118  *
119  * A small compilable example is as follows:
120  *
121  * @anchor WinBaseExampleAnchor
122  * @code
123  * #include <gtk/gtk.h>
124  * #include <c++-gtk-utils/window.h>
125  *
126  *
127  * // *** class headers ***
128  *
129  * extern "C" void message_button_clicked(GtkWidget*, void*);
130  *
131  * class Message: public Cgu::WinBase {
132  * public:
133  * friend void message_button_clicked(GtkWidget*, void*);
134  * Message(const char* text);
135  * };
136  *
137  *
138  * // *** class implementation ***
139  *
140  * void message_button_clicked(GtkWidget*, void* data) {
141  * static_cast<Message*>(data)->close();
142  * }
143  *
144  * Message::Message(const char* text): Cgu::WinBase("Message", 0, true) {
145  * GtkWidget* box = gtk_vbox_new(false, 2);
146  * gtk_container_add(GTK_CONTAINER(get_win()), box);
147  * GtkWidget* label = gtk_label_new(text);
148  * gtk_box_pack_start(GTK_BOX(box), label,
149  * true, false, 0);
150  * GtkWidget* button_box = gtk_hbutton_box_new();
151  * gtk_box_pack_start(GTK_BOX(box), button_box,
152  * false, false, 0);
153  * GtkWidget* button = gtk_button_new_from_stock(GTK_STOCK_OK);
154  * gtk_container_add(GTK_CONTAINER(button_box), button);
155  * g_signal_connect(G_OBJECT(button), "clicked",
156  * G_CALLBACK(message_button_clicked), this);
157  * gtk_widget_set_can_default(button, true);
158  *
159  * gtk_widget_show_all(GTK_WIDGET(get_win()));
160  * }
161  *
162  *
163  * // *** user code ***
164  *
165  * int main(int argc, char* argv[]) {
166  * gtk_init(&argc, &argv);
167  * Message dialog("This is a message");
168  * dialog.exec();
169  * return 0;
170  * }
171  * @endcode
172  *
173  * See @ref Linkage for further discussion of the
174  * message_button_clicked() callback.
175  *
176  * @note The WinBase class will work fine if a GtkDialog object is
177  * passed to the last argument of the class's constructor formed from
178  * a call to gtk_dialog_new()/gtk_dialog_new_with_buttons(), but a few
179  * points should be noted:
180  *
181  * @note 1. If the response signal has been connected to, a delete
182  * event will cause a response signal to be emitted with the
183  * GTK_RESPONSE_DELETE_EVENT id, as well as causing the normal
184  * WinBase::on_delete_event() method to be called. If the response
185  * handler acts on the GTK_RESPONSE_DELETE_EVENT id by calling
186  * close(), then WinBase::on_delete_event() should be overridden to do
187  * nothing so that a double call to close() is not made (although
188  * version 1.0.3 onwards of c++-gtk-utils will check against and
189  * prevent such a double call of close() from a single delete event).
190  *
191  * @note 2. It is usually best not to call gtk_dialog_run(). Instead,
192  * call WinBase::exec() for a blocking dialog, and override
193  * WinBase::get_exec_val() to return any required button response id.
194  *
195  * @note 3. If creating a GtkDialog object with
196  * gtk_dialog_new_with_buttons(), do not pass a GtkDialogFlags
197  * argument of GTK_DIALOG_DESTROY_WITH_PARENT. A GtkDialogFlags
198  * argument of GTK_DIALOG_MODAL can be passed, but alternatively to
199  * make the dialog modal the user can pass 'true' as the modal
200  * argument of the WinBase constructor and pass the parent widget to
201  * that constructor rather than to gtk_dialog_new_with_buttons() (so
202  * that GtkDialogFlags(0) is passed as the third argument of
203  * gtk_dialog_new_with_buttons()). Either approach will work, but the
204  * second has the advantage of consistency with the WinBase interface.
205  *
206  * @note 4. Likewise, if using gtk_dialog_new_with_buttons(), any
207  * dialog caption can be passed either to the title argument of that
208  * method or to the caption argument of the WinBase constructor.
209  *
210  * @note Similar principles apply to the management of objects derived from
211  * GtkDialog.
212  *
213  * This class is not compiled into the library if the library is built
214  * with the \--without-gtk configuration option.
215  */
216 
217 namespace Cgu {
218 
219 #if defined(DOXYGEN_PARSING) || defined(CGU_USE_GTK)
220 
221 #if GTK_CHECK_VERSION(2,99,0)
222 class Application;
223 #endif
224 
225 class WinBase {
226 
227  // main class object
228  GtkWindow* g_window_p;
229 
230  bool in_exec_loop;
231  bool is_modal;
232  bool close_guard;
233 
234  // we only use this struct to retain binary compatibility with
235  // 1.2 series versions before 1.2.12 (we have changed the parent_p
236  // pointer to the impl pointer). TODO: at the next ABI break,
237  // revert to inline implementation
238 struct Impl {
239  GtkWindow* parent_p;
240 #if GTK_CHECK_VERSION(2,99,0)
241  Application* app_p;
242 #endif
243 };
244  Impl* impl;
245 
246 #if GTK_CHECK_VERSION(2,99,0)
247  // only Cgu::Application can access these
248  void set_application(Application* app) {impl->app_p = app;}
249  void unset_application() {impl->app_p = 0;}
250 #endif
251 
252  // WinBase cannot be copied
253  WinBase(const WinBase&);
254  WinBase& operator=(const WinBase&);
255 protected:
256  /**
257  * A function for the use of derived classes which will cause the
258  * window to unblock if exec() has been called. If it is not a
259  * blocking window (ie exec() has not been called so it has been
260  * constructed on freestore), this function will cause the window to
261  * delete itself. By default it is called by on_delete_event().
262  * This method will not throw (assuming, in a case where the
263  * Cgu::WinBase object has been added to a Cgu::Application object,
264  * that merely iterating through a list does not throw, as it would
265  * not on any sane implementation), unless a derived class's
266  * destructor throws, which it should not do.
267  */
268  void close();
269 
270  /**
271  * Provides the value to be returned by exec(). This method will
272  * not throw (unless it is overridden by a derived class's method
273  * which throws).
274  * @return By default returns 0. It is intended to be overridden by
275  * derived classes where relevant to provide a more meaningful
276  * value.
277  */
278  virtual int get_exec_val() const;
279 
280  /**
281  * Called when there is a delete event on the managed window.
282  * Unless overridden by derived classes it just calls close().
283  */
284  virtual void on_delete_event();
285 public:
286 #if GTK_CHECK_VERSION(2,99,0)
287  friend class Application;
288 #endif
289 #ifndef DOXYGEN_PARSING
290  // this helper class avoids exposing GObject callbacks with C
291  // linkage to the global namespace
292  class CB;
293  friend class CB;
294 #endif
295  /**
296  * Returns the GtkWindow object managed by this class. This method
297  * will not throw.
298  * @return The managed GtkWindow object.
299  */
300  GtkWindow* get_win() const {return g_window_p;}
301 
302  /**
303  * Makes the window block. Calls gtk_main(). It is usually a bad
304  * idea to call this method (and so have nested loops) on a
305  * non-modal dialog. To cause the window to unblock, call close().
306  * Although the call to gtk_main() made by this method causes the
307  * nested main loop to block, callbacks such as timeouts, iowatches
308  * and similar events will continue to be triggered. This method
309  * will not throw.
310  * @return The value returned by get_exec_val()
311  * @note If this library is compiled against GTK+3 and the WinBase
312  * object has been added to a Cgu::Application object, then this
313  * method returns immediately with a value of -1.
314  */
315  int exec();
316 
317  /**
318  * A convenience function which calls
319  * gtk_widget_show_all((GtkWidget*)get_win()). For classes which
320  * are intended to be derived from, it may be undesirable to call
321  * gtk_widget_show_all() in the class's constructor (a derived class
322  * may add widgets of its own in a way which requires the base
323  * class's widgets not to be realized). In such a case, calling
324  * gtk_widget_show_all() should be left to the user code. This is a
325  * function which makes that less verbose. It will not throw.
326  *
327  * Since 1.2.5
328  */
329  void show_all() {gtk_widget_show_all((GtkWidget*)get_win());}
330 
331  /**
332  * The constructor will not throw.
333  * @param caption Window caption (optional).
334  * @param icon A pixbuf which will comprise the window icon (optional).
335  * @param modal Whether the window is to be modal. If this argument
336  * is false and the window is a dialog, the user may want to
337  * consider calling gtk_window_set_type_hint() and possibly
338  * gtk_window_set_transient_for() before it becomes visible.
339  * @param parent The parent of a modal dialog or NULL. This
340  * argument is only acted on where the modal argument is true. The
341  * parent will be made insensitive while the modal dialog is in
342  * existence, and automatically made sensitive again when the modal
343  * dialog is finished with. gtk_window_set_transient_for() is also
344  * called, which means that the dialog will normally be kept on top
345  * of its parent and/or centered over it by the window manager. If
346  * the user does not want the parent to appear as insensitive, pass
347  * NULL to this argument and call gtk_window_set_transient_for() in
348  * the derived class's constructor.
349  * @param window A preformed GtkWindow object (such as a GtkDialog
350  * object), or NULL. If NULL, gtk_window_new(GTK_WINDOW_TOPLEVEL)
351  * will be called.
352  */
353  WinBase(const char* caption = 0, GdkPixbuf* icon = 0, bool modal = false,
354  GtkWindow* parent = 0, GtkWindow* window = 0);
355 
356  /**
357  * The destructor will not throw assuming, in a case where the
358  * Cgu::WinBase object has been added to a Cgu::Application object,
359  * that merely iterating through a list does not throw (as it would
360  * not on any sane implementation). Amongst other things, the
361  * destructor calls gtk_widget_destroy() on the managed top level
362  * window object.
363  */
364  virtual ~WinBase();
365 
366 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
368 #endif
369 };
370 
371 #endif // CGU_USE_GTK
372 
373 } // namespace Cgu
374 
375 #endif // CGU_WINDOW_H
Cgu::WinBase
This is a class for managing the lifetime of top level widgets.
Definition: window.h:225
Cgu
Definition: application.h:45
Cgu::Application
This is a class for constructing and managing GtkApplication objects.
Definition: application.h:408
Cgu::WinBase::get_win
GtkWindow * get_win() const
Definition: window.h:300
Cgu::WinBase::on_delete_event
virtual void on_delete_event()
Cgu::WinBase::~WinBase
virtual ~WinBase()
Cgu::WinBase::show_all
void show_all()
Definition: window.h:329
CGU_GLIB_MEMORY_SLICES_FUNCS
#define CGU_GLIB_MEMORY_SLICES_FUNCS
Definition: cgu_config.h:84
Cgu::WinBase::get_exec_val
virtual int get_exec_val() const
Cgu::WinBase::close
void close()
cgu_config.h
Cgu::WinBase::exec
int exec()