### ----------------------------------------------------
### -- Gnome::GObject
### -- Licenses: Artistic-2.0
### -- Authors: Marcel Timmerman
### -- File: lib/Gnome/GObject/Type.rakumod
### ----------------------------------------------------
### -- Chunk 1 of 4
#TL:1:Gnome::GObject::Type:

use v6;

#-------------------------------------------------------------------------------
=begin pod

=head1 Gnome::GObject::Type

The GLib Runtime type identification and management system

I<B<Note: The methods described here are mostly used internally and is not of much interest for the normal Raku user.>>

=head1 Description

The GType API is the foundation of the GObject system. It provides the facilities for registering and managing all fundamental data types. To have a type stored next to its value. The class B<Gnome::GObject::Value> serves as a vehicle to get values in and out of an object. This class controls a C<N-GValue> object which has a type and a value.

The Glib types such as C<gint> and C<gfloat> are used to type variables and functions directly and are compiled to the proper sizes when used in code. These types are mapped to the C types like C<int> and C<float>. In the module B<Gnome::N::GlibToRakuTypes>, a mapping is made to be able to map the Glib types to the Raku types.

=comment , user-defined object and interface types.

=begin comment
For type creation and registration purposes, all types fall into one of two categories: static or dynamic. Static types are never loaded or unloaded at run-time as dynamic types may be.

Static types are created with C<g_type_register_static()> that gets type specific information passed in via a I<GTypeInfo> structure.

Dynamic types are created with C<g_type_register_dynamic()> which takes a I<GTypePlugin> structure instead. The remaining type information (the I<GTypeInfo> structure) is retrieved during runtime through I<GTypePlugin> and the g_type_plugin_*() API.

These registration functions are usually called only once from a function whose only purpose is to return the type identifier for a specific class. Once the type (or class or interface) is registered, it may be instantiated, inherited, or implemented depending on exactly what sort of type it is.

There is also a third registration function for registering fundamental types called C<g_type_register_fundamental()> which requires both a I<GTypeInfo> structure and a I<GTypeFundamentalInfo> structure but it is seldom used since most fundamental types are predefined rather than user-defined.

Type instance and class structs are limited to a total of 64 KiB, including all parent types. Similarly, type instances' private data (as created by C<G_ADD_PRIVATE()>) are limited to a total of 64 KiB. If a type instance needs a large static buffer, allocate it separately (typically by using I<GArray> or I<GPtrArray>) and put a pointer to the buffer in the structure.

As mentioned in the [GType conventions](https://developer.gnome.org/gobject/stable/gtype-conventions.html), type names must be at least three characters long. There is no upper length limit. The first character must be a letter (a–z or A–Z) or an underscore (‘_’). Subsequent characters can be letters, numbers or any of ‘-_+’.
=end comment


=head1 Synopsis
=head2 Declaration

  unit class Gnome::GObject::Type;


=comment '=head2 Example'

=end pod
#-------------------------------------------------------------------------------
use NativeCall;

#use Gnome::N::X:api<1>;
use Gnome::N::NativeLib:api<1>;
use Gnome::N::N-GObject:api<1>;
use Gnome::N::GlibToRakuTypes:api<1>;

#use Gnome::GObject::Value:api<1>;

#-------------------------------------------------------------------------------
unit class Gnome::GObject::Type:auth<github:MARTIMM>:api<1>;

#-------------------------------------------------------------------------------
#`{{
=begin pod
=head2 class N-GTypeInstance

An opaque structure used as the base of all type instances.

=end pod

# TT:0:N-GTypeInstance:
class N-GTypeInstance is repr('CPointer') is export { }
}}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GTypeInterface

An opaque structure used as the base of all interface types.

=end pod

# TT:0:N-GTypeInterface:
class N-GTypeInterface is repr('CPointer') is export { }
}}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GTypeClass

An opaque structure used as the base of all type instances.

=end pod

# TT:0::N-GTypeClass
class N-GTypeClass is repr('CPointer') is export { }
}}

#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GTypeQuery

A structure holding information for a specific type. It is filled in by the C<query()> function.

