### ----------------------------------------------------
### -- Gnome::GObject
### -- Licenses: Artistic-2.0
### -- Authors: Marcel Timmerman
### -- File: lib/Gnome/GObject/Object.rakumod
### ----------------------------------------------------
### -- Chunk 2 of 4
::x-debug;
      if $signal-types{$mn}:exists and ?$signal-types{$mn}{$signal-name} {
        $signal-type = $signal-types{$mn}{$signal-name};
        $module-name = $mn;
        note "  found key '$signal-type' for $mn" if $Gnome::N::x-debug;
        last;
      }
    }

    return False unless ?$signal-type;

    # self can't be closed over
    my $current-object = self;

    my %named-args = %user-options;
    %named-args<_widget> = $current-object;
    %named-args<_handler-id> = $handler-id;

    sub w0 ( N-GObject $w, gpointer $d ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw0, $handler-name for $signal-name: %named-args.gist()"
        if $Gnome::N::x-debug;

      # Mu is not an accepted value for the NativeCall interface
      # _convert_g_signal_connect_object() in Signal makes it a gpointer
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"(|%named-args);

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w0 handler result: $retval";
      }

      $retval
    }

    sub w1( N-GObject $w, $h0, gpointer $d ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw1, $handler-name for $signal-name: $h0, %named-args.gist()"
        if $Gnome::N::x-debug;

#      my List @converted-args = self!check-args($h0);
#      $handler-object."$handler-name"( |@converted-args, |%named-args);
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"( $h0, |%named-args);

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w1 handler result: $retval";
      }

      $retval
    }

    sub w2( N-GObject $w, $h0, $h1, gpointer $d ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw2, $handler-name for $signal-name: $h0, $h1, %named-args.gist()"
        if $Gnome::N::x-debug;

#      my List @converted-args = self!check-args( $h0, $h1);
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"(
        $h0, $h1, |%named-args
      );

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w2 handler result: $retval";
      }

      $retval
    }

    sub w3( N-GObject $w, $h0, $h1, $h2, gpointer $d ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw3, $handler-name for $signal-name: $h0, $h1, $h2, %named-args.gist()" if $Gnome::N::x-debug;

#      my List @converted-args = self!check-args( $h0, $h1, $h2);
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"(
        $h0, $h1, $h2, |%named-args
      );

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w3 handler result: $retval";
      }

      $retval
    }

    sub w4( N-GObject $w, $h0, $h1, $h2, $h3, gpointer $d ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw4, $handler-name for $signal-name: $h0, $h1, $h2, $h3, %named-args.gist()" if $Gnome::N::x-debug;

#      my List @converted-args = self!check-args( $h0, $h1, $h2, $h3);
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"(
        $h0, $h1, $h2, $h3, |%named-args
      );

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w4 handler result: $retval";
      }

      $retval
    }

    sub w5(
      N-GObject $w, $h0, $h1, $h2, $h3, $h4, gpointer $d
    ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw5, $handler-name for $signal-name: $h0, $h1, $h2, $h3, $h4, %named-args.gist()" if $Gnome::N::x-debug;

#      my List @converted-args = self!check-args( $h0, $h1, $h2, $h3, $h4);
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"(
        $h0, $h1, $h2, $h3, $h4, |%named-args
      );

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w5 handler result: $retval";
      }

      $retval
    }

    sub w6(
      N-GObject $w, $h0, $h1, $h2, $h3, $h4, $h5, gpointer $d
    ) is export {
      CATCH { default { .message.note; .backtrace.concise.note } }

      note "\nw6, $handler-name for $signal-name: $h0, $h1, $h2, $h3, $h4, $h5, %named-args.gist()" if $Gnome::N::x-debug;

#      my List @converted-args = self!check-args( $h0, $h1, $h2, $h3, $h4, $h5);
      %named-args<_native-object> := $w;
      my $retval = $handler-object."$handler-name"(
        $h0, $h1, $h2, $h3, $h4, $h5, |%named-args
      );

      if $sh.signature.returns.gist ~~ '(Mu)' {
        $retval = gpointer;
      }

      elsif $Gnome::N::x-debug {
        note "w6 handler result: $retval";
      }

      $retval
    }

    # Set the handler for the specified signal
    state %shkeys = %( :&w0, :&w1, :&w2, :&w3, :&w4, :&w5, :&w6);
    my $no = self._get-native-object-no-reffing;
    $handler-id = self._convert_g_signal_connect_object(
      $no, $signal-name, $sh, %shkeys{$signal-type}
    );

    note "\nSignal type and name: $signal-type, $handler-id, $signal-name\nHandler: $sh.gist(),\n" if $Gnome::N::x-debug;
  }

  else {
    note "\nCannot register $handler-object, $handler-name, options: ",
      %user-options, ', method, not found' if $Gnome::N::x-debug;
  }

  $handler-id
}

