#if !defined (__GLIB_GOBJECT_H_INSIDE__) && !defined (GOBJECT_COMPILATION)
#error "Only <glib-object.h> can be included directly."
#endif

#ifndef __G_PROPERTY_H__
#define __G_PROPERTY_H__

#include <glib.h>
#include <gobject/gparam.h>
#include <gobject/gobject.h>

G_BEGIN_DECLS

#define G_TYPE_PROPERTY         (g_property_get_type ())
#define G_PROPERTY(obj)         (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_PROPERTY, GProperty))
#define G_IS_PROPERTY(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_PROPERTY))

typedef struct _GProperty       GProperty;

/* general purpose API */
const gchar *   g_property_canonicalize (const gchar  *name);

void            g_property_invoke_set   (GProperty    *property,
                                         GObject      *gobject,
                                         const GValue *value);
void            g_property_invoke_get   (GProperty    *property,
                                         GObject      *gobject,
                                         GValue       *value);

/* per-type specific accessors */
typedef void     (* GPropertyBooleanSet) (gpointer gobject,
                                          gboolean value);
typedef gboolean (* GPropertyBooleanGet) (gpointer gobject);

typedef void     (* GPropertyIntSet)   (gpointer gobject,
                                        gint     value);
typedef gint     (* GPropertyIntGet)   (gpointer gobject);

typedef void     (* GPropertyInt8Set)  (gpointer gobject,
                                        gint8    value);
typedef gint8    (* GPropertyInt8Get)  (gpointer gobject);

typedef void     (* GPropertyInt16Set) (gpointer gobject,
                                        gint16   value);
typedef gint16   (* GPropertyInt16Get) (gpointer gobject);

typedef void     (* GPropertyInt32Set) (gpointer gobject,
                                        gint32   value);
typedef gint32   (* GPropertyInt32Get) (gpointer gobject);

typedef void     (* GPropertyInt64Set) (gpointer gobject,
                                        gint64   value);
typedef gint64   (* GPropertyInt64Get) (gpointer gobject);

typedef void     (* GPropertyLongSet)  (gpointer gobject,
                                        glong    value);
typedef glong    (* GPropertyLongGet)  (gpointer gobject);

/* per-type specific constructors */
GParamSpec *    g_boolean_property_new  (const gchar       *name,
                                         const gchar       *nick,
                                         const gchar       *blurb,
                                         GParamFlags        flags,
                                         gsize              field_offset,
                                         GPropertyBooleanSet  setter,
                                         GPropertyBooleanGet  getter);

GParamSpec *    g_int_property_new      (const gchar       *name,
                                         const gchar       *nick,
                                         const gchar       *blurb,
                                         GParamFlags        flags,
                                         gsize              field_offset,
                                         GPropertyIntSet    setter,
                                         GPropertyIntGet    getter);
GParamSpec *    g_int8_property_new     (const gchar       *name,
                                         const gchar       *nick,
                                         const gchar       *blurb,
                                         GParamFlags        flags,
                                         gsize              field_offset,
                                         GPropertyInt8Set   setter,
                                         GPropertyInt8Get   getter);
GParamSpec *    g_int16_property_new    (const gchar       *name,
                                         const gchar       *nick,
                                         const gchar       *blurb,
                                         GParamFlags        flags,
                                         gsize              field_offset,
                                         GPropertyInt16Set  setter,
                                         GPropertyInt16Get  getter);
GParamSpec *    g_int32_property_new    (const gchar       *name,
                                         const gchar       *nick,
                                         const gchar       *blurb,
                                         GParamFlags        flags,
                                         gsize              field_offset,
                                         GPropertyInt32Set  setter,
                                         GPropertyInt32Get  getter);
GParamSpec *    g_int64_property_new    (const gchar       *name,
                                         const gchar       *nick,
                                         const gchar       *blurb,
                                         GParamFlags        flags,
                                         gsize              field_offset,
                                         GPropertyInt64Set  setter,
                                         GPropertyInt64Get  getter);

