1 #ifndef _GLIBMM_PROPERTY_H
2 #define _GLIBMM_PROPERTY_H
3 
4 /* Copyright 2002 The gtkmm Development Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <glibmmconfig.h>
21 #include <glibmm/propertyproxy.h>
22 #include <glibmm/value.h>
23 
24 namespace Glib
25 {
26 
27 #ifndef DOXYGEN_SHOULD_SKIP_THIS
28 
29 #ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
30 // For the AIX xlC compiler, I can not find a way to do this without putting the functions in the
31 // global namespace. murrayc
32 extern "C" {
33 #endif // GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
34 
35 GLIBMM_API
36 void custom_get_property_callback(
37   GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec);
38 
39 GLIBMM_API
40 void custom_set_property_callback(
41   GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec);
42 
43 #ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
44 } // extern "C"
45 #endif // GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
46 
47 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
48 
49 /** This is the base class for Glib::Object properties.
50  *
51  * This class manages the generic parts of the object properties.
52  * Derived (templated) classes handle the specific value types.
53  */
54 class GLIBMM_API PropertyBase
55 {
56 public:
57   // noncopyable
58   PropertyBase(const PropertyBase&) = delete;
59   PropertyBase& operator=(const PropertyBase&) = delete;
60 
61   /** Returns the name of the property.
62    */
63   Glib::ustring get_name() const;
64 
65   /** Returns the nickname of the property.
66    */
67   Glib::ustring get_nick() const;
68 
69   /** Returns the short description of the property.
70    */
71   Glib::ustring get_blurb() const;
72 
73   /** Notifies the object containing the property that the property has changed.
74    * This emits the "notify" signal, passing the property name.
75    */
76   void notify();
77 
78 protected:
79   Glib::Object* object_;
80   Glib::ValueBase value_;
81   GParamSpec* param_spec_;
82 
83   /** This constructs a property of type @a value_type for the @a object.
84    * The property is not registered in the GObject object system
85    * until install_property() has been called. Derived classes do this in
86    * their constructors.
87    *
88    * The properties are usually installed during the initialization of the
89    * first instance of an object.
90    */
91   PropertyBase(Glib::Object& object, GType value_type);
92   ~PropertyBase() noexcept;
93 
94   /**
95    * Checks if the property has already been installed.
96    */
97   bool lookup_property(const Glib::ustring& name);
98 
99   /**
100    * Installs the property specified by the given @a param_spec.
101    */
102   void install_property(GParamSpec* param_spec);
103 
104   /**
105    * Returns the name of the property.
106    */
107   const char* get_name_internal() const;
108 
109 private:
110 #ifndef DOXYGEN_SHOULD_SKIP_THIS
111 
112   friend void Glib::custom_get_property_callback(
113     GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec);
114 
115   friend void Glib::custom_set_property_callback(
116     GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec);
117 
118 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
119 };
120 
121 /** A Glib::Object property.
122  *
123  * This class wraps a GObject property, providing a C++ API to the GObject property
124  * system, for use with classes derived from Glib::Object or Glib::Interface.
125  *
126  * A property is a value associated with each instance of a type and some
127  * class data for each property:
128  *  * Its unique name, used to identify the property.
129  *  * A human-readable nick name.
130  *  * A short description.
131  *  * The default value and the minimum and maximum bounds (depending on the type of the property).
132  *  * Flags, defining, among other things, whether the property can be read or written.
133  *
134  * This %Property class currently supports the name, nick name, description, default value and flags.
135  * The minimum and maximum bounds are set to the full range of the value.
136  * Because of internal implementation, flags shouldn't be set to values: Glib::PARAM_STATIC_NAME,
137  * Glib::PARAM_STATIC_NICK, Glib::PARAM_STATIC_BLURB, Glib::PARAM_CONSTRUCT and
138  * Glib::PARAM_CONSTRUCT_ONLY.
139  *
140  * The class information must be installed into the GObject system once per
141  * property, but this is handled automatically.
142  *
143  * Each property belongs to an object, inheriting from Glib::Object.
144  * A reference to the object must be passed to the constructor of the property.
145  *
146  * Each instance of a Glib::Object-derived type must construct the same properties
147  * (same type, same name) in the same order. One way to achieve this is to
148  * declare all properties as direct data members of the type.
149  *
150  * You may register new properties for your class (actually for the underlying GType)
151  * simply by adding a %Property instance as a class member.
152  * However, your constructor must call the Glib::ObjectBase constructor with a new GType name,
153  * in order to register a new GType.
154  *
155  * Example:
156  * @code
157  * class MyCellRenderer : public Gtk::CellRenderer
158  * {
159  * public:
160  *   MyCellRenderer()
161  *   :
162  *   Glib::ObjectBase (typeid(MyCellRenderer)),
163  *   Gtk::CellRenderer(),
164  *   property_mybool  (*this, "mybool", true),
165  *   property_myint_  (*this, "myint",    42)
166  *   {}
167  *
168  *   virtual ~MyCellRenderer() {}
169  *
170  *   // Glib::Property<> can be public,
171  *   Glib::Property<bool> property_mybool;
172  *   // or private, and combined with Glib::PropertyProxy<>.
173  *   Glib::PropertyProxy<int> property_myint() { return property_myint_.get_proxy(); }
174  *   Glib::PropertyProxy_ReadOnly<int> property_myint() const { return property_myint_.get_proxy(); }
175  *
176  * private:
177  *   Glib::Property<int> property_myint_;
178  * };
179  * @endcode
180  *
181  * @par %Glib::Property and Gtk::Builder
182  * The new GType is registered, and the properties installed in the GType, when
183  * the first instance of the class is created. When the underlying GObject-derived
184  * instance is created before the wrapping Glib::Object-derived instance, you may
185  * have to first create a dummy instance just to register the GType.
186  * See the description of Gtk::Builder for instructions how to combine %Property
187  * with Gtk::Builder.
188  */
189 template <class T>
190 class Property : public PropertyBase
191 {
192 public:
193   using PropertyType = T;
194   using ValueType = Glib::Value<T>;
195 
196   /**  Constructs a property of the @a object with the specified @a name.
197    * For each instance of the object, the same property must be constructed with the same name.
198    */
199   Property(Glib::Object& object, const Glib::ustring& name);
200 
201   /** Constructs a property of the @a object with the specified @a name and @a default_value.
202    * For  each instance of the object, the same property must be constructed with the same name.
203    */
204   Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value);
205 
206   /** Constructs a property of the @a object with the specified @a name, @a nick, @a blurb and
207    * @a flags.
208    * For  each instance of the object, the same property must be constructed with the same name.
209    */
210   Property(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick,
211            const Glib::ustring& blurb, Glib::ParamFlags flags);
212 
213   /** Constructs a property of the @a object with the specified @a name, @a default_value, @a nick,
214    * @a blurb and @a flags.
215    * For  each instance of the object, the same property must be constructed with the same name.
216    */
217   Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value,
218            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags);
219 
220   /** Sets the value of the property to @a data.
221    * The object containing the property will be notified about the change.
222    */
223   inline void set_value(const PropertyType& data);
224 
225   /** Returns the value of the property.
226    */
227   inline PropertyType get_value() const;
228 
229   /** Sets the value of the property to @a data.
230    * The object containing the property will be notified about the change.
231    */
232   inline Property<T>& operator=(const PropertyType& data);
233 
234   /** Returns the value of the property.
235    */
236   inline operator PropertyType() const;
237 
238   /** Returns a proxy object that can be used to read or write this property.
239    */
240   inline Glib::PropertyProxy<T> get_proxy();
241 
242   /** Returns a proxy object that can be used to read this property.
243    */
244   inline Glib::PropertyProxy_ReadOnly<T> get_proxy() const;
245 };
246 
247 /** See Property.
248  * This property can be read, but not written, so there is no set_value() method.
249  */
250 template <class T>
251 class Property_ReadOnly : public PropertyBase
252 {
253 public:
254   typedef T PropertyType;
255   typedef Glib::Value<T> ValueType;
256 
257   /**  Constructs a property of the @a object with the specified @a name.
258    * For each instance of the object, the same property must be constructed with the same name.
259    */
260   Property_ReadOnly(Glib::Object& object, const Glib::ustring& name);
261 
262   /** Constructs a property of the @a object with the specified @a name and @a default_value.
263    * For  each instance of the object, the same property must be constructed with the same name.
264    */
265   Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value);
266 
267   /** Constructs a property of the @a object with the specified @a name, @a nick, @a blurb and
268    * @a flags.
269    * For  each instance of the object, the same property must be constructed with the same name.
270    */
271   Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick,
272            const Glib::ustring& blurb, Glib::ParamFlags flags);
273 
274   /** Constructs a property of the @a object with the specified @a name, @a default_value, @a nick,
275    * @a blurb and @a flags.
276    * For  each instance of the object, the same property must be constructed with the same name.
277    */
278   Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value,
279            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags);
280 
281   /** Returns the value of the property.
282    */
283   inline PropertyType get_value() const;
284 
285   /** Returns the value of the property.
286    */
287   inline operator PropertyType() const;
288 
289   //TODO: Remove the non-const get_proxy() when we can break ABI.
290   /** Returns a proxy object that can be used to read this property.
291    */
292   inline Glib::PropertyProxy_ReadOnly<T> get_proxy();
293 
294   /** Returns a proxy object that can be used to read this property.
295    */
296   inline Glib::PropertyProxy_ReadOnly<T> get_proxy() const;
297 };
298 
299 /** See Property.
300  * This property can be written, but not read, so there is no get_value() method.
301  */
302 template <class T>
303 class Property_WriteOnly : public PropertyBase
304 {
305 public:
306   typedef T PropertyType;
307   typedef Glib::Value<T> ValueType;
308 
309   /**  Constructs a property of the @a object with the specified @a name.
310    * For each instance of the object, the same property must be constructed with the same name.
311    */
312   Property_WriteOnly(Glib::Object& object, const Glib::ustring& name);
313 
314   /** Constructs a property of the @a object with the specified @a name and @a default_value.
315    * For  each instance of the object, the same property must be constructed with the same name.
316    */
317   Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value);
318 
319   /** Constructs a property of the @a object with the specified @a name, @a nick, @a blurb and
320    * @a flags.
321    * For  each instance of the object, the same property must be constructed with the same name.
322    */
323   Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick,
324            const Glib::ustring& blurb, Glib::ParamFlags flags);
325 
326   /** Constructs a property of the @a object with the specified @a name, @a default_value, @a nick,
327    * @a blurb and @a flags.
328    * For  each instance of the object, the same property must be constructed with the same name.
329    */
330   Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value,
331            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags);
332 
333   /** Sets the value of the property to @a data.
334    * The object containing the property will be notified about the change.
335    */
336   inline void set_value(const PropertyType& data);
337 
338   /** Sets the value of the property to @a data.
339    * The object containing the property will be notified about the change.
340    */
341   inline Property_WriteOnly<T>& operator=(const PropertyType& data);
342 
343   /** Returns a proxy object that can be used to write this property.
344    */
345   inline Glib::PropertyProxy_WriteOnly<T> get_proxy();
346 };
347 
348 #ifndef DOXYGEN_SHOULD_SKIP_THIS
349 
350 /**** Glib::Property<T> ****************************************************/
351 
352 template <class T>
Property(Glib::Object & object,const Glib::ustring & name)353 Property<T>::Property(Glib::Object& object, const Glib::ustring& name)
354 : Property(object, name, Glib::ustring(), Glib::ustring(), Glib::PARAM_READWRITE)
355 {
356 }
357 
358 template <class T>
Property(Glib::Object & object,const Glib::ustring & name,const typename Property<T>::PropertyType & default_value)359 Property<T>::Property(Glib::Object& object, const Glib::ustring& name,
360   const typename Property<T>::PropertyType& default_value)
361 : Property(object, name, default_value, Glib::ustring(),
362     Glib::ustring(), Glib::PARAM_READWRITE)
363 {
364 }
365 
366 template <class T>
Property(Glib::Object & object,const Glib::ustring & name,const Glib::ustring & nick,const Glib::ustring & blurb,Glib::ParamFlags flags)367 Property<T>::Property(Glib::Object& object, const Glib::ustring& name,
368            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags)
369 : PropertyBase(object, ValueType::value_type())
370 {
371   flags |= Glib::PARAM_READWRITE;
372 
373   if (!lookup_property(name))
374     install_property(static_cast<ValueType&>(value_).create_param_spec(name, nick, blurb, flags));
375 }
376 
377 template <class T>
Property(Glib::Object & object,const Glib::ustring & name,const PropertyType & default_value,const Glib::ustring & nick,const Glib::ustring & blurb,Glib::ParamFlags flags)378 Property<T>::Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value,
379            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags)
380 :
381   PropertyBase(object, ValueType::value_type())
382 {
383   flags |= Glib::PARAM_READWRITE;
384 
385   static_cast<ValueType&>(value_).set(default_value);
386 
387   if (!lookup_property(name))
388     install_property(static_cast<ValueType&>(value_).create_param_spec(name, nick, blurb, flags));
389 }
390 
391 template <class T>
392 inline void
set_value(const typename Property<T>::PropertyType & data)393 Property<T>::set_value(const typename Property<T>::PropertyType& data)
394 {
395   static_cast<ValueType&>(value_).set(data);
396   this->notify();
397 }
398 
399 template <class T>
400 inline typename Property<T>::PropertyType
get_value()401 Property<T>::get_value() const
402 {
403   return static_cast<const ValueType&>(value_).get();
404 }
405 
406 template <class T>
407 inline Property<T>&
408 Property<T>::operator=(const typename Property<T>::PropertyType& data)
409 {
410   static_cast<ValueType&>(value_).set(data);
411   this->notify();
412   return *this;
413 }
414 
415 template <class T>
T()416 inline Property<T>::operator T() const
417 {
418   return static_cast<const ValueType&>(value_).get();
419 }
420 
421 template <class T>
422 inline Glib::PropertyProxy<T>
get_proxy()423 Property<T>::get_proxy()
424 {
425   return Glib::PropertyProxy<T>(object_, get_name_internal());
426 }
427 
428 template <class T>
429 inline Glib::PropertyProxy_ReadOnly<T>
get_proxy()430 Property<T>::get_proxy() const
431 {
432   return Glib::PropertyProxy_ReadOnly<T>(object_, get_name_internal());
433 }
434 
435 /**** Glib::Property_ReadOnly<T> ****************************************************/
436 
437 template <class T>
Property_ReadOnly(Glib::Object & object,const Glib::ustring & name)438 Property_ReadOnly<T>::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name)
439 : Property_ReadOnly(object, name, Glib::ustring(), Glib::ustring(), Glib::PARAM_READABLE)
440 {
441 }
442 
443 template <class T>
Property_ReadOnly(Glib::Object & object,const Glib::ustring & name,const typename Property_ReadOnly<T>::PropertyType & default_value)444 Property_ReadOnly<T>::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name,
445   const typename Property_ReadOnly<T>::PropertyType& default_value)
446 : Property_ReadOnly(object, name, default_value, Glib::ustring(), Glib::ustring(),
447     Glib::PARAM_READABLE)
448 {
449 }
450 
451 template <class T>
Property_ReadOnly(Glib::Object & object,const Glib::ustring & name,const Glib::ustring & nick,const Glib::ustring & blurb,Glib::ParamFlags flags)452 Property_ReadOnly<T>::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name,
453            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags)
454 : PropertyBase(object, ValueType::value_type())
455 {
456   flags |= Glib::PARAM_READABLE;
457   flags &= ~Glib::PARAM_WRITABLE;
458 
459   if (!lookup_property(name))
460     install_property(static_cast<ValueType&>(value_).create_param_spec(name, nick, blurb, flags));
461 }
462 
463 template <class T>
Property_ReadOnly(Glib::Object & object,const Glib::ustring & name,const PropertyType & default_value,const Glib::ustring & nick,const Glib::ustring & blurb,Glib::ParamFlags flags)464 Property_ReadOnly<T>::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value,
465            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags)
466 : PropertyBase(object, ValueType::value_type())
467 {
468   flags |= Glib::PARAM_READABLE;
469   flags &= ~Glib::PARAM_WRITABLE;
470 
471   static_cast<ValueType&>(value_).set(default_value);
472 
473   if (!lookup_property(name))
474     install_property(static_cast<ValueType&>(value_).create_param_spec(name, nick, blurb, flags));
475 }
476 
477 template <class T>
478 inline typename Property_ReadOnly<T>::PropertyType
get_value()479 Property_ReadOnly<T>::get_value() const
480 {
481   return static_cast<const ValueType&>(value_).get();
482 }
483 
484 template <class T>
T()485 inline Property_ReadOnly<T>::operator T() const
486 {
487   return static_cast<const ValueType&>(value_).get();
488 }
489 
490 template <class T>
491 inline Glib::PropertyProxy_ReadOnly<T>
get_proxy()492 Property_ReadOnly<T>::get_proxy()
493 {
494   return Glib::PropertyProxy_ReadOnly<T>(object_, get_name_internal());
495 }
496 
497 template <class T>
498 inline Glib::PropertyProxy_ReadOnly<T>
get_proxy()499 Property_ReadOnly<T>::get_proxy() const
500 {
501   return Glib::PropertyProxy_ReadOnly<T>(object_, get_name_internal());
502 }
503 
504 /**** Glib::Property_WriteOnly<T> ****************************************************/
505 
506 template <class T>
Property_WriteOnly(Glib::Object & object,const Glib::ustring & name)507 Property_WriteOnly<T>::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name)
508 : Property_WriteOnly(object, name, Glib::ustring(),
509     Glib::ustring(), Glib::PARAM_WRITABLE)
510 {
511 }
512 
513 template <class T>
Property_WriteOnly(Glib::Object & object,const Glib::ustring & name,const typename Property_WriteOnly<T>::PropertyType & default_value)514 Property_WriteOnly<T>::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name,
515   const typename Property_WriteOnly<T>::PropertyType& default_value)
516 : Property_WriteOnly(object, name, default_value, Glib::ustring(),
517     Glib::ustring(), Glib::PARAM_WRITABLE)
518 {
519 }
520 
521 template <class T>
Property_WriteOnly(Glib::Object & object,const Glib::ustring & name,const Glib::ustring & nick,const Glib::ustring & blurb,Glib::ParamFlags flags)522 Property_WriteOnly<T>::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name,
523            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags)
524 : PropertyBase(object, ValueType::value_type())
525 {
526   flags |= Glib::PARAM_WRITABLE;
527   flags &= ~Glib::PARAM_READABLE;
528 
529   if (!lookup_property(name))
530     install_property(static_cast<ValueType&>(value_).create_param_spec(name, nick, blurb, flags));
531 
532 }
533 
534 template <class T>
Property_WriteOnly(Glib::Object & object,const Glib::ustring & name,const PropertyType & default_value,const Glib::ustring & nick,const Glib::ustring & blurb,Glib::ParamFlags flags)535 Property_WriteOnly<T>::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value,
536            const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags)
537 : PropertyBase(object, ValueType::value_type())
538 {
539   flags |= Glib::PARAM_WRITABLE;
540   flags &= ~Glib::PARAM_READABLE;
541 
542   static_cast<ValueType&>(value_).set(default_value);
543 
544   if (!lookup_property(name))
545     install_property(static_cast<ValueType&>(value_).create_param_spec(name, nick, blurb, flags));
546 }
547 
548 template <class T>
549 inline void
set_value(const typename Property_WriteOnly<T>::PropertyType & data)550 Property_WriteOnly<T>::set_value(const typename Property_WriteOnly<T>::PropertyType& data)
551 {
552   static_cast<ValueType&>(value_).set(data);
553   this->notify();
554 }
555 
556 template <class T>
557 inline Property_WriteOnly<T>&
558 Property_WriteOnly<T>::operator=(const typename Property_WriteOnly<T>::PropertyType& data)
559 {
560   static_cast<ValueType&>(value_).set(data);
561   this->notify();
562   return *this;
563 }
564 
565 template <class T>
566 inline Glib::PropertyProxy_WriteOnly<T>
get_proxy()567 Property_WriteOnly<T>::get_proxy()
568 {
569   return Glib::PropertyProxy_WriteOnly<T>(object_, get_name_internal());
570 }
571 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
572 
573 } // namespace Glib
574 
575 #endif /* _GLIBMM_PROPERTY_H */
576