#`{{
#-------------------------------------------------------------------------------
#TODO create Raku objects from the native objects
method !check-args( *@args --> List ) {

  my @new-args = ();

  for @args -> $h {
# wrong; $h is a native object!
    my Str $class = $h.^name;
    if $class ~~ m/^ 'Gnome::' [ Gtk || Gdk || G ] '::' / {
      try {
        require ::($class);
        my $no = ::($class).new(:widget($h));
        @new-args.push: $no;
        CATCH {
          default {
            if $Gnome::N::x-debug {
              once {note "\nQuerying interfaces for module $!gtk-class-name"};

              if .message ~~ m:s/$class/ {
                note "Interface $class not (yet) implemented";
              }

              elsif .message ~~ m:s/Could not find/ {
                note ".new() or ._interface() not defined";
              }

              else {
                note "Error: ", .message();
              }
            }
          }
        }
      }
    }

    else {
      @new-args.push: $h;
    }
  }

  @args
}
}}
#`{{
#-------------------------------------------------------------------------------
#TM:0:g_object_replace_data:
=begin pod
=head2 [[g_] object_] replace_data

Compares the user data for the key I<key> on I<object> with
I<oldval>, and if they are the same, replaces I<oldval> with
I<newval>.

This is like a typical atomic compare-and-exchange
operation, for user data on an object.

If the previous value was replaced then ownership of the
old value (I<oldval>) is passed to the caller, including
the registered destroy notify for it (passed out in I<old_destroy>).
It’s up to the caller to free this as needed, which may
or may not include using I<old_destroy> as sometimes replacement
should not destroy the object in the normal way.

Returns: C<1> if the existing value for I<key> was replaced
by I<newval>, C<0> otherwise.

  method g_object_replace_data (
    Str $key, Pointer $oldval, Pointer $newval,
    GDestroyNotify $destroy, GDestroyNotify $old_destroy
    --> Int
  )

=item Str $key; a string, naming the user data pointer
=item Pointer $oldval; (nullable): the old value to compare against
=item Pointer $newval; (nullable): the new value
=item GDestroyNotify $destroy; (nullable): a destroy notify for the new value
=item GDestroyNotify $old_destroy; (out) (optional): destroy notify for the existing value

=end pod

method replace-data ( Str $key, Pointer $data ) {
  g_object_set_data( self._f('GObject'), $key, $data);
}

sub g_object_replace_data ( N-GObject $object, Str $key, Pointer $oldval, Pointer $newval, GDestroyNotify $destroy, GDestroyNotify $old_destroy )
  returns int32
  is native(&gobject-lib)
  { * }
}}

#-------------------------------------------------------------------------------
#TM:2:set-data:xt/Object.t
=begin pod
=head2 set-data

Each object carries around a table of associations from strings to pointers.  This function lets you set an association.

If the object already had an association with that name, the old association will be destroyed.

  method set-data ( Str $key, $data )

=item Str $key; name of the key.
=item $data; data to associate with that key. Supported types are int*, uint*, num*, Pointer, Buf, Int, Num, Str, Bool and N-GObject. A raku widget object such as Gnome::Gdk3::Screen can also be given. The native object is retrieved from the raku widget and then stored as a N-GObject. Further is it important to note that Int, UInt, and Num is transformed to their 32 bit representations.

