Index: dialogs.pp
===================================================================
--- dialogs.pp	(revision 10980)
+++ dialogs.pp	(working copy)
@@ -100,6 +100,7 @@
   
   TFileDialog = class(TCommonDialog)
   private
+    FInternalFilterIndex: Integer;
     FDefaultExt: string;
     FFileName : String;
     FFiles: TStrings;
@@ -109,15 +110,20 @@
     FInitialDir: string;
     FOldWorkingDir: string;
     FOnHelpClicked: TNotifyEvent;
+    FOnTypeChange: TNotifyEvent;
     procedure SetDefaultExt(const AValue: string);
+    procedure SetFilterIndex(const AValue: Integer);
   protected
     function DoExecute: boolean; override;
+    function GetFilterIndex: Integer; virtual;
     procedure SetFileName(const Value: String); virtual;
     procedure SetFilter(const Value: String); virtual;
     procedure SetHistoryList(const AValue: TStrings); virtual;
+    procedure UpdateFilterIndex(NewFilterIndex: Integer);
   public
     constructor Create(TheOwner: TComponent); override;
     destructor Destroy; override;
+    procedure DoTypeChange; virtual;
     function Execute: boolean; override;
     property Files: TStrings read FFiles;
     property HistoryList: TStrings read FHistoryList write SetHistoryList;
@@ -126,9 +132,10 @@
     property DefaultExt: string read FDefaultExt write SetDefaultExt;
     property FileName: String read FFileName write SetFileName;
     property Filter: String read FFilter write SetFilter;
-    property FilterIndex: Integer read FFilterIndex write FFilterIndex default 1;
+    property FilterIndex: Integer read GetFilterIndex write SetFilterIndex default 1;
     property InitialDir: string read FInitialDir write FInitialDir;
     property OnHelpClicked: TNotifyEvent read FOnHelpClicked write FOnHelpClicked;
+    property OnTypeChange: TNotifyEvent read FOnTypeChange write FOnTypeChange;
   end;
 
 
Index: include/filedialog.inc
===================================================================
--- include/filedialog.inc	(revision 10980)
+++ include/filedialog.inc	(working copy)
@@ -39,7 +39,17 @@
   inherited Destroy;
 end;
 
+
 {------------------------------------------------------------------------------}
+{  TFileDialog DoOnTypeChange                                                         }
+{------------------------------------------------------------------------------}
+procedure TFileDialog.DoTypeChange;
+begin
+  if Assigned(FOnTypeChange) then
+    OnTypeChange(Self);
+end;
+
+{------------------------------------------------------------------------------}
 {  TFileDialog Execute                                                         }
 {------------------------------------------------------------------------------}
 function TFileDialog.Execute : boolean;
@@ -61,6 +71,15 @@
   FHistoryList.Assign(AValue);
 end;
 
+procedure TFileDialog.UpdateFilterIndex(NewFilterIndex: Integer);
+begin
+  if FilterIndex <> NewFilterIndex then
+  begin
+    FInternalFilterIndex := NewFilterIndex;
+    DoTypeChange;
+  end;
+end;
+
 {------------------------------------------------------------------------------
   procedure TFileDialog.SetDefaultExt(const AValue: string);
 ------------------------------------------------------------------------------}
@@ -71,6 +90,13 @@
     FDefaultExt:='.'+FDefaultExt;
 end;
 
+procedure TFileDialog.SetFilterIndex(const AValue: Integer);
+begin
+  FFilterIndex := AValue;
+  if FHandle = 0 then
+    FInternalFilterIndex := AValue;
+end;
+
 {------------------------------------------------------------------------------}
 {  TFileDialog DoExecute                                                         }
 {------------------------------------------------------------------------------}
@@ -79,6 +105,14 @@
   Result:= inherited DoExecute;
 end;
 
+{------------------------------------------------------------------------------
+  TFileDialog GetFilterIndex
+------------------------------------------------------------------------------}
+function TFileDialog.GetFilterIndex: Integer;
+begin
+  Result := FInternalFilterIndex;
+end;
+
 {------------------------------------------------------------------------------}
 {  TFileDialog SetFilter                                                       }
 {------------------------------------------------------------------------------}
