A while back the
Gtk community started a project called
GObject Introspection. In short it exports the Gtk and Glib api, as well as many others, to an easily parsed xml format.
The result is
gir2pascal.
gir2pascal can create bindings to pascal from any library that supports gobject introspection in just a few moments! The result is that
Gtk3 bindings have been created fairly easily for pascal and can easily be updated simply by running gir2pascal against the latest version.
Here is part of the XML code from the Gtk3.gir file relating to the caption of the button:
<class name="Button"
c:symbol-prefix="button"
c:type="GtkButton"
parent="Bin"
glib:type-name="GtkButton"
glib:get-type="gtk_button_get_type"
glib:type-struct="ButtonClass">
<implements name="Atk.ImplementorIface"/>
<implements name="Actionable"/>
<implements name="Activatable"/>
<implements name="Buildable"/>
<constructor name="new" c:identifier="gtk_button_new">
<return-value transfer-ownership="none">
<type name="Widget" c:type="GtkWidget*"/>
</return-value>
</constructor>
<method name="get_label" c:identifier="gtk_button_get_label">
<return-value transfer-ownership="none">
<type name="utf8" c:type="gchar*"/>
</return-value>
</method> <method name="set_label" c:identifier="gtk_button_set_label">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="label" transfer-ownership="none">
<type name="utf8" c:type="gchar*"/>
</parameter>
</parameters>
</method>
<property name="label" construct="1"
transfer-ownership="none">
<type name="utf8"/>
</property>
</class>
One improvement over the current (Gtk2) bindings in use is that
Pascal objects (not classes) have been used in place of records. The
advantage is that GObjects, a C style quasi-object, can be accessed in
an object oriented way instead of the flat C functions we use currently.
Here is the corresponding generated pascal code from the XML above:
type
TGtkButton = object(TGtkBin)
priv3: PGtkButtonPrivate;
function new: PGtkButton; cdecl; inline; static;
function get_label: Pgchar; cdecl; inline;
procedure set_label(label_: Pgchar); cdecl; inline;
property label_: Pgchar read get_label write set_label;
end;
function gtk_button_new: PGtkButton; cdecl; external;
function gtk_button_get_label(AButton: PGtkButton): Pgchar; cdecl; external;
procedure gtk_button_set_label(AButton: PGtkButton; label_: Pgchar); cdecl; external;
implementation
function TGtkButton.new: PGtkButton; cdecl;
begin
Result := Gtk3.gtk_button_new();
end;
function TGtkButton.get_label: Pgchar; cdecl;
begin
Result := Gtk3.gtk_button_get_label(@self);
end;
procedure TGtkButton.set_label(label_: Pgchar); cdecl;
begin
Gtk3.gtk_button_set_label(@self, label_);
end;
You can see that we are using objects instead of records, compare this to the current Gtk2 bindings:
type
PGtkButton = ^TGtkButton;
TGtkButton = record
bin : TGtkBin;
event_window : PGdkWindow;
label_text : Pgchar;
activate_timeout : guint;
flag0 : word;
end;
function gtk_button_new:PGtkWidget; cdecl; external gtklib;
procedure gtk_button_set_label(button:PGtkButton; _label:Pgchar); cdecl; external gtklib;
function gtk_button_get_label(button:PGtkButton):Pgchar; cdecl; external gtklib;
Before, our code would look like this:
procedure Foo;
var
Button: PGtkWidget;
begin
Button := gtk_button_new;
gtk_button_set_label(PGtkButton(Button), 'Hello World!');
end;
But now it's possible to use this instead:
procedure Foo;
var
Button: PGtkButton;
begin
Button := TGtkButton.new;
Button^.label_ := 'Hello World!';
end;
As you see it's a bit shorter to type the second way. Although either will work since the 'flat' functions are still available to use.
Using objects instead of records it is of course possible to access inherited methods and properties with greater ease than before, especially when using the code completion feature of
Lazarus (which is extremely close to 1.0 now!).
Button in the example above descends from
GtkWidget which has the property
tooltip_text.
This can be accessed with
Button^.tooltip_text := 'Don''t click me unless you want to!';
whereas before you had to do
gtk_widget_set_tooltip_text(PGtkWidget(Button) ,'Don''t click me unless you want to!');
Here's the HelloWorld example included with the bindings, modified to have a tooltip.
The Pascal Gtk3 bindings are not yet well tested. There are a couple of examples in the
Lazarus-ccr repository in the folder /bindings/gtk3/examples/ including an example of GtkWebkit.
Perhaps you would like to try it out :)