c++-gtk-utils
gobj_handle.h
Go to the documentation of this file.
1 /* Copyright (C) 2005 to 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 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 #ifndef CGU_GOBJ_HANDLE_H
40 #define CGU_GOBJ_HANDLE_H
41 
42 #include <exception>
43 #include <functional> // for std::less and std::hash<T*>
44 #include <cstddef> // for std::size_t
45 
46 #include <glib-object.h>
47 
49 
50 /**
51  * @addtogroup handles handles and smart pointers
52  */
53 
54 namespace Cgu {
55 
56 /**
57  * @class GobjHandle gobj_handle.h c++-gtk-utils/gobj_handle.h
58  * @brief This is a handle for managing the reference count of
59  * GObjects.
60  * @ingroup handles
61  * @sa MainWidgetBase GobjWeakHandle
62  *
63  * This is a class which manages the reference count of GObjects. It
64  * does not maintain its own reference count, but interfaces with that
65  * kept by the glib object system.
66  *
67  * GobjHandles are most useful to manage GObjects which are not also
68  * GtkWidgets or GInitiallyUnowned objects - GtkWidgets and
69  * GInitiallyUnowned objects have initial floating references which
70  * will result in them being automatically managed by the container in
71  * which they are held. Nonetheless, GobjHandles can be used to hold
72  * GtkWidgets and GInitiallyUnowned objects, as the constructor of a
73  * GobjHandle which takes a pointer will automatically take ownership
74  * of a newly created GtkWidget or GInitiallyUnowned object, by
75  * calling g_object_ref_sink(). Plain GObjects do not need to be sunk
76  * to be owned by the GobjHandle.
77  *
78  * Note that g_object_ref_sink() is not called by the constructor
79  * taking a pointer if the floating reference has already been sunk,
80  * so if that constructor is passed an object already owned by a GTK+
81  * container it will be necessary to call g_object_ref() on it
82  * explicitly. This behaviour will ensure that the handle behaves the
83  * same whether it is holding a plain GObject, or it is holding a
84  * GInitiallyUnowned/GtkWidget object. Generally however, where an
85  * object is already owned by a container, the object should be passed
86  * by another handle - ie by the copy constructor (or by the
87  * assignment operator), as those always increment the reference count
88  * automatically.
89  *
90  * In other words, invoke the constructor taking a pointer only with a
91  * newly created object (whether a GObject, GInitiallyUnowned or
92  * GtkWidget object), and everything else will take care of itself. In
93  * this respect, GobjHandles work the same way as conventional shared
94  * pointer implementations managing objects allocated on free store.
95  * The same applies to the reset() method. (Care is required however
96  * if initializing a Cgu::GobjHandle with a widget or GObject object
97  * obtained from GtkBuilder, since these are not "newly created" in
98  * this sense. It is necessary to call g_object_ref() by hand in that
99  * case, since GtkBuilder does not by itself pass ownership of any
100  * objects it creates.)
101  *
102  * Because any GTK+ containers themselves increment the reference
103  * count of a GObject or GtkWidget where they need to take ownership,
104  * an already-managed object held by a GobjHandle can safely be passed
105  * by pointer to a GTK+ container, and that is one of the intended
106  * usages. For that purpose, although the class has operator*() and
107  * operator->() dereferencing operators, and so has normal smart
108  * pointer functionality, as it is intended for use with the normal C
109  * GObject/pango/GTK+ interfaces, ordinary use would involve passing
110  * the handle to a function taking a pointer by means of the
111  * operatorT*() type conversion operator (which returns the underlying
112  * pointer), or by explicitly calling the get() method to obtain the
113  * underlying pointer.
114  *
115  * The principal intended usage of GobjHandle is to automatically
116  * handle GObject reference counts and therefore to make GObjects
117  * exception-safe, but they also permit GObjects/GtkWidgets to be kept
118  * in standard C++ containers.
119  *
120  * As of glib-2.8, g_object_ref() and g_object_unref() are thread
121  * safe, so with glib-2.8 or greater there can be different GobjHandle
122  * instances in different threads referencing the same GObject object.
123  * Of course, if that is done, this does not affect the need (or
124  * otherwise) in the particular use in question to lock anything other
125  * than the reference count - say when accessing the referenced object
126  * itself in different threads.
127  *
128  * Typical usage might be, for example, as follows:
129  *
130  * @code
131  * using namespace Cgu;
132  * GobjHandle<GtkListStore> store(gtk_list_store_new(1, G_TYPE_STRING));
133  *
134  * [ ... fill the list store ... ]
135  *
136  * GobjHandle<GtkWidget> view(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store.get()));
137  * // 'view' will take sole ownership of the list store when 'store' goes out of scope, or
138  * // 'store' could be kept alive so that the list store will survive removal from the view
139  *
140  * [ ... set up an interface including a GtkVBox 'vbox' which will hold the tree view ... ]
141  *
142  * gtk_container_add(GTK_CONTAINER(vbox), view);
143  * // 'vbox' will take sole ownership of the tree view when 'view' goes out of scope, or
144  * // 'view' could be kept alive so that the tree view will survive removal from the vbox
145  * @endcode
146  */
147 
148 template <class T> class GobjHandle {
149 
150  T* obj_p;
151 
152  void unreference() {
153  if (obj_p) g_object_unref(obj_p);
154  }
155 
156  void reference() {
157  if (obj_p) g_object_ref(obj_p);
158  }
159 
160 public:
161 
162  /**
163  * The constructor does not throw. g_object_ref_sink() is called if
164  * the managed object has a floating reference.
165  * @param ptr The object which the GobjHandle is to manage (if any).
166  * @note The object passed should not normally be already owned by a
167  * GTK+ container or managed by any other GobjHandle object. If it
168  * is, g_object_ref() must be called explicitly by the user code.
169  */
170  explicit GobjHandle(T* ptr = 0) {
171  obj_p = ptr;
172 
173  // if an object with a floating reference has been passed to this constructor,
174  // take ownership of it
175  if (ptr && g_object_is_floating(ptr)) {
176  g_object_ref_sink(ptr);
177  }
178  }
179 
180  /**
181  * Causes the handle to cease to manage its managed object (if any)
182  * and decrements its reference count, so destroying it if the
183  * reference count thereby becomes 0. If the argument passed is not
184  * NULL, the handle will manage the new object passed and
185  * g_object_ref_sink() is called if the new object has a floating
186  * reference. This method does not throw.
187  * @param ptr NULL (the default), or a new object to manage.
188  * @note The new object passed should not normally be already owned
189  * by a GTK+ container or managed by any other GobjHandle object. If
190  * it is, g_object_ref() must be called explicitly by the user code.
191  */
192  void reset(T* ptr = 0) {
193 
194  unreference();
195  obj_p = ptr;
196 
197  // if an object with a floating reference has been passed to this method,
198  // take ownership of it
199  if (ptr && g_object_is_floating(ptr)) {
200  g_object_ref_sink(ptr);
201  }
202  }
203 
204  /**
205  * The copy constructor does not throw. It increments the reference
206  * count of the managed object.
207  * @param gobj The handle to be copied.
208  */
209  GobjHandle(const GobjHandle& gobj) {
210  obj_p = gobj.obj_p;
211  reference();
212  }
213 
214  /**
215  * The move constructor does not throw. It has move semantics.
216  * @param gobj The handle to be moved.
217  */
219  obj_p = gobj.obj_p;
220  gobj.obj_p = 0;
221  }
222 
223  // We don't have a constructor for GobjHandle taking a GobjWeakHandle
224  // object. If we did that, we would have to remove the GobjWeakHandle
225  // constructor taking a pointer so we know that its tracked object
226  // always has an owner when initialising a new GobjHandle with the
227  // GobjWeakHandle, so we can in turn know we can increase the reference
228  // count when initialising the GobjHandle. However, removing that
229  // constructor would be inconsistent with one of the purposes of having
230  // a GobjWeakHandle class. For the same reason, we don't have an
231  // assignment operator for GobjHandle taking such an object.
232  /**
233  * This method does not throw. It decrements the reference count of
234  * the former managed object (if any), so destroying it if the
235  * reference count thereby becomes 0, and increments the reference
236  * count of the new managed object.
237  * @param gobj The assignor.
238  * @return The GobjHandle object after assignment.
239  */
241 
242  // check whether we are already referencing this object -
243  // if so make this a null op. This will also deal with
244  // self-assignment
245  if (obj_p != gobj.obj_p) {
246 
247  // first unreference any object referenced by this handle
248  unreference();
249 
250  // now inherit the GObject from the assigning handle
251  // and reference it
252  obj_p = gobj.obj_p;
253  reference();
254  }
255  return *this;
256  }
257 
258  /**
259  * This method does not throw. It decrements the reference count of
260  * the former managed object (if any), so destroying it if the
261  * reference count thereby becomes 0, and has move semantics with
262  * respect to the new managed object.
263  * @param gobj The handle to be moved.
264  * @return The GobjHandle object after the move operation.
265  */
267 
268  // check for self-assignment
269  if (this != &gobj) {
270 
271  // first unreference any object referenced by this handle
272  unreference();
273 
274  // now inherit the GObject from the moving handle
275  obj_p = gobj.obj_p;
276  gobj.obj_p = 0;
277  }
278  return *this;
279  }
280 
281  /**
282  * This method does not throw.
283  * @return A pointer to the handled GObject (or NULL if none is
284  * handled).
285  */
286  T* get() const {return obj_p;}
287 
288  /**
289  * This method does not throw.
290  * @return A reference to the handled GObject.
291  */
292  T& operator*() const {return *obj_p;}
293 
294  /**
295  * This method does not throw.
296  * @return A pointer to the handled GObject (or NULL if none is
297  * handled).
298  */
299  T* operator->() const {return obj_p;}
300 
301  /**
302  * This method does not throw.
303  * @return A pointer to the handled GObject (or NULL if none is
304  * handled).
305  */
306  operator T*() const {return obj_p;}
307 
308  /**
309  * The destructor does not throw. It decrements the reference count
310  * of the managed object (if any), so destroying it if the reference
311  * count thereby becomes 0.
312  */
313  ~GobjHandle() {unreference();}
314 };
315 
316 /**
317  * @class GobjWeakHandle gobj_handle.h c++-gtk-utils/gobj_handle.h
318  * @brief This is a handle for managing weak references to GObjects.
319  * @ingroup handles
320  * @sa GobjHandle
321  *
322  * This class tracks a GObject, so that if that GObject no longer
323  * exists then operator bool() or the valid() method will return
324  * false, but does not take a strong reference by incrementing the
325  * reference count to the GObject and so take ownership of it. It has
326  * two main use areas: first, in order to break reference cycles that
327  * may otherwise arise if two classes would otherwise hold strong
328  * references to each other. Secondly, to manage a pointer to a
329  * GObject returned by a GTK+ getter function where ownership is not
330  * passed (that is, where the user is not expected to call
331  * g_object_unref() when finished with the return value). A typical
332  * example of this is the GtkTreeSelection object returned by
333  * gtk_tree_view_get_selection(). The GtkTreeSelection object is part
334  * of the GtkTreeView's implemention and will become invalid as soon
335  * as the GtkTreeView object is finalized.
336  *
337  * As in the case of the GobjHandle class, although this class has
338  * operator*() and operator->() dereferencing operators, and so has
339  * normal smart pointer functionality, as it is intended for use with
340  * the normal C GObject/pango/GTK+ interfaces, ordinary use would
341  * involve passing the handle to a function taking a pointer by means
342  * of the operatorT*() type conversion operator (which returns the
343  * underlying pointer), or by explicitly calling the get() method to
344  * obtain the underlying pointer.
345  *
346  * Typical usage is as follows:
347  *
348  * @code
349  * using namespace Cgu;
350  * GobjWeakHandle<GtkTreeSelection> s(gtk_tree_view_get_selection(tree_view));
351  * gtk_tree_selection_set_mode(s, GTK_SELECTION_SINGLE);
352  * ...
353  *
354  * [some code blocks later]
355  * if (s) { // check that the GtkTreeSelection object still exists.
356  * GtkTreeIter iter;
357  * GtkTreeModel* model = 0;
358  * gtk_tree_selection_get_selected(s, &model, &iter);
359  * ...
360  * }
361  * else [report error];
362  * @endcode
363  *
364  * Or instead of an 'if' block, GobjWeakHandleError could be caught:
365  *
366  * @code
367  * using namespace Cgu;
368  * GobjWeakHandle<GtkTreeSelection> s(gtk_tree_view_get_selection(tree_view));
369  * gtk_tree_selection_set_mode(s, GTK_SELECTION_SINGLE);
370  * ...
371  *
372  * [some code blocks later]
373  * GtkTreeIter iter;
374  * GtkTreeModel* model = 0;
375  * try {
376  * gtk_tree_selection_get_selected(s, &model, &iter);
377  * ...
378  * }
379  * catch (GobjWeakHandleError&) {[report error]}
380  * @endcode
381  *
382  * @b Thread-safe @b use
383  *
384  * This class wraps
385  * g_object_add_weak_pointer()/g_object_remove_weak_pointer(), and as
386  * those GObject functions have practical limitations concerning
387  * thread-safe use, this class has the same practical limitations. As
388  * shown above, typical usage for a weak pointer 's' would be 'if (s)
389  * do_it(s)', but if the thread calling that sequence (thread A) were
390  * not the thread controlling the lifetime of the referenced GObject
391  * (thread B), then thread B may have destroyed the GObject between
392  * thread A testing 's' and then calling the referenced object. The
393  * same applies to the test leading to GobjWeakHandleError being
394  * thrown.
395  *
396  * In other words, in the GtkTreeSelection code example above, if the
397  * thread calling gtk_tree_selection_get_selected() were not the main
398  * GUI thread (which would anyway require the use of
399  * gdk_threads_enter()/gdk_threads_leave()), then the calling thread
400  * must ensure that the main GUI thread does not destroy the relevant
401  * tree view, and so the GtkTreeSelection object, from the beginning
402  * of the 'if' test to the end of the 'if' block, or for the duration
403  * of the try block. (This cannot be done just by incrementing the
404  * reference count of the tree view or the tree selection in the
405  * calling thread before the 'if' test or the try block is entered,
406  * because by the time the reference is incremented and the weak
407  * pointer tested, the tree view and tree selection may already be in
408  * their dispose functions but the tree selection's dispose function
409  * may not yet have reached the point of dispatching the callback
410  * NULLing the weak pointer. As a general design issue, it is usually
411  * best only to call GTK+ functions in one thread, and in order to
412  * make that straightforward, this library contains a number of
413  * classes and functions for inter-thread communication.)
414  */
415 
416 struct GobjWeakHandleError: public std::exception {
417  virtual const char* what() const throw() {return "GobjWeakHandleError\n";}
418 };
419 
420 template <class T> class GobjWeakHandle {
421 
422  T* obj_p;
423 
424 public:
425 
426  /**
427  * This constructor does not throw.
428  * @param ptr The object which the GobjWeakHandle is to track (if any).
429  */
430  explicit GobjWeakHandle(T* ptr = 0) {
431  obj_p = ptr;
432  if (ptr) g_object_add_weak_pointer((GObject*)ptr,
433  (void**)&obj_p);
434  }
435 
436  /**
437  * Causes the handle to cease to track its tracked object (if any).
438  * If the argument passed is not NULL, the handle will track the new
439  * object passed. This method does not throw.
440  * @param ptr NULL (the default), or a new object to track.
441  */
442  void reset(T* ptr = 0) {
443 
444  if (obj_p) g_object_remove_weak_pointer((GObject*)obj_p,
445  (void**)&obj_p);
446  obj_p = ptr;
447  if (ptr) g_object_add_weak_pointer((GObject*)ptr,
448  (void**)&obj_p);
449  }
450 
451  /**
452  * The copy constructor does not throw. It constructs a new weak
453  * pointer tracking the same GObject as that tracked by the existing
454  * weak pointer.
455  * @param gobj The handle to be copied.
456  */
458  obj_p = gobj.obj_p;
459  if (obj_p) g_object_add_weak_pointer((GObject*)obj_p,
460  (void**)&obj_p);
461  }
462 
463  /**
464  * This constructor constructs a weak pointer for a GObject managed
465  * by a GobjHandle handle. It does not throw.
466  * @param gobj The GobjHandle managing the GObject which the
467  * GobjWeakHandle is to track.
468  */
470  obj_p = gobj.get();
471  if (obj_p) g_object_add_weak_pointer((GObject*)obj_p,
472  (void**)&obj_p);
473  }
474 
475  /**
476  * This method does not throw. It causes the handle to cease to
477  * track its tracked object (if any), and begin tracking the same
478  * GObject as that tracked by the assignor. This method does not
479  * throw.
480  * @param gobj The assignor.
481  * @return The GobjWeakHandle object after assignment.
482  */
484  // self assignment takes care of itself
485  reset(gobj.obj_p);
486  return *this;
487  }
488 
489  /**
490  * This method does not throw. It causes the handle to cease to
491  * track its tracked object (if any), and begin tracking the GObject
492  * managed by the GobjHandle argument. This method does not throw.
493  * @param gobj The assignor GobjHandle.
494  * @return The GobjWeakHandle object after assignment.
495  */
497  reset(gobj.get());
498  return *this;
499  }
500 
501  /**
502  * This method does not throw.
503  * @return True if the tracked GObject still exists, or false if it
504  * does not or no GObject is being tracked.
505  * @note The valid() method is a synonym for this method.
506  */
507  operator bool() const {return obj_p;}
508 
509 #ifndef DOXYGEN_PARSING
510  /*
511  * DEPRECATED: Do not use this method as it is only retained for
512  * source compatibility. Its semantics are the wrong way around:
513  * expired() returns true if the GObject still exists, instead of
514  * false. Use operator bool() or the valid() method instead, which
515  * have the correct semantics. This method does not throw.
516  */
517  bool expired() const {return obj_p;}
518 #endif
519 
520  /**
521  * This method does not throw.
522  * @return True if the tracked GObject still exists, or false if it
523  * does not or no GObject is being tracked.
524  * @note operator bool() is a synonym for this method.
525  *
526  * Since 2.0.5
527  */
528  bool valid() const {return obj_p;}
529 
530  /**
531  * This method does not throw.
532  * @return A pointer to the tracked GObject.
533  * @exception GobjWeakHandleError This method will throw
534  * GobjWeakHandleError if the tracked object no longer exists or none
535  * is being tracked. There is no need to check for this exception if
536  * the status of the tracked object has been established with
537  * operator bool() or valid().
538  */
539  T* get() const {if (!obj_p) throw GobjWeakHandleError(); return obj_p;}
540 
541  /**
542  * This method does not throw.
543  * @return A reference to the tracked GObject.
544  * @exception GobjWeakHandleError This method will throw
545  * GobjWeakHandleError if the tracked object no longer exists or none
546  * is being tracked. There is no need to check for this exception if
547  * the status of the tracked object has been established with
548  * operator bool() or valid().
549  */
550  T& operator*() const {if (!obj_p) throw GobjWeakHandleError(); return *obj_p;}
551 
552  /**
553  * This method does not throw.
554  * @return A pointer to the tracked GObject.
555  * @exception GobjWeakHandleError This method will throw
556  * GobjWeakHandleError if the tracked object no longer exists or none
557  * is being tracked. There is no need to check for this exception if
558  * the status of the tracked object has been established with
559  * operator bool() or valid().
560  */
561  T* operator->() const {if (!obj_p) throw GobjWeakHandleError(); return obj_p;}
562 
563  /**
564  * This method does not throw.
565  * @return A pointer to the tracked GObject.
566  * @exception GobjWeakHandleError This method will throw
567  * GobjWeakHandleError if the tracked object no longer exists or none
568  * is being tracked. There is no need to check for this exception if
569  * the status of the tracked object has been established with
570  * operator bool() or valid().
571  */
572  operator T*() const {if (!obj_p) throw GobjWeakHandleError(); return obj_p;}
573 
574  /**
575  * The destructor does not throw.
576  */
577  ~GobjWeakHandle() {if (obj_p) g_object_remove_weak_pointer((GObject*)obj_p,
578  (void**)&obj_p);}
579 };
580 
581 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
582 
583 // we can use built-in operator == when comparing pointers referencing
584 // different objects of the same type
585 /**
586  * @ingroup handles
587  *
588  * This comparison operator does not throw. It compares the addresses
589  * of the managed objects.
590  *
591  * Since 2.0.0-rc2
592  */
593 template <class T>
594 bool operator==(const GobjHandle<T>& h1, const GobjHandle<T>& h2) {
595  return (h1.get() == h2.get());
596 }
597 
598 /**
599  * @ingroup handles
600  *
601  * This comparison operator does not throw. It compares the addresses
602  * of the managed objects.
603  *
604  * Since 2.0.0-rc2
605  */
606 template <class T>
607 bool operator!=(const GobjHandle<T>& h1, const GobjHandle<T>& h2) {
608  return !(h1 == h2);
609 }
610 
611 // we must use std::less rather than the < built-in operator for
612 // pointers to objects not within the same array or object: "For
613 // templates greater, less, greater_equal, and less_equal, the
614 // specializations for any pointer type yield a total order, even if
615 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
616 /**
617  * @ingroup handles
618  *
619  * This comparison operator does not throw. It compares the addresses
620  * of the managed objects.
621  *
622  * Since 2.0.0-rc2
623  */
624 template <class T>
625 bool operator<(const GobjHandle<T>& h1, const GobjHandle<T>& h2) {
626  return std::less<T*>()(h1.get(), h2.get());
627 }
628 
629 #endif // CGU_USE_SMART_PTR_COMPARISON
630 
631 } // namespace Cgu
632 
633 // doxygen produces long filenames that tar can't handle:
634 // we have generic documentation for std::hash specialisations
635 // in doxygen.main.in
636 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
637 /* This struct allows GobjHandle objects to be keys in unordered
638  associative containers */
639 namespace std {
640 template <class T>
641 struct hash<Cgu::GobjHandle<T>> {
642  typedef std::size_t result_type;
643  typedef Cgu::GobjHandle<T> argument_type;
644  result_type operator()(const argument_type& h) const {
645  // this is fine: std::hash structs do not normally contain data and
646  // std::hash<T*> certainly won't, so we don't have overhead constructing
647  // std::hash<T*> on the fly
648  return std::hash<T*>()(h.get());
649  }
650 };
651 } // namespace std
652 #endif // CGU_USE_SMART_PTR_COMPARISON
653 
654 #endif