Index: interfaces/gtk2/gtk2int.pas
===================================================================
--- interfaces/gtk2/gtk2int.pas	(revision 10980)
+++ interfaces/gtk2/gtk2int.pas	(working copy)
@@ -159,6 +159,9 @@
 ////////////////////////////////////////////////////
   gtkProc;
 
+type
+  TFileDialogAccess = class(TFileDialog)
+  end;
 {$include gtk2object.inc}
 {$include gtk2winapi.inc}
 {$include gtk2lclintf.inc}
Index: interfaces/gtk2/gtk2object.inc
===================================================================
--- interfaces/gtk2/gtk2object.inc	(revision 10980)
+++ interfaces/gtk2/gtk2object.inc	(working copy)
@@ -1,4 +1,4 @@
-{%MainUnit gtk2int.pp}
+{%MainUnit gtk2int.pas}
 {******************************************************************************
                                    TGtk2WidgetSet
  ******************************************************************************
@@ -127,6 +127,24 @@
     Result := False;
 end;
 
+procedure Gtk2FileChooserNotifyCB(dialog: PGObject; pspec: PGParamSpec; user_data: gpointer); cdecl;
+var
+  TheDialog: TFileDialog;
+  GtkFilter: PGtkFileFilter;
+  GtkFilterList: PGSList;
+  NewFilterIndex: Integer;
+begin
+  if pspec^.name = 'filter' then
+  begin // filter changed
+    theDialog := TFileDialog(user_data);
+    GtkFilter := gtk_file_chooser_get_filter(dialog);
+    GtkFilterList := gtk_file_chooser_list_filters(dialog);
+    NewFilterIndex := g_slist_index(GtkFilterList, GtkFilter);
+    TFileDialogAccess(theDialog).UpdateFilterIndex(NewFilterIndex);
+    g_slist_free(GtkFilterList);
+  end;
+end;
+
 procedure Gtk2FileChooserResponseCB(widget: PGtkFileChooser; arg1: gint; data: gpointer); cdecl;
 
   procedure AddFile(List: TStrings; const NewFile: string);
@@ -822,6 +840,7 @@
     PChar(GTK_STOCK_CANCEL), [GTK_RESPONSE_CANCEL, PChar(Button1), GTK_RESPONSE_OK, nil]);
 
   g_signal_connect(SelWidget, 'response', gtk_signal_func(@Gtk2FileChooserResponseCB), FileDialog);
