mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-06 08:58:19 +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)
|
TModalSession = class(TObject)
|
||||||
window : NSWindow;
|
window : NSWindow;
|
||||||
sess : NSModalSession;
|
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;
|
end;
|
||||||
|
|
||||||
{ TCocoaWidgetSet }
|
{ TCocoaWidgetSet }
|
||||||
@ -126,10 +135,17 @@ type
|
|||||||
|
|
||||||
procedure SendCheckSynchronizeMessage;
|
procedure SendCheckSynchronizeMessage;
|
||||||
procedure OnWakeMainThread(Sender: TObject);
|
procedure OnWakeMainThread(Sender: TObject);
|
||||||
|
|
||||||
|
procedure DoSetMainMenu(AMenu: NSMenu; ALCLMenu: TMenu);
|
||||||
public
|
public
|
||||||
// modal session
|
// modal session
|
||||||
CurModalForm: NSWindow;
|
CurModalForm: NSWindow;
|
||||||
Modals : TList;
|
Modals : TList;
|
||||||
|
MainMenuEnabled: Boolean; // the latest main menu status
|
||||||
|
PrevMenu : NSMenu;
|
||||||
|
PrevLCLMenu : TMenu;
|
||||||
|
LCLMenu: TMenu;
|
||||||
|
PrevMenuEnabled: Boolean; // previous mainmenu status
|
||||||
|
|
||||||
constructor Create; override;
|
constructor Create; override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -159,10 +175,9 @@ type
|
|||||||
procedure FreeSysColorBrushes;
|
procedure FreeSysColorBrushes;
|
||||||
|
|
||||||
procedure SetMainMenu(const AMenu: HMENU; const ALCLMenu: TMenu);
|
procedure SetMainMenu(const AMenu: HMENU; const ALCLMenu: TMenu);
|
||||||
function StartModal(awin: NSWindow): Boolean;
|
function StartModal(awin: NSWindow; hasMenu: Boolean): Boolean;
|
||||||
procedure EndModal(awin: NSWindow);
|
procedure EndModal(awin: NSWindow);
|
||||||
|
|
||||||
|
|
||||||
{todo:}
|
{todo:}
|
||||||
function DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor; override;
|
function DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor; override;
|
||||||
procedure DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor); override;
|
procedure DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor); override;
|
||||||
@ -359,11 +374,15 @@ end;
|
|||||||
|
|
||||||
{ TModalSession }
|
{ TModalSession }
|
||||||
|
|
||||||
constructor TModalSession.Create(awin: NSWindow; asess: NSModalSession);
|
constructor TModalSession.Create(awin: NSWindow; asess: NSModalSession;
|
||||||
|
APrevMenuEnabled: Boolean; amainmenu: NSMenu; ALCL: TMenu);
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
window := awin;
|
window := awin;
|
||||||
sess := asess;
|
sess := asess;
|
||||||
|
prevMenuEnabled := APrevMenuEnabled;
|
||||||
|
cocoaMenu := amainmenu;
|
||||||
|
lclMenu := alcl;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TCocoaApplication }
|
{ TCocoaApplication }
|
||||||
@ -498,6 +517,105 @@ begin
|
|||||||
if Assigned(MainPool) then MainPool.release;
|
if Assigned(MainPool) then MainPool.release;
|
||||||
end;
|
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
|
initialization
|
||||||
// {$I Cocoaimages.lrs}
|
// {$I Cocoaimages.lrs}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
Params: ACursor - Cursor type
|
Params: ACursor - Cursor type
|
||||||
Returns: Cursor object in Cocoa for the specified 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
|
begin
|
||||||
case ACursor of
|
case ACursor of
|
||||||
crArrow,
|
crArrow,
|
||||||
@ -294,13 +294,9 @@ end; {TCocoaWidgetSet.PromptUser}
|
|||||||
Shows modal dialog with the specified caption, message and buttons and prompts
|
Shows modal dialog with the specified caption, message and buttons and prompts
|
||||||
user to push one.
|
user to push one.
|
||||||
------------------------------------------------------------------------------}
|
------------------------------------------------------------------------------}
|
||||||
function TCocoaWidgetSet.PromptUser(const DialogCaption : string;
|
function TCocoaWidgetSet.PromptUser(const DialogCaption, DialogMessage: String;
|
||||||
const DialogMessage : string;
|
DialogType: longint; Buttons: PLongint; ButtonCount, DefaultIndex,
|
||||||
DialogType : LongInt;
|
EscapeResult: Longint): Longint;
|
||||||
Buttons : PLongInt;
|
|
||||||
ButtonCount : LongInt;
|
|
||||||
DefaultIndex : LongInt;
|
|
||||||
EscapeResult : LongInt) : LongInt;
|
|
||||||
begin
|
begin
|
||||||
Result := CocoaPromptUser(DialogCaption, DialogMessage, DialogType, Buttons, ButtonCount,
|
Result := CocoaPromptUser(DialogCaption, DialogMessage, DialogType, Buttons, ButtonCount,
|
||||||
DefaultIndex, EscapeResult);
|
DefaultIndex, EscapeResult);
|
||||||
|
@ -478,74 +478,6 @@ begin
|
|||||||
DeleteAndNilObject(FSysColorBrushes[i]);
|
DeleteAndNilObject(FSysColorBrushes[i]);
|
||||||
end;
|
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
|
Method: TCocoaWidgetSet.GetAppHandle
|
||||||
Returns: Returns NSApp object, created via NSApplication.sharedApplication
|
Returns: Returns NSApp object, created via NSApplication.sharedApplication
|
||||||
|
@ -312,7 +312,6 @@ begin
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
debugln('Warning: Menu does not have a valid handle.');
|
debugln('Warning: Menu does not have a valid handle.');
|
||||||
ToggleAppMenu(true);
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
CocoaWidgetSet.SetMainMenu(0, nil);
|
CocoaWidgetSet.SetMainMenu(0, nil);
|
||||||
@ -759,14 +758,12 @@ begin
|
|||||||
// At this point of time, we simply force enabling of the new modal form
|
// 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)
|
// (which is happening in LCL code, but at the wrong time)
|
||||||
NSObject(ACustomForm.Handle).lclSetEnabled(true);
|
NSObject(ACustomForm.Handle).lclSetEnabled(true);
|
||||||
if not Assigned(ACustomForm.Menu) then ToggleAppMenu(false);
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
||||||
win := TCocoaWSCustomForm.GetWindowFromHandle(ACustomForm);
|
win := TCocoaWSCustomForm.GetWindowFromHandle(ACustomForm);
|
||||||
if win = nil then Exit;
|
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
|
// Another possible implementation is using runModalForWindow
|
||||||
{$ifdef COCOA_USE_NATIVE_MODAL}
|
{$ifdef COCOA_USE_NATIVE_MODAL}
|
||||||
|
Loading…
Reference in New Issue
Block a user