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