=head3 Example 1

Here is an example to show how to associate some data to an object and to retrieve it again. You must import the raku B<NativeCall> module to get access to some of the native types and routines.

  my Gnome::Gtk3::Button $button .= new(:label<Start>);
  my Gnome::Gtk3::Label $att-label .= new(:text<a-label>);
  $button.set-data( 'attached-label-data', $att-label);

  …

  my Gnome::Gtk3::Label $att-label2 =
    $button.get-data( 'attached-label-data', N-GObject);

or, if you want to be sure, add the C<widget-class> named argument;

  my Gnome::Gtk3::Label $att-label2 = $button.get-data(
    'attached-label-data', N-GObject,
    :widget-class<Gnome::Gtk3::Label>
  );

=head3 Example 2

Other types can be used as well to store data. The next example shows what is possible;

  $button.set-data( 'my-text-key', 'my important text');
  $button.set-data( 'my-uint32-key', my uint32 $x = 12345);

  …

  my Str $text = $button.get-data( 'my-text-key', Str);
  my Int $number = $button.get-data( 'my-uint32-key', uint32);


=head3 Example 3

An elaborate example of more complex data can be used with BSON. This is an implementation of a JSON like structure but is serialized into a binary representation. It is used for transport to and from a mongodb server. Here we use it to attach complex data in serialized form to an B<Gnome::GObject::Object>. (Please note that the BSON package must be of version 0.13.2 or higher. More [documenation at](https://martimm.github.io/raku-mongodb-driver/content-docs/reference/BSON/Document.html))

  # Create the data structure
  my BSON::Document $bson .= new: (
    :int-number(-10),
    :num-number(-2.34e-3),
    :strings( :s1<abc>, :s2<def>, :s3<xyz> )
  );

  # And store it on a label
  my Gnome::Gtk3::Label $bl .= new(:text<a-label>);
  $bl.set-data( 'my-buf-key', $bson.encode);

  …

  # Later, we want to access the data again,
  my BSON::Document $bson2 .= new($bl.get-data( 'my-buf-key', Buf));

  # Now you can use the data again.
  say $bson2<int-number>;  # -10
  say $bson2<num-number>;  # -234e-5
  say $bson2<strings><s2>; # 'def'

=end pod

method set-data ( Str $key, $data is copy ) {

  # if $data is a raku widget (Gnome::GObject::Object), get the native object
  $data .= _get-native-object if $data.^can('_get-native-object');

  my $d;
  given $data.^name {

    when 'int8' {
      $d = CArray[int8].new($data);
    }

    when /uint8 || byte/ {
      $d = CArray[byte].new($data);
    }

    when 'int16' {
      $d = CArray[int16].new($data);
    }

    when 'uint16' {
      $d = CArray[uint16].new($data);
    }

    when 'int32' {
      $d = CArray[int32].new($data);
    }

    when 'uint32' {
      $d = CArray[uint32].new($data);
    }

    when /int '64'?/ {
      $d = CArray[int64].new($data);
    }

    when /uint '64'?/ {
      $d = CArray[uint64].new($data);
    }

    when 'num32' {
      $d = CArray[num32].new($data);
    }

    when 'num64' {
      $d = CArray[num64].new($data);
    }

    when 'Pointer' {
      $d = CArray[Pointer].new($data);
    }

    when 'Buf' {
      $d = CArray[byte].new($data);
    }

    when 'Int' {
      $d = CArray[int32].new($data);
    }

    when 'Num' {
      $d = CArray[num32].new($data);
    }

    when 'Rat' {
      $d = CArray[num64].new($data.Num);
    }

    when 'Str' {
      $d = CArray[Str].new($data);
    }

    when 'Bool' {
      $d = CArray[gboolean].new($data);
    }

#    when Gnome::GObject::Object {
#      $d = CArray[N-GObject].new($data._get-native-object);
#    }

#TODO $data automatically coerced?
    when 'N-GObject' {
      $d = CArray[N-GObject].new($data);
    }

    default {
      die X::Gnome.new(:message("Type '$data.^name()' for key '$key' not supported"));
    }
  }

  g_object_set_data(
    self._f('GObject'), $key,
    $data ~~ Pointer ?? $data !! nativecast( Pointer, $d)
  );
}

sub g_object_set_data ( N-GObject $object, Str $key, Pointer $data )
  is native(&gobject-lib)
  { * }

#-------------------------------------------------------------------------------
#TM:2:set-properties:xt/Object.t
=begin pod
=head2 set-properties

Sets properties on an object.

Note that the "notify" signals are queued and only emitted (in reverse order) after all properties have been set.
=comment See C<g_object_freeze_notify()>.

  method set-properties ( Str :$prop-name($prop-value), … )

=item Str $prop-name; name of a property to set.
=item $prop-value; The value of the property to set. Its type can be any of Str, Int, Num, Bool, int8, int16, int32, int64, num32, num64, GEnum, GFlag, GQuark, GType, gboolean, gchar, guchar, gdouble, gfloat, gint, gint8, gint16, gint32, gint64, glong, gshort, guint, guint8, guint16, guint32, guint64, gulong, gushort, gsize, gssize, gpointer or time_t. Int is converted to int32 and Num to num32. You must use B<Gnome::N::GlibToRakuTypes> to have the g* types and time_t.

=head3 Example

A button has e.g. the properties C<label> and C<use-underline>. To set those and retrieve them, do the following

  my Gnome::Gtk3::Button $b .= new(:label<?>);
  $button.set-properties( :label<_Start>, :use-underline(True));
  …

  method my-button-click-event-handler (
    Gnome::Gtk3::Button :_native-object($button)
  ) {
    # Get the properties set elsewhere on the button
    my @rv = $button.get-properties( 'label', Str, 'use-underline', Bool);

    # Do something with intval, strval, objval
    say @rv[0];   # _Start
    say @rv[1];   # 1
    …

Note that boolean values from C are integers which are 0 or 1.

=end pod

method set-properties ( *%properties ) {

  my @parameter-list = ( Parameter.new(:type(N-GObject)), );    # object
  my @pl = ( );                                                 # arguments

  for %properties.kv -> $key, $v {
    @parameter-list.push: Parameter.new(:type(Str));            # prop name
    @pl.push: $key;                                             # name arg

    @pl.push: $v;                                               # value arg

    # prop type of value arg
    given $v.^name {

      when 'int8' {
        @parameter-list.push: Parameter.new(:type(CArray[int8]));
      }

      when /uint8 || byte/ {
        @parameter-list.push: Parameter.new(:type(CArray[byte]));
      }

      when 'int16' {
        @parameter-list.push: Parameter.new(:type(CArray[int16]));
      }

      when 'uint16' {
        @parameter-list.push: Parameter.new(:type(CArray[uint16]));
      }

      when 'int32' {
        @parameter-list.push: Parameter.new(:type(CArray[int32]));
      }

      when 'uint32' {
        @parameter-list.push: Parameter.new(:type(CArray[uint32]));
      }

      when /int '64'?/ {
        @parameter-list.push: Parameter.new(:type(CArray[int64]));
      }

      when /uint '64'?/ {
        @parameter-list.push: Parameter.new(:type(CArray[uint64]));
      }

      when 'num32' {
        @parameter-list.push: Parameter.new(:type(CArray[num32]));
      }

      when 'num64' {
        @parameter-list.push: Parameter.new(:type(CArray[num64]));
      }

      when 'UInt' {
        # 32bit more common?
        @parameter-list.push: Parameter.new(:type(uint32));
      }

      when 'Int' {
        # 32bit more common?
        @parameter-list.push: Parameter.new(:type(int32));
      }

      when 'Num' {
        # 32bit more common?
        @parameter-list.push: Parameter.new(:type(num32));
      }

      when 'Str' {
        @parameter-list.push: Parameter.new(:type(Str));
      }

      when /Bool || gboolean/ {
        @parameter-list.push: Parameter.new(:type(gboolean));
      }

#`{{
      when 'N-GObject' {
        @parameter-list.push: Parameter.new(:type(N-GObject));
      }

      default {
        die X::Gnome.new(
          :message("Type {.^name} for key $key not supported")
        );
      }
}}

      default {
        @parameter-list.push: Parameter.new(:type($v.WHAT));
      }
    }
  }

  # to finish the list with 0
  @parameter-list.push: Parameter.new(type => Pointer);

  # create signature
  my Signature $signature .= new(
    :params(|@parameter-list),
    :returns(int32)
  );


  # get a pointer to the sub, then cast it to a sub with the proper
  # signature. after that, the sub can be called, returning a value.
  state $ptr = cglobal( &gtk-lib, 'g_object_set', Pointer);
  my Callable $f = nativecast( $signature, $ptr);

  $f( self._get-native-object-no-reffing, |@pl, Nil);
}

#-------------------------------------------------------------------------------
#TM:2:set-property:xt/Object.t
=begin pod
=head2 set-property

Sets a property on an object.

  method set-property ( Str $property_name, N-GValue $value )

=item Str $property_name; the name of the property to set
=item N-GObject $value; the value

=end pod

method set-property ( gchar-ptr $property_name, $value is copy ) {
  $value .= _get-native-object-no-reffing unless $value ~~ N-GValue;

  g_object_set_property(
    self._get-native-object-no-reffing, $property_name, $value
  );
}

sub g_object_set_property (
  N-GObject $object, gchar-ptr $property_name, N-GValue $value
) is native(&gobject-lib)
  is symbol('g_object_set_property')
  { * }

#-------------------------------------------------------------------------------
#TM:4:start-thread:Gtk3 stress tests
=begin pod
=head2 start-thread

Start a thread in such a way that the function can modify the user interface in a save way and that these updates are automatically made visible without explicitly process events queued and waiting in the main loop.

  method start-thread (
    $handler-object, Str:D $handler-name,
    Bool :$new-context = False, Num :$start-time = now + 1,
    *%user-options
    --> Promise
  )

=item $handler-object is the object wherein the handler is defined.
=item $handler-name is name of the method.
=item $new-context; Whether to run the handler in a new context or to run it in the context of the main loop. Default is to run in the main loop.
=item $start-time. Start time of thread. Default is now + 1 sec. Most of the time a thread starts too fast when some widget are not ready yet. All depends of course what the thread has to do.

=begin item
%user-options; Any other user data in whatever type provided as one or more named arguments except for :start-time and :new-context. These arguments are provided to the user handler when the callback is invoked.

There will always be one named argument C<:$widget> which holds the class object on which the thread is started. The name 'widget' is therefore reserved.

The following named arguments can be used in the callback handler next to the other user definable options;

  =item C<:$_widget>; The instance which registered the signal.
=end item

Returns a C<Promise> object. If the call fails, the object is undefined.

The handlers signature holds at least C<:$_widget> extended with all provided named arguments to the call defined in C<*%user-options>. The handler may return any value which becomes the result of the C<Promise> returned from C<start-thread>.

=end pod

method start-thread (
  Any:D $handler-object, Str:D $handler-name,
  Bool :$new-context = False, Instant :$start-time = now + 1, *%user-options
  --> Promise
) {

  # don't start thread if handler is not available
  my Method $sh = $handler-object.^lookup($handler-name) // Method;
  die X::Gnome.new(
    :message("Method '$handler-name' not available in object")
  ) unless ? $sh;

  my Promise $p = Promise.at($start-time).then( {

#    CATCH { default { .message.note; .backtrace.concise.note } }

    # This part is important that it happens in the thread where the
      # function is invoked in that context!
      my Gnome::Glib::MainContext $gmain-context;
      if $new-context {
        $gmain-context .= new;
        $gmain-context.push-thread-default;
      }

      else {
        # when invoke is called and context is undefined, it takes the default
        $gmain-context .= new(:thread-default);
      }

      my $return-value;
      $gmain-context.invoke-raw(
        -> gpointer $d {

          CATCH { default { .message.note; .backtrace.concise.note } }

          $return-value = $handler-object."$handler-name"(
            :widget(self), :_widget(self), |%user-options
          );

          G_SOURCE_REMOVE
        },
      );

      if $new-context {
        $gmain-context.pop-thread-default;
      }

      $return-value
    }
  );

  $p
}

#-------------------------------------------------------------------------------
#TM:2:steal-data:xt/Object.t
=begin pod
=head2 steal-data

Remove a specified datum from the object's data associations, without invoking the association's destroy handler.

Returns: the data if found, or C<Any> if no such data exists.

  method steal-data ( Str $key --> Pointer )

=item Str $key; name of the key

=end pod

#`{{
method steal-data ( Str $key --> Pointer ) {
  g_object_steal_data( self._get-native-object-no-reffing, $key);
}
}}


