LCL: Fix ReleaseComponents hang with modal window. Issue #0021451

git-svn-id: trunk@64435 -
This commit is contained in:
martin 2021-01-29 18:53:45 +00:00
parent b269bcc49f
commit 6fc365af0b
2 changed files with 58 additions and 0 deletions

View File

@ -1356,6 +1356,8 @@ type
FCaptureExceptions: boolean; FCaptureExceptions: boolean;
FComponentsToRelease: TFPList; FComponentsToRelease: TFPList;
FComponentsReleasing: TFPList; FComponentsReleasing: TFPList;
FComponentsToReleaseSavedByModal: TFPList;
FComponentsReleasingSavedByModal: TFPList;
FCreatingForm: TForm;// currently created form (CreateForm), candidate for MainForm FCreatingForm: TForm;// currently created form (CreateForm), candidate for MainForm
FDoubleBuffered: TApplicationDoubleBuffered; FDoubleBuffered: TApplicationDoubleBuffered;
FExceptionDialog: TApplicationExceptionDlg; FExceptionDialog: TApplicationExceptionDlg;

View File

@ -257,6 +257,8 @@ end;
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
procedure TApplication.Notification(AComponent : TComponent; procedure TApplication.Notification(AComponent : TComponent;
Operation : TOperation); Operation : TOperation);
var
l: TFPList;
begin begin
if Operation = opRemove then begin if Operation = opRemove then begin
FLastMouseControlValid:=false; FLastMouseControlValid:=false;
@ -270,8 +272,16 @@ begin
FHintTimer:=nil; FHintTimer:=nil;
if FComponentsToRelease<>nil then if FComponentsToRelease<>nil then
FComponentsToRelease.Remove(AComponent); FComponentsToRelease.Remove(AComponent);
if FComponentsToReleaseSavedByModal<>nil then
for Pointer(l) in FComponentsToReleaseSavedByModal do
if l <> nil then
l.Remove(AComponent);
if FComponentsReleasing<>nil then if FComponentsReleasing<>nil then
FComponentsReleasing.Remove(AComponent); FComponentsReleasing.Remove(AComponent);
if FComponentsReleasingSavedByModal<>nil then
for Pointer(l) in FComponentsReleasingSavedByModal do
if l <> nil then
l.Remove(AComponent);
if AComponent = MainForm then begin if AComponent = MainForm then begin
FMainForm:= nil; FMainForm:= nil;
Terminate; Terminate;
@ -317,6 +327,15 @@ end;
procedure TApplication.ModalStarted; procedure TApplication.ModalStarted;
begin begin
inc(FModalLevel); inc(FModalLevel);
if FComponentsToReleaseSavedByModal = nil then
FComponentsToReleaseSavedByModal := TFPList.Create;
FComponentsToReleaseSavedByModal.Add(FComponentsToRelease);
FComponentsToRelease := nil;
(* If a component calls ShowModal while being destroyed by ReleaseComponents then FComponentsReleasing may be <> nil *)
if FComponentsReleasingSavedByModal = nil then
FComponentsReleasingSavedByModal := TFPList.Create;
FComponentsReleasingSavedByModal.Add(FComponentsReleasing);
FComponentsReleasing := nil;
if (FModalLevel = 1) then if (FModalLevel = 1) then
begin begin
if Assigned(FOnModalBegin) then if Assigned(FOnModalBegin) then
@ -327,6 +346,9 @@ begin
end; end;
procedure TApplication.ModalFinished; procedure TApplication.ModalFinished;
var
l: TFPList;
c: Pointer;
begin begin
dec(FModalLevel); dec(FModalLevel);
RestoreStayOnTop(True); RestoreStayOnTop(True);
@ -336,6 +358,40 @@ begin
FOnModalEnd(Self); FOnModalEnd(Self);
FApplicationHandlers[ahtModalEnd].CallNotifyEvents(Self); FApplicationHandlers[ahtModalEnd].CallNotifyEvents(Self);
end; end;
// Cannot leave modal, while in ReleaseComponents
assert(FComponentsReleasing = nil, 'TApplication.ModalFinished: FComponentsReleasing = nil');
assert(FComponentsToReleaseSavedByModal.Count > 0, 'TApplication.ModalFinished: FComponentsToReleaseSavedByModal.Count > 0');
if FComponentsToReleaseSavedByModal.Count > 0 then begin
l := TFPList(FComponentsToReleaseSavedByModal[FComponentsToReleaseSavedByModal.Count - 1]);
FComponentsToReleaseSavedByModal.Delete(FComponentsToReleaseSavedByModal.Count - 1);
if l <> nil then begin
if FComponentsToRelease <> nil then begin
for c in FComponentsToRelease do
l.Add(c);
FComponentsToRelease.Free;
end;
FComponentsToRelease := l;
end;
if FComponentsToRelease <> nil then
QueueAsyncCall(@FreeComponent, 0);
l := TFPList(FComponentsReleasingSavedByModal[FComponentsReleasingSavedByModal.Count - 1]);
FComponentsReleasingSavedByModal.Delete(FComponentsReleasingSavedByModal.Count - 1);
if l <> nil then begin
if FComponentsReleasing <> nil then begin
for c in FComponentsReleasing do
l.Add(c);
FComponentsReleasing.Free;
end;
FComponentsReleasing := l;
end;
end;
if (FModalLevel = 0) then
begin
assert(FComponentsToReleaseSavedByModal.Count = 0, 'TApplication.ModalFinished: FComponentsToReleaseSavedByModal.Count = 0');
FreeAndNil(FComponentsToReleaseSavedByModal);
FreeAndNil(FComponentsReleasingSavedByModal);
end;
end; end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------