=item UInt $.type: the GType value of the type.
=item Str $.type_name: the name of the type.
=item UInt $.class_size: the size of the class structure.
=item UInt $.instance_size: the size of the instance structure.

=end pod

#TT:2:N-GTypeQuery:
class N-GTypeQuery is export is repr('CStruct') {
  has GType $.type;
  has gchar-ptr $.type_name;
  has guint $.class_size;
  has guint $.instance_size;
}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GTypeInfo

This structure is used to provide the type system with the information required to initialize and destruct (finalize) a type's class and its instances.

The initialized structure is passed to the C<g_type_register_static()> function (or is copied into the provided I<N-GTypeInfo> structure in the C<g_type_plugin_complete_type_info()>). The type system will perform a deep copy of this structure, so its memory does not need to be persistent across invocation of C<g_type_register_static()>.

=item UInt $.class_size: Size of the class structure (required for interface, classed and instantiatable types)
=item GBaseInitFunc $.base_init: Location of the base initialization function (optional)
=item GBaseFinalizeFunc $.base_finalize: Location of the base finalization function (optional)
=item GClassInitFunc $.class_init: Location of the class initialization function for classed and instantiatable types. Location of the default vtable  inititalization function for interface types. (optional) This function  is used both to fill in virtual functions in the class or default vtable,  and to do type-specific setup such as registering signals and object properties.
=item GClassFinalizeFunc $.class_finalize: Location of the class finalization function for classed and instantiatable types. Location of the default vtable finalization function for interface types. (optional)
=item Pointer $.class_data: User-supplied data passed to the class init/finalize functions
=item UInt $.instance_size: Size of the instance (object) structure (required for instantiatable types only)
=item UInt $.n_preallocs: Prior to GLib 2.10, it specified the number of pre-allocated (cached) instances to reserve memory for (0 indicates no caching). Since GLib 2.10, it is ignored, since instances are allocated with the [slice allocator][glib-Memory-Slices] now.
=item GInstanceInitFunc $.instance_init: Location of the instance initialization function (optional, for instantiatable types only)
=item int32 $.value_table: A I<N-GTypeValueTable> function table for generic handling of GValues of this type (usually only useful for fundamental types)


=end pod


# TT:0:N-GTypeInfo:
class N-GTypeInfo
  is repr('CPointer')
  is export
  { }


class N-GTypeInfo is export is repr('CStruct') {
  has uint16 $.class_size;
  has Pointer $.base_init;      #has GBaseInitFunc $.base_init;
  has Pointer $.base_finalize;  #has GBaseFinalizeFunc $.base_finalize;
  has Pointer $.class_init;     #has GClassInitFunc $.class_init;
  has Pointer $.class_finalize; #has GClassFinalizeFunc $.class_finalize;
  has Pointer $.class_data;
  has uint16 $.instance_size;
  has uint16 $.n_preallocs;
  has Pointer $.instance_init;  #has GInstanceInitFunc $.instance_init;
  has Pointer $.value_table;
}
}}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GTypeFundamentalInfo

A structure that provides information to the type system which is used specifically for managing fundamental types.

=item int32 $.type_flags: I<N-GTypeFundamentalFlags> describing the characteristics of the fundamental type

=end pod

# TT:0:N-GTypeFundamentalInfo:
class N-GTypeFundamentalInfo is export is repr('CStruct') {
  has GFlag $.type_flags;
}
}}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 enum N-GTypeFundamentalFlags

Bit masks used to check or determine specific characteristics of a fundamental type.

=item G_TYPE_FLAG_CLASSED; Indicates a classed type
=item G_TYPE_FLAG_INSTANTIATABLE; Indicates an instantiable type (implies classed)
=item G_TYPE_FLAG_DERIVABLE; Indicates a flat derivable type
=item G_TYPE_FLAG_DEEP_DERIVABLE; Indicates a deep derivable type (implies derivable)

=end pod

# TT:0::N-GTypeFundamentalFlags
enum N-GTypeFundamentalFlags is export <
  G_TYPE_FLAG_CLASSED G_TYPE_FLAG_INSTANTIATABLE
  G_TYPE_FLAG_DERIVABLE G_TYPE_FLAG_DEEP_DERIVABLE
