cocoa: additional control over cocoa window levels

git-svn-id: trunk@59185 -
This commit is contained in:
dmitry 2018-09-29 21:33:29 +00:00
parent e355e20721
commit a4503bccc0
3 changed files with 52 additions and 11 deletions

View File

@ -177,6 +177,7 @@ type
procedure SetMainMenu(const AMenu: HMENU; const ALCLMenu: TMenu);
function StartModal(awin: NSWindow; hasMenu: Boolean): Boolean;
procedure EndModal(awin: NSWindow);
function isModalSession: Boolean;
{todo:}
function DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor; override;
@ -580,11 +581,19 @@ end;
function TCocoaWidgetSet.StartModal(awin: NSWindow; hasMenu: Boolean): Boolean;
var
sess : NSModalSession;
lvl : NSInteger;
begin
Result := false;
if not Assigned(awin) then Exit;
lvl := awin.level;
sess := NSApplication(NSApp).beginModalSessionForWindow(awin);
if not Assigned(sess) then Exit;
// beginModalSession "configures" the modality and potentially is changing window level
awin.setLevel(lvl);
if not Assigned(Modals) then Modals := TList.Create;
// If a modal menu has it's menu, then SetMainMenu has already been called
@ -619,6 +628,10 @@ begin
Modals.Delete(Modals.Count-1);
end;
function TCocoaWidgetSet.isModalSession: Boolean;
begin
Result := Assigned(Modals) and (Modals.Count > 0);
end;
initialization
// {$I Cocoaimages.lrs}

View File

@ -138,6 +138,7 @@ type
procedure windowDidExitFullScreen(notification: NSNotification); message 'windowDidExitFullScreen:';
public
callback: IWindowCallback;
keepWinLevel : NSInteger;
//LCLForm: TCustomForm;
procedure dealloc; override;
function acceptsFirstResponder: Boolean; override;
@ -758,6 +759,18 @@ end;
procedure TCocoaWindow.windowDidBecomeKey(notification: NSNotification);
begin
// forcing to keep the level as all other LCL windows
// Modal windows tend to "restore" their elevated level
// And that doesn't work for modal windows that are "Showing" other windows
// Another approach is to set elevated levels for windows, shown during modal session
// That requires to revoke the elevated level from windows on closing a window session
// This might be the way to go, if FormStyle (such as fsStayOnTop) would come
// in conflict with modality
if level <> keepWinLevel then begin
setLevel(keepWinLevel);
end;
if Assigned(callback) then
callback.Activate;
end;

View File

@ -170,6 +170,7 @@ type
procedure ArrangeTabOrder(const AWinControl: TWinControl);
function HWNDToForm(AFormHandle: HWND): TCustomForm;
procedure WindowSetFormStyle(win: NSWindow; AFormStyle: TFormStyle);
implementation
@ -210,6 +211,25 @@ begin
Result := AForm.BorderStyle;
end;
procedure WindowSetFormStyle(win: NSWindow; AFormStyle: TFormStyle);
var
lvl : NSInteger;
begin
if not (AFormStyle in [fsNormal, fsMDIChild, fsMDIForm]) then
begin
lvl := FormStyleToWindowLevel[AFormStyle];
win.setHidesOnDeactivate(FormStyleToHideOnDeactivate[AFormStyle]);
end
else
begin
lvl := 0;
win.setHidesOnDeactivate(false);
end;
win.setLevel(lvl);
if win.isKindOfClass(TCocoaWindow) then
TCocoaWindow(win).keepWinLevel := lvl;
end;
{ TCocoaWSHintWindow }
class function TCocoaWSHintWindow.CreateHandle(const AWinControl: TWinControl;
@ -323,6 +343,9 @@ begin
ACustForm.SetFocusedControl(ACustForm.ActiveControl);
IsActivating:=False;
if CocoaWidgetSet.isModalSession then
NSView(ACustForm.Handle).window.orderFront(nil);
end;
end;
@ -580,12 +603,8 @@ begin
UpdateWindowIcons(win, GetDesigningBorderStyle(Form), Form.BorderIcons);
// For safety, it is better to not apply any setLevel & similar if the form is just a standard style
// see issue http://bugs.freepascal.org/view.php?id=28473
if not (Form.FormStyle in [fsNormal, fsMDIChild, fsMDIForm])
and not (csDesigning in AWinControl.ComponentState) then
begin
win.setLevel(FormStyleToWindowLevel[Form.FormStyle]);
win.setHidesOnDeactivate(FormStyleToHideOnDeactivate[Form.FormStyle]);
end;
if not (csDesigning in AWinControl.ComponentState) then
WindowSetFormStyle(win, Form.FormStyle);
win.enableCursorRects;
TCocoaWindow(win).callback := cb;
@ -831,11 +850,7 @@ begin
if AForm.HandleAllocated and not (csDesigning in AForm.ComponentState) then
begin
win := TCocoaWindowContent(AForm.Handle).lclOwnWindow;
if Assigned(win) then
begin
win.setLevel(FormStyleToWindowLevel[AFormStyle]);
win.setHidesOnDeactivate(FormStyleToHideOnDeactivate[AFormStyle]);
end;
WindowSetFormStyle(win, AFormStyle);
end;
end;