method steal-data ( Str $key, Any $type, Str :$widget-class --> Any ) {

  my $data;
  my $odata = g_object_steal_data( self._f('GObject'), $key);
  given $type.^name {

    when 'int8' {
      my CArray[int8] $d = nativecast( CArray[int8], $odata);
      $data = $d[0];
    }

    when /uint8 || byte/ {
      my CArray[byte] $d = nativecast( CArray[byte], $odata);
      $data = $d[0];
    }

    when 'int16' {
      my CArray[int16] $d = nativecast( CArray[int16], $odata);
      $data = $d[0];
    }

    when 'uint16' {
      my CArray[uint16] $d = nativecast( CArray[uint16], $odata);
      $data = $d[0];
    }

    when 'int32' {
      my CArray[int32] $d = nativecast( CArray[int32], $odata);
      $data = $d[0];
    }

    when 'uint32' {
      my CArray[uint32] $d = nativecast( CArray[uint32], $odata);
      $data = $d[0];
    }

    # (g)int might be shorter but placed in longest possible, doesn't harm
    when 'int64' {
      my CArray[int64] $d = nativecast( CArray[int64], $odata);
      $data = $d[0];
    }

    when 'uint64' {
      my CArray[uint64] $d = nativecast( CArray[uint64], $odata);
      $data = $d[0];
    }

    when 'num32' {
      my CArray[num32] $d = nativecast( CArray[num32], $odata);
      $data = $d[0];
    }

    when 'num64' {
      my CArray[] $d = nativecast( CArray[], $odata);
      $data = $d[0];
    }

    when 'Pointer' {
      $data = $odata;
    }

    when 'Buf' {
      $data = nativecast( CArray[byte], $odata);
    }

    when 'Int' {
      my CArray[int32] $d = nativecast( CArray[int32], $odata);
      $data = $d[0];
    }

    when 'Num' {
      my CArray[num32] $d = nativecast( CArray[num32], $odata);
      $data = $d[0];
    }

    when 'Str' {
      my CArray[Str] $d = nativecast( CArray[Str], $odata);
      $data = $d[0];
    }

    when 'Bool' {
      my CArray[gboolean] $d = nativecast( CArray[gboolean], $odata);
      $data = $d[0];
    }

    when 'N-GObject' {
      my CArray[N-GObject] $d = nativecast( CArray[N-GObject], $odata);
      if ?$widget-class {
        require ::($widget-class);
        my $class = ::($widget-class);
        $data = $class.new(:native-object($d[0]));
      }

      else {
        $data = $d[0].defined
          ?? self._wrap-native-type-from-no($d[0])
          !! N-GObject;
      }
    }

    default {
      die X::Gnome.new(:message("Type of key '$key' not supported"));
    }
  }

  $data
}