#define _G_PROPERTY_BEGIN(T_n, t_n, field_type, field_name, _nick, _blurb, _flags) \
{ \
  GTypeClass *g_property_class = g_type_class_peek (t_n##_get_type ()); \
  gpointer g_property_setter = NULL; \
  gpointer g_property_getter = NULL; \
  gsize g_property_offset; \
  GProperty *g_property; \
\
  if (_flags & G_PARAM_STATIC_NICK) \
    _flags &= ^G_PARAM_STATIC_NICK; \
\
  if (_flags & G_PARAM_NO_ACCESSORS) \
    { \
      if (_flags & G_PARAM_PRIVATE_FIELD) \
        g_property_offset = G_STRUCT_OFFSET (T_n##Private, field_name); \
      else if (_flags & G_PARAM_PUBLIC_FIELD) \
        g_property_offset = G_STRUCT_OFFSET (T_n, field_name); \
      else \
        g_property_offset = 0; \
    } \
  else \
    { \
      if (_flags & G_PARAM_READABLE) \
        g_property_setter = t_n##_set_##field_name; \
      if (_flags & G_PARAM_WRITABLE) \
        g_property_getter = t_n##_get_##field_name; \
    } \
\
  g_property = \
    g_##field_type##_property_new (g_property_canonicalize (#field_name), \
                                   _nick, _blurb, \
                                   flags, \
                                   g_property_offset, \
                                   g_property_setter, \
                                   g_property_getter); \
  { /* custom code follows */
#define _G_PROPERTY_END() \
  } /* following custom code */ \
  g_object_class_install_property ((GObjectClass *) g_property_class, \
                                   (GParamSpec *) g_property);
}

/**
 * G_PROPERTY_WITH_CODE:
 * @T_n: the name of the type of the class, in CamelCase
 * @t_n: the name of the type of the class, in lower case
 * @field_type: the C type of the property
 * @field_name: the name of the field to set in the private data structure
 * @_nick: a user-readable name for the property (may be translated)
 * @_blurb: a user-readable description for the property (may be translated)
 * @_flags: #GParamFlags
 * @_C_: custom code to be called prior to the installation of the property
 *
 * Defines and installs a #GObject property, and allows calling custom
 * code before installing the property onto the class, for instance:
 *
 * |[
 *  G_PROPERTY_WITH_CODE (ClutterActor, clutter_actor, double, x_align,
 *                        _("Horizontal Alignment"),
 *                        _("The alignment on the X axis"),
 *                        G_PARAM_READWRITE,
 *                        G_PROPERTY_RANGE (double, 0.0, 1.0, 0.5));
 * ]|
 *
 * Since: 2.32
 */
#define G_PROPERTY_WITH_CODE(T_n, t_n, field_type, field_name, _nick, _blurb, _flags, _C_) \
_G_PROPERTY_BEGIN (T_n, t_n, field_type, field_name, _nick, _blurb, _flags) \
{ _C_; } \
_G_PROPERTY_END ()

/**
 * G_PROPERTY:
 * @T_n: the name of the type of the class, in CamelCase
 * @t_n: the name of the type of the class, in lower case
 * @field_type: the C type of the property
 * @field_name: the name of the field to set in the private data structure
 * @_nick: a user-readable name for the property (may be translated)
 * @_blurb: a user-readable description for the property (may be translated)
 * @_flags: #GParamFlags
 *
 * Defines and installs a #GObject property.
 *
 * This code:
 *
 * |[
 *  G_PROPERTY (ClutterActor, clutter_actor, float, margin_top,
 *              _("Margin Top"),
 *              _("The size of the margin from the top"),
 *              G_PARAM_READWRITE);
 * ]|
 *
 * will generate the equivalent of the following code:
 *
 * |[
 * {
 *   GProperty *g_property =
 *     g_float_property_new ("margin_top",
 *                           _("Margin Top"),
 *                           _("The size of the margin from the top"),
 *                           G_PARAM_READWRITE,
 *                           G_STRUCT_OFFSET (ClutterActorPrivate, margin_top),
 *                           clutter_actor_set_margin_top,
 *                           clutter_actor_get_margin_top);
 *   GTypeClass *_klass = g_type_class_peek (clutter_actor_get_type ());
 *   g_object_class_install_property ((GObjectClass *) _klass,
 *                                    (GParamSpec *) g_property);
 * }
 * ]|
 *
 * If the property requires further annotations, like a range, you should
 * use the %G_PROPERTY_WITH_CODE() macro instead.
 *
 * Since: 2.32
 */
#define G_PROPERTY(T_n, t_n, field_type, field_name, _nick, _blurb, _flags) \
G_PROPERTY_WITH_CODE (T_n, t_n, field_type, field_name, _nick, _blurb, _flags, ;)

/* per-type specific decorators */
void            g_int_property_set_range        (GProperty   *property,
                                                 gint         min_value,
                                                 gint         max_value,
                                                 gint         default_value);
void            g_int8_property_set_range       (GProperty   *property,
                                                 gint8        min_value,
                                                 gint8        max_value,
                                                 gint8        default_value);
void            g_int16_property_set_range      (GProperty   *property,
                                                 gint16       min_value,
                                                 gint16       max_value,
                                                 gint16       default_value);
void            g_int32_property_set_range      (GProperty   *property,
                                                 gint32       min_value,
                                                 gint32       max_value,
                                                 gint32       default_value);
void            g_int64_property_set_range      (GProperty   *property,
                                                 gint64       min_value,
                                                 gint64       max_value,
                                                 gint64       default_value);

void            g_uint_property_set_range       (GProperty   *property,
                                                 guint        min_value,
                                                 guint        max_value,
                                                 guint        default_value);
void            g_uint8_property_set_range      (GProperty   *property,
                                                 guint8       min_value,
                                                 guint8       max_value,
                                                 guint8       default_value);
void            g_uint16_property_set_range     (GProperty   *property,
                                                 guint16      min_value,
                                                 guint16      max_value,
                                                 guint16      default_value);
void            g_uint32_property_set_range     (GProperty   *property,
                                                 guint32      min_value,
                                                 guint32      max_value,
                                                 guint32      default_value);
void            g_uint64_property_set_range     (GProperty   *property,
                                                 guint64      min_value,
                                                 guint64      max_value,
                                                 guint64      default_value);

void            g_long_property_set_range       (GProperty   *property,
                                                 glong        min_value,
                                                 glong        max_value,
                                                 glong        default_value);
void            g_ulong_property_set_range      (GProperty   *property,
                                                 gulong       min_value,
                                                 gulong       max_value,
                                                 gulong       default_value);

#define g_char_property_set_range       g_int8_property_set_range
#define g_uchar_property_set_range      g_uint8_property_set_range
#define g_unichar_property_set_range    g_uint32_property_set_range

void            g_float_property_set_range      (GProperty   *property,
                                                 gfloat       min_value,
                                                 gfloat       max_value,
                                                 gfloat       default_value);
void            g_double_property_set_range     (GProperty   *property,
                                                 gdouble      min_value,
                                                 gdouble      max_value,
                                                 gdouble      default_value);

void            g_boolean_property_set_default  (GProperty   *property,
                                                 gboolean     default_value);

void            g_string_property_set_default   (GProperty   *property,
                                                 const gchar *default_value);

void            g_gtype_property_set_is_a       (GProperty   *property,
                                                 GType        is_a);

/**
 * G_PROPERTY_RANGE:
 * @C_t: the name of the C type of the property
 * @minVal: the minimum value of the property
 * @maxVal: the maximum value of the property
 * @defVal: the default value of the property
 *
 * A macro invoking the right annotation for setting the valid range
 * on the property. This macro uses the "g_property" symbol defined
 * by %G_PROPERTY_WITH_CODE and it should only be used with one of the
 * property types that support a range.
 *
 * Since: 2.32
 */
#define G_PROPERTY_RANGE(C_t, minVal, maxVal, defVal)   g_##C_t##_property_set_range (g_property, (minVal), (maxVal), (defVal))

/* accessors generation */
#define _G_DEFINE_PROPERTY_SYNTH_GET_DECL(TypeName, type_name, field_type, field_name) \
field_type type_name##_get_##field_name (TypeName *self)

#define _G_DEFINE_PROPERTY_SYNTH_GET_BEGIN(TypeName, type_name, field_type, field_name, default_value) \
{ \
  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, type_name##_get_type ()), default_value); \
  { /* custom code follows */
#define _G_DEFINE_PROPERTY_SYNTH_GET_END(field_name)    \
  } /* following custom code */                         \
  return self->priv->field_name;                        \
}

#define _G_DEFINE_PROPERTY_SYNTH_SET_DECL(TypeName, type_name, field_type, field_name) \
\
void type_name##_set_##field_name (TypeName *self, field_type value)

#define _G_DEFINE_PROPERTY_SYNTH_SET_BEGIN(TypeName, type_name, field_type, field_name) \
{ \
  TypeName##Private *priv; \
\
  g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, type_name##_get_type ())); \
\
  priv = self->priv; \
\
  if (priv->field_name != value) \
    { \
      priv->field_name = value; \
      { /* custom code follows */
#define _G_DEFINE_PROPERTY_SYNTH_SET_END()      \
      }/* following custom code */              \
    }                                           \
}

/*< private >
 * G_DEFINE_PROPERTY:
 * @TypeName: the name of the type, in Camel case
 * @type_name: the name of the type, in lowercase, with words separated by '_'
 * @field_type: the type of the property, which must match the type of the
 *   field in the @TypeName<!-- -->Private structure
 * @field_name: the name of the property, which must match the name of the
 *   field in the @TypeName<!-- -->Private structure
 *
 * Declares the accessor functions for a @field_name property in the
 * class @TypeName. This macro should only be used in header files.
 */
#define G_DEFINE_PROPERTY(TypeName, type_name, field_type, field_name)           \
_G_DEFINE_PROPERTY_SYNTH_SET_DECL (TypeName, type_name, field_type, field_name); \
_G_DEFINE_PROPERTY_SYNTH_GET_DECL (TypeName, type_name, field_type, field_name);

/*< private >
 * G_DEFINE_PROPERTY_SYNTH_SET_WITH_CODE:
 * @TypeName: the name of the type, in Camel case
 * @type_name: the name of the type, in lowercase, with words separated by '_'
 * @field_type: the type of the property, which must match the type of the
 *   field in the @TypeName<!-- -->Private structure
 * @field_name: the name of the property, which must match the name of the
 *   field in the @TypeName<!-- -->Private structure
 *
 * Defines the setter function for a @field_name property in the
 * class @TypeName, with the possibility of calling custom code.
 *
 * This macro should only be used in C source files.
 *
 * This macro should be used when intending to notify on #GObject properties,
 * for instance:
 *
 * |[
 * G_DEFINE_PROPERTY_SYNTH_SET_WITH_CODE (ClutterActor, clutter_actor,
 *                                        int, margin_top,
 *                                        g_object_notify (G_OBJECT (self), "margin-top"))
 * ]|
 */
#define G_DEFINE_PROPERTY_SYNTH_SET_WITH_CODE(TypeName, type_name, field_type, field_name, _C_) \
_G_DEFINE_PROPERTY_SYNTH_SET_DECL (TypeName, type_name, field_type, field_name) \
_G_DEFINE_PROPERTY_SYNTH_SET_BEGIN (TypeName, type_name, field_type, field_name) \
{ _C_; } \
_G_DEFINE_PROPERTY_SYNTH_SET_END ()

/*< private >
 * G_DEFINE_PROPERTY_SYNTH_GET_WITH_CODE:
 * @TypeName: the name of the type, in Camel case
 * @type_name: the name of the type, in lowercase, with words separated by '_'
 * @field_type: the type of the property, which must match the type of the
 *   field in the @TypeName<!-- -->Private structure
 * @field_name: the name of the property, which must match the name of the
 *   field in the @TypeName<!-- -->Private structure
 * @ret: default return value (mostly for error conditions) for the getter
 *   function
 *
 * Defines the getter function for a @field_name property in the
 * class @TypeName, with the possibility of calling custom code.
 *
 * This macro should only be used in C source files.
 */
#define G_DEFINE_PROPERTY_SYNTH_GET_WITH_CODE(TypeName, type_name, field_type, field_name, ret, _C_) \
_G_DEFINE_PROPERTY_SYNTH_GET_DECL (TypeName, type_name, field_type, field_name) \
_G_DEFINE_PROPERTY_SYNTH_GET_BEGIN (TypeName, type_name, field_type, field_name, ret) \
{ _C_; } \
_G_DEFINE_PROPERTY_SYNTH_GET_END (field_name);

/*< private >
 * G_DEFINE_PROPERTY_SYNTH_SET:
 * @TypeName: the name of the type, in Camel case
 * @type_name: the name of the type, in lowercase, with words separated by '_'
 * @field_type: the type of the property, which must match the type of the
 *   field in the @TypeName<!-- -->Private structure
 * @field_name: the name of the property, which must match the name of the
 *   field in the @TypeName<!-- -->Private structure
 *
 * Defines the setter function for a @field_name property in the
 * class @TypeName. This macro should only be used in C source files.
 *
 * See also %G_DEFINE_PROPERTY_SYNTH_SET_WITH_CODE.
 */
#define G_DEFINE_PROPERTY_SYNTH_SET(TypeName, type_name, field_type, field_name)        G_DEFINE_PROPERTY_SYNTH_SET_WITH_CODE (TypeName, type_name, field_type, field_name, ;)

/*< private >
 * G_DEFINE_PROPERTY_SYNTH_GET:
 * @TypeName: the name of the type, in Camel case
 * @type_name: the name of the type, in lowercase, with words separated by '_'
 * @field_type: the type of the property, which must match the type of the
 *   field in the @TypeName<!-- -->Private structure
 * @field_name: the name of the property, which must match the name of the
 *   field in the @TypeName<!-- -->Private structure
 * @ret: default return value (mostly for error conditions) for the getter
 *   function
 *
 * Defines the getter function for a @field_name property in the
 * class @TypeName. This macro should only be used in C source files.
 *
 * See also %G_DEFINE_PROPERTY_SYNTH_GET_WITH_CODE.
 */
#define G_DEFINE_PROPERTY_SYNTH_GET(TypeName, type_name, field_type, field_name, ret)   G_DEFINE_PROPERTY_SYNTH_GET_WITH_CODE (TypeName, type_name, field_type, field_name, ret, ;)

/*< private >
 * G_DEFINE_PROPERTY_SYNTH:
 * @TypeName: the name of the type, in Camel case
 * @type_name: the name of the type, in lowercase, with words separated by '_'
 * @field_type: the type of the property, which must match the type of the
 *   field in the @TypeName<!-- -->Private structure
 * @field_name: the name of the property, which must match the name of the
 *   field in the @TypeName<!-- -->Private structure
 * @ret: default return value (mostly for error conditions) for the getter
 *   function
 *
 * Defines the accessor functions for a @field_name property in the
 * class @TypeName. This macro should only be used in C source files, for
 * instance:
 *
 * |[
 *   G_DEFINE_PROPERTY_SYNTH (ClutterActor, clutter_actor, int, margin_top, 0)
 * ]|
 *
 * will synthesize the following code:
 *
 * |[
 * void
 * clutter_actor_set_margin_top (ClutterActor *self,
 *                               int           value)
 * {
 *   ClutterActorPrivate *priv;
 *
 *   g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()));
 *
 *   priv = self->priv;
 *
 *   if (priv->margin_top != value)
 *     {
 *       priv->value = value
 *     }
 * }
 *
 * int
 * clutter_actor_get_margin_top (ClutterActor *self)
 * {
 *   g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (self, clutter_actor_get_type ()), 0);
 *
 *   return self->priv->margin_top;
 * }
 * ]|
 */
#define G_DEFINE_PROPERTY_SYNTH(TypeName, type_name, field_type, field_name, ret)       \
G_DEFINE_PROPERTY_SYNTH_SET (TypeName, type_name, field_type, field_name)               \
G_DEFINE_PROPERTY_SYNTH_GET (TypeName, type_name, field_type, field_name, ret)

G_END_DECLS

#endif /* __G_PROPERTY_H__ */
