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 public
isembedded: Boolean; // true - if the content is inside of another control, false - if the content is in its own window; isembedded: Boolean; // true - if the content is inside of another control, false - if the content is in its own window;
ownwin: NSWindow; 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'; function lclOwnWindow: NSWindow; message 'lclOwnWindow';
procedure lclSetFrame(const r: TRect); override; procedure lclSetFrame(const r: TRect); override;
procedure viewDidMoveToSuperview; override; procedure viewDidMoveToSuperview; override;
@ -924,6 +926,28 @@ begin
callback.DidResignKeyNotification; callback.DidResignKeyNotification;
end; 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; function TCocoaWindowContent.lclOwnWindow: NSWindow;
begin begin
if not isembedded then if not isembedded then

View File

@ -97,6 +97,7 @@ type
class procedure UpdateWindowMask(AWindow: NSWindow; ABorderStyle: TFormBorderStyle; ABorderIcons: TBorderIcons); class procedure UpdateWindowMask(AWindow: NSWindow; ABorderStyle: TFormBorderStyle; ABorderIcons: TBorderIcons);
public public
class function GetWindowFromHandle(const ACustomForm: TCustomForm): TCocoaWindow; class function GetWindowFromHandle(const ACustomForm: TCustomForm): TCocoaWindow;
class function GetWindowContentFromHandle(const ACustomForm: TCustomForm): TCocoaWindowContent;
published published
class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
@ -431,6 +432,13 @@ begin
Result := TCocoaWindow(TCocoaWindowContent(ACustomForm.Handle).lclOwnWindow); Result := TCocoaWindow(TCocoaWindowContent(ACustomForm.Handle).lclOwnWindow);
end; 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; class function TCocoaWSCustomForm.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): TLCLIntfHandle; const AParams: TCreateParams): TLCLIntfHandle;
var var
@ -488,13 +496,10 @@ var
win.LCLForm := Form; win.LCLForm := Form;
win.setContentView(cnt); win.setContentView(cnt);
if (AParams.WndParent <> 0) then // Don't call addChildWindow_ordered here because this function can cause
begin // events to arrive for this window, creating a second call to TCocoaWSCustomForm.CreateHandle
if (NSObject(AParams.WndParent).isKindOfClass(TCocoaWindowContent)) and (not TCocoaWindowContent(AParams.WndParent).isembedded) then // while the first didn't finish yet, instead delay the call
TCocoaWindowContent(AParams.WndParent).window.addChildWindow_ordered(win, NSWindowAbove) cnt.popup_parent := AParams.WndParent;
else
NSWindow(AParams.WndParent).addChildWindow_ordered(win, NSWindowAbove);
end;
// support for drag & drop // support for drag & drop
win.registerForDraggedTypes(NSArray.arrayWithObjects_count(@NSFilenamesPboardType, 1)); win.registerForDraggedTypes(NSArray.arrayWithObjects_count(@NSFilenamesPboardType, 1));
@ -582,11 +587,16 @@ end;
class procedure TCocoaWSCustomForm.ShowModal(const ACustomForm: TCustomForm); class procedure TCocoaWSCustomForm.ShowModal(const ACustomForm: TCustomForm);
var var
win: TCocoaWindow; win: TCocoaWindow;
lWinContent: TCocoaWindowContent;
begin begin
// Another possible implementation is to have modal started in ShowHide with (fsModal in AForm.FormState) // Another possible implementation is to have modal started in ShowHide with (fsModal in AForm.FormState)
win := TCocoaWSCustomForm.GetWindowFromHandle(ACustomForm); win := TCocoaWSCustomForm.GetWindowFromHandle(ACustomForm);
if win = nil then Exit; if win = nil then Exit;
// Handle PopupParent
lWinContent := GetWindowContentFromHandle(ACustomForm);
lWinContent.resolvePopupParent();
{ Another possible implementation is using a session, but this requires { Another possible implementation is using a session, but this requires
disabling the other windows ourselves disabling the other windows ourselves
CurModalSession: NSModalSession; CurModalSession: NSModalSession;