sub g_object_steal_data ( N-GObject $object, Str $key --> Pointer )
  is native(&gobject-lib)
  { * }

#-------------------------------------------------------------------------------
# this sub belongs to Gnome::Gtk3::Main but is needed here to avoid
# circular dependencies,
sub _object_init_check (
#  CArray[int32] $argc, CArray[CArray[Str]] $argv
  int-ptr $argc, char-ppptr $argv
  --> int32
) is native(&gtk-lib)
  is symbol('gtk_init_check')
  { * }

#`{{
#-------------------------------------------------------------------------------
sub _path_to_string ( N-GObject $path --> Str )
  is native(&gtk-lib)
  is symbol('gtk_widget_path_to_string')
  { * }

#-------------------------------------------------------------------------------
sub _get_path (
  N-GObject $widget --> N-GObject
) is native(&gtk-lib)
  is symbol('gtk_widget_get_path')
  { * }
}}

#-------------------------------------------------------------------------------
#TM:1:_g_object_ref:
#`{{
=begin pod
=head2 [g_] object_ref

Increases the reference count of this object and returns the same object.

  method g_object_ref ( --> N-GObject )

=end pod
}}

sub _g_object_ref ( N-GObject $object --> N-GObject )
  is native(&gobject-lib)
  is symbol('g_object_ref')
  { * }