+  g_signal_connect(SelWidget, 'notify', gtk_signal_func(@Gtk2FileChooserNotifyCB), FileDialog);
 
 (*gtk 2.8 
   if FileDialog is TSaveDialog then begin
Index: interfaces/gtk/gtkcallback.inc
===================================================================
--- interfaces/gtk/gtkcallback.inc	(revision 10980)
+++ interfaces/gtk/gtkcallback.inc	(working copy)
@@ -2128,15 +2128,17 @@
   theDialog: TCommonDialog;
 
   procedure CheckFilterActivated(FilterWidget: PGtkWidget);
-  var AFilterEntry: PFileSelFilterEntry;
+  var
+    AFilterEntry: PFileSelFilterEntry;
   begin
     if FilterWidget=nil then exit;
     AFilterEntry:=gtk_object_get_data(PGtkObject(FilterWidget),
                                       'LCLIsFilterMenuItem');
-    if (AFilterEntry<>nil) and (AFilterEntry^.Mask<>nil) then begin
+    if (AFilterEntry<>nil) and (AFilterEntry^.Mask<>nil) then
+    begin
       PopulateFileAndDirectoryLists(PGtkFileSelection(theDialog.Handle),
         AFilterEntry^.Mask);
-      TOpenDialog(TheDialog).FilterIndex := AFilterEntry^.FilterIndex + 1;
+      TFileDialogAccess(TheDialog).UpdateFilterIndex(AFilterEntry^.FilterIndex);
       UpdateDetailView(TOpenDialog(theDialog));
     end;
   end;
Index: interfaces/gtk/gtkproc.pp
===================================================================
--- interfaces/gtk/gtkproc.pp	(revision 10980)
+++ interfaces/gtk/gtkproc.pp	(working copy)
@@ -75,6 +75,9 @@
     PrevHandler: PWaitHandleEventHandler;
     NextHandler: PWaitHandleEventHandler;
   end;
+  
+  TFileDialogAccess = class(TFileDialog)
+  end;
 
 {$ifdef UNIX}
   PPChildSignalEventHandler = ^PChildSignalEventHandler;
Index: interfaces/win32/win32wsdialogs.pp
===================================================================
--- interfaces/win32/win32wsdialogs.pp	(revision 10980)
+++ interfaces/win32/win32wsdialogs.pp	(working copy)
@@ -64,6 +64,8 @@
   protected
   public
     class function  CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
+    class procedure DestroyHandle(const ACommonDialog: TCommonDialog); override;
+    class procedure ShowModal(const ACommonDialog: TCommonDialog); override;
   end;
 
   { TWin32WSSaveDialog }
@@ -73,6 +75,8 @@
   protected
   public
     class function  CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
+    class procedure DestroyHandle(const ACommonDialog: TCommonDialog); override;
+    class procedure ShowModal(const ACommonDialog: TCommonDialog); override;
   end;
 
   { TWin32WSSelectDirectoryDialog }
@@ -113,6 +117,16 @@
 
 implementation
 
+type
+  TOpenFileDialogRec = packed record
+    Dialog: TFileDialog;
+    FileNames: String;
+  end;
+  POpenFileDialogRec = ^TOpenFileDialogRec;
+  
+  TFileDialogAccess = class(TFileDialog)
+  end;
+
 // The size of the OPENFILENAME record depends on the windows version
 // In the initialization section the correct size is determined.
 var
@@ -234,46 +248,57 @@
   OpenFileNotify: LPOFNOTIFY;
   OpenFileName: Windows.POPENFILENAME;
   NeededSize: SizeInt;
-  FileNames: pstring;
+  DialogRec: POpenFileDialogRec;
 begin
-  if uMsg = WM_NOTIFY then begin
+  if uMsg = WM_NOTIFY then
+  begin
     OpenFileNotify := LPOFNOTIFY(lParam);
-    if OpenFileNotify^.hdr.code=CDN_SELCHANGE then begin
+    if OpenFileNotify <> nil then
+    begin
       OpenFileName := OpenFileNotify^.lpOFN;
-      // NeededSize is the size that the lpStrFile buffer must have.
-      // the lpstrFile buffer contains the directory and a list of files
-      // for example 'c:\winnt'#0'file1.txt'#0'file2.txt'#0#0.
-      // GetFolderPath returns upper limit for the path, GetSpec for the files.
-      // This is not exact because the GetSpec returns the size for
-      // '"file1.txt" "file2.txt"', so that size will be two bytes per filename
-      // more than needed in thlengthe lpStrFile buffer.
-      NeededSize := CommDlg_OpenSave_GetFolderPath(GetParent(hwnd), nil, 0) +
-                      CommDlg_OpenSave_GetSpec(GetParent(hwnd), nil, 0);
-      // test if we need to use our own storage
-      if SizeInt(OpenFileName^.nMaxFile)<NeededSize then begin
-        if OpenFileName^.lCustData=0 then
-          OpenFileName^.lCustData := Windows.LParam(new(PString));
-        FileNames := PString(OpenFileName^.lCustData);
-        if length(FileNames^)<NeededSize then
-          SetLength(FileNames^, NeededSize*2);
-        CommDlg_OpenSave_GetSpec(GetParent(hwnd),
-                                   PChar(FileNames^), Length(FileNames^));
-      end;
+      DialogRec := POpenFileDialogRec(OpenFileName^.lCustData);
+    end
+    else
+    begin
+      OpenFileName := nil;
+      DialogRec := nil;
     end;
+
+    case OpenFileNotify^.hdr.code of
+      CDN_SELCHANGE:
+        begin
+          // NeededSize is the size that the lpStrFile buffer must have.
+          // the lpstrFile buffer contains the directory and a list of files
+          // for example 'c:\winnt'#0'file1.txt'#0'file2.txt'#0#0.
+          // GetFolderPath returns upper limit for the path, GetSpec for the files.
+          // This is not exact because the GetSpec returns the size for
+          // '"file1.txt" "file2.txt"', so that size will be two bytes per filename
+          // more than needed in thlengthe lpStrFile buffer.
+          NeededSize := CommDlg_OpenSave_GetFolderPath(GetParent(hwnd), nil, 0) +
+                          CommDlg_OpenSave_GetSpec(GetParent(hwnd), nil, 0);
+          // test if we need to use our own storage
+          if (SizeInt(OpenFileName^.nMaxFile) < NeededSize) and (OpenFileName^.lCustData <> 0) then
+          begin
+            if length(DialogRec^.FileNames) < NeededSize then
+              SetLength(DialogRec^.FileNames, NeededSize*2);
+            CommDlg_OpenSave_GetSpec(GetParent(hwnd),
+                                       PChar(DialogRec^.FileNames), Length(DialogRec^.FileNames));
+          end;
+        end;
+      CDN_TYPECHANGE:
+        begin
+          TFileDialogAccess(DialogRec^.Dialog).UpdateFilterIndex(OpenFileNotify^.lpOFN^.nFilterIndex);
+        end;
+    end;
   end;
   Result:= 0;
 end;
 
-procedure ShowFileDialog(AOpenDialog: TOpenDialog; AWinFunc: TWinFileDialogFunc);
-var
-  OpenFile: OPENFILENAME;
-  UserResult: WINBOOL;
-
+function CreateFileDialogHandle(AOpenDialog: TOpenDialog): THandle;
   function GetFlagsFromOptions(Options: TOpenOptions): DWord;
   begin
-    Result := 0;
-    if ofAllowMultiSelect in Options then
-      Result := Result or OFN_ALLOWMULTISELECT or OFN_ENABLEHOOK;
+    Result := OFN_ENABLEHOOK;
+    if ofAllowMultiSelect in Options then Result := Result or OFN_ALLOWMULTISELECT;
     if ofCreatePrompt in Options then Result := Result or OFN_CREATEPROMPT;
     if not (ofOldStyleDialog in Options) then Result := Result or OFN_EXPLORER;
     if ofExtensionDifferent in Options then Result := Result or OFN_EXTENSIONDIFFERENT;
@@ -301,15 +326,71 @@
       if AFilter[i] = '|' then AFilter[i]:=#0;
     AFilter:=AFilter + #0#0;
   end;
+  
+var
+  DialogRec: POpenFileDialogRec;
+  OpenFile: LPOPENFILENAME;
+  Filter: string;
+  FileName: string;
+  InitialDir: String;
+  FileNameBuffer: array[0..1000] of char;
+begin
+  FillChar(FileNameBuffer[0], sizeof(FileNameBuffer), 0);
+  FileName := AOpenDialog.FileName;
+  InitialDir := AOpenDialog.InitialDir;
+  if (FileName<>'') and (FileName[length(FileName)]=PathDelim) then
+  begin
+    // if the filename contains a directory, set the initial directory
+    // and clear the filename
+    InitialDir := Copy(FileName,1, Length(FileName)-1);
+    FileName := '';
+  end;
+  StrLCopy(@FileNameBuffer[0],PChar(Filename),sizeof(FileNameBuffer)-1);
+  if AOpenDialog.Filter <> '' then 
+  begin
+    Filter := AOpenDialog.Filter;
+    ReplacePipe(Filter);
+  end
+  else
+    Filter:='All File Types(*.*)'+#0+'*.*'+#0#0; // Default -> avoid empty combobox
 
+  OpenFile := AllocMem(SizeOf(OpenFileName));
+  with OpenFile^ Do
+  begin
+    lStructSize := OpenFileNameSize;
+    hWndOwner := GetOwnerHandle(AOpenDialog);
+    hInstance := System.hInstance;
+    lpStrFilter := StrAlloc(Length(Filter)+1);
+    StrPCopy(lpStrFilter, Filter);
+    nFilterIndex := AOpenDialog.FilterIndex;
+    lpStrFile := FileNameBuffer;
+    lpStrTitle := PChar(AOpenDialog.Title);
+    lpStrInitialDir := PChar(InitialDir);
+    nMaxFile := sizeof(FileNameBuffer);
+    lpfnHook := @OpenFileDialogCallBack;
+    Flags := GetFlagsFromOptions(AOpenDialog.Options);
+    New(DialogRec);
+    DialogRec^.Dialog := AOpenDialog;
+    DialogRec^.FileNames := '';
+    lCustData := LParam(DialogRec);
+  end;
+  Result := THandle(OpenFile);
+end;
+
+procedure ProcessFileDialogResult(AOpenDialog: TOpenDialog; UserResult: WordBool);
+var
+  DialogRec: POpenFileDialogRec;
+  OpenFile: LPOPENFILENAME;
+
   procedure SetFilesProperty(AFiles:TStrings);
-  var 
+  var
     I: integer;
     pName: PChar;
   begin
-    pName := OpenFile.lpStrFile;
+    pName := OpenFile^.lpStrFile;
     I:=Length(pName);
-    if I < OpenFile.nFileOffset then begin
+    if I < OpenFile^.nFileOffset then
+    begin
       Inc(pName,Succ(I));
       I:=Length(pName);
       while I > 0 do
@@ -328,14 +409,16 @@
     i, Start: integer;
     FileNames: String;
   begin
-    FileNames := PString(OpenFile.lCustData)^;
-    if (FileNames[1] = '"') then begin
+    FileNames := DialogRec^.FileNames;
+    if (FileNames[1] = '"') then
+    begin
       Start := 1; // first quote is on pos 1
-      while FileNames[Start] <> #0 do begin
+      while FileNames[Start] <> #0 do
+      begin
         i := Start + 1;
         while FileNames[i] <> '"' do
           inc(i);
-        AFiles.Add(ExpandFileName(Copy(FileNames,Start+1,I - Start - 1)));
+        AFiles.Add(ExpandFileName(Copy(FileNames, Start + 1, I - Start - 1)));
         start := i+1;
         while (FileNames[Start] <> #0) and (FileNames[start] <> '"') do
           inc(Start);
@@ -348,7 +431,7 @@
     SelectedStr: string;
     I,Start: integer;
   begin
-    SelectedStr:=StrPas(OpenFile.lpStrFile);
+    SelectedStr:=StrPas(OpenFile^.lpStrFile);
     I:=Pos(' ',SelectedStr);
     if I = 0 then
       AFiles.Add(SelectedStr)
@@ -357,55 +440,19 @@
       SelectedStr:=SelectedStr+' ';
       Start:=1;
       for I:= 1 to Length(SelectedStr) do
-        if SelectedStr[I] =  ' ' then 
+        if SelectedStr[I] =  ' ' then
         begin
           AFiles.Add(ExpandFileName(Copy(SelectedStr,Start,I - Start)));
           Start:=Succ(I);
         end;
     end;
   end;
-
+  
 var
-  Filter: string;
-  FileName: string;
-  InitialDir: String;
-  FileNameBuffer: array[0..1000] of char;
   BufferTooSmall: boolean;
 begin
-  FillChar(FileNameBuffer[0], sizeof(FileNameBuffer), 0);
-  FileName := AOpenDialog.FileName;
-  InitialDir := AOpenDialog.InitialDir;
-  if (FileName<>'') and (FileName[length(FileName)]=PathDelim) then begin
-    // if the filename contains a directory, set the initial directory
-    // and clear the filename
-    InitialDir := Copy(FileName,1, Length(FileName)-1);
-    FileName := '';
-  end;
-  StrLCopy(@FileNameBuffer[0],PChar(Filename),sizeof(FileNameBuffer)-1);
-  if AOpenDialog.Filter <> '' then 
-  begin
-    Filter := AOpenDialog.Filter;
-    ReplacePipe(Filter);
-  end
-  else
-    Filter:='All File Types(*.*)'+#0+'*.*'+#0#0; // Default -> avoid empty combobox
-  ZeroMemory(@OpenFile, sizeof(OpenFileName));
-  with OpenFile Do
-  begin
-    lStructSize := OpenFileNameSize;
-    hWndOwner := GetOwnerHandle(AOpenDialog);
-    hInstance := System.hInstance;
-    lpStrFilter := StrAlloc(Length(Filter)+1);
-    StrPCopy(lpStrFilter, Filter);
-    nFilterIndex := AOpenDialog.FilterIndex;
-    lpStrFile := FileNameBuffer;
-    lpStrTitle := PChar(AOpenDialog.Title);
-    lpStrInitialDir := PChar(InitialDir);
-    nMaxFile := sizeof(FileNameBuffer);
-    lpfnHook := @OpenFileDialogCallBack;
-    Flags := GetFlagsFromOptions(AOpenDialog.Options);
-  end;
-  UserResult := AWinFunc(@OpenFile);
+  OPENFILE := LPOPENFILENAME(AOpenDialog.Handle);
+  DialogRec := POpenFileDialogRec(OPENFILE^.lCustData);
   BufferTooSmall := not UserResult and (CommDlgExtendedError=FNERR_BUFFERTOOSMALL);
   if BufferTooSmall then
     UserResult := true;
@@ -415,7 +462,7 @@
     Files.Clear;
     if UserResult then
     begin
-      AOpenDialog.FilterIndex := OpenFile.nFilterIndex;
+      AOpenDialog.FilterIndex := OpenFile^.nFilterIndex;
       if (ofOldStyleDialog in Options) then
         SetFilesPropertyForOldStyle(Files)
       else if BufferTooSmall then
@@ -425,10 +472,6 @@
       FileName := Files[0];
     end else
       FileName := '';
-
-    if OpenFile.lCustData<>0 then
-      Dispose(PString(OpenFile.lCustData));
-    StrDispose(OpenFile.lpStrFilter);
   end;
 end;
 
@@ -436,18 +479,56 @@
 
 class function TWin32WSSaveDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
 begin
-  ShowFileDialog(TOpenDialog(ACommonDialog), @GetSaveFileName);
-  Result := 0;
+  Result := CreateFileDialogHandle(TOpenDialog(ACommonDialog));
 end;
 
+class procedure TWin32WSSaveDialog.DestroyHandle(const ACommonDialog: TCommonDialog);
+var
+  OPENFILE: LPOPENFILENAME;
+begin
+  if ACommonDialog.Handle <> 0 then
+  begin
+    OPENFILE := LPOPENFILENAME(ACommonDialog.Handle);
+    if OPENFILE^.lCustData <> 0 then
+      Dispose(POpenFileDialogRec(OPENFILE^.lCustData));
+    StrDispose(OpenFile^.lpStrFilter);
+  end;
+end;
+
+class procedure TWin32WSSaveDialog.ShowModal(const ACommonDialog: TCommonDialog);
+begin
+  if ACommonDialog.Handle <> 0 then
+    ProcessFileDialogResult(TOpenDialog(ACommonDialog),
+      GetSaveFileName(LPOPENFILENAME(ACommonDialog.Handle)));
+end;
+
 { TWin32WSOpenDialog }
 
 class function TWin32WSOpenDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
 begin
-  ShowFileDialog(TOpenDialog(ACommonDialog), @GetOpenFileName);
-  Result := 0;
+  Result := CreateFileDialogHandle(TOpenDialog(ACommonDialog));
 end;
 
+class procedure TWin32WSOpenDialog.DestroyHandle(const ACommonDialog: TCommonDialog);
+var
+  OPENFILE: LPOPENFILENAME;
+begin
+  if ACommonDialog.Handle <> 0 then
+  begin
+    OPENFILE := LPOPENFILENAME(ACommonDialog.Handle);
+    if OPENFILE^.lCustData <> 0 then
+      Dispose(POpenFileDialogRec(OPENFILE^.lCustData));
+    StrDispose(OpenFile^.lpStrFilter);
+  end;
+end;
+
+class procedure TWin32WSOpenDialog.ShowModal(const ACommonDialog: TCommonDialog);
+begin
+  if ACommonDialog.Handle <> 0 then
+    ProcessFileDialogResult(TOpenDialog(ACommonDialog),
+      GetOpenFileName(LPOPENFILENAME(ACommonDialog.Handle)));
+end;
+
 { TWin32WSFontDialog }
 
 class function TWin32WSFontDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
