From 0428e3cab54a538a6cab7e718d96c661a9a3e696 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Tue, 20 Sep 2016 07:25:18 +0000 Subject: [PATCH] cocoa: Fixes crash due to cyclic calls to CreateHandle in modal forms, bug #30527 git-svn-id: trunk@52998 - --- lcl/interfaces/cocoa/cocoaprivate.pp | 24 ++++++++++++++++++++++++ lcl/interfaces/cocoa/cocoawsforms.pp | 24 +++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoaprivate.pp b/lcl/interfaces/cocoa/cocoaprivate.pp index 8ccde8079b..388ea3d0ed 100644 --- a/lcl/interfaces/cocoa/cocoaprivate.pp +++ b/lcl/interfaces/cocoa/cocoaprivate.pp @@ -435,6 +435,8 @@ type public isembedded: Boolean; // true - if the content is inside of another control, false - if the content is in its own window; ownwin: NSWindow; + popup_parent: HWND; // if not 0, indicates that we should set the popup parent + procedure resolvePopupParent(); message 'resolvePopupParent'; function lclOwnWindow: NSWindow; message 'lclOwnWindow'; procedure lclSetFrame(const r: TRect); override; procedure viewDidMoveToSuperview; override; @@ -924,6 +926,28 @@ begin callback.DidResignKeyNotification; end; +procedure TCocoaWindowContent.resolvePopupParent(); +var + lWindow: NSWindow; +begin + lWindow := nil; + if (popup_parent <> 0) then + begin + if (NSObject(popup_parent).isKindOfClass(TCocoaWindowContent)) then + begin + if (not TCocoaWindowContent(popup_parent).isembedded) then + lWindow := TCocoaWindowContent(popup_parent).window; + end + else + begin + lWindow := NSWindow(popup_parent); + end; + end; + if lWindow <> nil then + lWindow.addChildWindow_ordered(Self.window, NSWindowAbove); + popup_parent := 0; +end; + function TCocoaWindowContent.lclOwnWindow: NSWindow; begin if not isembedded then diff --git a/lcl/interfaces/cocoa/cocoawsforms.pp b/lcl/interfaces/cocoa/cocoawsforms.pp index b1bcef1e63..459c64a864 100644 --- a/lcl/interfaces/cocoa/cocoawsforms.pp +++ b/lcl/interfaces/cocoa/cocoawsforms.pp @@ -97,6 +97,7 @@ type class procedure UpdateWindowMask(AWindow: NSWindow; ABorderStyle: TFormBorderStyle; ABorderIcons: TBorderIcons); public class function GetWindowFromHandle(const ACustomForm: TCustomForm): TCocoaWindow; + class function GetWindowContentFromHandle(const ACustomForm: TCustomForm): TCocoaWindowContent; published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; @@ -431,6 +432,13 @@ begin Result := TCocoaWindow(TCocoaWindowContent(ACustomForm.Handle).lclOwnWindow); end; +class function TCocoaWSCustomForm.GetWindowContentFromHandle(const ACustomForm: TCustomForm): TCocoaWindowContent; +begin + Result := nil; + if not ACustomForm.HandleAllocated then Exit; + Result := TCocoaWindowContent(ACustomForm.Handle); +end; + class function TCocoaWSCustomForm.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; var @@ -488,13 +496,10 @@ var win.LCLForm := Form; win.setContentView(cnt); - if (AParams.WndParent <> 0) then - begin - if (NSObject(AParams.WndParent).isKindOfClass(TCocoaWindowContent)) and (not TCocoaWindowContent(AParams.WndParent).isembedded) then - TCocoaWindowContent(AParams.WndParent).window.addChildWindow_ordered(win, NSWindowAbove) - else - NSWindow(AParams.WndParent).addChildWindow_ordered(win, NSWindowAbove); - end; + // Don't call addChildWindow_ordered here because this function can cause + // events to arrive for this window, creating a second call to TCocoaWSCustomForm.CreateHandle + // while the first didn't finish yet, instead delay the call + cnt.popup_parent := AParams.WndParent; // support for drag & drop win.registerForDraggedTypes(NSArray.arrayWithObjects_count(@NSFilenamesPboardType, 1)); @@ -582,11 +587,16 @@ end; class procedure TCocoaWSCustomForm.ShowModal(const ACustomForm: TCustomForm); var win: TCocoaWindow; + lWinContent: TCocoaWindowContent; begin // Another possible implementation is to have modal started in ShowHide with (fsModal in AForm.FormState) win := TCocoaWSCustomForm.GetWindowFromHandle(ACustomForm); if win = nil then Exit; + // Handle PopupParent + lWinContent := GetWindowContentFromHandle(ACustomForm); + lWinContent.resolvePopupParent(); + { Another possible implementation is using a session, but this requires disabling the other windows ourselves CurModalSession: NSModalSession;