OSX 10.7 when menu.delete is triggered by a menu click
Original Reporter info from Mantis: crlab @neurolabusc1
-
Reporter name: Chris Rorden
Original Reporter info from Mantis: crlab @neurolabusc1
- Reporter name: Chris Rorden
Description:
This problem is specific to OSX. It is common to create menus with most-recently used items. Once the user selects an item from this list the list is reordered. The typical way to do this is to delete the menu items using one of these functions (assuming 'Recent1' is the parent menu):
Recent1.Clear;
While Recent1.Count > 1 do Recent1.Delete(0);
While Recent1.Count > 1 do Recent1.Items[0].Free
a popular example of this technique is here
http://www.mail-archive.com/lazarus@miraclec.com/msg18242.html
This works on Windows, Linux and OSX 10.4-10.6. However, using the carbon widget set on OSX 10.7, each of these causes a crash. The software crashes at carbon object.inc in the procedure "CarbonApp_CommandProcess", with an error in the "CarbonMenu.Parent.Dismissed". I assume the error is that the item is trying to dismiss itself after having already been deleted.
As a work-around, instead of deleting menu items one can change their names and visibility (e.g. if there are 10 menu items and only 7 items in the MRU, then 3 have visibility set to false). However, I think any program where selecting a menu item causes the menu to be deleted will cause a crash on OSX 10.7.
Additional information:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus;
type
{ TForm1 }
TForm1 = class(TForm)
MainMenu1: TMainMenu;
File1: TMenuItem;
Recent1: TMenuItem;
procedure FormShow(Sender: TObject);
procedure UpdateMRU;
procedure ClickMRU(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
const
knMRU = 5;
var
gMRUstr: array [1..knMRU] of string;
procedure AddMRU (lCaption: string);
var
lPos,lNew: integer;
lOldstr: array [1..knMRU] of string;
begin
for lPos := 1 to knMRU do begin
lOldstr[lPos] := gMRUstr[lPos];
gMRUstr[lPos] := '';
end;
gMRUstr[1] := lCaption;
lNew := 1;
for lPos := 1 to knMRU do begin
if (lOldstr[lPos] <> lCaption) and (lNew < knMRU) then begin
inc(lNew);
gMRUstr[lNew] := lOldstr[lPos];
end;
end;
end;
procedure TForm1.ClickMRU(Sender: TObject);
var
lName: string;
begin
lName := (Sender as TMenuItem).caption ;
AddMRU(lName);
UpdateMRU;
end;
procedure TForm1.UpdateMRU;//most-recently-used menu
var
NewItem: TMenuItem;
lPos,lN : integer;
begin
//Recent1.Clear; //<-crashes OSX 10.7
//While Recent1.Count > 1 do Recent1.Delete(0); //<-crashes OSX 10.7
//While Recent1.Count > 1 do Recent1.Items[0].Free; //<-crashes OSX 10.7
lN := 0;
for lPos := 1 to knMRU do begin//for each MRU
if gMRUstr[lPos] <> '' then begin
inc(lN);
NewItem := TMenuItem.Create(Self);
NewItem.Caption :=ExtractFileName(gMRUstr[lPos]);
NewItem.Tag := lN;
NewItem.onclick := @ClickMRU;
NewItem.ShortCut := ShortCut(Word('1')+ord(lN-1), [ssCtrl]);
Recent1.Add(NewItem);
end;//if mru exists
end;//for each MRU
end; //UpdateMRU
procedure TForm1.FormShow(Sender: TObject);
var
lPos: integer;
begin
for lPos := 1 to knMRU do
gMRUstr[lPos] := 'menu'+inttostr(lPos);
UpdateMRU;
end;
end.
Mantis conversion info:
- Mantis ID: 20688
- Version: 0.9.30.2
- Monitored by: » @michaliskambi (Michalis Kamburelis)