[gtkada] Signal handler

Dmitry A. Kazakov mailbox at dmitry-kazakov.de
Wed Aug 3 13:52:41 CEST 2011


On Wed, 03 Aug 2011 12:23:16 +0200, you wrote:

> We also do not want to make GtkAda and Ada05 library, we have customers using it 
> from Ada95.
> 
>>     type Clicked_Handler is limited interface;
>>     procedure Connect
>>                    (   Button : not null access Gtk_Button_Record;
>>                        Handler : in out Clicked_Handler'Class
>>                    );
>>     procedure Connect
>>                    (   Button : not null access Gtk_Button_Record;
>>                        Handler : in out Clicked_Handler'Class;
>>                        ID : out Handler_Id
>>                    );
> 
> We could indeed generate one Connect function per signal, why not. I would not 
> use interfaces for the callbacks though, and I am not sure either that using 
> objects for the callback is a good approach (that's what Java used to do before 
> they also decided it wasn't good).

The advantages of handlers as objects against handlers as free functions:

1. As you said, the user data. Free functions cannot deal with user data
without becoming generic.

2. Scoping. Free functions have almost always the library scope. A handler
never acts there. Its life-time is much shorter and never bound to any
static scope. Having an object allows you to bind the handler's life span
to some object's life time. That is much easier to control.

3. A related issue. Signals are normally sent between objects rather than
broadcasted into the void. A handler object can be put into the recipient
object. A free function cannot.

4. Unfortunately Ada does not have full multiple inheritance, but for the
sake of argument, if it had, the handler could be an abstract type, keeping
its ID, automatically disconnecting upon its finalization. I had several
times the problem of prematurely destroyed user object (passed to the
handler). This a very nasty kind of error.

> The only interesting aspect (non-negligible) 
> is to remove the need to user data since it can then be encapsulated in the 
> callback object, but that makes the code harder to write (can you show an 
> example of user-code using your API) ?

Maybe the names Connect and Handle should rather include the event name.
E.g. Connect_To_Clicked and Handle_Clicked. That would ease adding handler
interfaces to the composite widgets.

procedure body Main is

   package Window_Handlers is
      type Destroy_Main is
          new Destroy_Event_Handler with null record;
      overriding procedure Handle_Destroy_Event
         (  Handler : in out Destroy_Main;
            Object : not null access Gtk_Object_Record'Class;
         );
      type Delete_Main is
          new Delete_Event_Handler with null record;
      overriding function Handle_Delete_Event
         (  Handler : in out Delete_Main;
            Widget : not null access Gtk_Widget_Record'Class;
            Event : Gdk_Event
         ) return Boolean;
   end Window_Handlers;

   package body Window_Handlers is
      procedure Handle_Destroy_Event
         (  Handler : in out Destroy_Main;
            Object : not null access Gtk_Object_Record'Class;
         )  is
      begin
          Gtk.Main.Main_Quit;
      end Handle_Destroy_Event;
      function Handle_Delete_Event
         (  Handler : in out Delete_Main;
            Widget : not null access Gtk_Widget_Record'Class;
            Event : Gdk_Event
         ) return Boolean is
      begin
          return True;
      end Handle_Delete_Event;
   end Window_Handlers;
   use Window_Handlers;

   Window      : Gtk_Window;
   On_Destroy : Destroy_Main;
   On_Delete  : Delete_Main;
begin
   Gtk_New (Window);
   Window.Connect_To_Destroy_Event (On_Destroy);
   Window.Connect_To_Delete_Event (On_Delete);
   ...

>> This schema can be implemented on top of the existing one.
> 
> Right, and that would be easier to do with the generate API indeed.
> 
> One other thing we are changing in the generated API is the handling of gtk+'s 
> interfaces (still not using Ada interfaces, since we do not want to force 
> Ada05).

Under Ada 95 it could indeed be an abstract Ada.Finalization.Controlled
object. With Connect storing its ID and Finalize disconnecting. The problem
is implementation of Adjust. It should connect the new instance. Handler
cannot be Limited_Controlled because GObject_Record is not limited (to be
able to place handlers into widgets).

BTW, did you consider possible impact of turning GObject_Record limited? It
would make life much easier when developing user and composite widgets.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



More information about the gtkada mailing list