program gtktext;

{$mode objfpc}{$H+}

uses
  //{$IFDEF UNIX}{$IFDEF UseCThreads}
  //cthreads,
  //{$ENDIF}{$ENDIF}
  Classes, Sysutils,
  //{$IFDEF GTK} gtk2, gdk2, glib2, pango
  //{$ELSE}gtk, gdk, glib{$ENDIF}
  gtk2, gdk2, glib2, pango
  ;

  
type

  { TGtkForm }

  TGtkForm = class
  private
    FWindow: PGtkWidget;
    FPango: Boolean;
    
    FPangoLayout: PPangoLayout;
    FPangoContext: PPangoContext;
    FPerformance: PGtkWidget;
    
    FDrawArea: PGtkWidget;
    FFont: PGdkFont;
    FFontBold: PGdkFont;
    
    FColorsLoaded: Boolean;
    
    FSymbolGC,
    FStringGC,
    FNumberGC,
    FBackGroundGC,
    FTextGC: PGdkGC;
    FGutterGC: PGdkGC;
    FCraziness: Boolean;
    
    
    procedure LoadColors(Widget:PgtkWidget);
    
    function HandlePaint(Event: PGdkEventExpose; Widget: PGtkWidget): gboolean; cdecl;
    
    procedure PangoPaintClick(Widget: PGtkWidget); cdecl;
    procedure GDKPaintClick(Widget: PGtkWidget); cdecl;
    procedure QuitClick(Widget: PGtkWidget); cdecl;
    procedure WindowDestroy(Widget: PGtkWidget); cdecl;
    
    procedure ConnectSignal(Widget: PGtkWidget; Signal: String; Proc: TMethod);
  public
    constructor Create;
    destructor Destroy; override;
    
    procedure PaintPango(Window: PGdkDrawable);
    procedure PaintGdk(Window: PGdkDrawable);
    
    procedure TestPerformance;
  end;
  
const

  TEXT_LEFT = 35;

{ TGtkForm }

procedure TGtkForm.LoadColors(Widget:PgtkWidget);
var
  Color: TGdkColor;
  
  procedure SetColor(r,g,b: guint16);
  begin
    FillChar(Color, SizeOf(Color), 0);
    Color.red:=r;
    Color.green:=g;
    Color.blue:=b;
  end;
  
var
  cmap: PGdkColormap;
  Window: PGdkDrawable;
begin
  if FColorsLoaded then
    Exit;
  FColorsLoaded:= True;
  
  Window := Widget^.window;

  cmap := gtk_widget_get_colormap(Widget);
  
  FStringGC:= gdk_gc_new(Window);
  FSymbolGC:= gdk_gc_new(Window);
  FNumberGC:= gdk_gc_new(Window);
  FBackGroundGC := gdk_gc_new(Window);
  FTextGC := gdk_gc_new(Window);
  FGutterGC := gdk_gc_new(Window);
  
  
  SetColor($FFFF, 0,0);
  gdk_color_alloc(cmap, @Color);
  gdk_gc_set_foreground(FSymbolGC, @Color);
  
  SetColor(0, 0, $FFFF);
  gdk_color_alloc(cmap, @Color);
  gdk_gc_set_foreground(FStringGC, @Color);
  

  SetColor($FF00, $B8FF, $A000);
  gdk_color_alloc(cmap, @Color);
  gdk_gc_set_foreground(FNumberGC, @Color);
  
  SetColor(0,0,0);
  gdk_color_alloc(cmap, @Color);
  gdk_gc_set_foreground(FTextGC, @Color);
  
  SetColor($FFFF,$FFFF,$FFFF);
  gdk_color_alloc(cmap, @Color);
  gdk_gc_set_foreground(FBackGroundGC, @Color);
  
  SetColor($C000,$C000,$C000);
  gdk_color_alloc(cmap, @Color);
  gdk_gc_set_foreground(FGutterGC, @Color);
end;

function TGtkForm.HandlePaint(Event: PGdkEventExpose; Widget: PGtkWidget): gboolean;
  cdecl;
var
  Window: PGdkWindow;
  Alloc: TGtkAllocation;
begin
  Result := True;
  
  Window := widget^.window;
  
  LoadColors(Widget);
  Alloc  := widget^.allocation;
  
  // clear background
  gdk_draw_rectangle(Window, FBackGroundGC, 1, 31, 0, Alloc.width, Alloc.height);
  
  // draw gutter
  gdk_draw_rectangle(Window, FGutterGC, 1, 0, 0, 29, Alloc.height);
  gdk_draw_line(Window, FTextGC, 30,0,30,Alloc.height);
  
  if not FPango then
    PaintGdk(Window)
  else
    PaintPango(Window);