#-------------------------------------------------------------------------------
#TM:1:_g_object_unref:
#`{{
=begin pod
=head2 [g_] object_unref

Decreases the reference count of the native object. When its reference count drops to 0, the object is finalized (i.e. its memory is freed).

When the object has a floating reference because it is not added to a container or it is not a toplevel window, the reference is first sunk followed by C<g_object_unref()>.

  method g_object_unref ( )

=item N-GObject $object; a native I<GObject>.

=end pod

sub g_object_unref ( N-GObject $object is copy ) {

  $object = g_object_ref_sink($object) if g_object_is_floating($object);
  _g_object_unref($object)
}
}}

sub _g_object_unref ( N-GObject $object )
  is native(&gobject-lib)
  is symbol('g_object_unref')
  { * }























=finish

#-------------------------------------------------------------------------------
#TM:0:g_initially_unowned_get_type:
=begin pod
=head2 [g_] initially_unowned_get_type

  method g_initially_unowned_get_type ( --> int32  )

=end pod

sub g_initially_unowned_get_type (  )
  returns int32
  is native(&gobject-lib)
  { * }

#`{{
#-------------------------------------------------------------------------------
#TM:0:g_object_setv:
=begin pod
=head2 [g_] object_setv

Sets I<$n_properties> properties for this object. Properties to be set will be taken from I<$values>. All properties must be valid. Warnings will be emitted and undefined behaviour may result if invalid properties are passed in.


  method g_object_setv ( @names, @values )