>;
}}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GInterfaceInfo

A structure that provides information to the type system which is used specifically for managing interface types.

=item GInterfaceInitFunc $.interface_init: location of the interface initialization function
=item GInterfaceFinalizeFunc $.interface_finalize: location of the interface finalization function
=item Pointer $.interface_data: user-supplied data passed to the interface init/finalize functions

=end pod

# TT:0:N-GInterfaceInfo:
class N-GInterface!build-types-conversion-moduleInfo is export is repr('CStruct') {
  has Pointer $.interface_init;     #has GInterfaceInitFunc $.interface_init;
  has Pointer $.interface_finalize; #has GInterfaceFinalizeFunc $.interface_finalize;
  has Pointer $.interface_data;
}
}}

#`{{
#-------------------------------------------------------------------------------
=begin pod
=head2 class N-GTypeValueTable

The I<GTypeValueTable> provides the functions required by the I<GValue>
implementation, to serve as a container for values of a type.

=item ___value_init: Default initialize I<values> contents by poking values directly into the value->data array. The data array of the I<GValue> passed into this function was zero-filled with `C<memset()>`, so no care has to be taken to free any old contents. E.g. for the implementation of a string value that may never be C<Any>, the implementation might look like: |[<!-- language="C" --> value->data[0].v_pointer = g_strdup (""); ]|
=item ___value_free: Free any old contents that might be left in the data array of the passed in I<value>. No resources may remain allocated through the I<GValue> contents after this function returns. E.g. for our above string type: |[<!-- language="C" --> // only free strings without a specific flag for static storage if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS)) g_free (value->data[0].v_pointer); ]|
=item ___value_copy: I<dest_value> is a I<GValue> with zero-filled data section and I<src_value> is a properly setup I<GValue> of same or derived type. The purpose of this function is to copy the contents of I<src_value> into I<dest_value> in a way, that even after I<src_value> has been freed, the contents of I<dest_value> remain valid. String type example: |[<!-- language="C" --> dest_value->data[0].v_pointer = g_strdup (src_value->data[0].v_pointer); ]|
=item ___value_peek_pointer: If the value contents fit into a pointer, such as objects or strings, return this pointer, so the caller can peek at the current contents. To extend on our above string example: |[<!-- language="C" --> return value->data[0].v_pointer; ]|
=item Str $.collect_format: A string format describing how to collect the contents of this value bit-by-bit. Each character in the format represents an argument to be collected, and the characters themselves indicate the type of the argument. Currently supported arguments are: - 'i' - Integers. passed as collect_values[].v_int. - 'l' - Longs. passed as collect_values[].v_long. - 'd' - Doubles. passed as collect_values[].v_double. - 'p' - Pointers. passed as collect_values[].v_pointer. It should be noted that for variable argument list construction, ANSI C promotes every type smaller than an integer to an int, and floats to doubles. So for collection of short int or char, 'i' needs to be used, and for collection of floats 'd'.
=item ___collect_value: The C<collect_value()> function is responsible for converting the values collected from a variable argument list into contents suitable for storage in a GValue. This function should setup I<value> similar to C<value_init()>; e.g. for a string value that does not allow C<Any> pointers, it needs to either spew an error, or do an implicit conversion by storing an empty string. The I<value> passed in to this function has a zero-filled data array, so just like for C<value_init()> it is guaranteed to not contain any old contents that might need freeing. I<n_collect_values> is exactly the string length of I<collect_format>, and I<collect_values> is an array of unions I<GTypeCValue> with length I<n_collect_values>, containing the collected values according to I<collect_format>. I<collect_flags> is an argument provided as a hint by the caller. It may contain the flag C<G_VALUE_NOCOPY_CONTENTS> indicating, that the collected value contents may be considered "static" for the duration of the I<value> lifetime. Thus an extra copy of the contents stored in I<collect_values> is not required for assignment to I<value>. For our above string example, we continue with: |[<!-- language="C" --> if (!collect_values[0].v_pointer) value->data[0].v_pointer = g_strdup (""); else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) { value->data[0].v_pointer = collect_values[0].v_pointer; // keep a flag for the C<value_free()> implementation to not free this string value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS; } else value->data[0].v_pointer = g_strdup (collect_values[0].v_pointer); return NULL; ]| It should be noted, that it is generally a bad idea to follow the I<G_VALUE_NOCOPY_CONTENTS> hint for reference counted types. Due to reentrancy requirements and reference count assertions performed by the signal emission code, reference counts should always be incremented for reference counted contents stored in the value->data array.  To deviate from our string example for a moment, and taking a look at an exemplary implementation for C<collect_value()> of I<GObject>: |[<!-- language="C" --> if (collect_values[0].v_pointer) { GObject *object = G_OBJECT (collect_values[0].v_pointer); // never honour G_VALUE_NOCOPY_CONTENTS for ref-counted types value->data[0].v_pointer = g_object_ref (object); return NULL; } else return g_strdup_printf ("Object passed as invalid NULL pointer"); } ]| The reference count for valid objects is always incremented, regardless of I<collect_flags>. For invalid objects, the example returns a newly allocated string without altering I<value>. Upon success, C<collect_value()> needs to return C<Any>. If, however, an error condition occurred, C<collect_value()> may spew an error by returning a newly allocated non-C<Any> string, giving a suitable description of the error condition. The calling code makes no assumptions about the I<value> contents being valid upon error returns, I<value> is simply thrown away without further freeing. As such, it is a good idea to not allocate I<GValue> contents, prior to returning an error, however, C<collect_values()> is not obliged to return a correctly setup I<value> for error returns, simply because any non-C<Any> return is considered a fatal condition so further program behaviour is undefined.
=item Str $.lcopy_format: Format description of the arguments to collect for I<lcopy_value>, analogous to I<collect_format>. Usually, I<lcopy_format> string consists only of 'p's to provide C<lcopy_value()> with pointers to storage locations.
=item ___lcopy_value: This function is responsible for storing the I<value> contents into arguments passed through a variable argument list which got collected into I<collect_values> according to I<lcopy_format>. I<n_collect_values> equals the string length of I<lcopy_format>, and I<collect_flags> may contain C<G_VALUE_NOCOPY_CONTENTS>. In contrast to C<collect_value()>, C<lcopy_value()> is obliged to always properly support C<G_VALUE_NOCOPY_CONTENTS>. Similar to C<collect_value()> the function may prematurely abort by returning a newly allocated string describing an error condition. To complete the string example: |[<!-- language="C" --> gchar **string_p = collect_values[0].v_pointer; if (!string_p) return g_strdup_printf ("string location passed as NULL"); if (collect_flags & G_VALUE_NOCOPY_CONTENTS) *string_p = value->data[0].v_pointer; else *string_p = g_strdup (value->data[0].v_pointer); ]| And an illustrative version of C<lcopy_value()> for reference-counted types: |[<!-- language="C" --> GObject **object_p = collect_values[0].v_pointer; if (!object_p) return g_strdup_printf ("object location passed as NULL"); if (!value->data[0].v_pointer) *object_p = NULL; else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) // always honour *object_p = value->data[0].v_pointer; else *object_p = g_object_ref (value->data[0].v_pointer); return NULL; ]|

=end pod

# TT:0:N-GTypeValueTable:
class N-GTypeValueTable is export is repr('CStruct') {
  has voi $.d     (*value_init)         (GValue       *value);
  has voi $.d     (*value_free)         (GValue       *value);
  has N-GObject $.dest_value);
  has gpointe $.r (*value_peek_pointer) (const GValue *value);
  has str $.collect_format;
  has uint32 $.collect_flags);
  has str $.lcopy_format;
  has uint32 $.collect_flags);
}
}}

