On 2021-09-09 20:41, Jere wrote:
> I'm not as versed in GtkAda, but it looks like those have 'Class types so if
> it is like most of the other GUI frameworks out there, you typically would
> extend the type that you are doing the handler for and your user data would
> be fields of the new record type. Since the handler uses 'Class you could just
> cast the parameter to your new type and have access to the user data.
The problem is that GtkAda uses generics instead of tagged types. And,
as I frequently say, generics are lousy.
Here is the design, very simplified:
generic
type Widget_Type is new Glib.Object.GObject_Record with private; -
type User_Type (<>) is private;
package User_Callback is
type Int_Handler is access procedure
( Widget : access Widget_Type'Class;
Param : GInt;
User_Data : User_Type
);
procedure Connect
( ...,
Int_Handler
...
);
type GUInt_Handler is access procedure
( Widget : access Widget_Type'Class;
Param : GUInt;
User_Data : User_Type
);
procedure Connect
( ...,
Int_Handler
...
);
... -- An so on for each parameter type
In reality it is much messier because handlers are created per generic
instances. But you see the problem. For each combination of parameters
you need a handler type and a connect procedure.
Furthermore, observe, that this is inherently type unsafe as you could
attach any handler from a generic instance to any event regardless the
parameters of the event.
Welcome to generics, enjoy.
Handlers without user data are non-generic and exist for each event
because GtkAda is generated. So, it is possible to generate a
non-generic handler/connect pair for each of hundreds of events per each
widget. This is what Emmanuel suggested:
Cb_GObject_Gdk_Event_Motion_Boolean
But, no user data.
You could not do same and stuff thousands of cases in a single generic
handler package! There is only one for all widgets-events.
There is much hatred towards OO design in Ada community which is
possibly was a motive behind this.
An OO design would be to create an abstract base type for each event
with a primitive operation handle the event. The target widget type
would be fixed class-wide, but since it is practically never used, that
is no problem.