Browse Source

+ Initial check-in

michael 24 years ago
parent
commit
6db08d5a0c

+ 23 - 0
docs/gtk1ex/ex1.pp

@@ -0,0 +1,23 @@
+program ex1;
+
+{$mode objfpc}
+
+uses
+ glib,gtk;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+var
+  window :  pGtkWidget;
+
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (pGTKOBJECT (window), 'destroy',
+                    GTK_SIGNAL_FUNC (@destroy), NULL);
+  gtk_widget_show (window);
+  gtk_main ();
+end.

+ 28 - 0
docs/gtk1ex/ex2.pp

@@ -0,0 +1,28 @@
+program ex2;
+
+{$mode objfpc}
+
+uses
+ glib,gtk;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+var
+  window : PGtkWidget;
+  button : PGtkWidget;
+   
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  button := gtk_button_new_with_label('Click me');
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),button);
+  gtk_signal_connect (PGTKOBJECT (window), 'destroy',
+                      GTK_SIGNAL_FUNC (@destroy), NULL);
+  gtk_widget_show (button);
+  gtk_widget_show (window);
+  gtk_main ();
+end.

+ 55 - 0
docs/gtk1ex/ex3.pp

@@ -0,0 +1,55 @@
+program ex3;
+
+{$mode objfpc}
+
+uses
+ glib,gtk;
+
+function newbutton(ALabel : PChar) : PGtkWidget;
+
+begin
+  Result:=gtk_button_new_with_label(ALabel);
+  gtk_widget_show(result);
+end;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+var
+  window,
+  totalbox,
+  hbox,vbox : PgtkWidget;
+   
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  // Box to divide window in 2 halves:
+  totalbox := gtk_vbox_new(true,10);
+  gtk_widget_show(totalbox);
+  // A box for each half of the screen:
+  hbox := gtk_hbox_new(false,5);
+  gtk_widget_show(hbox);
+  vbox := gtk_vbox_new(true,5);
+  gtk_widget_show(vbox);
+  // Put boxes in their halves
+  gtk_box_pack_start(GTK_BOX(totalbox),hbox,true,true,0);
+  gtk_box_pack_start(GTK_BOX(totalbox),vbox,true,true,0);
+  // Now fill boxes with buttons.
+  // Horizontal box
+  gtk_box_pack_start(GTK_BOX(hbox),newbutton('Button 1'),false,false,0);
+  gtk_box_pack_start(GTK_BOX(hbox),newbutton('Button 2'),false,false,0);
+  gtk_box_pack_start(GTK_BOX(hbox),newbutton('Button 3'),false,false,0);
+  // Vertical box
+  gtk_box_pack_start(GTK_BOX(vbox),newbutton('Button A'),true,true,0);
+  gtk_box_pack_start(GTK_BOX(vbox),newbutton('Button B'),true,true,0);
+  gtk_box_pack_start(GTK_BOX(vbox),newbutton('Button C'),true,true,0);
+  // Put totalbox in window
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),totalbox);
+  gtk_signal_connect (PGTKOBJECT (window), 'destroy',
+                      GTK_SIGNAL_FUNC (@destroy), NULL);
+  gtk_widget_show (window);
+  gtk_main ();
+end.

+ 46 - 0
docs/gtk1ex/ex4.pp

@@ -0,0 +1,46 @@
+program ex4;
+
+{$mode objfpc}
+
+uses
+ glib,gtk;
+
+function newbutton(ALabel : PChar) : PGtkWidget;
+
+begin
+  Result:=gtk_button_new_with_label(ALabel);
+  gtk_widget_show(result);
+end;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+var
+  window,
+  maintable:  PgtkWidget;
+
+procedure AddToTable(Widget : PGtkWidget; 
+                     Left,Right, Top,Bottom : guint);
+begin
+  gtk_table_attach_defaults (GTK_TABLE(MainTable),Widget,
+                             Left,right,top,bottom);
+end;                     
+   
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  Maintable := gtk_table_new(6,6,True);
+  gtk_widget_show(MainTable);
+  AddToTable(newbutton('1,1 At 1,1'),1,2,1,2);
+  AddToTable(newbutton('2,2 At 3,1'),3,5,1,3);
+  AddToTable(newbutton('4,1 At 4,1'),1,5,4,5);
+  // Put all in window
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),maintable);
+  gtk_signal_connect (PGTKOBJECT (window), 'destroy',
+                      GTK_SIGNAL_FUNC (@destroy), NULL);
+  gtk_widget_show (window);
+  gtk_main ();
+end.

+ 31 - 0
docs/gtk1ex/ex5.pp

@@ -0,0 +1,31 @@
+program ex5;
+
+{$mode objfpc}
+
+uses
+ glib,gtk;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+var
+  window : PGtkWidget;
+  button : PGtkWidget;
+   
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  button := gtk_button_new_with_label('Click me');
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),button);
+  gtk_signal_connect (PGTKOBJECT (window), 'destroy',
+                      GTK_SIGNAL_FUNC (@destroy), NULL);
+  gtk_signal_connect_object(PGTKOBJECT(button),'clicked',
+                      GTK_SIGNAL_FUNC(@gtk_widget_destroy),
+                      PGTKOBJECT(window));
+  gtk_widget_show (button);
+  gtk_widget_show (window);
+  gtk_main ();
+end.

+ 71 - 0
docs/gtk1ex/ex6.pp

@@ -0,0 +1,71 @@
+program ex6;
+
+{$mode objfpc}
+
+uses
+ glib,gtk;
+
+Type 
+  TButtonSignalState = Record 
+    Obj : PgtkObject;
+    SignalID : longint;
+    Disable : Boolean;
+  end;
+  PButtonSignalState = ^TButtonSignalState;
+  
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+
+procedure disablesignal(widget : pGtkWidget ; data: pgpointer ); cdecl;
+
+
+begin
+ With PButtonSignalState(Data)^ do
+   begin
+   If Disable then
+     gtk_signal_handler_block(Obj,SignalID)
+   else
+     gtk_signal_handler_unblock(Obj,SignalID);
+   disable:=Not disable;  
+   end;
+end;
+
+var
+  window : PGtkWidget;
+  quitbutton : PGtkWidget;
+  disablebutton : PGTKWidget;
+  windowbox : PGTKWidget;
+  quitsignal : guint;
+  QuitState : TButtonSignalState;
+   
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  quitbutton := gtk_button_new_with_label('Quit program');
+  disablebutton := gtk_button_new_with_label('Disable button');
+  windowbox:=gtk_vbox_new(TRUE,10);
+  gtk_box_pack_start(GTK_BOX(windowbox),disablebutton,True,false,0);
+  gtk_box_pack_start(GTK_BOX(windowbox),quitbutton,True,false,0);
+  gtk_container_set_border_width(GTK_CONTAINER(Window),10);
+  gtk_container_add(GTK_Container(window),windowbox);
+  gtk_signal_connect (PGTKOBJECT (window), 'destroy',
+                      GTK_SIGNAL_FUNC (@destroy), NULL);
+  With QuitState do
+    begin
+    Obj:=PGTKObject(QuitButton);
+    SignalID:=gtk_signal_connect_object(Obj,'clicked',
+                      GTK_SIGNAL_FUNC(@gtk_widget_destroy),
+                      PGTKOBJECT(window));
+    Disable:=True;
+    end;
+  gtk_signal_connect(PGTKOBJECT(disablebutton),'clicked',
+                      GTK_SIGNAL_FUNC(@disablesignal),@QuitState);
+  gtk_widget_show (quitbutton);
+  gtk_widget_show (disablebutton);
+  gtk_widget_show (windowbox);
+  gtk_widget_show (window);
+  gtk_main ();
+end.

+ 54 - 0
docs/gtk1ex/ex7.pp