#-------------------------------------------------------------------------------
=begin pod
=head2 Type names

=item G_TYPE_CHAR; An 8 bit integer.
=item G_TYPE_UCHAR; An 8 bit unsigned integer.
=item G_TYPE_BOOLEAN; A boolean. This is the size of an int32.
=item G_TYPE_INT; An integer, also the size of an int32.
=item G_TYPE_UINT; An unsigned integer.
=item G_TYPE_LONG; A larger type integer.
=item G_TYPE_ULONG; A larger type unsigned integer.
=item G_TYPE_INT64; A larger type integer.
=item G_TYPE_UINT64; A larger type unsigned integer.
=item G_TYPE_ENUM; An integer used for C enumerations.
=item G_TYPE_FLAGS; An integer used for bitmap flags.
=item G_TYPE_FLOAT; A floating point value.
=item G_TYPE_DOUBLE; A large floating point value.
=item G_TYPE_STRING; A string.
=comment item G_TYPE_POINTER. 
=comment item G_TYPE_BOXED
=comment item G_TYPE_PARAM
=item G_TYPE_OBJECT; A gnome object.
=item G_TYPE_VARIANT; A variant.

To show the glib types together with the Raku types and the type names mentioned above a small table is shown below;

=begin table
  Type name       | Glib type | Raku type
  =======================================
  G_TYPE_CHAR     | gchar     | int8
  G_TYPE_UCHAR    | guchar    | uint8
  G_TYPE_BOOLEAN  | gboolean  | int32
  G_TYPE_INT      | gint      | int32
  G_TYPE_UINT     | guint     | uint32
  G_TYPE_LONG     | glong     | int64
  G_TYPE_ULONG    | gulong    | uint64
  G_TYPE_INT64    | gint64    | int64
  G_TYPE_UINT64   | guint64   | uint64
  G_TYPE_ENUM     | GEnum     | int32
  G_TYPE_FLAGS    | GFlag     | uint32
  G_TYPE_FLOAT    | gfloat    | num32
  G_TYPE_DOUBLE   | gdouble   | num64
  G_TYPE_STRING   | gchar-ptr | Str
  G_TYPE_OBJECT   | -         | Gnome::GObject::Object
  G_TYPE_VARIANT  | -         | Gnome::Glib::Variant