end;

procedure TGtkForm.PangoPaintClick(Widget: PGtkWidget); cdecl;
begin
  FPango := True;
  TestPerformance;

end;

procedure TGtkForm.GDKPaintClick(Widget: PGtkWidget); cdecl;
begin
  FPango := False;
  TestPerformance;
end;

procedure TGtkForm.QuitClick(Widget: PGtkWidget); cdecl;
begin
  gtk_main_quit;
end;

procedure TGtkForm.WindowDestroy(Widget: PGtkWidget); cdecl;
begin
  QuitClick(Widget);
end;

procedure TGtkForm.ConnectSignal(Widget: PGtkWidget; Signal: String;
  Proc: TMethod);
type
  PMethod = ^TMethod;
begin
  g_signal_connect_swapped(Widget, PChar(Signal), TGCallback(Proc.Code), Self);
end;

constructor TGtkForm.Create;
var
  VBox,
  HBox,
  Button1,
  Button2,
  Button3: PGtkWidget;
begin
  FWindow := gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(FWindow), 'GDK vs Pango Speed Test');
  
  VBox := gtk_vbox_new(False, 2);
  HBox := gtk_hbox_new(False, 2);
  
  FPerformance := gtk_check_button_new_with_label('Performance test');
  Button1 := gtk_button_new_with_label('GDK Paint');
  Button2 := gtk_button_new_with_label('Pango Paint');
  Button3 := gtk_button_new_with_label('Quit');
  
  
  FDrawArea := gtk_drawing_area_new;
  
  FPangoContext:= gtk_widget_get_pango_context(FDrawArea);
  
  //FFont:= gdk_font_load('-adobe-courier-medium-r-normal--*-140-*-*-*-*-*-*');
  //FFontBold:= gdk_font_load('-adobe-courier-bold-r-normal--*-140-*-*-*-*-*-*');
  FFont:= gdk_font_load('-*-courier-medium-r-normal-*-14-*-*-*-m-*-iso8859-1');
  FFontBold:= gdk_font_load('-*-courier-bold-r-normal-*-14-*-*-*-m-*-iso8859-1');

  
  gtk_widget_set_double_buffered(FDrawArea, False);
  
  gtk_drawing_area_size(PGtkDrawingArea(FDrawArea), 870,400);
  
  gtk_container_add(GTK_CONTAINER(FWindow), VBox);
  gtk_container_add(GTK_CONTAINER(VBox), FDrawArea);
  gtk_container_add(GTK_CONTAINER(VBox), HBox);
  
  gtk_container_add(GTK_CONTAINER(HBox), Button1);
  gtk_container_add(GTK_CONTAINER(HBox), Button2);
  gtk_container_add(GTK_CONTAINER(HBox), FPerformance);
  gtk_container_add(GTK_CONTAINER(HBox), Button3);
  
  ConnectSignal(Button1, 'clicked', TMethod(@GDKPaintClick));
  ConnectSignal(Button2, 'clicked', TMethod(@PangoPaintClick));
  ConnectSignal(Button3, 'clicked', TMethod(@QuitClick));
  
  ConnectSignal(FWindow, 'hide', TMethod(@WindowDestroy));
  
  ConnectSignal(FDrawArea, 'expose-event', TMethod(@HandlePaint));
  
  gtk_widget_show_all(FWindow);
  
end;

destructor TGtkForm.Destroy;
begin
  inherited Destroy;
end;

procedure TGtkForm.PaintPango(Window: PGdkDrawable);
  procedure EnsurePango;
  var
    Font: PPangoFontDescription;
  begin
    if FPangoLayout <> nil then Exit;
    FPangoLayout:= pango_layout_new( FPangoContext);
    //Font := pango_font_description_from_string('-*-courier-medium-r-normal-*-14-*-*-*-m-*-iso8859-1');
    Font := pango_font_description_from_string('Courier New 11');
    pango_layout_set_font_description(FPangoLayout, Font);
  end;