@@ -0,0 +1,54 @@
+program ex2;
+
+uses
+ gdk,glib,gtk,strings;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+Const 
+  Inside  : PChar ='Mouse is over label';
+  OutSide : PChar ='Mouse is not over label';
+
+var
+  OverLabel : Boolean;
+  window, box1, box2, stackbox, label1, Label2  : PGtkWidget;
+
+Procedure ChangeLabel(P : PGtkWidget; 
+                      Event : PGdkEventCrossing;
+                      Var Data : Boolean);cdecl;
+
+begin
+ If Not Data then
+    gtk_label_set_text(PGTKLABEL(Label2),Inside)
+  else
+    gtk_label_set_text(PGTKLABEL(Label2),Outside);
+ Data := Not Data;
+end;
+
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  stackbox:=gtk_vbox_new(TRUE,10);
+  box1 := gtk_event_box_new();
+  label1 := gtk_label_new(strnew('Move mouse over label'));
+  gtk_container_add(GTK_CONTAINER(box1),label1);
+  box2 := gtk_event_box_new();
+  label2 := gtk_label_new(strNew(OutSide));
+  gtk_container_add(GTK_CONTAINER(box2),label2);
+  gtk_box_pack_start(GTK_BOX(stackbox),box1,TRUE,TRUE,0);
+  gtk_box_pack_start(GTK_BOX(stackbox),box2,TRUE,TRUE,0);
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),stackbox);
+  gtk_signal_connect(PGTKOBJECT (window), 'destroy',
+                     GTK_SIGNAL_FUNC (@destroy), NULL);
+  overlabel:=False;                   
+  gtk_signal_connect(PGTKOBJECT(box1),'enter_notify_event',
+                     GTK_SIGNAL_FUNC (@ChangeLabel), @Overlabel);
+  gtk_signal_connect(PGTKOBJECT(box1),'leave_notify_event',
+                     GTK_SIGNAL_FUNC (@ChangeLabel), @Overlabel);
+  gtk_widget_show_all (window);
+  gtk_main ();
+end.

+ 40 - 0
docs/gtk1ex/ex8.pp

@@ -0,0 +1,40 @@
+program ex8;
+
+uses
+ glib,gtk;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+var
+  window, stackbox, label1, Label2  : PGtkWidget;
+  labelstyle : pgtkstyle;
+  
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  stackbox:=gtk_vbox_new(TRUE,10);
+  label1 := gtk_label_new('Red label text');
+  labelstyle := gtk_style_copy(gtk_widget_get_style(label1));
+  With LabelStyle^.fg[GTK_STATE_NORMAL] do
+    begin
+    pixel:=0;
+    red:=$ffff;
+    blue:=0;
+    green:=0;
+    end;
+  gtk_widget_set_style(label1,labelstyle);    
+  // Uncomment this to see the effect of setting the default style.
+  // gtk_widget_set_default_style(labelstyle);    
+  label2 := gtk_label_new('Black label text');
+  gtk_box_pack_start(GTK_BOX(stackbox),label1,TRUE,TRUE,0);
+  gtk_box_pack_start(GTK_BOX(stackbox),label2,TRUE,TRUE,0);
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),stackbox);
+  gtk_signal_connect(PGTKOBJECT (window), 'destroy',
+                     GTK_SIGNAL_FUNC (@destroy), NULL);
+  gtk_widget_show_all (window);
+  gtk_main ();
+end.

+ 62 - 0
docs/gtk1ex/ex9.pp

@@ -0,0 +1,62 @@
+program ex9;
+
+uses
+ gdk,glib,gtk,strings;
+
+procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  gtk_main_quit();
+end;
+
+Const 
+  Inside  : PChar ='Mouse is over label';
+  OutSide : PChar ='Mouse is not over label';
+
+var
+  window, button1,Button2, Alabel,stackbox : PGtkWidget;
+  buttonstyle : pgtkstyle;
+  OverButton : boolean;
+  
+Procedure ChangeLabel(P : PGtkWidget; 
+                      Event : PGdkEventCrossing;
+                      Var Data : Boolean);cdecl;
+
+begin
+ If Not Data then
+    gtk_label_set_text(PGTKLABEL(ALabel),Inside)
+  else
+    gtk_label_set_text(PGTKLABEL(ALabel),Outside);
+ Data := Not Data;
+end;
+
+begin
+  gtk_init (@argc, @argv);
+  window := gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  stackbox:=gtk_vbox_new(TRUE,10);
+  button1 := gtk_button_new_with_label(strnew('Move mouse over button'));
+  buttonstyle := gtk_style_copy(gtk_widget_get_style(Button1));
+    With ButtonStyle^.bg[GTK_STATE_PRELIGHT] do
+      begin
+      pixel:=0;
+      red:=$ffff;
+      blue:=0;
+      green:=0;
+      end;
+  gtk_widget_set_style(button1,buttonstyle);    
+  button2 := gtk_button_new;
+  ALabel:=gtk_label_new(Outside);
+  gtk_container_add(GTK_CONTAINER(button2),ALAbel);
+  gtk_box_pack_start(GTK_BOX(stackbox),button1,TRUE,TRUE,0);
+  gtk_box_pack_start(GTK_BOX(stackbox),button2,TRUE,TRUE,0);
+  gtk_container_set_border_width(GTK_CONTAINER(Window),5);
+  gtk_container_add(GTK_Container(window),stackbox);
+  gtk_signal_connect(PGTKOBJECT (window), 'destroy',
+                     GTK_SIGNAL_FUNC (@destroy), NULL);
+  overbutton:=False;                   
+  gtk_signal_connect(PGTKOBJECT(button1),'enter_notify_event',
+                     GTK_SIGNAL_FUNC (@ChangeLabel), @OverButton);
+  gtk_signal_connect(PGTKOBJECT(button1),'leave_notify_event',
+                     GTK_SIGNAL_FUNC (@ChangeLabel), @OverButton);
+  gtk_widget_show_all (window);
+  gtk_main ();
+end.

+ 25 - 0
docs/gtk4ex/delete.xpm

@@ -0,0 +1,25 @@
+/* XPM */
+static char *delete[] = {
+/* width height num_colors chars_per_pixel */
+"    16    16        2            1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+/* pixels */
+"################",
+"################",
+"##...#########.#",
+"##....######..##",
+"###....####..###",
+"#####...##..####",
+"######.....#####",
+"#######...######",
+"######.....#####",
+"#####...##..####",
+"####...####..###",
+"###...######.###",
+"##....#######.##",
+"##...###########",
+"###.##########.#",
+"################"
+};

+ 115 - 0
docs/gtk4ex/dirlist.inc