=end table

Some types might have a longer or shorter size depending on the OS Raku is running on. It is a reflection of the C macro types of the C compiler include files. So to use the proper types, always use the glib type instead of the Raku type which are generated in the B<Gnome::N::GlibToRakuTypes> module at Build time when C<Gnome::N> is installed.

=end pod

#define	G_TYPE_FUNDAMENTAL_SHIFT (2)
constant G_TYPE_FUNDAMENTAL_SHIFT = 2;

#define	G_TYPE_FUNDAMENTAL_MAX		(255 << G_TYPE_FUNDAMENTAL_SHIFT)
constant G_TYPE_MAKE_FUNDAMENTAL_MAX is export =
         255 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define	G_TYPE_MAKE_FUNDAMENTAL(x)	((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT))
#define G_TYPE_INVALID G_TYPE_MAKE_FUNDAMENTAL (0)
constant G_TYPE_INVALID is export = 0 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_NONE G_TYPE_MAKE_FUNDAMENTAL (1)
constant G_TYPE_NONE is export = 1 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_INTERFACE G_TYPE_MAKE_FUNDAMENTAL (2)
constant G_TYPE_INTERFACE is export = 2 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_CHAR G_TYPE_MAKE_FUNDAMENTAL (3)
constant G_TYPE_CHAR is export = 3 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_UCHAR G_TYPE_MAKE_FUNDAMENTAL (4)
constant G_TYPE_UCHAR is export = 4 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_BOOLEAN G_TYPE_MAKE_FUNDAMENTAL (5)
constant G_TYPE_BOOLEAN is export = 5 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6)
constant G_TYPE_INT is export = 6 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_UINT G_TYPE_MAKE_FUNDAMENTAL (7)
constant G_TYPE_UINT is export = 7 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_LONG G_TYPE_MAKE_FUNDAMENTAL (8)
constant G_TYPE_LONG is export = 8 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_ULONG G_TYPE_MAKE_FUNDAMENTAL (9)
constant G_TYPE_ULONG is export = 9 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_INT64 G_TYPE_MAKE_FUNDAMENTAL (10)
constant G_TYPE_INT64 is export = 10 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_UINT64 G_TYPE_MAKE_FUNDAMENTAL (11)
constant G_TYPE_UINT64 is export = 11 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_ENUM G_TYPE_MAKE_FUNDAMENTAL (12)
constant G_TYPE_ENUM is export = 12 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_FLAGS G_TYPE_MAKE_FUNDAMENTAL (13)
constant G_TYPE_FLAGS is export = 13 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_FLOAT G_TYPE_MAKE_FUNDAMENTAL (14)
constant G_TYPE_FLOAT is export = 14 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_DOUBLE G_TYPE_MAKE_FUNDAMENTAL (15)
constant G_TYPE_DOUBLE is export = 15 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_STRING G_TYPE_MAKE_FUNDAMENTAL (16)
constant G_TYPE_STRING is export = 16 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_POINTER G_TYPE_MAKE_FUNDAMENTAL (17)
constant G_TYPE_POINTER is export = 17 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_BOXED G_TYPE_MAKE_FUNDAMENTAL (18)
constant G_TYPE_BOXED is export = 18 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_PARAM G_TYPE_MAKE_FUNDAMENTAL (19)
constant G_TYPE_PARAM is export = 19 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20)
constant G_TYPE_OBJECT is export = 20 +< G_TYPE_FUNDAMENTAL_SHIFT;

