#ifndef _GLIBMM_PROPERTY_H #define _GLIBMM_PROPERTY_H /* Copyright 2002 The gtkmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include #include namespace Glib { #ifndef DOXYGEN_SHOULD_SKIP_THIS #ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC // For the AIX xlC compiler, I can not find a way to do this without putting the functions in the // global namespace. murrayc extern "C" { #endif // GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC GLIBMM_API void custom_get_property_callback( GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec); GLIBMM_API void custom_set_property_callback( GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec); #ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC } // extern "C" #endif // GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC #endif /* DOXYGEN_SHOULD_SKIP_THIS */ /** This is the base class for Glib::Object properties. * * This class manages the generic parts of the object properties. * Derived (templated) classes handle the specific value types. */ class GLIBMM_API PropertyBase { public: // noncopyable PropertyBase(const PropertyBase&) = delete; PropertyBase& operator=(const PropertyBase&) = delete; /** Returns the name of the property. */ Glib::ustring get_name() const; /** Returns the nickname of the property. */ Glib::ustring get_nick() const; /** Returns the short description of the property. */ Glib::ustring get_blurb() const; /** Notifies the object containing the property that the property has changed. * This emits the "notify" signal, passing the property name. */ void notify(); protected: Glib::Object* object_; Glib::ValueBase value_; GParamSpec* param_spec_; /** This constructs a property of type @a value_type for the @a object. * The property is not registered in the GObject object system * until install_property() has been called. Derived classes do this in * their constructors. * * The properties are usually installed during the initialization of the * first instance of an object. */ PropertyBase(Glib::Object& object, GType value_type); ~PropertyBase() noexcept; /** * Checks if the property has already been installed. */ bool lookup_property(const Glib::ustring& name); /** * Installs the property specified by the given @a param_spec. */ void install_property(GParamSpec* param_spec); /** * Returns the name of the property. */ const char* get_name_internal() const; private: #ifndef DOXYGEN_SHOULD_SKIP_THIS friend void Glib::custom_get_property_callback( GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec); friend void Glib::custom_set_property_callback( GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec); #endif /* DOXYGEN_SHOULD_SKIP_THIS */ }; /** A Glib::Object property. * * This class wraps a GObject property, providing a C++ API to the GObject property * system, for use with classes derived from Glib::Object or Glib::Interface. * * A property is a value associated with each instance of a type and some * class data for each property: * * Its unique name, used to identify the property. * * A human-readable nick name. * * A short description. * * The default value and the minimum and maximum bounds (depending on the type of the property). * * Flags, defining, among other things, whether the property can be read or written. * * This %Property class currently supports the name, nick name, description, default value and flags. * The minimum and maximum bounds are set to the full range of the value. * Because of internal implementation, flags shouldn't be set to values: Glib::PARAM_STATIC_NAME, * Glib::PARAM_STATIC_NICK, Glib::PARAM_STATIC_BLURB, Glib::PARAM_CONSTRUCT and * Glib::PARAM_CONSTRUCT_ONLY. * * The class information must be installed into the GObject system once per * property, but this is handled automatically. * * Each property belongs to an object, inheriting from Glib::Object. * A reference to the object must be passed to the constructor of the property. * * Each instance of a Glib::Object-derived type must construct the same properties * (same type, same name) in the same order. One way to achieve this is to * declare all properties as direct data members of the type. * * You may register new properties for your class (actually for the underlying GType) * simply by adding a %Property instance as a class member. * However, your constructor must call the Glib::ObjectBase constructor with a new GType name, * in order to register a new GType. * * Example: * @code * class MyCellRenderer : public Gtk::CellRenderer * { * public: * MyCellRenderer() * : * Glib::ObjectBase (typeid(MyCellRenderer)), * Gtk::CellRenderer(), * property_mybool (*this, "mybool", true), * property_myint_ (*this, "myint", 42) * {} * * virtual ~MyCellRenderer() {} * * // Glib::Property<> can be public, * Glib::Property property_mybool; * // or private, and combined with Glib::PropertyProxy<>. * Glib::PropertyProxy property_myint() { return property_myint_.get_proxy(); } * Glib::PropertyProxy_ReadOnly property_myint() const { return property_myint_.get_proxy(); } * * private: * Glib::Property property_myint_; * }; * @endcode * * @par %Glib::Property and Gtk::Builder * The new GType is registered, and the properties installed in the GType, when * the first instance of the class is created. When the underlying GObject-derived * instance is created before the wrapping Glib::Object-derived instance, you may * have to first create a dummy instance just to register the GType. * See the description of Gtk::Builder for instructions how to combine %Property * with Gtk::Builder. */ template class Property : public PropertyBase { public: using PropertyType = T; using ValueType = Glib::Value; /** Constructs a property of the @a object with the specified @a name. * For each instance of the object, the same property must be constructed with the same name. */ Property(Glib::Object& object, const Glib::ustring& name); /** Constructs a property of the @a object with the specified @a name and @a default_value. * For each instance of the object, the same property must be constructed with the same name. */ Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value); /** Constructs a property of the @a object with the specified @a name, @a nick, @a blurb and * @a flags. * For each instance of the object, the same property must be constructed with the same name. */ Property(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags); /** Constructs a property of the @a object with the specified @a name, @a default_value, @a nick, * @a blurb and @a flags. * For each instance of the object, the same property must be constructed with the same name. */ Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags); /** Sets the value of the property to @a data. * The object containing the property will be notified about the change. */ inline void set_value(const PropertyType& data); /** Returns the value of the property. */ inline PropertyType get_value() const; /** Sets the value of the property to @a data. * The object containing the property will be notified about the change. */ inline Property& operator=(const PropertyType& data); /** Returns the value of the property. */ inline operator PropertyType() const; /** Returns a proxy object that can be used to read or write this property. */ inline Glib::PropertyProxy get_proxy(); /** Returns a proxy object that can be used to read this property. */ inline Glib::PropertyProxy_ReadOnly get_proxy() const; }; /** See Property. * This property can be read, but not written, so there is no set_value() method. */ template class Property_ReadOnly : public PropertyBase { public: typedef T PropertyType; typedef Glib::Value ValueType; /** Constructs a property of the @a object with the specified @a name. * For each instance of the object, the same property must be constructed with the same name. */ Property_ReadOnly(Glib::Object& object, const Glib::ustring& name); /** Constructs a property of the @a object with the specified @a name and @a default_value. * For each instance of the object, the same property must be constructed with the same name. */ Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value); /** Constructs a property of the @a object with the specified @a name, @a nick, @a blurb and * @a flags. * For each instance of the object, the same property must be constructed with the same name. */ Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags); /** Constructs a property of the @a object with the specified @a name, @a default_value, @a nick, * @a blurb and @a flags. * For each instance of the object, the same property must be constructed with the same name. */ Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags); /** Returns the value of the property. */ inline PropertyType get_value() const; /** Returns the value of the property. */ inline operator PropertyType() const; //TODO: Remove the non-const get_proxy() when we can break ABI. /** Returns a proxy object that can be used to read this property. */ inline Glib::PropertyProxy_ReadOnly get_proxy(); /** Returns a proxy object that can be used to read this property. */ inline Glib::PropertyProxy_ReadOnly get_proxy() const; }; /** See Property. * This property can be written, but not read, so there is no get_value() method. */ template class Property_WriteOnly : public PropertyBase { public: typedef T PropertyType; typedef Glib::Value ValueType; /** Constructs a property of the @a object with the specified @a name. * For each instance of the object, the same property must be constructed with the same name. */ Property_WriteOnly(Glib::Object& object, const Glib::ustring& name); /** Constructs a property of the @a object with the specified @a name and @a default_value. * For each instance of the object, the same property must be constructed with the same name. */ Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value); /** Constructs a property of the @a object with the specified @a name, @a nick, @a blurb and * @a flags. * For each instance of the object, the same property must be constructed with the same name. */ Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags); /** Constructs a property of the @a object with the specified @a name, @a default_value, @a nick, * @a blurb and @a flags. * For each instance of the object, the same property must be constructed with the same name. */ Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags); /** Sets the value of the property to @a data. * The object containing the property will be notified about the change. */ inline void set_value(const PropertyType& data); /** Sets the value of the property to @a data. * The object containing the property will be notified about the change. */ inline Property_WriteOnly& operator=(const PropertyType& data); /** Returns a proxy object that can be used to write this property. */ inline Glib::PropertyProxy_WriteOnly get_proxy(); }; #ifndef DOXYGEN_SHOULD_SKIP_THIS /**** Glib::Property ****************************************************/ template Property::Property(Glib::Object& object, const Glib::ustring& name) : Property(object, name, Glib::ustring(), Glib::ustring(), Glib::PARAM_READWRITE) { } template Property::Property(Glib::Object& object, const Glib::ustring& name, const typename Property::PropertyType& default_value) : Property(object, name, default_value, Glib::ustring(), Glib::ustring(), Glib::PARAM_READWRITE) { } template Property::Property(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags) : PropertyBase(object, ValueType::value_type()) { flags |= Glib::PARAM_READWRITE; if (!lookup_property(name)) install_property(static_cast(value_).create_param_spec(name, nick, blurb, flags)); } template Property::Property(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags) : PropertyBase(object, ValueType::value_type()) { flags |= Glib::PARAM_READWRITE; static_cast(value_).set(default_value); if (!lookup_property(name)) install_property(static_cast(value_).create_param_spec(name, nick, blurb, flags)); } template inline void Property::set_value(const typename Property::PropertyType& data) { static_cast(value_).set(data); this->notify(); } template inline typename Property::PropertyType Property::get_value() const { return static_cast(value_).get(); } template inline Property& Property::operator=(const typename Property::PropertyType& data) { static_cast(value_).set(data); this->notify(); return *this; } template inline Property::operator T() const { return static_cast(value_).get(); } template inline Glib::PropertyProxy Property::get_proxy() { return Glib::PropertyProxy(object_, get_name_internal()); } template inline Glib::PropertyProxy_ReadOnly Property::get_proxy() const { return Glib::PropertyProxy_ReadOnly(object_, get_name_internal()); } /**** Glib::Property_ReadOnly ****************************************************/ template Property_ReadOnly::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name) : Property_ReadOnly(object, name, Glib::ustring(), Glib::ustring(), Glib::PARAM_READABLE) { } template Property_ReadOnly::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const typename Property_ReadOnly::PropertyType& default_value) : Property_ReadOnly(object, name, default_value, Glib::ustring(), Glib::ustring(), Glib::PARAM_READABLE) { } template Property_ReadOnly::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags) : PropertyBase(object, ValueType::value_type()) { flags |= Glib::PARAM_READABLE; flags &= ~Glib::PARAM_WRITABLE; if (!lookup_property(name)) install_property(static_cast(value_).create_param_spec(name, nick, blurb, flags)); } template Property_ReadOnly::Property_ReadOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags) : PropertyBase(object, ValueType::value_type()) { flags |= Glib::PARAM_READABLE; flags &= ~Glib::PARAM_WRITABLE; static_cast(value_).set(default_value); if (!lookup_property(name)) install_property(static_cast(value_).create_param_spec(name, nick, blurb, flags)); } template inline typename Property_ReadOnly::PropertyType Property_ReadOnly::get_value() const { return static_cast(value_).get(); } template inline Property_ReadOnly::operator T() const { return static_cast(value_).get(); } template inline Glib::PropertyProxy_ReadOnly Property_ReadOnly::get_proxy() { return Glib::PropertyProxy_ReadOnly(object_, get_name_internal()); } template inline Glib::PropertyProxy_ReadOnly Property_ReadOnly::get_proxy() const { return Glib::PropertyProxy_ReadOnly(object_, get_name_internal()); } /**** Glib::Property_WriteOnly ****************************************************/ template Property_WriteOnly::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name) : Property_WriteOnly(object, name, Glib::ustring(), Glib::ustring(), Glib::PARAM_WRITABLE) { } template Property_WriteOnly::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const typename Property_WriteOnly::PropertyType& default_value) : Property_WriteOnly(object, name, default_value, Glib::ustring(), Glib::ustring(), Glib::PARAM_WRITABLE) { } template Property_WriteOnly::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags) : PropertyBase(object, ValueType::value_type()) { flags |= Glib::PARAM_WRITABLE; flags &= ~Glib::PARAM_READABLE; if (!lookup_property(name)) install_property(static_cast(value_).create_param_spec(name, nick, blurb, flags)); } template Property_WriteOnly::Property_WriteOnly(Glib::Object& object, const Glib::ustring& name, const PropertyType& default_value, const Glib::ustring& nick, const Glib::ustring& blurb, Glib::ParamFlags flags) : PropertyBase(object, ValueType::value_type()) { flags |= Glib::PARAM_WRITABLE; flags &= ~Glib::PARAM_READABLE; static_cast(value_).set(default_value); if (!lookup_property(name)) install_property(static_cast(value_).create_param_spec(name, nick, blurb, flags)); } template inline void Property_WriteOnly::set_value(const typename Property_WriteOnly::PropertyType& data) { static_cast(value_).set(data); this->notify(); } template inline Property_WriteOnly& Property_WriteOnly::operator=(const typename Property_WriteOnly::PropertyType& data) { static_cast(value_).set(data); this->notify(); return *this; } template inline Glib::PropertyProxy_WriteOnly Property_WriteOnly::get_proxy() { return Glib::PropertyProxy_WriteOnly(object_, get_name_internal()); } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ } // namespace Glib #endif /* _GLIBMM_PROPERTY_H */