------------------------------------------------------------------------------
--                  GtkAda - Ada95 binding for Gtk+/Gnome                   --
--                                                                          --
--      Copyright (C) 1998-2000 E. Briot, J. Brobecker and A. Charlet       --
--                     Copyright (C) 1998-2022, AdaCore                     --
--                                                                          --
-- This library is free software;  you can redistribute it and/or modify it --
-- under terms of the  GNU General Public License  as published by the Free --
-- Software  Foundation;  either version 3,  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 MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE.                            --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
------------------------------------------------------------------------------

--  <description>
--
--  The aim of this package is to provide some services to connect a
--  handler to a signal emitted by a Gtk Object. To understand the
--  services provided by this package, some definitions are necessary:
--
--    Signal: A signal is a kind of message that an object wants to
--    broadcast. All GObjects can emit signals. These messages are
--    associated to certain events happening during the life of an
--    object. For instance, when a user clicks on a button, the
--    "clicked" signal is emitted by the button.
--
--    Handler (or callback): A handler is a function or procedure that
--    the user "connects" to a signal for a particular object.
--    Connecting a handler to a signal means associating this handler to
--    the signal.  When the signal is emitted, all connected handlers
--    are called back. Usually, the role of those callbacks is to do
--    some processing triggered by a user action. For instance, when
--    "clicked" signal is emitted by the "OK" button of a dialog, the
--    connected handler can be used to close the dialog or recompute
--    some value.
--
--    In GtkAda, the handlers are defined in a form as general as
--    possible. The first argument is always an access to the object it
--    has been connected to. The second object is a table of values
--    (See Glib.Values for more details about this table). It is the
--    responsibility of this handler to extract the values from it, and
--    to convert them to the correct Ada type.
--
--    Because such handlers are not very convenient to use, this package
--    also provides some services to connect a marshaller instead. It
--    will then do the extraction work before calling the more
--    programmer-friendly handler, as defined in Gtk.Marshallers (see
--    Gtk.Marshallers for more details).
--
--  The subdivision of this package is identical to Gtk.Marshallers; it
--  is made of four generic sub-packages, each representing one of the
--  four possible kinds of handlers: they can return a value or not, and
--  they can have some user specific data associated to them or not.
--  Selecting the right package depends on the profile of the handler.
--  For example, the handler for the "delete_event" signal of a
--  Gtk_Window has a return value, and has an extra parameter (a Gint).
--  All handlers also have a user_data field by default, but its usage
--  is optional. To connect a handler to this signal, if the user_data
--  field is not used, the Return_Callback generic should be
--  instantiated. On the other hand, if the user_data field is
--  necessary, then the User_Return_Callback generic should be used.
--
--  Note also that the real handler in Gtk+ should expect at least as
--  many arguments as in the marshaller you are using. If your
--  marshaller has one argument, the C handler must have at least one
--  argument too.
--
--  The common generic parameter to all sub-packages is the widget type,
--  which is the basic widget manipulated. This can be
--  Glib.Object.GObject_Record type if you want to reduce the number of
--  instantiations, but the conversion to the original type will have to be
--  done inside the handler.
--
--  All sub-packages are organized in the same way.
--
--    First, the type "Handler" is defined. It represents the general
--    form of the callbacks supported by the sub-package.
--
--    The corresponding sub-package of Gtk.Marshallers is instantiated.
--
--    A series of "Connect" procedures and functions is given. All cases
--    are covered: the functions return the Handler_Id of the newly
--    created association, while the procedures just connect the
--    handler, dropping the Handler_Id; some services allow the user to
--    connect a Handler while some others allow the usage of
--    Marshallers, which are more convenient. Note that more than one
--    handler may be connected to a signal; the handlers will then be
--    invoked in the order of connection.
--
--    Some "Connect_Object" services are also provided. Those services
--    never have a user_data. They accept an additional parameter called
--    Slot_Object. When the callback in invoked, the Gtk Object emitting
--    the signal is substituted by this Slot_Object.
--    These callbacks are always automatically disconnected as soon as one
--    of the two widgets involved is destroyed.
--
--    There are several methods to connect a handler. For each method,
--    although the option of connecting a Handler is provided, the
--    recommended way is to use Marshallers. Each connect service is
--    documented below, in the first sub-package.
--
--    A series of "To_Marshaller" functions are provided. They return
--    some marshallers for the most commonly used types in order to ease
--    the usage of this package. Most of the time, it will not be
--    necessary to use some other marshallers.
--    For instance, if a signal is documented as receiving a single argument,
--    the widget (for instance the "clicked" signal for a Gtk_Button), you
--    will connect to it with:
--        with Gtkada.Handlers;
--        procedure On_Clicked (Button : access Gtk_Widget_Record'Class);
--        ...
--           Widget_Callback.Connect (Button, "clicked", On_Clicked'Access);
--
--    The simple form above also applies for most handlers that take one
--    additional argument, for instance the "button_press_event" in
--    gtk-widget.ads. Just declare your subprogram with the appropriate profile
--    and connect it, as in:
--        with Gtkada.Handlers;
--        procedure On_Button (Widget : access Gtk_Widget_Record'Class;
--                             Event  : Gdk_Event);
--        ...
--           Widget_Callback.Connect (Widget, "button_press_event",
--                                    On_Button'Access);
--
--    More complex forms of handlers exists however in GtkAda, for which no
--    predefined marshaller exists. In this case, you have to use the general
--    form of callbacks. For instance, the "select_row" signal of Gtk.Clist.
--        with Gtkada.Handlers;
--        with Gtk.Arguments;
--        procedure On_Select (Clist : access Gtk_Widget_Record'Class;
--                             Args  : Glib.Values.GValues)
--        is
--           Row : constant Gint := To_Gint (Args, 1);
--           Column : constant Gint := To_Gint (Args, 2);
--           Event  : constant Gdk_Event := To_Event (Args, 3);
--        begin
--           ...
--        end On_Select;
--        ...
--            Widget_Callback.Connect (Clist, "select_row", On_Select'Access);
--
--    As for the "To_Marshaller" functions, a series of "Emit_By_Name"
--    procedures are also provided for the same most common types, to
--    allow the user to easily emit signals. These procedures are mainly
--    intended for people building new GObjects.
--
--  At the end of this package, some general services related to the
--  management of signals and handlers are also provided. Each one of
--  them is documented individually below.
--
--  IMPORTANT NOTE: These packages must be instantiated at library-level
--
--  </description>
--  <c_version>2.8.17</c_version>
--  <group>Signal handling</group>

with Cairo;
with Glib.Values;
with Gdk.Event;
with Glib.Object;
with Gtkada.Bindings;   use Gtkada.Bindings;
with Gtk.Marshallers;
pragma Elaborate_All (Gtk.Marshallers);

with Gtk.Tree_Model;
with Gtk.Tree_View_Column;
with Gtk.Widget;

with Ada.Unchecked_Conversion;

package Gtk.Handlers is

   --  <doc_ignore>

   pragma Elaborate_Body;

   Null_Handler_Id : constant Gulong := 0;

   type Handler_Id is record
      Id      : Gulong := Null_Handler_Id;
      Closure : GClosure;
   end record;
   --  This uniquely identifies a connection widget<->signal.
   --  Closure is an internal data, that you should not use.

   function To_Address (Path : Gtk.Tree_Model.Gtk_Tree_Path)
      return System.Address;

   function Get_Tree_View_Column
     (Val : Glib.Values.GValue)
      return Gtk.Tree_View_Column.Gtk_Tree_View_Column;

   procedure Set_On_Exception (Handler : Gtkada.Bindings.Exception_Handler)
     renames Gtkada.Bindings.Set_On_Exception;
   --  Set the handler that catch all exceptions occurring in a a callback. An
   --  exception should never be propagated to C to avoid undefined behavior.
   --  By default, unhandled exceptions are printed to stderr.
   --  This function can be used to provide your own global exception handler,
   --  which presumably will simply log the exception in application-specific
   --  manner.

   ---------------------------------------------------------
   --  These handlers should return a value
   --  They do not have a User_Data
   ---------------------------------------------------------

   generic
      type Widget_Type is new Glib.Object.GObject_Record with private;
      type Return_Type is (<>);
   package Return_Callback is

      type Handler is access function
        (Widget : access Widget_Type'Class;
         Params : Glib.Values.GValues) return Return_Type;

      type Simple_Handler is access function
        (Widget : access Widget_Type'Class) return Return_Type;

      package Marshallers is new Gtk.Marshallers.Return_Marshallers
        (Widget_Type, Return_Type);

      --  Connecting a handler to an object

      --  In all the Connect services below, the following arguments
      --  will be used:
      --    o Widget, Name: This represents the association (Gtk Object,
      --      Glib.Signal_Name) to which the handler is to be connected.
      --    o After: If this boolean is set to True, then the handler
      --      will be connected after all the default handlers. By
      --      default, it is set to False.

      procedure Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Marsh  : Marshallers.Marshaller;
         After  : Boolean := False);
      --  Connects a Marshaller. The Handler_Id is dropped.

      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False);
      --  Connect a Marshaller. The Handler_Id is dropped.
      --  This is automatically disconnected as soon as either Widget or
      --  Slot_Object is destroyed.
      --  Slot_Object *must* be of type Gtk_Object or one of its children.

      procedure Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Cb     : Simple_Handler;
         After  : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Simple_Handler;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False);
      --  Same as above, except with a simple handle with no parameter. This
      --  is the same as using a To_Marshaller call to the above two
      --  procedures, except it is shorter to write.

      procedure Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Cb     : Handler;
         After  : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False);
      --  Connect a Handler. The Handler_Id is dropped.
      --  This is automatically disconnected as soon as either Widget or
      --  Slot_Object is destroyed.
      --  Slot_Object *must* be of type Gtk_Object or one of its children.

      pragma Inline (Connect);
      pragma Inline (Object_Connect);

      function Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Marsh  : Marshallers.Marshaller;
         After  : Boolean := False) return Handler_Id;
      --  Connects a Marshaller. Returns the Handler_Id.

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False) return Handler_Id;
      --  Connect a Marshaller. Return the Handler_Id.
      --  This is automatically disconnected as soon as either Widget or
      --  Slot_Object is destroyed.
      --  Slot_Object *must* be of type Gtk_Object or one of its children.

      function Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Cb     : Handler;
         After  : Boolean := False) return Handler_Id;
      --  Connects a Handler. Returns the Handler_Id.

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False) return Handler_Id;
      --  Connect a Handler. Returns the Handler_Id.
      --  This is automatically disconnected as soon as either Widget or
      --  Slot_Object is destroyed.
      --  Slot_Object *must* be of type Gtk_Object or one of its children.

      --  Some convenient functions to create marshallers

      package Gint_Marshaller is new Marshallers.Generic_Marshaller
        (Gint, Glib.Values.Get_Int);
      package Guint_Marshaller is new Marshallers.Generic_Marshaller
        (Guint, Glib.Values.Get_Uint);
      package Event_Marshaller is new Marshallers.Generic_Marshaller
        (Gdk.Event.Gdk_Event, Gdk.Event.Get_Event);
      package Context_Marshaller is new Marshallers.Generic_Marshaller
        (Cairo.Cairo_Context, Cairo.Get_Context);
      package Widget_Marshaller is new Marshallers.Generic_Widget_Marshaller
        (Gtk.Widget.Gtk_Widget_Record, Gtk.Widget.Gtk_Widget);

      function To_Marshaller
        (Cb : Gint_Marshaller.Handler)
         return Marshallers.Marshaller renames Gint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Context_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Context_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Guint_Marshaller.Handler)
         return Marshallers.Marshaller renames Guint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Event_Marshaller.Handler)
         return Marshallers.Marshaller renames Event_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Widget_Marshaller.Handler)
         return Marshallers.Marshaller renames Widget_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Marshallers.Void_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Marshallers.Void_Marshaller.To_Marshaller;

      --  Emitting a signal

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gint)
         return Return_Type renames Gint_Marshaller.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Guint)
         return Return_Type renames Guint_Marshaller.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gdk.Event.Gdk_Event) return Return_Type;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : access Gtk.Widget.Gtk_Widget_Record'Class)
         return Return_Type renames Widget_Marshaller.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name)
         return Return_Type renames Marshallers.Void_Marshaller.Emit_By_Name;

   private
      --  <doc_ignore>
      type Acc is access all Widget_Type'Class;
      --  This type has to be declared at library level, otherwise
      --  Program_Error might be raised when trying to cast from the
      --  parameter of Marshaller to another type.

      type Data_Type_Record is record
         Func   : Handler;
         --  User's callback

         Proxy  : Marshallers.Handler_Proxy := null;
         --  Handler_Proxy to use

         Object : Acc := null;
         --  Slot Object for Object_Connect
      end record;
      type Data_Type_Access is access all Data_Type_Record;
      pragma Convention (C, Data_Type_Access);
      --  Data passed to the C handler

      function Convert is new Ada.Unchecked_Conversion
        (Data_Type_Access, System.Address);
      function Convert is new Ada.Unchecked_Conversion
        (System.Address, Data_Type_Access);

      procedure Free_Data (Data : Data_Type_Access);
      pragma Convention (C, Free_Data);
      --  Free the memory associated with the callback's data

      procedure First_Marshaller
        (Closure         : GClosure;
         Return_Value    : Glib.Values.GValue;
         N_Params        : Guint;
         Params          : Glib.Values.C_GValues;
         Invocation_Hint : System.Address;
         User_Data       : System.Address);
      pragma Convention (C, First_Marshaller);
      First_M : constant C_Marshaller := First_Marshaller'Access;
      --  First level marshaller. This is the function that is actually
      --  called by gtk+. It then calls the Ada functions as required.
      --
      --  If you get an error here while compiling, this is because you are not
      --  instantiating this package at library-level.
      --
      --  </doc_ignore>

   end Return_Callback;

   ---------------------------------------------------------
   --  These handlers should return a value
   --  They require a User_Data
   --  See also the package User_Callback_With_Setup
   ---------------------------------------------------------

   generic
      type Widget_Type is new Glib.Object.GObject_Record with private;
      type Return_Type is (<>);
      type User_Type (<>) is private;
   package User_Return_Callback is

      type Handler is access function
        (Widget    : access Widget_Type'Class;
         Params    : Glib.Values.GValues;
         User_Data : User_Type) return Return_Type;
      type Simple_Handler is access function
        (Widget    : access Widget_Type'Class;
         User_Data : User_Type) return Return_Type;

      package Marshallers is new Gtk.Marshallers.User_Return_Marshallers
        (Widget_Type, Return_Type, User_Type);

      --  Connecting a handler to an object

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Simple_Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Simple_Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      pragma Inline (Connect);

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      --  Some convenient functions to create marshallers

      package Gint_Marshaller is new Marshallers.Generic_Marshaller
        (Gint, Glib.Values.Get_Int);
      package Guint_Marshaller is new Marshallers.Generic_Marshaller
        (Guint, Glib.Values.Get_Uint);
      package Event_Marshaller is new Marshallers.Generic_Marshaller
        (Gdk.Event.Gdk_Event, Gdk.Event.Get_Event);
      package Widget_Marshaller is new Marshallers.Generic_Widget_Marshaller
        (Gtk.Widget.Gtk_Widget_Record, Gtk.Widget.Gtk_Widget);

      function To_Marshaller
        (Cb : Gint_Marshaller.Handler)
         return Marshallers.Marshaller renames Gint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Guint_Marshaller.Handler)
         return Marshallers.Marshaller renames Guint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Event_Marshaller.Handler)
         return Marshallers.Marshaller renames Event_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Widget_Marshaller.Handler)
         return Marshallers.Marshaller renames Widget_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Marshallers.Void_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Marshallers.Void_Marshaller.To_Marshaller;

      --  Emitting a signal

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gint)
         return Return_Type renames Gint_Marshaller.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Guint)
         return Return_Type renames Guint_Marshaller.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gdk.Event.Gdk_Event) return Return_Type;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : access Gtk.Widget.Gtk_Widget_Record'Class)
         return Return_Type renames Widget_Marshaller.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name)
         return Return_Type renames Marshallers.Void_Marshaller.Emit_By_Name;

   private
      --  <doc_ignore>
      type Acc is access all Widget_Type'Class;
      --  This type has to be declared at library level, otherwise
      --  Program_Error might be raised when trying to cast from the
      --  parameter of Marshaller to another type.

      type User_Access is access User_Type;
      type Data_Type_Record is record
         Func   : Handler;
         --  User's callback

         Proxy  : Marshallers.Handler_Proxy := null;
         --  Handler_Proxy to use

         User   : User_Access := null;
         Object : Acc := null;
         --  Slot Object for Object_Connect
      end record;
      type Data_Type_Access is access all Data_Type_Record;
      pragma Convention (C, Data_Type_Access);
      --  Data passed to the C handler

      function Convert is new Ada.Unchecked_Conversion
        (Data_Type_Access, System.Address);
      function Convert is new Ada.Unchecked_Conversion
        (System.Address, Data_Type_Access);

      procedure Free_Data (Data : Data_Type_Access);
      pragma Convention (C, Free_Data);
      --  Free the memory associated with the callback's data

      procedure First_Marshaller
        (Closure         : GClosure;
         Return_Value    : Glib.Values.GValue;
         N_Params        : Guint;
         Params          : Glib.Values.C_GValues;
         Invocation_Hint : System.Address;
         User_Data       : System.Address);
      pragma Convention (C, First_Marshaller);
      First_M : constant C_Marshaller := First_Marshaller'Access;
      --  First level marshaller. This is the function that is actually
      --  called by gtk+. It then calls the Ada functions as required.
      --  </doc_ignore>

   end User_Return_Callback;

   -------------------------------------
   -- User_Return_Callback_With_Setup --
   -------------------------------------
   --  This package is basically the same as User_Return_Callback, except that
   --  an extra function (Setup) is called after a handler has been
   --  connected. Typical usage is to automatically call Add_Watch (see below)
   --  in case the User_Type is (or contains) widgets.

   generic
      type Widget_Type is new Glib.Object.GObject_Record with private;
      type Return_Type is (<>);
      type User_Type (<>) is private;
      with procedure Setup (User_Data : User_Type; Id : Handler_Id);
   package User_Return_Callback_With_Setup is

      package Internal_Cb is new User_Return_Callback
        (Widget_Type, Return_Type, User_Type);

      subtype Handler is Internal_Cb.Handler;
      subtype Simple_Handler is Internal_Cb.Simple_Handler;
      package Marshallers renames Internal_Cb.Marshallers;

      --  Connecting a handler to an object

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Simple_Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Simple_Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      pragma Inline (Connect);

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      --  Some convenient functions to create marshallers

      package Gint_Marshaller renames Internal_Cb.Gint_Marshaller;
      package Guint_Marshaller renames Internal_Cb.Guint_Marshaller;
      package Event_Marshaller renames Internal_Cb.Event_Marshaller;
      package Widget_Marshaller renames Internal_Cb.Widget_Marshaller;

      function To_Marshaller
        (Cb : Gint_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Guint_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Event_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Widget_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Internal_Cb.Marshallers.Void_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;

      --  Emitting a signal

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gint) return Return_Type renames Internal_Cb.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Guint) return Return_Type renames Internal_Cb.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gdk.Event.Gdk_Event) return Return_Type
         renames Internal_Cb.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : access Gtk.Widget.Gtk_Widget_Record'Class)
         return Return_Type renames Internal_Cb.Emit_By_Name;

      function Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name)
         return Return_Type renames Internal_Cb.Emit_By_Name;

   end User_Return_Callback_With_Setup;

   ---------------------------------------------------------
   --  These handlers do not return a value
   --  They do not have a User_Data
   ---------------------------------------------------------

   generic
      type Widget_Type is new Glib.Object.GObject_Record with private;
   package Callback is

      type Handler is access procedure
        (Widget : access Widget_Type'Class;
         Params : Glib.Values.GValues);
      type Simple_Handler is access procedure
        (Widget : access Widget_Type'Class);

      package Marshallers is new
        Gtk.Marshallers.Void_Marshallers (Widget_Type);

      --  Connecting a handler to an object

      procedure Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Marsh  : Marshallers.Marshaller;
         After  : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False);

      procedure Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Cb     : Handler;
         After  : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False);

      procedure Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Cb     : Simple_Handler;
         After  : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Simple_Handler;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False);

      pragma Inline (Connect);
      pragma Inline (Object_Connect);

      function Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Marsh  : Marshallers.Marshaller;
         After  : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False) return Handler_Id;

      function Connect
        (Widget : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Cb     : Handler;
         After  : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         After       : Boolean := False) return Handler_Id;

      --  Some convenient functions to create marshallers

      package Gint_Marshaller is new Marshallers.Generic_Marshaller
        (Gint, Glib.Values.Get_Int);
      package Guint_Marshaller is new Marshallers.Generic_Marshaller
        (Guint, Glib.Values.Get_Uint);
      package Event_Marshaller is new Marshallers.Generic_Marshaller
        (Gdk.Event.Gdk_Event, Gdk.Event.Get_Event);
      package Widget_Marshaller is new Marshallers.Generic_Widget_Marshaller
        (Gtk.Widget.Gtk_Widget_Record, Gtk.Widget.Gtk_Widget);
      package Tree_Path_Marshaller is new Marshallers.Generic_Marshaller
        (Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path);
      package Tree_Iter_Tree_Path_Marshaller is
         new Marshallers.Generic_Marshaller_2
               (Gtk.Tree_Model.Gtk_Tree_Iter, Gtk.Tree_Model.Get_Tree_Iter,
                Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path);
      package Tree_Path_Tree_Iter_Marshaller is
         new Marshallers.Generic_Marshaller_2
               (Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path,
                Gtk.Tree_Model.Gtk_Tree_Iter, Gtk.Tree_Model.Get_Tree_Iter);
      package Tree_Path_Tree_Column_Marshaller is
        new Marshallers.Generic_Marshaller_2
          (Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path,
           Gtk.Tree_View_Column.Gtk_Tree_View_Column, Get_Tree_View_Column);

      function To_Marshaller
        (Cb : Gint_Marshaller.Handler)
         return Marshallers.Marshaller renames Gint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Guint_Marshaller.Handler)
         return Marshallers.Marshaller renames Guint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Event_Marshaller.Handler)
         return Marshallers.Marshaller renames Event_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Widget_Marshaller.Handler)
         return Marshallers.Marshaller renames Widget_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Marshallers.Void_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Marshallers.Void_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Path_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Path_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Iter_Tree_Path_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Iter_Tree_Path_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Path_Tree_Iter_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Path_Tree_Iter_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Path_Tree_Column_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Path_Tree_Column_Marshaller.To_Marshaller;

      --  Emitting a signal

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gint) renames Gint_Marshaller.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Guint) renames Guint_Marshaller.Emit_By_Name;

      procedure Emit_By_Name
         (Object : access Widget_Type'Class;
          Name   : Glib.Signal_Name;
          Param  : Gdk.Event.Gdk_Event);

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : access Gtk.Widget.Gtk_Widget_Record'Class)
         renames Widget_Marshaller.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name)
         renames Marshallers.Void_Marshaller.Emit_By_Name;

      procedure Emit_By_Name is
        new Tree_Path_Marshaller.Emit_By_Name_Generic
              (To_Address);

      procedure Emit_By_Name is
        new Tree_Iter_Tree_Path_Marshaller.Emit_By_Name_Generic
              (Gtk.Tree_Model.To_Address,
               To_Address);

      procedure Emit_By_Name is
        new Tree_Path_Tree_Iter_Marshaller.Emit_By_Name_Generic
              (To_Address,
               Gtk.Tree_Model.To_Address);

   private
      --  <doc_ignore>
      type Acc is access all Widget_Type'Class;
      --  This type has to be declared at library level, otherwise
      --  Program_Error might be raised when trying to cast from the
      --  parameter of Marshaller to another type.

      type Data_Type_Record is record
         Func   : Handler;             --  User's callback
         Proxy  : Marshallers.Handler_Proxy := null;  --  Handler_Proxy to use
         Object : Acc := null;         --  Slot Object for Object_Connect
      end record;
      type Data_Type_Access is access all Data_Type_Record;
      pragma Convention (C, Data_Type_Access);
      --  Data passed to the C handler

      function Convert is new Ada.Unchecked_Conversion
        (Data_Type_Access, System.Address);
      function Convert is new Ada.Unchecked_Conversion
        (System.Address, Data_Type_Access);

      procedure Free_Data (Data : Data_Type_Access);
      pragma Convention (C, Free_Data);
      --  Free the memory associated with the callback's data

      procedure First_Marshaller
        (Closure         : GClosure;
         Return_Value    : Glib.Values.GValue;
         N_Params        : Guint;
         Params          : Glib.Values.C_GValues;
         Invocation_Hint : System.Address;
         User_Data       : System.Address);
      pragma Convention (C, First_Marshaller);
      First_M : constant C_Marshaller := First_Marshaller'Access;
      --  First level marshaller. This is the function that is actually
      --  called by gtk+. It then calls the Ada functions as required.
      --  </doc_ignore>

   end Callback;

   ---------------------------------------------------------
   --  These handlers do not return a value
   --  They require a User_Data
   --  See also the package User_Callback_With_Setup
   ---------------------------------------------------------

   generic
      type Widget_Type is new Glib.Object.GObject_Record with private;
      type User_Type (<>) is private;
   package User_Callback is

      type Handler is access procedure
        (Widget    : access Widget_Type'Class;
         Params    : Glib.Values.GValues;
         User_Data : User_Type);
      type Simple_Handler is access procedure
        (Widget    : access Widget_Type'Class;
         User_Data : User_Type);

      package Marshallers is new
        Gtk.Marshallers.User_Void_Marshallers (Widget_Type, User_Type);

      --  Connecting a handler to an object

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Simple_Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Simple_Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      pragma Inline (Connect);

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      --  Some convenient functions to create marshallers

      package Gint_Marshaller is new Marshallers.Generic_Marshaller
        (Gint, Glib.Values.Get_Int);
      package Guint_Marshaller is new Marshallers.Generic_Marshaller
        (Guint, Glib.Values.Get_Uint);
      package Event_Marshaller is new Marshallers.Generic_Marshaller
        (Gdk.Event.Gdk_Event, Gdk.Event.Get_Event);
      package Widget_Marshaller is new Marshallers.Generic_Widget_Marshaller
        (Gtk.Widget.Gtk_Widget_Record, Gtk.Widget.Gtk_Widget);
      package Tree_Path_Marshaller is new Marshallers.Generic_Marshaller
        (Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path);
      package Tree_Iter_Tree_Path_Marshaller is
         new Marshallers.Generic_Marshaller_2
               (Gtk.Tree_Model.Gtk_Tree_Iter, Gtk.Tree_Model.Get_Tree_Iter,
                Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path);
      package Tree_Path_Tree_Iter_Marshaller is
         new Marshallers.Generic_Marshaller_2
               (Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path,
                Gtk.Tree_Model.Gtk_Tree_Iter, Gtk.Tree_Model.Get_Tree_Iter);
      package Tree_Path_Tree_Column_Marshaller is
        new Marshallers.Generic_Marshaller_2
          (Gtk.Tree_Model.Gtk_Tree_Path, Gtk.Tree_Model.Get_Tree_Path,
           Gtk.Tree_View_Column.Gtk_Tree_View_Column, Get_Tree_View_Column);

      function To_Marshaller
        (Cb : Gint_Marshaller.Handler)
         return Marshallers.Marshaller renames Gint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Guint_Marshaller.Handler)
         return Marshallers.Marshaller renames Guint_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Event_Marshaller.Handler)
         return Marshallers.Marshaller renames Event_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Widget_Marshaller.Handler)
         return Marshallers.Marshaller renames Widget_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Marshallers.Void_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Marshallers.Void_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Path_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Path_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Iter_Tree_Path_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Iter_Tree_Path_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Path_Tree_Iter_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Path_Tree_Iter_Marshaller.To_Marshaller;

      function To_Marshaller
        (Cb : Tree_Path_Tree_Column_Marshaller.Handler)
         return Marshallers.Marshaller
         renames Tree_Path_Tree_Column_Marshaller.To_Marshaller;

      --  Emitting a signal

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gint) renames Gint_Marshaller.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Guint) renames Guint_Marshaller.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gdk.Event.Gdk_Event);

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : access Gtk.Widget.Gtk_Widget_Record'Class)
         renames Widget_Marshaller.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name)
         renames Marshallers.Void_Marshaller.Emit_By_Name;

      procedure Emit_By_Name is
        new Tree_Path_Marshaller.Emit_By_Name_Generic
              (To_Address);

      procedure Emit_By_Name is
        new Tree_Iter_Tree_Path_Marshaller.Emit_By_Name_Generic
              (Gtk.Tree_Model.To_Address,
               To_Address);

      procedure Emit_By_Name is
        new Tree_Path_Tree_Iter_Marshaller.Emit_By_Name_Generic
              (To_Address,
               Gtk.Tree_Model.To_Address);

   private
      --  <doc_ignore>
      type Acc is access all Widget_Type'Class;
      --  This type has to be declared at library level, otherwise
      --  Program_Error might be raised when trying to cast from the
      --  parameter of Marshaller to another type.

      type User_Access is access User_Type;
      type Data_Type_Record is record
         Func   : Handler;
         --  User's callback

         Proxy  : Marshallers.Handler_Proxy := null;
         --  Handler_Proxy to use

         User   : User_Access := null;
         Object : Acc := null;
         --  Slot_Object for Object_Connect
      end record;
      type Data_Type_Access is access all Data_Type_Record;
      pragma Convention (C, Data_Type_Access);
      --  Data passed to the C handler

      function Convert is new Ada.Unchecked_Conversion
        (Data_Type_Access, System.Address);
      function Convert is new Ada.Unchecked_Conversion
        (System.Address, Data_Type_Access);

      procedure Free_Data (Data : Data_Type_Access);
      pragma Convention (C, Free_Data);
      --  Free the memory associated with the callback's data

      procedure First_Marshaller
        (Closure         : GClosure;
         Return_Value    : Glib.Values.GValue;
         N_Params        : Guint;
         Params          : Glib.Values.C_GValues;
         Invocation_Hint : System.Address;
         User_Data       : System.Address);
      pragma Convention (C, First_Marshaller);
      First_M : constant C_Marshaller := First_Marshaller'Access;
      --  First level marshaller. This is the function that is actually
      --  called by gtk+. It then calls the Ada functions as required.
      --  </doc_ignore>

   end User_Callback;

   ------------------------------
   -- User_Callback_With_Setup --
   ------------------------------
   --  This package is basically the same as User_Callback, except that an
   --  extra function (Setup) is called after a handler has been
   --  connected. Typical usage is to automatically call Add_Watch (see below)
   --  in case the User_Type is (or contains) widgets.

   generic
      type Widget_Type is new Glib.Object.GObject_Record with private;
      type User_Type (<>) is private;
      with procedure Setup (User_Data : User_Type; Id : Handler_Id);
   package User_Callback_With_Setup is

      package Internal_Cb is new User_Callback (Widget_Type, User_Type);
      package Marshallers renames Internal_Cb.Marshallers;

      subtype Handler is Internal_Cb.Handler;
      subtype Simple_Handler is Internal_Cb.Simple_Handler;

      --  Connecting a handler to an object

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      procedure Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Simple_Handler;
         User_Data : User_Type;
         After     : Boolean := False);
      procedure Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Simple_Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False);

      pragma Inline (Connect);

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Marsh     : Marshallers.Marshaller;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Marsh       : Marshallers.Marshaller;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      function Connect
        (Widget    : access Widget_Type'Class;
         Name      : Glib.Signal_Name;
         Cb        : Handler;
         User_Data : User_Type;
         After     : Boolean := False) return Handler_Id;

      function Object_Connect
        (Widget      : access Glib.Object.GObject_Record'Class;
         Name        : Glib.Signal_Name;
         Cb          : Handler;
         Slot_Object : access Widget_Type'Class;
         User_Data   : User_Type;
         After       : Boolean := False) return Handler_Id;

      --  Some convenient functions to create marshallers

      package Gint_Marshaller renames Internal_Cb.Gint_Marshaller;
      package Guint_Marshaller renames Internal_Cb.Guint_Marshaller;
      package Event_Marshaller renames Internal_Cb.Event_Marshaller;
      package Widget_Marshaller renames Internal_Cb.Widget_Marshaller;

      function To_Marshaller
        (Cb : Gint_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Guint_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Event_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Widget_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;
      function To_Marshaller
        (Cb : Internal_Cb.Marshallers.Void_Marshaller.Handler)
         return Internal_Cb.Marshallers.Marshaller
         renames Internal_Cb.To_Marshaller;

      --  Emitting a signal

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gint) renames Internal_Cb.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Guint) renames Internal_Cb.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : Gdk.Event.Gdk_Event) renames Internal_Cb.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name;
         Param  : access Gtk.Widget.Gtk_Widget_Record'Class)
         renames Internal_Cb.Emit_By_Name;

      procedure Emit_By_Name
        (Object : access Widget_Type'Class;
         Name   : Glib.Signal_Name) renames Internal_Cb.Emit_By_Name;

   end User_Callback_With_Setup;

   ------------------------------------------------------------------
   --  General functions
   ------------------------------------------------------------------

   procedure Add_Watch
     (Id : Handler_Id; Object : access Glib.Object.GObject_Record'Class);
   --  Make sure that when Object is destroyed, the handler Id is also
   --  destroyed. This function should mostly be used in cases where you use a
   --  User_Data that is Object. If you don't destroy the callback at the same
   --  time, then the next time the callback is called it will try to access
   --  some invalid memory (Object being destroyed), and you will likely get a
   --  Storage_Error.

   procedure Disconnect
     (Object : access Glib.Object.GObject_Record'Class;
      Id     : in out Handler_Id);
   --  Disconnect the handler identified by the given Handler_Id.

   procedure Emit_Stop_By_Name
     (Object : access Glib.Object.GObject_Record'Class;
      Name   : Glib.Signal_Name);
   --  During a signal emission, invoking this procedure will halt the
   --  emission.

   procedure Handler_Block
     (Obj : access Glib.Object.GObject_Record'Class;
      Id  : Handler_Id);
   --  Blocks temporily the signal. For each call to this procedure,
   --  a call to Handler_Unblock must be performed in order to really
   --  unblock the signal.

   procedure Handlers_Destroy
     (Obj : access Glib.Object.GObject_Record'Class);
   --  Destroys all the handlers associated to the given object.

   procedure Handler_Unblock
     (Obj : access Glib.Object.GObject_Record'Class;
      Id  : Handler_Id);
   --  See Handler_Block.

   --------------
   -- Internal --
   --------------
   --  The following subprograms are used internally by GtkAda, and should not
   --  be used directly from applications.

   function Do_Signal_Connect
     (Object              : Glib.Object.GObject;
      Name                : Glib.Signal_Name;
      Marshaller          : C_Marshaller;
      Handler             : System.Address;
      Func_Data           : System.Address;
      Destroy             : System.Address;
      After               : Boolean;
      Slot_Object         : System.Address := System.Null_Address;
      Expect_Return_Value : Boolean) return Handler_Id;
   --  Internal function used to connect the signal.
   --  * Object is the object that will emit the signal.
   --  * Marshaller is the C convention subprogram that will be called directly
   --    by gtk+, and is in charge of translating the arguments into a form
   --    suitable for calling the user's Handler callback. This subprogram
   --    does not check the profile of the Handler and whether the Marshaller
   --    will call it with the proper format, so is potentially dangerous.
   --  * Func_Data is an extra parameter passed to Handler by the Marshaller.
   --    It might be ignored, depending on the Marshaller.
   --  * Destroy is called when the handler is destroyed, for instance because
   --    the object itself is destroyed.
   --  * After indicates whether the handler is called after or before the
   --    default handler set by gtk+ for this signal.
   --  * Slot_Object is the object passed to the handler, if any. When this
   --    object is destroyed, the handler should be automatically disconnected.
   --    This object is not automatically connected to the handler, only the
   --    watch to destroy the handler is set in place.
   --  * Expect_Return_Value should be true if the user is connecting a
   --    function to the signal, False if he is connecting a procedure. This is
   --    used to check that the user has used the proper form of handler.

   --  </doc_ignore>

end Gtk.Handlers;

--  <example>
--  --  This example connects the "delete_event" signal to a widget.
--  --  The handlers for this signal get an extra argument which is
--  --  the Gdk_Event that generated the signal.
--
--  with Gtk.Handlers;    use Gtk.Handlers;
--  with Gtk.Marshallers; use Gtk.Marshallers;
--
--  function My_Cb (Widget : access Gtk_Widget_Record'Class;
--                  Event  : Gdk.Event.Gdk_Event)
--                  return Gint;
--  --  your own function
--
--  package Return_Widget_Cb is new Gtk.Handlers.Return_Callback
--     (Gtk.Widget.Gtk_Widget_Record, Gint);
--
--  Return_Widget_Cb.Connect (W, "delete_event",
--     Return_Widget_Cb.To_Marshaller (My_Cb'Access));
--
--  </example>
