From 2ebfedf6fa9175ce3d8e8108000e7008b7eddb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=BDeljan=20Rikalo?= Date: Sat, 15 Feb 2025 16:26:57 +0000 Subject: [PATCH] Qt5, Qt6: fixed showing and destroying popup window with popup parent modal form. issue #41433 (cherry picked from commit 740f63fe4c86e5caab896a516ff4c1cf4e6fd051) Co-authored-by: zeljan1 --- lcl/interfaces/qt5/qtwidgets.pas | 27 +++++++++++++++++++++------ lcl/interfaces/qt5/qtwscontrols.pp | 5 ++++- lcl/interfaces/qt5/qtwsforms.pp | 10 +++++++++- lcl/interfaces/qt6/qtwidgets.pas | 24 ++++++++++++++++++++---- lcl/interfaces/qt6/qtwscontrols.pp | 5 ++++- lcl/interfaces/qt6/qtwsforms.pp | 10 +++++++++- 6 files changed, 67 insertions(+), 14 deletions(-) diff --git a/lcl/interfaces/qt5/qtwidgets.pas b/lcl/interfaces/qt5/qtwidgets.pas index 289c19e6d5..0cf1849083 100644 --- a/lcl/interfaces/qt5/qtwidgets.pas +++ b/lcl/interfaces/qt5/qtwidgets.pas @@ -671,7 +671,7 @@ type ScrollArea: TQtWindowArea; {$ENDIF} destructor Destroy; override; - + procedure Destroyed; cdecl; override; procedure BeginUpdate; override; procedure EndUpdate; override; @@ -713,8 +713,9 @@ type property Blocked: Boolean read FBlocked write FBlocked; property IsFrameWindow: Boolean read FIsFrameWindow write FIsFrameWindow; {check if our LCLObject is TCustomFrame} property FirstPaintEvent: boolean read FFirstPaintEvent write FFirstPaintEvent; {only for x11 - if firstpaintevent arrived we are 100% sure that frame is 100% accurate} - property ShowOnTaskBar: Boolean read FShowOnTaskBar; property MenuBar: TQtMenuBar read FMenuBar; + property PopupParent: QWidgetH read FPopupParent; + property ShowOnTaskBar: Boolean read FShowOnTaskBar; public function WinIDNeeded: boolean; override; procedure AttachEvents; override; @@ -2973,15 +2974,15 @@ end; Params: None Returns: Nothing - Note: LCL uses LM_CLOSEQUERY to set the form visibility and if we don�t send this - message, you won�t be able to show a form twice. + Note: LCL uses LM_CLOSEQUERY to set the form visibility and if we don't send this + message, you won't be able to show a form twice. ------------------------------------------------------------------------------} function TQtWidget.SlotClose: Boolean; cdecl; var Msg : TLMessage; begin {$ifdef VerboseQt} - WriteLn('TQtWidget.SlotClose'); + WriteLn('TQtWidget.SlotClose ',dbgsName(LCLObject)); {$endif} FillChar(Msg{%H-}, SizeOf(Msg), 0); @@ -3004,7 +3005,7 @@ var Msg: TLMessage; begin {$ifdef VerboseQt} - WriteLn('TQtWidget.SlotDestroy'); + WriteLn('TQtWidget.SlotDestroy ',dbgsName(LCLObject)); {$endif} FillChar(Msg{%H-}, SizeOf(Msg), #0); @@ -7416,6 +7417,20 @@ begin inherited Destroy; end; +procedure TQtMainWindow.Destroyed; cdecl; +begin + //this is event from qt, must inform LCL about it. issue #41433 + //when non modal popup is shown over modal form and modal form = real popup parent + //if popup form, and modal form is closed on button close then qt releases + //popup form automatically, so all we have todo is inform LCL. + if Assigned(LCLObject) and (LCLObject.Parent = nil) and not IsMdiChild then + begin + Widget := nil; + SlotDestroy; + end else + inherited Destroyed; +end; + procedure TQtMainWindow.BeginUpdate; begin inherited BeginUpdate; diff --git a/lcl/interfaces/qt5/qtwscontrols.pp b/lcl/interfaces/qt5/qtwscontrols.pp index 147bd23544..3a731c7670 100644 --- a/lcl/interfaces/qt5/qtwscontrols.pp +++ b/lcl/interfaces/qt5/qtwscontrols.pp @@ -258,7 +258,10 @@ end; ------------------------------------------------------------------------------} class procedure TQtWSWinControl.DestroyHandle(const AWinControl: TWinControl); begin - TQtWidget(AWinControl.Handle).Release; + if not WSCheckHandleAllocated(AWinControl, 'DestroyHandle') then + Exit; + if QtWidgetSet.IsValidHandle(AWinControl.Handle) then + TQtWidget(AWinControl.Handle).Release; end; {------------------------------------------------------------------------------ diff --git a/lcl/interfaces/qt5/qtwsforms.pp b/lcl/interfaces/qt5/qtwsforms.pp index 26ef23ba51..a2bc29e807 100644 --- a/lcl/interfaces/qt5/qtwsforms.pp +++ b/lcl/interfaces/qt5/qtwsforms.pp @@ -629,7 +629,9 @@ begin APopupParent := TCustomForm(AWinControl).GetRealPopupParent; if (APopupParent <> nil) then begin - Widget.setParent(TQtWidget(APopupParent.Handle).Widget); + //attach destroy event to PopupParent.Handle.Widget via signal on Widget + //use setRealPopupParent, issue #41433 + Widget.setRealPopupParent(TQtWidget(APopupParent.Handle).Widget); Widget.setWindowFlags(Widget.windowFlags or QtDialog); // issue #41241 end; end; @@ -644,6 +646,12 @@ begin end; Widget.setVisible(AWinControl.HandleObjectShouldBeVisible); + if not AWinControl.HandleObjectShouldBeVisible then + begin + // issue #41433 + if Widget.PopupParent <> nil then + Widget.setRealPopupParent(nil); + end; Widget.EndUpdate; {$IFDEF HASX11} diff --git a/lcl/interfaces/qt6/qtwidgets.pas b/lcl/interfaces/qt6/qtwidgets.pas index d4f6de4fde..a3492bdf62 100644 --- a/lcl/interfaces/qt6/qtwidgets.pas +++ b/lcl/interfaces/qt6/qtwidgets.pas @@ -669,6 +669,7 @@ type ScrollArea: TQtWindowArea; {$ENDIF} destructor Destroy; override; + procedure Destroyed; cdecl; override; procedure BeginUpdate; override; procedure EndUpdate; override; @@ -713,6 +714,7 @@ type property IsFrameWindow: Boolean read FIsFrameWindow write FIsFrameWindow; {check if our LCLObject is TCustomFrame} property FirstPaintEvent: boolean read FFirstPaintEvent write FFirstPaintEvent; {only for x11 - if firstpaintevent arrived we are 100% sure that frame is 100% accurate} property MenuBar: TQtMenuBar read FMenuBar; + property PopupParent: QWidgetH read FPopupParent; property ShowOnTaskBar: Boolean read FShowOnTaskBar; public function WinIDNeeded: boolean; override; @@ -2969,15 +2971,15 @@ end; Params: None Returns: Nothing - Note: LCL uses LM_CLOSEQUERY to set the form visibility and if we don�t send this - message, you won�t be able to show a form twice. + Note: LCL uses LM_CLOSEQUERY to set the form visibility and if we don't send this + message, you won't be able to show a form twice. ------------------------------------------------------------------------------} function TQtWidget.SlotClose: Boolean; cdecl; var Msg : TLMessage; begin {$ifdef VerboseQt} - WriteLn('TQtWidget.SlotClose'); + WriteLn('TQtWidget.SlotClose ',dbgsName(LCLObject)); {$endif} FillChar(Msg{%H-}, SizeOf(Msg), 0); @@ -3000,7 +3002,7 @@ var Msg: TLMessage; begin {$ifdef VerboseQt} - WriteLn('TQtWidget.SlotDestroy'); + WriteLn('TQtWidget.SlotDestroy ',dbgsName(LCLObject)); {$endif} FillChar(Msg{%H-}, SizeOf(Msg), #0); @@ -7366,6 +7368,20 @@ begin inherited Destroy; end; +procedure TQtMainWindow.Destroyed; cdecl; +begin + //this is event from qt, must inform LCL about it. issue #41433 + //when non modal popup is shown over modal form and modal form = real popup parent + //if popup form, and modal form is closed on button close then qt releases + //popup form automatically, so all we have todo is inform LCL. + if Assigned(LCLObject) and (LCLObject.Parent = nil) and not IsMdiChild then + begin + Widget := nil; + SlotDestroy; + end else + inherited Destroyed; +end; + procedure TQtMainWindow.BeginUpdate; begin inherited BeginUpdate; diff --git a/lcl/interfaces/qt6/qtwscontrols.pp b/lcl/interfaces/qt6/qtwscontrols.pp index ceaff1931c..944abb8ec7 100644 --- a/lcl/interfaces/qt6/qtwscontrols.pp +++ b/lcl/interfaces/qt6/qtwscontrols.pp @@ -256,7 +256,10 @@ end; ------------------------------------------------------------------------------} class procedure TQtWSWinControl.DestroyHandle(const AWinControl: TWinControl); begin - TQtWidget(AWinControl.Handle).Release; + if not WSCheckHandleAllocated(AWinControl, 'DestroyHandle') then + Exit; + if QtWidgetSet.IsValidHandle(AWinControl.Handle) then + TQtWidget(AWinControl.Handle).Release; end; {------------------------------------------------------------------------------ diff --git a/lcl/interfaces/qt6/qtwsforms.pp b/lcl/interfaces/qt6/qtwsforms.pp index 1ee26235ef..22299dfe1b 100644 --- a/lcl/interfaces/qt6/qtwsforms.pp +++ b/lcl/interfaces/qt6/qtwsforms.pp @@ -626,7 +626,9 @@ begin APopupParent := TCustomForm(AWinControl).GetRealPopupParent; if (APopupParent <> nil) then begin - Widget.setParent(TQtWidget(APopupParent.Handle).Widget); + //attach destroy event to PopupParent.Handle.Widget via signal on Widget + //use setRealPopupParent, issue #41433 + Widget.setRealPopupParent(TQtWidget(APopupParent.Handle).Widget); Widget.setWindowFlags(Widget.windowFlags or QtDialog); // issue #41241 end; end; @@ -641,6 +643,12 @@ begin end; Widget.setVisible(AWinControl.HandleObjectShouldBeVisible); + if not AWinControl.HandleObjectShouldBeVisible then + begin + // issue #41433 + if Widget.PopupParent <> nil then + Widget.setRealPopupParent(nil); + end; Widget.EndUpdate; {$IFDEF HASX11}