#define	G_TYPE_VARIANT G_TYPE_MAKE_FUNDAMENTAL (21)
constant G_TYPE_VARIANT is export = 21 +< G_TYPE_FUNDAMENTAL_SHIFT;

#-------------------------------------------------------------------------------
class N-TypesMap is repr('CUnion') is export {
  has int8 $.int8;          # G_TYPE_CHAR
  has uint8 $.uint8;        # G_TYPE_UCHAR
  has int32 $.bool;         # G_TYPE_BOOLEAN
  has int32 $.int32;        # G_TYPE_INT
  has uint32 $.uint32;      # G_TYPE_UINT
  has int64 $.long;         # G_TYPE_LONG
  has uint64 $.ulong;       # G_TYPE_ULONG
  has int64 $.int64;        # G_TYPE_INT64
  has uint64 $.uint64;      # G_TYPE_UINT64
  has int $.enum;           # G_TYPE_ENUM
  has int $.flags;          # G_TYPE_FLAGS
  has num32 $.float;        # G_TYPE_FLOAT
  has num64 $.double;       # G_TYPE_DOUBLE
  has str $.string;         # G_TYPE_STRING
  has Pointer $.pointer;    # G_TYPE_POINTER
  has Pointer $.boxed;      # G_TYPE_BOXED
  has Pointer $.param;      # G_TYPE_PARAM
  has N-GObject $.object;   # G_TYPE_OBJECT
  has Pointer $.variant;    # G_TYPE_VARIANT
}

#-------------------------------------------------------------------------------
#my Bool $signals-added = False;
#-------------------------------------------------------------------------------
=begin pod
=head1 Methods
=head2 new
=head3 default, no options

Create a new plain object. In contrast with other objects, this class doesn't wrap a native object, so therefore no options to specify something.

=end pod

#TM:1:new():
submethod BUILD ( *%options ) {

  if %options.keys.elems {
    die X::Gnome.new(
      :message('Unsupported options for ' ~ self.^name ~
               ': ' ~ %options.keys.join(', ') ~
               ', cannot have any arguments'
              )
    );
  }
}

#-------------------------------------------------------------------------------
method FALLBACK ( $native-sub is copy, |c ) {

  CATCH { .note; die; }

#`{{
  $native-sub ~~ s:g/ '-' /_/ if $native-sub.index('-');
  die X::Gnome.new(:message(
    "Native sub name '$native-sub' made too short. Keep at least one '-' or '_'."
    )
  ) unless $native-sub.index('_') >= 0;
}}

  my Str $new-patt = $native-sub.subst( '_', '-', :g);

  my Callable $s;
  try { $s = &::("g_type_$native-sub"); };
  if ?$s {
    Gnome::N::deprecate(
      "g_type_$native-sub", $new-patt, '0.19.11', '0.20.0'
    );
  }

  else {
    try { $s = &::("g_$native-sub") } unless ?$s;
    if ?$s {
      Gnome::N::deprecate(
        "g_$native-sub", $new-patt.subst('type-'),
        '0.19.11', '0.20.0'
      );
    }

    else {
      try { $s = &::($native-sub); } if !$s and $native-sub ~~ m/^ 'g_' /;
      if ?$s {
        Gnome::N::deprecate(
          "$native-sub", $new-patt.subst('g-type-'),
          '0.19.11', '0.20.0'
        );
      }
    }
  }

  $s(|c)
}

