mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-09 10:47:58 +02:00
Cocoa/Form: #40606 improved, Merge branch 'cocoa/form'
This commit is contained in:
commit
575e58d312
@ -53,25 +53,12 @@ type
|
||||
|
||||
{ TAppDelegate }
|
||||
|
||||
TWinLevelOrder = record
|
||||
win : NSWindow;
|
||||
lvl : NSInteger;
|
||||
ord : NSinteger;
|
||||
vis : Boolean;
|
||||
end;
|
||||
PWinLevelOrder = ^TWinLevelOrder;
|
||||
TWinLevelOrderArray = array [Word] of TWinLevelOrder;
|
||||
PWinLevelOrderArray = ^TWinLevelOrderArray;
|
||||
|
||||
TAppDelegate = objcclass(NSObject, NSApplicationDelegateProtocol)
|
||||
public
|
||||
orderArray : PWinLevelOrderArray;
|
||||
orderArrayCount : Integer;
|
||||
procedure application_openFiles(sender: NSApplication; filenames: NSArray);
|
||||
procedure applicationDidHide(notification: NSNotification);
|
||||
procedure applicationDidUnhide(notification: NSNotification);
|
||||
procedure applicationDidBecomeActive(notification: NSNotification);
|
||||
procedure applicationWillResignActive(notification: NSNotification);
|
||||
procedure applicationDidResignActive(notification: NSNotification);
|
||||
procedure applicationDidChangeScreenParameters(notification: NSNotification);
|
||||
procedure applicationWillFinishLaunching(notification: NSNotification);
|
||||
@ -206,6 +193,10 @@ type
|
||||
procedure AppBringToFront; override;
|
||||
procedure AppSetIcon(const Small, Big: HICON); override;
|
||||
procedure AppSetTitle(const ATitle: string); override;
|
||||
function AppRemoveStayOnTopFlags(const ASystemTopAlso: Boolean=False
|
||||
): Boolean; override;
|
||||
function AppRestoreStayOnTopFlags(const ASystemTopAlso: Boolean=False
|
||||
): Boolean; override;
|
||||
|
||||
function BeginMessageProcess: TLCLHandle; override;
|
||||
procedure EndMessageProcess(context: TLCLHandle); override;
|
||||
@ -897,19 +888,13 @@ 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;
|
||||
|
||||
MenuTrackCancelAll();
|
||||
|
@ -319,6 +319,20 @@ begin
|
||||
// There is no way to change the dock title
|
||||
end;
|
||||
|
||||
// NSModalPanelWindowLevel has higher priority than NSFloatingWindowLevel
|
||||
// on Cocoa, so nothing needs to be done
|
||||
function TCocoaWidgetSet.AppRemoveStayOnTopFlags(const ASystemTopAlso: Boolean
|
||||
): Boolean;
|
||||
begin
|
||||
Result:= true;
|
||||
end;
|
||||
|
||||
function TCocoaWidgetSet.AppRestoreStayOnTopFlags(const ASystemTopAlso: Boolean
|
||||
): Boolean;
|
||||
begin
|
||||
Result:= true;
|
||||
end;
|
||||
|
||||
function TCocoaWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt;
|
||||
begin
|
||||
case ACapability of
|
||||
@ -601,77 +615,93 @@ end;
|
||||
|
||||
procedure TAppDelegate.applicationDidBecomeActive(notification: NSNotification);
|
||||
var
|
||||
i : integer;
|
||||
windows: NSArray;
|
||||
window: NSWindow;
|
||||
form: TObject;
|
||||
style: TFormStyle;
|
||||
i: Integer;
|
||||
begin
|
||||
// Cocoa changes level and order of windows to it's liking
|
||||
// (it happens between Will- and DidBecomeActive)
|
||||
// for example Model windows becoming level 8,
|
||||
// even if LCL set them to level 0 before.
|
||||
// As a result the OrderedIndex also goes messed up.
|
||||
// It's being restored here
|
||||
for i := orderArrayCount-1 downto 0 do
|
||||
begin
|
||||
if not orderArray^[i].vis then
|
||||
windows := NSApp.orderedWindows;
|
||||
for i:= windows.count-1 downto 0 do begin
|
||||
window:= NSWindow( windows.objectAtIndex(i) );
|
||||
if not window.isVisible then
|
||||
continue;
|
||||
if orderArray^[i].lvl=NSNormalWindowLevel then
|
||||
form:= window.lclGetTarget;
|
||||
if not (form is TCustomForm) then
|
||||
continue;
|
||||
orderArray^[i].win.setLevel( orderArray^[i].lvl );
|
||||
orderArray^[i].win.orderFrontRegardless;
|
||||
end;
|
||||
orderArrayCount := 0;
|
||||
if orderArray <> nil then
|
||||
begin
|
||||
Freemem(orderArray);
|
||||
orderArray := nil;
|
||||
if csDesigning in TCustomForm(form).ComponentState then
|
||||
continue;
|
||||
style:= TCustomForm(form).FormStyle;
|
||||
if style in fsAllNonSystemStayOnTop then
|
||||
window.setLevel( NSFloatingWindowLevel );
|
||||
end;
|
||||
|
||||
Application.IntfAppActivate;
|
||||
end;
|
||||
|
||||
procedure TAppDelegate.applicationWillResignActive(notification: NSNotification
|
||||
);
|
||||
procedure TAppDelegate.applicationDidResignActive(notification: NSNotification);
|
||||
var
|
||||
baseWindowNumber: NSInteger;
|
||||
lastWindowNumber: NSInteger;
|
||||
topWindowNumber: NSInteger;
|
||||
windows: NSArray;
|
||||
window: NSWindow;
|
||||
form: TObject;
|
||||
info: PWinLevelOrder;
|
||||
style: TFormStyle;
|
||||
state: TFormState;
|
||||
i: Integer;
|
||||
begin
|
||||
windows := NSApp.orderedWindows;
|
||||
// no window in this space
|
||||
if NSWindow.windowNumbersWithOptions(0).count = 0 then
|
||||
Exit;
|
||||
|
||||
baseWindowNumber:= 0;
|
||||
for window in windows do begin
|
||||
if window.level=NSNormalWindowLevel then begin
|
||||
baseWindowNumber:= window.windowNumber;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
windows:= NSApp.orderedWindows;
|
||||
|
||||
orderArrayCount:= windows.count;
|
||||
orderArray:= GetMem(orderArrayCount * sizeof(TWinLevelOrder));
|
||||
|
||||
info:= orderArray^;
|
||||
for window in windows do begin
|
||||
info^.win := window;
|
||||
info^.lvl := window.level;
|
||||
info^.ord := window.orderedIndex;
|
||||
info^.vis := window.isVisible;
|
||||
inc( info );
|
||||
end;
|
||||
|
||||
for window in windows do begin
|
||||
// reset fsStayOnTop form
|
||||
lastWindowNumber:= 0;
|
||||
for i:=windows.count-1 downto 0 do begin
|
||||
window:= NSWindow( windows.objectAtIndex(i) );
|
||||
if not window.isVisible then
|
||||
continue;
|
||||
form:= window.lclGetTarget;
|
||||
if form is TCustomForm then begin
|
||||
if TCustomForm(form).FormStyle=fsStayOnTop then begin
|
||||
window.setLevel( NSNormalWindowLevel );
|
||||
window.orderWindow_relativeTo( NSWindowAbove, baseWindowNumber );
|
||||
end;
|
||||
if not (form is TCustomForm) then
|
||||
continue;
|
||||
if csDesigning in TCustomForm(form).ComponentState then
|
||||
continue;
|
||||
style:= TCustomForm(form).FormStyle;
|
||||
if style in fsAllNonSystemStayOnTop then begin
|
||||
window.setLevel( NSNormalWindowLevel );
|
||||
if lastWindowNumber<>0 then
|
||||
window.orderWindow_relativeTo( NSWindowAbove, lastWindowNumber );
|
||||
end;
|
||||
lastWindowNumber:= window.windowNumber;
|
||||
end;
|
||||
|
||||
// find top window of NSNormalWindowLevel
|
||||
topWindowNumber:= 0;
|
||||
for window in windows do begin
|
||||
if not window.isVisible then
|
||||
continue;
|
||||
if window.level <> NSNormalWindowLevel then
|
||||
continue;
|
||||
topWindowNumber:= window.windowNumber;
|
||||
break;
|
||||
end;
|
||||
|
||||
// bring up modal form
|
||||
for i:=windows.count-1 downto 0 do begin
|
||||
window:= NSWindow( windows.objectAtIndex(i) );
|
||||
if not window.isVisible then
|
||||
continue;
|
||||
form:= window.lclGetTarget;
|
||||
if not (form is TCustomForm) then
|
||||
continue;
|
||||
state:= TCustomForm(form).FormState;
|
||||
if fsModal in state then begin
|
||||
window.orderWindow_relativeTo( NSWindowAbove, topWindowNumber );
|
||||
topWindowNumber:= window.windowNumber;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TAppDelegate.applicationDidResignActive(notification: NSNotification);
|
||||
begin
|
||||
Application.IntfAppDeactivate;
|
||||
Application.DoBeforeMouseMessage(nil);
|
||||
end;
|
||||
|
@ -725,25 +725,14 @@ end;
|
||||
|
||||
procedure TCocoaWindow.DoWindowDidBecomeKey();
|
||||
begin
|
||||
if CocoaWidgetSet.isModalSession then
|
||||
self.orderFront(nil);
|
||||
if Assigned(NSApp.keyWindow) then
|
||||
NSApp.keyWindow.orderFrontRegardless;
|
||||
|
||||
CursorHelper.SetCursorOnActive();
|
||||
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;
|
||||
|
||||
@ -787,6 +776,8 @@ begin
|
||||
// MacOS does 10.7 fullscreen switch with an animation (that's about 1 second long)
|
||||
// if during that animation there's another call toggleFullScreen() is made
|
||||
// then macOS produces an output "not in fullscreen state" and ignores the call.
|
||||
|
||||
self.setLevel( NSNormalWindowLevel );
|
||||
end;
|
||||
|
||||
procedure TCocoaWindow.windowDidEnterFullScreen(notification: NSNotification);
|
||||
@ -800,6 +791,9 @@ begin
|
||||
if orderOutAfterFS then begin
|
||||
self.orderOut(nil);
|
||||
orderOutAfterFS := false;
|
||||
end else begin
|
||||
if self.level<>self.keepWinLevel then
|
||||
self.setLevel(self.keepWinLevel);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user