c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
48 #include <c++-gtk-utils/cgu_config.h>
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 */
218 GobjHandle(GobjHandle&& gobj) {
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 */
240 GobjHandle& operator=(const GobjHandle& gobj) {
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 */
266 GobjHandle& operator=(GobjHandle&& gobj) {
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 */
457 GobjWeakHandle(const GobjWeakHandle& gobj) {
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 */
469 GobjWeakHandle(const GobjHandle<T>& gobj) {
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 */
483 GobjWeakHandle& operator=(const GobjWeakHandle& gobj) {
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 */
496 GobjWeakHandle& operator=(const GobjHandle<T>& gobj) {
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