Tuesday, August 28, 2012

Gtk3, GObject Introspection and Free Pascal

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 :)

Thursday, August 2, 2012

Preparing for Lazarus 1.0 (RC1)

Just to announce: Lazarus is preparing to go 1.0.

The first release candidate for the new Version has just been made public on sourceforge. Please test it.

You can find the announcement for the RC here: http://forum.lazarus.freepascal.org/index.php/topic,17717
And a list of what changed is here: http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes