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