mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-04 20:18:14 +02:00
cocoa: improve tracking of menu changes when modal dialogs are switching. Merged menu routines from coocaojbect.inc into cocoaint.pas
git-svn-id: trunk@59131 -
This commit is contained in:
parent
7b1d87b432
commit
be159e85b6
@ -81,7 +81,16 @@ type
|
||||
TModalSession = class(TObject)
|
||||
window : NSWindow;
|
||||
sess : NSModalSession;
|
||||
constructor Create(awin: NSWindow; asess: NSModalSession);
|
||||
// recording menu state for the modality stack
|
||||
// there's no limitation for a modal window to have its own menu
|
||||
// if it override the mainMenu, we still need the information
|
||||
// to restore the previous state of the mainmenu
|
||||
prevMenuEnabled: Boolean;
|
||||
cocoaMenu : NSMenu;
|
||||
lclMenu : TMenu;
|
||||
constructor Create(awin: NSWindow; asess: NSModalSession;
|
||||
APrevMenuEnabled: Boolean;
|
||||
amainmenu: NSMenu; ALCL: TMenu);
|
||||
end;
|
||||
|
||||
{ TCocoaWidgetSet }
|
||||
@ -126,10 +135,17 @@ type
|
||||
|
||||
procedure SendCheckSynchronizeMessage;
|
||||
procedure OnWakeMainThread(Sender: TObject);
|
||||
|
||||
procedure DoSetMainMenu(AMenu: NSMenu; ALCLMenu: TMenu);
|
||||
public
|
||||
// modal session
|
||||
CurModalForm: NSWindow;
|
||||
Modals : TList;
|
||||
MainMenuEnabled: Boolean; // the latest main menu status
|
||||
PrevMenu : NSMenu;
|
||||
PrevLCLMenu : TMenu;
|
||||
LCLMenu: TMenu;
|
||||
PrevMenuEnabled: Boolean; // previous mainmenu status
|
||||
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
@ -159,10 +175,9 @@ type
|
||||
procedure FreeSysColorBrushes;
|
||||
|
||||
procedure SetMainMenu(const AMenu: HMENU; const ALCLMenu: TMenu);
|
||||
function StartModal(awin: NSWindow): Boolean;
|
||||
function StartModal(awin: NSWindow; hasMenu: Boolean): Boolean;
|
||||
procedure EndModal(awin: NSWindow);
|
||||
|
||||
|
||||
{todo:}
|
||||
function DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor; override;
|
||||
procedure DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor); override;
|
||||
@ -359,11 +374,15 @@ end;
|
||||
|
||||
{ TModalSession }
|
||||
|
||||
constructor TModalSession.Create(awin: NSWindow; asess: NSModalSession);
|
||||
constructor TModalSession.Create(awin: NSWindow; asess: NSModalSession;
|
||||
APrevMenuEnabled: Boolean; amainmenu: NSMenu; ALCL: TMenu);
|
||||
begin
|
||||
inherited Create;
|
||||
window := awin;
|
||||
sess := asess;
|
||||
prevMenuEnabled := APrevMenuEnabled;
|
||||
cocoaMenu := amainmenu;
|
||||
lclMenu := alcl;
|
||||
end;
|
||||
|
||||
{ TCocoaApplication }
|
||||
@ -498,6 +517,105 @@ begin
|
||||
if Assigned(MainPool) then MainPool.release;
|
||||
end;
|
||||
|
||||
|
||||
procedure TCocoaWidgetSet.DoSetMainMenu(AMenu: NSMenu; ALCLMenu: TMenu);
|
||||
var
|
||||
i: Integer;
|
||||
lCurItem: TMenuItem;
|
||||
lMenuObj: NSObject;
|
||||
lNSMenu: NSMenu absolute AMenu;
|
||||
begin
|
||||
PrevMenu := NSApplication(NSApp).mainMenu;
|
||||
PrevLCLMenu := LCLMenu;
|
||||
NSApp.setMainMenu(lNSMenu);
|
||||
LCLMenu := ALCLMenu;
|
||||
|
||||
if (ALCLMenu = nil) or not ALCLMenu.HandleAllocated then Exit;
|
||||
|
||||
// Find the Apple menu, if the user provided any by setting the Caption to
|
||||
// Some older docs say we should use setAppleMenu to obtain the Services/Hide/Quit items,
|
||||
// but its now private and in 10.10 it doesn't seam to do anything
|
||||
// NSApp.setAppleMenu(NSMenu(lMenuObj));
|
||||
for i := 0 to ALCLMenu.Items.Count-1 do
|
||||
begin
|
||||
lCurItem := ALCLMenu.Items.Items[i];
|
||||
if not lNSMenu.isKindOfClass_(TCocoaMenu) then Break;
|
||||
if not lCurItem.HandleAllocated then Continue;
|
||||
|
||||
lMenuObj := NSObject(lCurItem.Handle);
|
||||
if not lMenuObj.isKindOfClass_(TCocoaMenuItem) then Continue;
|
||||
if TCocoaMenuItem(lMenuObj).isValidAppleMenu() then
|
||||
begin
|
||||
TCocoaMenu(lNSMenu).overrideAppleMenu(TCocoaMenuItem(lMenuObj));
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCocoaWidgetSet.SetMainMenu(const AMenu: HMENU; const ALCLMenu: TMenu);
|
||||
begin
|
||||
if AMenu<>0 then
|
||||
begin
|
||||
DoSetMainMenu(NSMenu(AMenu), LCLMenu);
|
||||
|
||||
PrevMenuEnabled := MainMenuEnabled;
|
||||
MainMenuEnabled := true;
|
||||
ToggleAppMenu(true);
|
||||
//if not Assigned(ACustomForm.Menu) then ToggleAppMenu(false);
|
||||
|
||||
// for modal windows work around bug, but doesn't work :(
|
||||
{$ifdef COCOA_USE_NATIVE_MODAL}
|
||||
{if CurModalForm <> nil then
|
||||
for i := 0 to lNSMenu.numberOfItems()-1 do
|
||||
begin
|
||||
lNSMenu.itemAtIndex(i).setTarget(TCocoaWSCustomForm.GetWindowFromHandle(CurModalForm));
|
||||
end;}
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCocoaWidgetSet.StartModal(awin: NSWindow; hasMenu: Boolean): Boolean;
|
||||
var
|
||||
sess : NSModalSession;
|
||||
begin
|
||||
Result := false;
|
||||
if not Assigned(awin) then Exit;
|
||||
sess := NSApplication(NSApp).beginModalSessionForWindow(awin);
|
||||
if not Assigned(sess) then Exit;
|
||||
if not Assigned(Modals) then Modals := TList.Create;
|
||||
|
||||
// cannot use MainMenuEnabled to record the status, because "MainMenuEnabled"
|
||||
// has been changed in SetMainMenu for the menu of ModalWindow
|
||||
Modals.Add( TModalSession.Create(awin, sess, PrevMenuEnabled, PrevMenu, PrevLCLMenu));
|
||||
|
||||
if not hasMenu then begin
|
||||
MainMenuEnabled := false;
|
||||
ToggleAppMenu(false); // modal menu doesn't have a window, disabling it
|
||||
end;
|
||||
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
procedure TCocoaWidgetSet.EndModal(awin: NSWindow);
|
||||
var
|
||||
ms : TModalSession;
|
||||
begin
|
||||
if not Assigned(Modals) or (Modals.Count = 0) then Exit;
|
||||
ms := TModalSession(Modals[Modals.Count-1]);
|
||||
if (ms.window <> awin) then Exit;
|
||||
NSApplication(NSApp).endModalSession(ms.sess);
|
||||
|
||||
// restoring the menu status that was before the modality
|
||||
DoSetMainMenu(ms.cocoaMenu, ms.lclMenu);
|
||||
PrevMenuEnabled := MainMenuEnabled;
|
||||
MainMenuEnabled := ms.prevMenuEnabled;
|
||||
ToggleAppMenu(ms.prevMenuEnabled); // modal menu doesn't have a window, disabling it
|
||||
|
||||
ms.Free;
|
||||
Modals.Delete(Modals.Count-1);
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
// {$I Cocoaimages.lrs}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
Params: ACursor - Cursor type
|
||||
Returns: Cursor object in Cocoa for the specified cursor type
|
||||
------------------------------------------------------------------------------}
|
||||
function TCocoaWidgetSet.CreateStandardCursor(ACursor: SmallInt): HCursor;
|
||||
function TCocoaWidgetSet.CreateStandardCursor(ACursor: SmallInt): hCursor;
|
||||
begin
|
||||
case ACursor of
|
||||
crArrow,
|
||||
@ -294,13 +294,9 @@ end; {TCocoaWidgetSet.PromptUser}
|
||||
Shows modal dialog with the specified caption, message and buttons and prompts
|
||||
user to push one.
|
||||
------------------------------------------------------------------------------}
|
||||
function TCocoaWidgetSet.PromptUser(const DialogCaption : string;
|
||||
const DialogMessage : string;
|
||||
DialogType : LongInt;
|
||||
Buttons : PLongInt;
|
||||
ButtonCount : LongInt;
|
||||
DefaultIndex : LongInt;
|
||||
EscapeResult : LongInt) : LongInt;
|
||||
function TCocoaWidgetSet.PromptUser(const DialogCaption, DialogMessage: String;
|
||||
DialogType: longint; Buttons: PLongint; ButtonCount, DefaultIndex,
|
||||
EscapeResult: Longint): Longint;
|
||||
begin
|
||||
Result := CocoaPromptUser(DialogCaption, DialogMessage, DialogType, Buttons, ButtonCount,
|
||||
DefaultIndex, EscapeResult);
|
||||
|
@ -478,74 +478,6 @@ begin
|
||||
DeleteAndNilObject(FSysColorBrushes[i]);
|
||||
end;
|
||||
|
||||
procedure TCocoaWidgetSet.SetMainMenu(const AMenu: HMENU; const ALCLMenu: TMenu);
|
||||
var
|
||||
i: Integer;
|
||||
lCurItem: TMenuItem;
|
||||
lMenuObj: NSObject;
|
||||
lNSMenu: NSMenu absolute AMenu;
|
||||
begin
|
||||
if AMenu<>0 then
|
||||
begin
|
||||
NSApp.setMainMenu(lNSMenu);
|
||||
if (ALCLMenu = nil) or not ALCLMenu.HandleAllocated then Exit;
|
||||
|
||||
// Find the Apple menu, if the user provided any by setting the Caption to
|
||||
// Some older docs say we should use setAppleMenu to obtain the Services/Hide/Quit items,
|
||||
// but its now private and in 10.10 it doesn't seam to do anything
|
||||
// NSApp.setAppleMenu(NSMenu(lMenuObj));
|
||||
for i := 0 to ALCLMenu.Items.Count-1 do
|
||||
begin
|
||||
lCurItem := ALCLMenu.Items.Items[i];
|
||||
if not lNSMenu.isKindOfClass_(TCocoaMenu) then Break;
|
||||
if not lCurItem.HandleAllocated then Continue;
|
||||
|
||||
lMenuObj := NSObject(lCurItem.Handle);
|
||||
if not lMenuObj.isKindOfClass_(TCocoaMenuItem) then Continue;
|
||||
if TCocoaMenuItem(lMenuObj).isValidAppleMenu() then
|
||||
begin
|
||||
TCocoaMenu(lNSMenu).overrideAppleMenu(TCocoaMenuItem(lMenuObj));
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
// for modal windows work around bug, but doesn't work :(
|
||||
{$ifdef COCOA_USE_NATIVE_MODAL}
|
||||
{if CurModalForm <> nil then
|
||||
for i := 0 to lNSMenu.numberOfItems()-1 do
|
||||
begin
|
||||
lNSMenu.itemAtIndex(i).setTarget(TCocoaWSCustomForm.GetWindowFromHandle(CurModalForm));
|
||||
end;}
|
||||
{$endif}
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCocoaWidgetSet.StartModal(awin: NSWindow): Boolean;
|
||||
var
|
||||
sess : NSModalSession;
|
||||
begin
|
||||
Result := false;
|
||||
if not Assigned(awin) then Exit;
|
||||
sess := NSApplication(NSApp).beginModalSessionForWindow(awin);
|
||||
if not Assigned(sess) then Exit;
|
||||
if not Assigned(Modals) then Modals := TList.Create;
|
||||
|
||||
Modals.Add( TModalSession.Create(awin, sess));
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
procedure TCocoaWidgetSet.EndModal(awin: NSWindow);
|
||||
var
|
||||
ms : TModalSession;
|
||||
begin
|
||||
if not Assigned(Modals) or (Modals.Count = 0) then Exit;
|
||||
ms := TModalSession(Modals[Modals.Count-1]);
|
||||
if (ms.window <> awin) then Exit;
|
||||
NSApplication(NSApp).endModalSession(ms.sess);
|
||||
ms.Free;
|
||||
Modals.Delete(Modals.Count-1);
|
||||
end;
|
||||
|
||||
{------------------------------------------------------------------------------
|
||||
Method: TCocoaWidgetSet.GetAppHandle
|
||||
Returns: Returns NSApp object, created via NSApplication.sharedApplication
|
||||
|
@ -312,7 +312,6 @@ begin
|
||||
end
|
||||
else
|
||||
debugln('Warning: Menu does not have a valid handle.');
|
||||
ToggleAppMenu(true);
|
||||
end
|
||||
else
|
||||
CocoaWidgetSet.SetMainMenu(0, nil);
|
||||
@ -759,14 +758,12 @@ begin
|
||||
// At this point of time, we simply force enabling of the new modal form
|
||||
// (which is happening in LCL code, but at the wrong time)
|
||||
NSObject(ACustomForm.Handle).lclSetEnabled(true);
|
||||
if not Assigned(ACustomForm.Menu) then ToggleAppMenu(false);
|
||||
|
||||
|
||||
// Another possible implementation is using a session, but this requires
|
||||
// disabling the other windows ourselves
|
||||
win := TCocoaWSCustomForm.GetWindowFromHandle(ACustomForm);
|
||||
if win = nil then Exit;
|
||||
CocoaWidgetSet.StartModal(NSView(ACustomForm.Handle).window);
|
||||
CocoaWidgetSet.StartModal(NSView(ACustomForm.Handle).window, Assigned(ACustomForm.Menu));
|
||||
|
||||
// Another possible implementation is using runModalForWindow
|
||||
{$ifdef COCOA_USE_NATIVE_MODAL}
|
||||
|
Loading…
Reference in New Issue
Block a user