#-------------------------------------------------------------------------------
# conveniance method to convert a type to a Raku parameter
#TM:4:get-parameter:Gnome::Gtk3::ListStore
method get-parameter( UInt $type, :$otype --> Parameter ) {

  # tests showed elsewhere that types can come in negative. this should be
  # trapped at the generated spot but it could be anywhere so here it
  # should be converted in any case. It is caused by returned types with
  # 32th bit set which is seen as negative. remedy is to take a two's
  # complement of the negative value.
  #$type = ^+ $type if $type < 0;

  my Parameter $p;
  given $type {
    when G_TYPE_CHAR    { $p .= new(type => gchar); }
    when G_TYPE_UCHAR   { $p .= new(type => guchar); }
    when G_TYPE_BOOLEAN { $p .= new(type => gboolean); }
    when G_TYPE_INT     { $p .= new(type => gint); }
    when G_TYPE_UINT    { $p .= new(type => guint); }
    when G_TYPE_LONG    { $p .= new(type => glong); }
    when G_TYPE_ULONG   { $p .= new(type => gulong); }
    when G_TYPE_INT64   { $p .= new(type => gint64); }
    when G_TYPE_UINT64  { $p .= new(type => guint64); }
    when G_TYPE_ENUM    { $p .= new(type => gint); }
    when G_TYPE_FLAGS   { $p .= new(type => gint); }
    when G_TYPE_FLOAT   { $p .= new(type => gfloat); }
    when G_TYPE_DOUBLE  { $p .= new(type => gdouble); }
    when G_TYPE_STRING  { $p .= new(type => gchar-ptr); }

#    when G_TYPE_OBJECT | G_TYPE_BOXED {
#      die X::Gnome.new(:message('Object in named argument :o not defined'))
#          unless ?$otype;
#      $p .= new(type => $otype.get-class-gtype);
#      $p .= new(:$type);
#    }

#    when G_TYPE_POINTER { $p .= new(type => ); }
#    when G_TYPE_PARAM { $p .= new(type => ); }
#    when G_TYPE_VARIANT {$p .= new(type => ); }
#    when N-GObject {
#      $p .= new(type => G_TYPE_OBJECT);
#    }

    default {
      # if type is larger than the max of fundamental types (like G_TYPE_INT) it
      # is a type which is set when a GTK+ object is created. In Raku the
      # object type is stored in the class as $!class-gtype in
      # Gnome::N::TopLevelSupport and retrievable with .get-class-gtype()
      if $type > G_TYPE_MAKE_FUNDAMENTAL_MAX {
        $p .= new(:$type);
      }

      elsif ?$otype {
        $p .= new(type => $otype.get-class-gtype);
      }

      else {
        die X::Gnome.new(
          :message("Unknown basic type $type and \$otype is undefined")
        );
      }
    }
  }

  $p
}



#`{{
#-------------------------------------------------------------------------------
# TM:0:add-class-cache-func:
=begin pod
=head2 add-class-cache-func

Adds a B<Gnome::GObject::TypeClassCacheFunc> to be called before the reference count of a class goes from one to zero. This can be used to prevent premature class destruction. All installed B<Gnome::GObject::TypeClassCacheFunc> functions will be chained until one of them returns C<True>. The functions have to check the class id passed in to figure whether they actually want to cache the class of this type, since all classes are routed through the same B<Gnome::GObject::TypeClassCacheFunc> chain.

  method add-class-cache-func ( Pointer $cache_data, GTypeClassCacheFunc $cache_func )

