cocoa: Fixes crash due to cyclic calls to CreateHandle in modal forms, bug #30527

git-svn-id: trunk@52998 -
This commit is contained in:
sekelsenmat 2016-09-20 07:25:18 +00:00
parent 1d7b19f9f2
commit 0428e3cab5
2 changed files with 41 additions and 7 deletions

View File

@ -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

View File

@ -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;