var
  OutText: String;
  procedure PaintLine(MarkedText: String);
  begin
    OutText := OutText + MarkedText+ LineEnding;
  end;
  function Symbol(ASymbol: String): String;
  begin
    Result := '<span foreground="red">'+ ASymbol+ '</span>';
  end;
  function Param(Text: String): String;
  begin
    Result := Symbol('(') + Text+ Symbol(')')
  end;
  function String_(Text: String): String;
  begin
    Result := '<span foreground="blue">'''+ Text+ '''</span>';
  end;
  function Comment(Text: String): String;
  begin
    Result := '<span foreground="blue" weight="bold">'+ Text+ '</span>';
  end;
  function KeyWord(Text: String): String;
  begin
    Result := '<span weight="bold">'+ Text+ '</span>';
  end;
begin
  EnsurePango;

  if pango_layout_get_text(FPangoLayout) = '' then
  begin
    PaintLine ('gtk_container_add'+Param('GTK_CONTAINER'+Param('FWindow')+ Symbol(',') +' VBox' )+Symbol(';'));
    PaintLine ('gtk_container_add'+Param('GTK_CONTAINER'+Param('VBox')+ Symbol(',') +' FDrawArea' )+Symbol(';'));
    PaintLine ('gtk_container_add'+Param('GTK_CONTAINER'+Param('VBox')+ Symbol(',') +' HBox' )+Symbol(';'));
    PaintLine ('');
    PaintLine ('gtk_container_add'+Param('GTK_CONTAINER'+Param('HBox')+ Symbol(',') +' Button1' )+Symbol(';'));
    PaintLine ('gtk_container_add'+Param('GTK_CONTAINER'+Param('HBox')+ Symbol(',') +' Button2' )+Symbol(';'));
    PaintLine ('gtk_container_add'+Param('GTK_CONTAINER'+Param('HBox')+ Symbol(',') +' Button3' )+Symbol(';'));
    PaintLine ('');
    PaintLine ('ConnectSignal' + Param('Button1' + Symbol(', ') + String_('clicked') + Symbol(',') + ' TMethod' + Param(Symbol('@')+'GDKPaintClick'))+Symbol(';'));
    PaintLine ('ConnectSignal' + Param('Button2' + Symbol(', ') + String_('clicked') + Symbol(',') + ' TMethod' + Param(Symbol('@')+'PangoPaintClick'))+Symbol(';'));
    PaintLine ('ConnectSignal' + Param('Button3' + Symbol(', ') + String_('clicked') + Symbol(',') + ' TMethod' + Param(Symbol('@')+'QuitClick'))+Symbol(';'));
    PaintLine ('');
    PaintLine ('ConnectSignal' + Param('FDrawArea' + Symbol(', ') + String_('expose-event') + Symbol(',') + ' TMethod' + Param(Symbol('@')+'HandlePaint'))+Symbol(';'));
    PaintLine ('gtk_widget_show_all'+Param('FWindow')+Symbol(';'));
    PaintLine (Comment('// This is a comment'));
    PaintLine ('');
    PaintLine ('Inc'+Param('SomeVar'+Symbol(', ')+'22')+Symbol(';'));
    PaintLine ('');
    PaintLine (KeyWord('function ')+'TGtkForm'+Symbol('.')+'HandlePaint'+
               Param('Event'+Symbol(': ')+ 'PGdkEventExpose'+Symbol('; ') + 'Widget'+Symbol(': ')+'PGtkWidget'
               ) + Symbol(':')+ ' gboolean'+ Symbol(';')+ Keyword(' cdecl')+Symbol(';'));
    PaintLine (KeyWord('begin'));
    PaintLine (Comment('  // This is a comment'));
    PaintLine (KeyWord('end')+Symbol(';'));

    pango_layout_set_markup(FPangoLayout, PChar(OutText), Length(OutText));
  end;
  gdk_draw_layout(Window, FTextGC, TEXT_LEFT, 8, FPangoLayout);

end;

function Max(A, b: Integer): Integer;
begin
  if A > B then Result := A
  else Result := B;
end;

procedure TGtkForm.PaintGdk(Window: PGdkDrawable);
var
  XPos,
  YPos: Integer;
  LineHeight: Integer = 0;
    function PaintText(Text: String; AGC: PGdkGC; X, Y: Integer; Bold: Boolean = false): Integer;
    var
      Font: PGdkFont;
    begin
      if Bold then
        Font := FFontBold
      else
        Font := FFont;
      LineHeight := Max(LineHeight, gdk_text_height(Font, PChar(Text), Length(Text)));
      Result := gdk_text_width(Font, PChar(Text), Length(Text));
      gdk_draw_string(Window, Font, AGC, X, Y, PChar(Text));
    
    end;
    Procedure NewLine;
    begin
      Inc(YPos, LineHeight);
      XPos := TEXT_LEFT;
    end;
begin
  XPos := TEXT_LEFT;
  YPos := 20;
  Inc(XPos, PaintText('gtk_container_add', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GTK_CONTAINER', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('FWindow', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('), ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('VBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));
  
  NewLine;

  Inc(XPos, PaintText('gtk_container_add', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GTK_CONTAINER', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('VBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('), ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('FDrawArea', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));
  
  NewLine;

  Inc(XPos, PaintText('gtk_container_add', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GTK_CONTAINER', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('VBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('), ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('HBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));
  
  NewLine;
  NewLine;
  
  Inc(XPos, PaintText('gtk_container_add', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GTK_CONTAINER', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('HBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('), ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Button1', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));

  NewLine;
  
  Inc(XPos, PaintText('gtk_container_add', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GTK_CONTAINER', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('HBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('), ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Button2', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));

  NewLine;
  Inc(XPos, PaintText('gtk_container_add', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GTK_CONTAINER', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('HBox', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('), ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Button3', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));

  NewLine;
  NewLine;
  
  Inc(XPos, PaintText('ConnectSignal', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Button1', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('''clicked''', FStringGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('TMethod', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(@', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('GDKPaintClick', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('));', FSymbolGC, XPos, YPos));
  NewLine;

  Inc(XPos, PaintText('ConnectSignal', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Button1', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('''clicked''', FStringGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('TMethod', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(@', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('PangoPaintClick', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('));', FSymbolGC, XPos, YPos));
  NewLine;

  Inc(XPos, PaintText('ConnectSignal', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Button1', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('''clicked''', FStringGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('TMethod', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(@', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('QuitClick', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('));', FSymbolGC, XPos, YPos));
  
  NewLine;
  NewLine;

  Inc(XPos, PaintText('ConnectSignal', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos, True));
  Inc(XPos, PaintText('FDrawArea', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('''expose-event''', FStringGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('TMethod', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(@', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('HandlePaint', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(')', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText(')', FSymbolGC, XPos, YPos, True));
  Inc(XPos, PaintText(';', FSymbolGC, XPos, YPos));

  NewLine;
  Inc(XPos, PaintText('gtk_widget_show_all', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('FWindow', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));
  
  NewLine;
  Inc(XPos, PaintText('// This is a comment', FStringGC, XPos, YPos, True));
  
  NewLine;
  Inc(XPos, PaintText('Inc', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('SomeVar', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(', ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('22', FNumberGC, XPos, YPos));
  Inc(XPos, PaintText(');', FSymbolGC, XPos, YPos));
  
  NewLine;
  NewLine;
  
  Inc(XPos, PaintText('function ', FTextGC, XPos, YPos, True));
  Inc(XPos, PaintText('TGtkForm', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('.', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('HandlePaint', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('(', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Event', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(': ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('PGdkEventExpose', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('; ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('Widget', FTextGC, XPos, YPos));
  Inc(XPos, PaintText(': ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('PGtkWidget', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('): ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('gboolean', FTextGC, XPos, YPos));
  Inc(XPos, PaintText('; ', FSymbolGC, XPos, YPos));
  Inc(XPos, PaintText('cdecl', FTextGC, XPos, YPos, True));
  Inc(XPos, PaintText('; ', FSymbolGC, XPos, YPos));

  NewLine;
  
  Inc(XPos, PaintText('begin', FTextGC, XPos, YPos, True));
  NewLine;
  Inc(XPos, PaintText('  // This is a comment', FStringGC, XPos, YPos, True));
  NewLine;
  Inc(XPos, PaintText('end', FTextGC, XPos, YPos, True));
  Inc(XPos, PaintText('; ', FSymbolGC, XPos, YPos));
end;

function GetTickCount: DWord;
begin
  Result := DWord(Trunc(Now * 24 * 60 * 60 * 1000));
end;


procedure TGtkForm.TestPerformance;
var
  i,j:integer;
  tick:Cardinal;
  loops: Integer;
  times: Integer;
begin
  if gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(FPerformance)) = False then
  begin
    gdk_window_invalidate_rect(FDrawArea^.window, nil, False);
    exit;
  end;
  loops:=0;
  times:=0;
  for i:=0 to 10 do
  begin
    inc(loops);
    tick:=GetTickCount;
    for j:=0 to 5000 do
    begin
      gdk_window_invalidate_rect(FDrawArea^.window, nil, False);
      //gtk_widget_queue_draw(FDrawArea);
      gdk_window_process_updates(FDrawArea^.window, False);
    end;
    inc(times,(GetTickCount-tick));
  end;
  gtk_window_set_title(GTK_WINDOW(FWindow), PChar('Avg time for 5000 paint cycles: ms: '+ IntToStr(times div loops)));
end;

procedure Run;
var
  Form: TGtkForm;
begin
  Form := TGtkForm.Create;
  gtk_main;
  Form.Free;
end;

begin
  gtk_init(nil, nil);

  Run;
end.