=item Str @names; the names of each property to be set
=item N-GValue @values; the values of each property to be set

=end pod

method g-object-setv ( Array $names, Array $values ) {

  my Int $l = $names.elems;

  die X::Gnome.new(:message("Arrays do not have equal length"))
      unless $l == $values.elems;

  my CArray[Str] $n .= new;
  my CArray[N-GValue] $v .= new;
  loop ( my $i = 0; $i < $l; $i++ ) {
    $n[$i] = $names[$i];
    $v[$i] = $values[$i];
  }

  _g_object_setv( self._get-native-object, $l, $n, $v)
}

sub _g_object_setv (
  N-GObject $object, uint32 $n_properties,
  CArray[Str] $names, CArray[N-GValue] $values
) is native(&gobject-lib)
  is symbol('g_object_setv')
  { * }

#-------------------------------------------------------------------------------
#TM:0:g_object_set_valist:
=begin pod
=head2 [[g_] object_] set_valist

Sets properties on an object.

  method g_object_set_valist (
    Str $first_property_name, CArray[N-GValue] $var_args
  )

=item Str $first_property_name; name of the first property to set
=item CArray[N-GValue] $var_args; value for the first property, followed optionally by more name/value pairs, followed by C<Any>

=end pod

sub g_object_set_valist ( N-GObject $object, Str $first_property_name, CArray[N-GValue] $var_args