@@ -0,0 +1,115 @@
+
+Procedure Scandirs(Path: String; Tree : PgtkTree;
+                   Node: PGtkTreeItem ; SubSub : Boolean;
+                   Window : PMainWindow); forward;
+
+
+Function GetPathName(Item : PGtkTreeItem) : String;
+
+Var P : PChar;
+    PTree : PGtkTree;
+begin
+  gtk_label_get(PgtkLabel(PGtkBin(Item)^.Child),@P);
+  Result:=StrPas(P);
+  If (PGtkWidget(item)^.Parent<>Nil) then
+    begin
+    PTree:=PGtkTree(PgtkWidget(Item)^.Parent);
+    If (Ptree^.Level<>0) Then
+      Result:=AddTrailingSeparator(GetPathName(PgtkTreeItem(PTree^.Tree_Owner)))+Result
+    end;  
+end;
+
+Procedure DirSelect(Item : PGtkTreeItem; Window : PMainWindow);cdecl;
+  
+begin
+  ShowDir(Window,GetPathName(Item));
+end;
+
+Procedure DirExpand(Item : PGtkTreeItem; Window : PMainWindow);cdecl;
+ 
+Var 
+  Dir : String;
+  SubTree : PGtkTree;
+  SubNodes : PGList;
+  Node : PGtkTreeItem;
+   
+begin
+  SubTree:=PgtkTree(Item^.SubTree);
+  SubNodes:=gtk_container_children(PGtkContainer(SubTree));
+  While SubNodes<>Nil do
+    begin
+    Node:=PgtkTreeItem(SubNodes^.Data);
+    If (Node^.SubTree<>Nil) then 
+      gtk_tree_item_remove_subtree(Node);
+    Scandirs(GetPathName(Node),Nil,Node,False,Window);
+    SubNodes:=g_list_remove_link(SubNodes,SubNodes);
+    end;
+end;
+
+Procedure Scandirs(Path: String; Tree : PgtkTree;
+                   Node: PGtkTreeItem ; SubSub : Boolean;
+                   Window : PMainWindow);
+
+Var
+  NewTree : PGtkTree;
+  NewNode : PGtkTreeItem;
+  Info : TSearchRec;
+  S,FP : AnsiString;
+
+begin
+  NewTree:=Nil;
+  FP:=AddTrailingSeparator(Path);
+  If FindFirst(FP+'*.*',faAnyfile,Info)=0 then
+    Try 
+      repeat
+        If ((Info.Attr and faDirectory)=faDirectory) then
+          begin
+          S:=Info.Name;
+          If (S<>'.') and (S<>'..') then
+            begin
+            If (Node<>Nil) then
+              begin
+              If (NewTree=Nil) and (node<>Nil) then
+                begin
+                NewTree:=PGtkTree(gtk_tree_new);
+                gtk_tree_item_set_subtree(Node,PGtkWidget(NewTree));
+                end
+              end
+            else
+              NewTree:=Tree;                
+            NewNode:=PGtkTreeItem(gtk_tree_item_new_with_label(Pchar(S)));
+            gtk_tree_append(NewTree,PgtkWidget(NewNode));
+            gtk_signal_connect(PGtkObject(NewNode),'select',
+                               TGtkSignalFunc(@DirSelect),Window);
+            gtk_signal_connect(PGtkObject(NewNode),'expand',
+                               TGtkSignalFunc(@DirExpand),Window);
+            If SubSub then 
+              ScanDirs(FP+S,Tree,NewNode,False,Window);
+            gtk_widget_show(PGtkWidget(NewNode));
+            end;
+          end;  
+      until FindNext(Info)<>0;
+    Finally 
+      FindClose(Info);
+    end;
+  gtk_widget_show(PGtkWidget(Node));
+end;    
+
+Function NewDirtree (MainWindow : PMainWindow) : PGtkTree;
+
+begin
+  Result:=PGtkTree(gtk_tree_new());
+  With MainWindow^ do
+    begin
+    TreeScrollWindow:=PGtkScrolledWindow(gtk_scrolled_window_new(Nil,Nil));
+    gtk_widget_show(PGtkWidget(TreeScrollWindow));  
+    gtk_scrolled_window_set_policy(TreeScrollWindow,
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+    gtk_scrolled_window_add_with_viewport(TreeScrollWindow,PGtkWidget(Result));
+    RootNode:=PGtkTreeItem(gtk_tree_Item_new_with_label(Pchar(PathSeparator)));
+    gtk_tree_append(Result,PgtkWidget(RootNode));
+    scandirs(PathSeparator,Result, RootNode,True,MainWindow);
+    gtk_tree_item_expand(rootnode);
+    end;
+end;

+ 33 - 0
docs/gtk4ex/factions.inc

@@ -0,0 +1,33 @@
+Procedure DoProperties(widget : pGtkWidget ; Window : PMainWindow); cdecl;
+
+Var i : longint;
+    S : string;
+    Dlg : PFilePropertiesDialog;
+    
+begin
+  With Window^ do
+    S:=AddTrailingSeparator(FDir)+GetFileFirstSelection(FileList);
+  Dlg:=NewFilePropertiesDialog(S);
+  ShowFilePropertiesDialog(Dlg);
+end;
+
+Procedure DeleteFile(Widget : PGtkWidget; Window : PMainWindow); cdecl;
+
+Var i : longint;
+    S : TStringList;
+    
+begin
+  S:=TStringList.Create;
+  Try
+    GetFileSelection(Window^.FileList,S);
+    For I:=0 to S.Count-1 do
+      begin
+      For I:=0 to S.Count-1 do
+        SysUtils.DeleteFile(Window^.FDir+S[i]);
+      end;
+  Finally
+    If S.Count>0 then
+      RefreshFileView(Window);
+    S.Free;
+  end;        
+end;

+ 213 - 0
docs/gtk4ex/filelist.inc

@@ -0,0 +1,213 @@
+
+Const
+  DefCompare : TGtkCListCompareFunc = Nil;
+  
+Function FileCompareFunc(List:PGtkCList; Row1,Row2 : PGtkCListRow) : Longint; Cdecl;
+
+Var 
+  SC : Longint;
+
+begin
+  SC:=List^.sort_column;
+  If SC in [2,3] then
+    begin
+    SC:=SC-2;
+    Result:=PLongint(Row1^.Data)[SC]-PLongint(Row2^.Data)[SC];
+    end
+  Else
+    Result:=DefCompare(List,Row1,Row2);  
+end;
+                       
+Procedure DestroySortData(FSD : Pointer);cdecl;
+
+begin
+  FreeMem(FSD);
+end;
+
+Procedure AddFileToList(List : PGtkCList; Info : TSearchRec);
+
+Var
+  Texts : Array[1..6] of AnsiString;
+  FSD   : PLongint;
+  I     : longint;
+      
+begin
+  Texts[1]:=ExtractFileName(Info.Name);
+  Texts[2]:=ExtractFileExt(Info.Name);
+  Texts[3]:=FileSizeToString(Info.Size);
+  Texts[4]:=DateTimeToStr(FileDateToDateTime(Info.Time));
+  Texts[5]:=FileAttrsToString(Info.Attr);
+  Texts[6]:='';
+  i:=gtk_clist_append(List,@Texts[1]);
+  FSD:=GetMem(2*SizeOf(Longint));
+  FSD[0]:=Info.Size;
+  FSD[1]:=Info.Time;
+  gtk_clist_set_row_data_full (List,I,FSD,@DestroySortData);
+end;
+
+Function FillList(List : PGtkCList; Const Dir,Mask : String) : Integer;
+
+Var
+  Info : TSearchRec;
+  Size : Int64;
+  I : longint;
+  
+begin
+  Result:=0;
+  Size:=0;
+  gtk_clist_freeze(List);
+  Try
+    gtk_clist_clear(List);
+    If FindFirst (AddTrailingSeparator(Dir)+Mask,faAnyFile,Info)=0 then
+      Repeat
+        Inc(Size,Info.Size);
+        AddFileToList(List,Info);
+        Inc(Result);
+      Until FindNext(Info)<>0;
+    FindClose(info);
+  finally
+    For I:=0 to 4 do
+      gtk_clist_set_column_width(List,i,gtk_clist_optimal_column_width(List,i));
+    gtk_clist_thaw(List)
+  end;
+end;
+
+Procedure ShowPopup(Widget : PGtkWidget; Event : PGdkEventButton; Window : PMainWindow);cdecl;
+
+begin
+  if (event^.thetype=GDK_BUTTON_PRESS) and (event^.button=3) then
+    begin
+    gtk_menu_popup(Window^.PMFiles,Nil,Nil,Nil,NIl,3,event^.time);
+    end;
+end;
+
+Procedure FileColumnClick(List : PGtkCList;Column:gint; Window : PMainWindow);cdecl;
+
+Var 
+  I  : longint;
+  NS : TGtkSortType;
+   
+begin
+  If Column<>List^.sort_column Then
+    begin
+    gtk_clist_set_sort_type(List,GTK_SORT_ASCENDING);
+    gtk_clist_set_sort_column(list,Column);
+    end
+  else
+    begin
+    If (List^.Sort_type=GTK_SORT_ASCENDING) Then 
+      NS:=GTK_SORT_DESCENDING
+    else
+      NS:=GTK_SORT_ASCENDING;
+    gtk_clist_set_sort_type(List,NS);
+    end;
+  gtk_clist_sort(list);
+end;
+
+Function NewFileList(MainWindow : PMainWindow) : PGtkClist;
+
+Const 
+  Titles : Array[1..6] of pchar = ('Name','ext','Size','Date','Attributes','');
+
+begin
+  MainWindow^.ListScrollWindow:=PGtkScrolledWindow(gtk_scrolled_window_new(Nil,Nil));
+  gtk_scrolled_window_set_policy(MainWindow^.ListScrollWindow,
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  Result:=PGtkClist(Gtk_Clist_New_with_titles(6,@Titles));
+  gtk_signal_connect(PgtkObject(Result),'button_press_event',TGtkSignalFunc(@ShowPopup),MainWindow);
+  gtk_signal_connect(PgtkObject(Result),'click_column',TGtkSignalFunc(@FileColumnClick),MainWindow);
+  gtk_Container_add(PGTKContainer(MainWindow^.ListScrollWindow),PGtkWidget(Result));
+  gtk_clist_set_shadow_type(Result,GTK_SHADOW_ETCHED_OUT);
+  gtk_clist_set_column_justification(result,2,GTK_JUSTIFY_RIGHT);
+  gtk_clist_set_selection_mode(Result,GTK_SELECTION_MULTIPLE);
+  gtk_clist_set_auto_sort(Result,True);
+  If DefCompare=Nil then
+    DefCompare:=Result^.compare;
+  gtk_clist_set_compare_func(Result,TGtkCListCompareFunc(@FileCompareFunc));
+end;
+
+Procedure ToggleFileListTitles(Sender : PGtkCheckMenuItem;Window : PMainWindow);cdecl;
+
+begin
+  If active(Sender^)=0 then
+    gtk_clist_column_titles_show(Window^.FileList)
+  else  
+    gtk_clist_column_titles_hide(Window^.FileList)
+end;
+
+Procedure ToggleFileListColumns(Sender : PGtkCheckMenuItem;Window : PMainWindow);cdecl;
+
+Var Col : Longint;
+
+begin
+  With Window^ do
+    If Sender=MIShowExt Then
+      Col:=1
+    else if Sender=MiShowSize Then
+      Col:=2
+    else if Sender=MIShowDate then
+      Col:=3
+    else 
+      Col:=4;
+   gtk_clist_set_column_visibility(Window^.FileList,Col,(Active(Sender^)=0));   
+end;
+
+Procedure GetFileSelection (List : PGtkClist; Selection : TStrings);
+
+Var
+  SList : PGList;
+  Index : Longint;
+  P : PChar;
+  
+begin
+  Selection.Clear;
+  Slist:=List^.Selection;
+  While SList<>nil do
+    begin
+    Index:=Longint(SList^.Data);
+    gtk_clist_get_text(List,Index,0,@p);
+    Selection.Add(StrPas(p));
+    SList:=g_list_next(SList);
+    end;
+end;
+
+Function GetFileFirstSelection (List : PGtkClist) : String;
+
+Var
+  SList : PGList;
+  Index : Longint;
+  P : PChar;
+  
+begin
+  REsult:='';
+  Slist:=List^.Selection;
+  If SList<>nil then
+    begin
+    Index:=Longint(SList^.Data);
+    gtk_clist_get_text(List,Index,0,@p);
+    Result:=StrPas(p);
+    end;
+end;
+
+Function GetFileSelectionCount (List : PGtkClist) : Longint;
+
+Var
+  SList : PGList;
+  
+begin
+  Slist:=List^.Selection;
+  Result:=0;
+  While SList<>nil do
+    begin
+    Inc(Result);
+    SList:=g_list_next(SList);
+    end;
+end;
+
+Procedure RefreshFileView(Window : PMainWindow);
+
+begin
+  With Window^ do
+    FillList(FileList,FDir,FMask);
+end;

BIN
docs/gtk4ex/filemask.png


BIN
docs/gtk4ex/fileprops.png


+ 66 - 0
docs/gtk4ex/frmabout.pp

@@ -0,0 +1,66 @@
+unit frmabout;
+
+{$mode objfpc}
+
+Interface
+
+uses glib,gdk,gtk;
+
+Type 
+  TAboutForm = Record
+    Window : PGtkDialog;
+    OkButton : PgtkButton;
+    InfoLabel : PGtkLabel;    
+  end;
+  PAboutForm = ^TAboutForm;
+
+Function NewAboutForm : PAboutForm;
+Procedure ShowAboutForm(Form : PAboutForm);
+
+Implementation
+
+Const
+  SInfo : PChar = 'File explorer demo'#10'Florian Klaempfl'#10'Michael Van Canneyt';
+  SAboutTitle : Pchar = 'About File explorer';
+  
+procedure DestroyAbout(Widget : PGtkWidget; About : PAboutForm);cdecl;
+
+begin
+  Dispose(About);
+end;
+
+Function NewAboutForm : PAboutForm;
+
+begin
+  Result:=New(PAboutForm);
+  With Result^ do
+    begin
+    Window:=PgtkDialog(gtk_dialog_new);
+    gtk_window_set_modal(PgtkWindow(Window),True);
+    gtk_window_set_title(PgtkWindow(Window),SAboutTitle);
+    gtk_widget_set_usize(PGtkWidget(Window),250,150);
+    gtk_window_set_policy(PgtkWindow(Window),0,0,0);
+    gtk_window_set_position(PGtkWindow(Window),GTK_WIN_POS_CENTER);
+    OkButton:=PGtkButton(gtk_button_new_with_label(' Ok '));
+    gtk_box_pack_start(PgtkBox(Window^.action_area),PGtkWidget(Okbutton),False,False,5);
+    gtk_window_set_focus(PGtkWindow(Window),PGtkWidget(OkButton));
+    gtk_widget_show(PGtkWidget(OkButton));
+    InfoLabel:=PgtkLabel(gtk_label_new(SInfo));
+    gtk_box_pack_start(PGtkBox(Window^.vbox),PGtkWidget(InfoLabel),True,True,10);
+    gtk_widget_show(PGtkWidget(InfoLabel));
+    gtk_signal_connect(PGtkObject(Window),'destroy',
+                       TGTKSignalFunc(@DestroyAbout),Result);
+    gtk_signal_connect_object(PgtkObject(OKButton),'clicked',
+                      GTK_SIGNAL_FUNC(@gtk_widget_destroy),
+                      PGTKOBJECT(Window));
+    end;
+end;
+
+Procedure ShowAboutForm(Form : PAboutForm);
+
+begin
+  gtk_window_set_modal(PgtkWindow(Form^.Window),True);
+  gtk_widget_show(PgtkWidget(Form^.Window));
+end;
+
+end.

+ 244 - 0
docs/gtk4ex/frmmain.pp

@@ -0,0 +1,244 @@
+unit frmmain;
+
+{$mode objfpc}
+
+Interface
+
+Uses gtk,gdk,glib,sysutils,classes;
+
+Type
+  TMainWindow = Record
+    FDir,
+    FMask : String;
+    Window : PGtkWindow;
+    Menu : PGtkMenuBar;
+    Toolbar : PGtkToolBar;
+    DirTree : PGtkTree;
+    FileList : PGtkClist;
+    Pane : PGtkPaned;
+    StatusBar : PGtkStatusBar;
+    FilesHeader,DirHeader : PGtkLabel;
+    // helper objects - Menu
+    Accel : PGtkAccelGroup;
+    MFile,
+    MView,
+    MColumns,
+    MHelp,
+    // Main menu items
+    PMFiles : PGtkMenu;
+    MIFile,
+    MIFileProperties,
+    MIFileDelete,
+    MIExit,
+    MIColumns,
+    MIMask,
+    MIAbout,
+    MIHelp : PGtkMenuItem;
+    MIShowTitles,
+    MIShowExt,
+    MIShowSize,
+    MiShowDate,
+    MIShowAttrs : PGtkCheckMenuItem;
+    // Files PopupMenu Items:
+    PMIFileProperties,
+    PMIFileDelete : PGtkMenuItem;
+    // Packing boxes
+    VBox,
+    LeftBox,
+    RightBox : PGtkBox;
+    // Scroll boxes
+    TreeScrollWindow,
+    ListScrollWindow : PGtkScrolledWindow;
+    // Tree root node.
+    RootNode : PGtkTreeItem;
+    
+  end;
+  PMainWindow = ^TMainWindow;   
+
+Function NewMainForm : PMainWindow;
+Function NewMainMenu(MainWindow : PMainWindow) : PGtkMenuBar;
+Function NewToolbar(MainWindow : PMainWindow) : PGtkToolbar;
+Function NewDirtree(MainWindow : PMainWindow) : PGtkTree;
+Function NewFileList(MainWindow : PMainWindow) : PGtkClist;
+Procedure ShowDir (Window : PMainWindow; Dir : String);
+Function NewFilePopupMenu (MainWindow : PMainWindow) : PGtkMenu;
+
+Implementation
+
+uses menus,futils,frmabout,fxbitmaps,frmprops,frmmask;
+
+Const
+  SFileExplorer : PChar = 'File explorer';
+  SFilesindir = 'Files in directory %s';
+  SDirTree : Pchar = 'Directory tree';
+
+{$i filelist.inc}
+{$i dirlist.inc}
+{$i factions.inc}
+
+procedure destroy(widget : pGtkWidget ; Window : PMainWindow); cdecl;
+begin
+  gtk_clist_clear(Window^.FileList);
+  dispose(Window);
+  gtk_main_quit();
+end;
+
+procedure DoAbout(widget : pGtkWidget ; data: pgpointer ); cdecl;
+begin
+  ShowAboutForm(NewAboutform);
+end;
+
+Procedure ApplyMask(Mask : String; Data : Pointer);
+
+begin
+  PMainWindow(data)^.FMask:=Mask;
+  RefreshFileView(PMainWindow(Data));
+end; 
+
+procedure DoMask(Widget : PGtkWidget ; MainForm : PMainWindow ); cdecl;
+
+Var
+  S : AnsiString;
+    
+begin
+  With NewMaskForm^ do
+    begin
+    S:=MainForm^.FMask;
+    gtk_entry_set_text(EMask,PChar(S));
+    CallBack:=@ApplyMask;
+    CallBackData:=MainForm;
+    gtk_widget_show_all(PgtkWidget(Window));
+    end;  
+end;
+
+Function NewMainForm : PMainWindow;
+
+begin
+  Result:=New(PMainWindow);
+  With Result^ do
+    begin
+    FMask:='*.*';
+    Window:=PgtkWindow(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+    gtk_window_set_title(Window,SFileExplorer);
+    gtk_widget_set_usize(PgtkWidget(Window),640,480);
+    gtk_signal_connect (PGTKOBJECT (window), 'destroy',
+                    GTK_SIGNAL_FUNC (@destroy), Result);
+    gtk_widget_realize(PgtkWidget(window));
+    Menu:=NewMainMenu(Result);
+    ToolBar:=NewToolbar(Result);
+    Pane:=PgtkPaned(gtk_hpaned_new);
+    StatusBar:=PgtkStatusBar(gtk_statusbar_new);
+    FileList:=NewFileList(Result);
+    DirTree:=NewDirtree(Result);
+    PMFiles:=NewFilePopupMenu(Result);
+    FilesHeader:=PgtkLabel(gtk_label_new(pchar(SFilesInDir)));
+    DirHeader:=PgtkLabel(gtk_label_new(pchar(SDirTree)));
+    LeftBox:=PGtkBox(gtk_vbox_new(false,0));
+    gtk_box_pack_start(Leftbox,PGtkWidget(DirHeader),False,False,0);
+    gtk_box_pack_start(Leftbox,PgtkWidget(TreeScrollWindow),true,True,0);
+    gtk_paned_add1(pane,PGtkWidget(Leftbox));
+    RightBox:=PGtkBox(gtk_vbox_new(false,0));
+    gtk_box_pack_start(Rightbox,PGtkWidget(FilesHeader),False,False,0);
+    gtk_box_pack_start(Rightbox,PGtkWidget(ListScrollWindow),true,True,0);
+    gtk_paned_add2(pane,PGtkWidget(Rightbox));
+    VBox:=PGtkBox(gtk_vbox_new(false,0));
+    gtk_container_add(PGtkContainer(Window),PgtkWidget(VBox));
+    gtk_box_pack_start(vbox,PGtkWidget(Menu),False,False,0);
+    gtk_widget_show_all(PGtkWidget(vbox));
+    gtk_box_pack_start(vbox,PGtkWidget(ToolBar),False,False,0);
+    gtk_box_pack_start(vbox,PGtkWidget(Pane),true,true,0);
+    gtk_box_pack_start(vbox,PGtkWidget(StatusBar),false,false,0);
+    end;
+end;
+
+
+
+Function NewMainMenu(MainWindow : PMainWindow) : PGtkMenuBar;
+
+begin
+  With MainWindow^ do
+    begin
+    Result:=pgtkmenubar(gtk_menu_bar_new);
+    Accel:=gtk_accel_group_new;
+    gtk_window_add_accel_group(Window,accel);
+    MFile:=AddMenuToMenuBar(Result,accel,'_File',Nil,Nil,False,MIFile);
+    MIFileProperties:=AddItemToMenu(MFile,accel,'_Properties','<alt>p',TgtkSignalFunc(@DoProperties),MainWindow);
+    MIFileDelete:=AddItemToMenu(MFile,accel,'_Delete','',TgtkSignalFunc(@DeleteFile),MainWindow);
+    AddSeparatorToMenu(MFile);
+    MIExit:=AddItemToMenu(MFile,accel,'E_xit','<alt>x',TgtkSignalFunc(@destroy),MainWindow);
+    MView:=AddMenuToMenuBar(Result,accel,'_View',Nil,Nil,False,MIFile);
+    MIShowTitles:=AddCheckItemToMenu(MView,accel,'Hide titles','',TgtkSignalFunc(@ToggleFileListTitles),MainWindow);
+    MIColumns:=AddItemToMenu(MView,accel,'Hide columns','',Nil,MainWindow);
+    MIMask:=AddItemToMenu(MView,accel,'File Mask','',TGtkSignalFunc(@DoMask),MainWindow);
+    MColumns:=PgtkMenu(gtk_menu_new);
+    gtk_menu_item_set_submenu(MIColumns, PgtkWidget(MColumns));
+    MIShowExt:=AddCheckItemToMenu(MColumns,accel,'Extension','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow);
+    MIShowSize:=AddCheckItemToMenu(MColumns,accel,'Size','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow);
+    MIShowDate:=AddCheckItemToMenu(MColumns,accel,'Date','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow);
+    MIShowAttrs:=AddCheckItemToMenu(MColumns,accel,'Attributes','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow);
+    MHelp:=AddMenuToMenuBar(Result,accel,'_Help',Nil,Nil,True,MIHelp);
+    MIAbout:=AddItemToMenu(MHelp,accel,'_About','',TgtkSignalFunc(@DoAbout),Nil);
+    gtk_widget_show(PgtkWidget(result));
+    end;
+end;
+
+Function NewToolbar (MainWindow : PMainWindow) : PGtkToolbar;
+
+begin
+  Result:=pGtkToolBar(gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,GTK_TOOLBAR_ICONS));
+  gtk_toolbar_append_item(result,
+                          Nil,
+                          'File Properties',
+                          nil,
+                          CreateWidgetFromXPm(PgtkWidget(MainWindow^.Window),@PropertiesXPM),
+                          TgtkSignalFunc(@DoProperties),
+                          MainWindow);
+  gtk_toolbar_append_item(result,
+                          Nil,
+                          'Delete File',
+                          Nil,
+                          CreateWidgetFromXPm(PgtkWidget(MainWindow^.Window),@DeleteXPM),
+                          TgtkSignalFunc(@DeleteFile),
+                          MainWindow);
+end;
+
+
+
+Procedure ShowDir (Window : PMainWindow; Dir : String);
+
+begin
+  With Window^ do
+    begin
+    FDir:=Dir;
+    FillList(FileList,Dir,FMask);
+    gtk_label_set_text(FilesHeader,pchar(Format(SFilesInDir,[Dir])));
+    end;
+end;
+
+Procedure PMFilesActivate(Widget : PGtkWidget; Window : PMainWindow); cdecl;
+
+Var State : TGtkStateType;
+
+begin
+  if GetFileSelectionCount(Window^.FileList)>1 then
+    State:=GTK_STATE_INSENSITIVE
+  else
+    State:=GTK_STATE_Normal;
+  gtk_widget_set_state(PgtkWidget(Window^.PMIFileProperties),State);
+end;
+
+
+Function NewFilePopupMenu (MainWindow : PMainWindow) : PGtkMenu;
+
+begin
+  result:=PGtkMenu(gtk_menu_new);
+  gtk_signal_connect(PGtkObject(result),'show',
+                     TGtkSignalFunc(@PMFilesActivate),MainWindow);
+  With MainWindow^ do
+    begin
+    PMIFileProperties:=AddItemToMenu(Result,Accel,'_Properties','',TgtkSignalFunc(@DoProperties),MainWindow);
+    PMIFileDelete:=AddItemToMenu(Result,Accel,'_Delete','<ctrl>d',TgtkSignalFunc(@DeleteFile),MainWindow);
+    end; 
+end;
+
+end.

+ 88 - 0
docs/gtk4ex/frmmask.pp

@@ -0,0 +1,88 @@
+unit frmmask;
+
+{$mode objfpc}
+
+Interface
+
+uses glib,gdk,gtk;
+
+Type
+  TMaskCallBack = Procedure (Mask : String; Data : Pointer);
+  TMaskForm = Record
+    Window : PGtkDialog;
+    EMask : PGtkEntry;
+    LEMAsk : PGtkLabel;
+    HBox : PGtkBox;
+    OKButton,
+    CancelButton : PGtkButton;
+    Mask : ShortString;
+    CallBack : TMaskCallBack;
+    CallBackData : Pointer;
+  end;
+  PMaskForm = ^TMaskForm;
+
+Function NewMaskForm : PMaskForm;
+
+Implementation
+
+Const
+  SEnterMask : PChar = 'Enter new file mask';
+  SNewMask : PChar = 'New mask';
+  SOK : PChar = ' OK ';
+  SCancel : PChar = ' Cancel ';
+  
+Procedure ApplyMask(Widget : PGtkWidget; Window : PMaskForm);cdecl;
+
+begin
+  With Window^ do
+    begin
+    Mask:=StrPas(gtk_entry_get_text(EMask));
+    If (CallBack<>Nil) then
+      CallBack(Mask,CallBackData);
+    end;  
+end;
+
+Procedure DestroyMaskForm(Widget : PGtkWidget; Window : PMaskForm);cdecl;
+
+begin
+  Dispose(Window);
+end;
+
+Function NewMaskForm : PMaskForm;
+
+begin
+  Result:=New(PMaskForm);
+  With Result^ do
+    begin
+    Window:=PGtkDialog(gtk_dialog_new);
+    gtk_window_set_title(PgtkWindow(Window),SEnterMask);
+    gtk_widget_set_usize(PGtkWidget(Window),350,150);
+    gtk_window_set_policy(PgtkWindow(Window),0,0,0);
+    gtk_window_set_position(PGtkWindow(Window),GTK_WIN_POS_CENTER);
+    OKButton:=PGtkButton(gtk_button_new_with_label(SOK));
+    CancelButton:=PGtkButton(gtk_button_new_with_label(SCancel));
+    gtk_box_pack_end(PgtkBox(Window^.action_area),PGtkWidget(Okbutton),False,False,5);
+    gtk_box_pack_end(PgtkBox(Window^.action_area),PGtkWidget(Cancelbutton),False,False,5);
+    Emask:=PGtkEntry(gtk_entry_new_with_max_length(255));
+    LEMask:=PGtkLabel(gtk_label_new(SNewMask));
+    HBox:=PGtkBox(gtk_hbox_new(False,8));
+    gtk_box_pack_start(PgtkBox(HBox),PGtkWidget(LEMask),True,False,0);
+    gtk_box_pack_start(PgtkBox(HBox),PGtkWidget(EMask),True,False,0);
+    gtk_box_pack_start(PGtkBox(Window^.vbox),PGtkWidget(HBox),True,True,10);
+    gtk_window_set_modal(PGtkWindow(Window),TRUE);
+    gtk_signal_connect(PgtkObject(OKButton),'clicked',
+                      TGtkSignalFunc(@ApplyMask),Result);
+    gtk_signal_connect_object(PgtkObject(OKButton),'clicked',
+                      GTK_SIGNAL_FUNC(@gtk_widget_destroy),
+                      PGTKOBJECT(Window));
+    gtk_signal_connect_object(PgtkObject(CancelButton),'clicked',
+                      GTK_SIGNAL_FUNC(@gtk_widget_destroy),
+                      PGTKOBJECT(Window));
+    gtk_signal_connect(PgtkObject(Window),'destroy',
+                      TGtkSignalFunc(@DestroyMaskForm),Result);
+    CallBack:=Nil;
+    CallBackdata:=Nil;                  
+    end;
+end;
+
+end.

+ 130 - 0
docs/gtk4ex/frmprops.pp

@@ -0,0 +1,130 @@
+Unit frmprops;
+
+{$mode objfpc}
+
+Interface
+
+uses glib,gdk,gtk,sysutils;
+
+Const
+  NrTableLines = 8;
+  CheckBoxLineStart = 5;
+
+
+Type
+  TFilePropertiesDialog = Record
+    Window : PgtkDialog;
+    Table  : PGtkTable;
+    OkButton : PGtkButton;
+    Labels : Array[0..1,0..NrTableLines] of PGtkLabel;
+    CheckBoxes : Array[CheckBoxLineStart..NrTableLines] of PgtkCheckButton;
+  end;
+  PFilePropertiesDialog = ^TFilePropertiesDialog;
+  
+Function NewFilePropertiesDialog(FileName : String) : PFilePropertiesDialog;
+Procedure ShowFilePropertiesDialog(Dialog : PFilePropertiesDialog);
+
+Implementation
+
+uses Futils;
+
+Const
+  SPropsTitle : PChar = 'File properties';
+  SOk : PChar = ' OK ';  
+  SFile = ' File.';
+  LabelTexts :  Array[0..NrTableLines] of Pchar = (
+               'Name',
+               'Directory',
+               'Type',
+               'Size',
+               'Date',
+               'Attributes',
+               '',
+               '',
+               ''
+               );
+               
+  CheckBoxTexts :  Array[CheckBoxLineStart..NrTableLines] of Pchar = (
+               'Read-only',
+               'Archive',
+               'Hidden',
+               'System'
+               ); 
+
+procedure DestroyPropDialog(Widget : PGtkWidget; Dlg : PFilePropertiesDialog);cdecl;
+
+begin
+  Dispose(Dlg);
+end;
+
+  
+Function NewFilePropertiesDialog(FileName : String) : PFilePropertiesDialog;
+
+Const 
+  CheckAttrs : Array [CheckBoxLineStart..NrTableLines] of Integer 
+             = (faReadOnly,faArchive,faHidden,faSysFile);
+
+Var 
+  Info : TSearchRec;
+  I : Longint;
+  
+begin
+  Result:=New(PFilePropertiesDialog);
+  With Result^ do
+    begin
+    Window:=PgtkDialog(gtk_dialog_new);
+    gtk_window_set_title(PgtkWindow(Window),SPropsTitle);
+    gtk_window_set_modal(PgtkWindow(Window),True);
+    gtk_window_set_policy(PgtkWindow(Window),0,0,0);
+    gtk_window_set_position(PGtkWindow(Window),GTK_WIN_POS_CENTER);
+    OkButton:=PGtkButton(gtk_button_new_with_label(SOK));
+    gtk_box_pack_start(PgtkBox(Window^.action_area),PGtkWidget(Okbutton),False,False,5);
+    gtk_window_set_focus(PGtkWindow(Window),PGtkWidget(OkButton));
+    gtk_widget_show(PGtkWidget(OkButton));
+    Table:=PgtkTable(gtk_table_new(NrTableLines+1,2,TRUE));
+    gtk_box_pack_start(PGtkBox(Window^.vbox),PGtkWidget(Table),True,True,10);
+    For I:=0 to NrTableLines do
+      begin 
+      Labels[0,i]:=PGtkLabel(gtk_label_new(LabelTexts[i]));
+      gtk_label_set_justify(Labels[0,I],GTK_JUSTIFY_RIGHT);
+      gtk_table_attach_defaults(Table,PgtkWidget(Labels[0,I]),0,1,I,I+1); 
+      end;
+    For I:=0 to CheckboxLineStart-1 do
+      begin 
+      Labels[1,i]:=PGtkLabel(gtk_label_new(''));
+      gtk_label_set_justify(Labels[1,I],GTK_JUSTIFY_LEFT);
+      gtk_table_attach_defaults(Table,PgtkWidget(Labels[1,I]),1,2,I,I+1); 
+      end;
+    For I:=CheckboxLineStart to NrTableLines do
+      begin
+      checkBoxes[i]:=PgtkCheckButton(gtk_check_button_new_with_label(CheckBoxTexts[I]));
+      gtk_widget_set_state(PGtKWidget(CheckBoxes[i]),GTK_STATE_INSENSITIVE);
+      gtk_table_attach_defaults(Table,PgtkWidget(CheckBoxes[i]),1,2,I,I+1); 
+      end;  
+    gtk_label_set_text(Labels[1,0],PChar(ExtractFileName(FileName)));
+    gtk_label_set_text(Labels[1,1],PChar(ExtractFilePath(FileName)));
+    gtk_label_set_text(Labels[1,2],PChar(ExtractFileExt(FileName)+SFile));
+    If FindFirst(FileName,faAnyFile,Info)=0 Then
+      begin
+      gtk_label_set_text(Labels[1,3],PChar(FileSizeToString(Info.Size)));
+      gtk_label_set_text(Labels[1,4],PChar(DateTimeToStr(FileDateToDateTime(Info.Time))));
+      For I:=CheckboxLineStart to NrTableLines do
+        If (CheckAttrs[i] and Info.Attr)=CheckAttrs[i] then
+          gtk_toggle_button_set_active(PgtkToggleButton(CheckBoxes[I]),True);
+      FindClose(Info);
+      end;
+    gtk_signal_connect(PGtkObject(Window),'destroy',
+                       TGTKSignalFunc(@DestroyPropDialog),Result);
+    gtk_signal_connect_object(PgtkObject(OKButton),'clicked',
+                      GTK_SIGNAL_FUNC(@gtk_widget_destroy),
+                      PGTKOBJECT(Window));
+    end;    
+end;
+
+Procedure ShowFilePropertiesDialog(Dialog : PFilePropertiesDialog);
+
+begin
+  gtk_widget_show_all(PgtkWidget(Dialog^.Window));
+end;
+
+end.

+ 92 - 0
docs/gtk4ex/futils.pp

@@ -0,0 +1,92 @@
+unit futils;
+
+{$mode objfpc}
+{$h+}
+
+Interface
+
+Const
+{$ifdef win32}
+  PathSeparator='\';
+{$else}
+  PathSeparator='/';
+{$endif}
+
+
+Function StripTrailingSeparator(Const Dir : String) : String;
+Function AddTrailingSeparator(Const Dir : String) : String;
+Function FileSizeToString(Size: Int64) : String;  
+Function FileAttrsToString(FileAttrs : Integer) : String;
+
+Implementation
+
+Uses sysutils;
+
+Function  StripTrailingSeparator(Const Dir : String) : String;
+ 
+Var
+  L : Integer;
+ 
+begin
+  Result:=Dir;
+  L:=Length(result);
+  If (L>1) and (Result[l]=PathSeparator) then
+    SetLength(Result,L-1);
+end;
+ 
+Function  AddTraiLingSeparator(Const Dir : String) : String;
+ 
+Var
+  L : Integer;
+ 
+begin
+  Result:=Dir;
+  L:=Length(Result);
+  If (L>0) and (Result[l]<>PathSeparator) then
+    Result:=Result+PathSeparator;
+end; 
+  
+Function  FileSizeToString(Size: Int64) : String;
+ 
+Const
+  Sizes : Array [0..4] of String =
+     ('Bytes','Kb','Mb','Gb','Tb');
+Var
+    F : Double;
+    I : longint;
+ 
+begin
+  If Size>1024 Then
+    begin
+    F:=Size;
+    I:=0;
+    While (F>1024) and (I<4) do
+      begin
+      F:=F / 1024;
+      Inc(i);
+      end;
+    Result:=Format('%4.2f %s',[F,Sizes[i]]);
+    end
+  else
+    Result:=Format('%d %s',[Size,Sizes[0]]);
+end; 
+
+Function FileAttrsToString(FileAttrs : Integer) : String;
+
+Const
+  Attrs : Array[1..4] of integer = 
+          (faArchive,faReadOnly,faHidden,faSysfile);
+  AttrChars : Array[1..4] of char = 
+          ('A','R','H','S');
+
+Var 
+  i : longint;
+
+begin
+  Result:='';
+  For I:=1 to 4 do
+    If (Attrs[i] and FileAttrs)=Attrs[i] then
+      Result:=Result+AttrChars[i];
+end;
+
+end.

+ 14 - 0
docs/gtk4ex/fx.pp

@@ -0,0 +1,14 @@
+program fx;
+
+uses glib,gdk,gtk,frmmain,sysutils;
+
+Var 
+  MainWindow : PMainWindow;
+
+begin
+  gtk_init(@argc,@argv);
+  MainWindow:=NewMainForm;
+  gtk_widget_show_all(PGtkWidget(MainWindow^.Window));
+  ShowDir(mainwindow,Extractfilepath(Paramstr(0)){'/usr/bin/'});
+  gtk_main;
+end.

+ 78 - 0
docs/gtk4ex/fxbitmaps.pp

@@ -0,0 +1,78 @@
+Unit fxbitmaps;
+
+{$mode objfpc}
+
+Interface
+
+uses glib,gdk,gtk;
+
+Const 
+  DeleteXpmHeight=16;
+  DeleteXpmColors=2;
+  DeleteXpmArraySize=DeleteXpmHeight+DeleteXpmColors+1;
+  DeleteXpm : Array[1..DeleteXpmArraySize] of Pchar = (
+    '16 16 2 1',        { 16x16 bitmap using 2 colors, 1 char per color}
+    '. c #000000',      { First color: Black  }
+    '# c None',         { Second color : Transparent}
+    '################', { The bitmap }
+    '################',
+    '##...#########.#',
+    '##....######..##',
+    '###....####..###',
+    '#####...##..####',
+    '######.....#####',
+    '#######...######',
+    '######.....#####',
+    '#####...##..####',
+    '####...####..###',
+    '###...######.###',
+    '##....#######.##',
+    '##...###########',
+    '###.##########.#',
+    '################'
+    );
+
+  PropertiesXpmHeight = 16;
+  PropertiesXpmColors = 4;
+  PropertiesXpmArraySize = PropertiesXpmHeight+PropertiesXpmColors+1;
+  PropertiesXpm : Array [1..PropertiesXpmArraySize] of PChar = (
+    '16 16 4 1',        { 16x16 bitmap using 2 colors, 1 char per color}
+    '. c #000000',      { First color : Black }
+    '# c #000080',      { Second color : Light Blue }
+    'a c None',         { Third color : Transparent }
+    'b c #f8fcf8',      { Last color : greyish }
+    'aaaaaaaaaaaaaaaa',
+    'aaaaaaa......a##',
+    'aaaaaa.aaaaaa.##',
+    'aaaaa.a.aaaaaa##',
+    '.....a.a.aaaaa##',
+    '.bb.a.a.a.aaa.##',
+    '.b.a.b.a.a...a##',
+    '.b..bbb.a.b.aaaa',
+    '.bbbbbbb.bb.aaaa',
+    '.bbbbbbbbbb.aaaa',
+    '.b..b.....b.aaaa',
+    '.bbbbbbbbbb.aaaa',
+    '.b..b.....b.aaaa',
+    '.bbbbbbbbbb.aaaa',
+    '............aaaa',
+    'aaaaaaaaaaaaaaaa'
+);
+
+function CreateWidgetFromXPM (Window : PGtkWidget; Data : PPChar) : PgtkWidget;
+
+Implementation
+
+function CreateWidgetFromXPM (Window : PGtkWidget; Data : PPChar) : PGtkWidget;
+
+Var
+  mask   : PGdkBitmap;
+  pixmap : PGdkPixMap;
+
+begin
+  pixmap:=gdk_pixmap_create_from_xpm_d(window^.window,@mask,nil,ppgchar(Data));
+  Result:=gtk_pixmap_new(Pixmap,Mask);
+  gtk_widget_show(Result);
+end;
+
+end.

BIN
docs/gtk4ex/mainwin.png


+ 209 - 0
docs/gtk4ex/menus.pp

@@ -0,0 +1,209 @@
+Unit menus;
+
+{$mode objfpc}
+
+Interface
+
+Uses Gtk,Gdk,Glib;
+
+
+Function AddMenuToMenuBar (MenuBar : PGtkMenuBar; 
+                           ShortCuts : PGtkAccelGroup;
+                           Caption : AnsiString;
+                           CallBack : TgtkSignalFunc;
+                           CallBackdata : Pointer;
+                           AlignRight : Boolean;
+                           Var MenuItem : PgtkMenuItem
+                           ) : PGtkMenu; 
+
+Function AddItemToMenu (Menu : PGtkMenu; 
+                        ShortCuts : PGtkAccelGroup;
+                        Caption : AnsiString;
+                        ShortCut : AnsiString;
+                        CallBack : TgtkSignalFunc;
+                        CallBackdata : Pointer
+                       ) : PGtkMenuItem; 
+
+Function AddCheckItemToMenu (Menu : PGtkMenu; 
+                        ShortCuts : PGtkAccelGroup;
+                        Caption : AnsiString;
+                        ShortCut : AnsiString;
+                        CallBack : TgtkSignalFunc;
+                        CallBackdata : Pointer
+                       ) : PGtkCheckMenuItem; 
+
+Function AddImageItemToMenu (Menu : PGtkMenu; 
+                        ShortCuts : PGtkAccelGroup;
+                        Caption : AnsiString;
+                        ShortCut : AnsiString;
+                        Bitmap : AnsiString;
+                        CallBack : TgtkSignalFunc;
+                        CallBackdata : Pointer
+                       ) : PGtkMenuItem; 
+
+Function AddSeparatorToMenu(Menu : PgtkMenu) : PgtkMenuItem;
+
+Implementation
+
+Function AddMenuToMenuBar (MenuBar : PGtkMenuBar; 
+                           ShortCuts : PGtkAccelGroup;
+                           Caption : AnsiString;
+                           CallBack : TgtkSignalFunc;
+                           CallBackdata : Pointer;
+                           AlignRight : Boolean;
+                           Var MenuItem : PgtkMenuItem
+                           ) : PGtkMenu; 
+
+Var
+  Key : guint;
+  TheLabel : PGtkLabel;
+
+begin
+  MenuItem:=pgtkmenuitem(gtk_menu_item_new_with_label(''));
+  If AlignRight Then
+    gtk_menu_item_right_justify(MenuItem);
+  TheLabel:=GTK_LABEL(GTK_BIN(MenuItem)^.child);
+  Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
+  If Key<>0 then
+    gtk_widget_add_accelerator(PGtkWidget(MenuItem),'activate_item',
+                               Shortcuts,Key,
+                               GDK_MOD1_MASK,GTK_ACCEL_LOCKED);         
+  Result:=PGtkMenu(gtk_menu_new);
+  If CallBack<>Nil then
+    gtk_signal_connect(PGtkObject(result),'activate',
+                        CallBack,CallBackdata);
+  gtk_widget_show(PgtkWidget(MenuItem));  
+  gtk_menu_item_set_submenu(MenuItem, PgtkWidget(Result));
+  gtk_menu_bar_append(MenuBar,PgtkWidget(MenuItem));
+end;
+
+Function AddItemToMenu (Menu : PGtkMenu; 
+                        ShortCuts : PGtkAccelGroup;
+                        Caption : AnsiString;
+                        ShortCut : AnsiString;
+                        CallBack : TgtkSignalFunc;
+                        CallBackdata : Pointer
+                       ) : PGtkMenuItem; 
+
+Var
+  Key,Modifiers : guint;
+  LocalAccelGroup : PGtkAccelGroup;                      
+  TheLabel : PGtkLabel;
+  
+begin
+  Result:=pgtkmenuitem(gtk_menu_item_new_with_label(''));
+  TheLabel:=GTK_LABEL(GTK_BIN(Result)^.child);
+  Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
+  If Key<>0 then
+     begin
+{ $ifndef win32}
+     LocalAccelGroup:=gtk_menu_ensure_uline_accel_group(Menu);
+{ $endif}     
+     gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
+                                LocalAccelGroup,Key,
+                                0,TGtkAccelFlags(0));         
+     end;
+  gtk_menu_append(Menu,pgtkWidget(result));
+  If (ShortCut<>'') and (ShortCuts<>Nil) then  
+    begin
+    gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers);
+    gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
+                               ShortCuts,Key,
+                               modifiers, GTK_ACCEL_VISIBLE);
+    end;
+  If CallBack<>Nil then  
+    gtk_signal_connect(PGtkObject(result),'activate',
+                       CallBack,CallBackdata);
+  gtk_widget_show(PgtkWidget(result));  
+end;                       
+
+Function AddCheckItemToMenu (Menu : PGtkMenu; 
+                        ShortCuts : PGtkAccelGroup;
+                        Caption : AnsiString;
+                        ShortCut : AnsiString;
+                        CallBack : TgtkSignalFunc;
+                        CallBackdata : Pointer
+                       ) : PGtkCheckMenuItem; 
+
+Var
+  Key,Modifiers : guint;
+  LocalAccelGroup : PGtkAccelGroup;                      
+  TheLabel : PGtkLabel;
+  
+begin
+  Result:=pgtkcheckmenuitem(gtk_check_menu_item_new_with_label(PChar(Caption)));
+  gtk_check_menu_item_set_show_toggle(Result,True);  
+  gtk_menu_append(Menu,pgtkWidget(result));
+  If (ShortCut<>'') and (ShortCuts<>Nil) then  
+    begin
+    gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers);
+    gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
+                               ShortCuts,Key,
+                               modifiers, GTK_ACCEL_VISIBLE);
+    end;
+  If CallBack<>Nil then  
+    gtk_signal_connect(PGtkObject(result),'toggled',
+                       CallBack,CallBackdata);
+  gtk_widget_show(PgtkWidget(result));  
+end;                       
+
+Function AddImageItemToMenu (Menu : PGtkMenu; 
+                        ShortCuts : PGtkAccelGroup;
+                        Caption : AnsiString;
+                        ShortCut : AnsiString;
+                        Bitmap : AnsiString;
+                        CallBack : TgtkSignalFunc;
+                        CallBackdata : Pointer
+                       ) : PGtkMenuItem; 
+
+Var
+  Key,Modifiers : guint;
+  LocalAccelGroup : PGtkAccelGroup;                      
+  TheLabel : PGtkLabel;
+  Image : PGtkPixmap;
+  hbox : PGtkHBox;
+  pixmap : PGdkPixmap;
+  BitMapdata : PGdkBitmap;
+  
+begin
+  Result:=pgtkmenuitem(gtk_menu_item_new);
+  hbox:=PGtkHBox(gtk_hbox_new(false,0));
+  gtk_container_add(pgtkcontainer(result),pgtkWidget(hbox));
+  pixmap:=gdk_pixmap_create_from_xpm(Nil,@BitmapData,Nil,pchar(BitMap));
+  Image := PgtkPixMap(gtk_pixmap_new(Pixmap,BitmapData));
+  gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(image),false,false,0);                                   
+  TheLabel:=PgtkLabel(gtk_label_new(''));
+  gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(TheLabel),True,True,0);
+  Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
+  If Key<>0 then
+     begin
+{ $ifndef win32}
+     LocalAccelGroup:=gtk_menu_ensure_uline_accel_group(Menu);
+{ $endif}
+     gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
+                                LocalAccelGroup,Key,
+                                0,TGtkAccelFlags(0));         
+     end;
+  gtk_menu_append(Menu,pgtkWidget(result));
+  If (ShortCut<>'') and (ShortCuts<>Nil) then  
+    begin
+    gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers);
+    gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
+                               ShortCuts,Key,
+                               modifiers, GTK_ACCEL_VISIBLE);
+    end;
+  If CallBack<>Nil then  
+    gtk_signal_connect(PGtkObject(result),'activate',
+                       CallBack,CallBackdata);
+  gtk_widget_show_all(PgtkWidget(result));  
+end;                       
+
+Function AddSeparatorToMenu(Menu : PgtkMenu) : PgtkMenuItem;
+
+begin
+  Result:=pgtkmenuitem(gtk_menu_item_new());
+  gtk_menu_append(Menu,pgtkWidget(result));
+  gtk_widget_show(PgtkWidget(result));
+end;
+
+end.

+ 27 - 0
docs/gtk4ex/properties.xpm

@@ -0,0 +1,27 @@
+/* XPM */
+static char *properties[] = {
+/* width height num_colors chars_per_pixel */
+"    16    16        4            1",
+/* colors */
+". c #000000",
+"# c #000080",
+"a c #c0c0c0",
+"b c #f8fcf8",
+/* pixels */
+"aaaaaaaaaaaaaaaa",
+"aaaaaaa......a##",
+"aaaaaa.aaaaaa.##",
+"aaaaa.a.aaaaaa##",
+".....a.a.aaaaa##",
+".bb.a.a.a.aaa.##",
+".b.a.b.a.a...a##",
+".b..bbb.a.b.aaaa",
+".bbbbbbb.bb.aaaa",
+".bbbbbbbbbb.aaaa",
+".b..b.....b.aaaa",
+".bbbbbbbbbb.aaaa",
+".b..b.....b.aaaa",
+".bbbbbbbbbb.aaaa",
+"............aaaa",
+"aaaaaaaaaaaaaaaa"
+};