=item Pointer $cache_data; data to be passed to I<cache-func>
=item GTypeClassCacheFunc $cache_func; a B<Gnome::GObject::TypeClassCacheFunc>
=end pod

method add-class-cache-func ( Pointer $cache_data, GTypeClassCacheFunc $cache_func ) {

  g_type_add_class_cache_func(
    self._get-native-object-no-reffing, $cache_data, $cache_func
  );
}

sub g_type_add_class_cache_func (
  gpointer $cache_data, GTypeClassCacheFunc $cache_func
) is native(&gobject-lib)
  { * }

#-------------------------------------------------------------------------------
# TM:0:add-class-private:
=begin pod
=head2 add-class-private

Registers a private class structure for a classed type; when the class is allocated, the private structures for the class and all of its parent types are allocated sequentially in the same memory block as the public structures, and are zero-filled.

This function should be called in the type's C<get-type()> function after the type is registered. The private structure can be retrieved using the C<G-TYPE-CLASS-GET-PRIVATE()> macro.

  method add-class-private ( UInt $private_size )

=item UInt $private_size; size of private structure
=end pod

method add-class-private ( UInt $private_size ) {

  g_type_add_class_private(
    self._get-native-object-no-reffing, $private_size
  );
}

sub g_type_add_class_private (
  N-GObject $class_type, gsize $private_size
) is native(&gobject-lib)
  { * }

#-------------------------------------------------------------------------------
# TM:0:add-instance-private:
=begin pod
=head2 add-instance-private



  method add-instance-private ( UInt $private_size --> Int )

=item UInt $private_size;
=end pod

method add-instance-private ( UInt $private_size --> Int ) {

  g_type_add_instance_private(
    self._get-native-object-no-reffing, $private_size
  )
}

sub g_type_add_instance_private (
  N-GObject $class_type, gsize $private_size --> gint
) is native(&gobject-lib)
  { * }

#-------------------------------------------------------------------------------
# TM:0:add-interface-check:
=begin pod
=head2 add-interface-check

Adds a function to be called after an interface vtable is initialized for any class (i.e. after the I<interface-init> member of B<Gnome::GObject::InterfaceInfo> has been called).

This function is useful when you want to check an invariant that depends on the interfaces of a class. For instance, the implementation of B<Gnome::GObject::Object> uses this facility to check that an object implements all of the properties that are defined on its interfaces.

  method add-interface-check ( Pointer $check_data, GTypeInterfaceCheckFunc $check_func )

=item Pointer $check_data; data to pass to I<check-func>
=item GTypeInterfaceCheckFunc $check_func; function to be called after each interface is initialized
=end pod

method add-interface-check ( Pointer $check_data, GTypeInterfaceCheckFunc $check_func ) {

  g_type_add_interface_check(
    self._get-native-object-no-reffing, $check_data, $check_func
  );
}

sub g_type_add_interface_check (
  gpointer $check_data, GTypeInterfaceCheckFunc $check_func
) is native(&gobject-lib)
  { * }

#-------------------------------------------------------------------------------
# TM:0:add-interface-dynamic:
=begin pod
=head2 add-interface-dynamic

Adds the dynamic I<interface-type> to I<instantiable-type>. The information contained in the B<Gnome::GObject::TypePlugin> structure pointed to by I<plugin> is used to manage the relationship.

  method add-interface-dynamic ( N-GObject $interface_type, N-GObject $plugin )

=item N-GObject $interface_type; B<Gnome::GObject::Type> value of an interface type
=item N-GObject $plugin; B<Gnome::GObject::TypePlugin> structure to retrieve the B<Gnome::GObject::InterfaceInfo> from
=end pod

method add-interface-dynamic ( $interface_type is copy, $plugin is copy ) {
  $interface_type .= _get-native-object-no-reffing unless $interface_type ~~ N-GObject;
  $plugin .= _get-native-object-no-reffing unless $plugin ~~ N-GObject;

  g_type_add_interface_dynamic(
    self._get-native-object-no-reffing, $interface_type, $plugin
  );
}

sub g_type_add_interface_dynamic (
  N-GObject $instance_type, N-GObject $interface_type, N-GObject $plugin
) is native(&