Mac Porting a programme using Lazarus from Windows to Mac Windows


The issues and experiences in porting an application from Windows to Mac are outlined. I (Greg Vinall) have a 'Fitness' programme written in Object Pascal using the Lazarus IDE. Having recently purchased a Macbook Air, I ported the application to the Mac.

Installation of Lazarus

Installation of Lazarus was a straight forward three-step process:

  • Read the how-to
  • download and install xcode 4 (for the debugger) from the Apple Store (using the standard application in the Dock)
  • download and install Lazarus for Mac OS X from here.

Preparing to code

It was important to get one's head around the differences in the look and feel of the Mac GUI to that of the Windows GUI. I found the following couple of links informative:

Points to note when coding

The following points are detailed further in the article.

  • Buttons are smaller and rounded on the Mac.
  • The default Font is a different size.
  • There is an 'Apple' menu as the first menu, and is manditory.
  • The location and naming of menu items, such as 'Preferences...'/'Options' are different.
  • The Menu is not part of the form, and thus alters the positioning of controls.
  • Shortcut keys for common functions (eg Save) differ.
  • Dialog and AboutBoxes are generally not modal.
  • Location of configuration and other supporting files differ
  • Invisible tabsheets cannot have controls created by code
  • TcomboBox onselect events are fired inconsistently

Buttons are smaller and rounded on the Mac, and the default Font is a different size

Lazarus automatically makes buttons rounded if their height is 22 or less. Thus I put in conditional code to change every button on the form, when compiling on the Mac:

    for i := 0 to frmMainGUI.ControlCount -1 do
        if frmMainGUI.Controls[i] is TButton then
            with frmMainGUI.Controls[i] do begin
                // Change the 'Height' to 22, and
                // Increase the width to accommodate the Apple Font
                Height := 22;
                Width  := 62;

There is an 'Apple' menu as the first menu, and the location and naming of menu items, such as 'Preferences...'/'Options' are different

Every Apple application has an 'Apple' menu, with the 'Preferences...' (generally called 'Options' in the Windows environment) a submenu.

Conditionally define menu controls, and create and configure them. Firstly, in the definition of your form, define the controls:

        AppMenu     : TMenuItem;
        AppAboutCmd : TMenuItem;
        AppSep1Cmd  : TMenuItem;
        AppPrefCmd  : TMenuItem;

Secondly, create and configure them (assuming that you have a Menu control called 'MainMenu')

        // Add 'Apple' Menu
        AppMenu := TMenuItem.Create(Self);  // Application menu
        AppMenu.Caption := #$EF#$A3#$BF;    // Unicode Apple logo char
        MainMenu.Items.Insert(0, AppMenu);

        // Add 'About' as item in application menu
        AppAboutCmd := TMenuItem.Create(Self);
        AppAboutCmd.Caption := 'About ' + BundleName;  // Bundlename is the name of one of your global variables.
        AppAboutCmd.OnClick := @mnuAboutClick;         // mnuAboutClick is the procedure to show the AboutBox.

        // Add Separator to application menu
        AppSep1Cmd := TMenuItem.Create(Self);
        AppSep1Cmd.Caption := '-';

        // Add 'Preferences'/'Options' to application menu
        AppPrefCmd := TMenuItem.Create(Self);
        AppPrefCmd.Caption := 'Preferences...';
        AppPrefCmd.Shortcut := ShortCut(VK_OEM_COMMA, [ssMeta]);
        AppPrefCmd.OnClick := @OptionsCmdClick;

Thirdly, remove the Exit submenu from the 'File' menu, and the 'About' submenu from the 'Help' menu, which is the normal location for these menus in the Windows environment, and assumes that you have these already created in your windows application, and called mnuFileExit and mnuHelpAbout:

        mnuFileExit.Visible := False;
        mnuHelpAbout.Visible := False;

The Menu is not part of the form, and thus alters the positioning of controls

I have controls along the bottom of my form, and in the Mac environment, with no menu as part of the form, leaves too much space at the bottom. I adjust the form's height:

        frmMainGui.Height := 507;

Shortcut keys for common functions (eg Save) differ

For example, 'Save' on Windows is Ctrl-S, while on the Apple, it is Meta-S. To re-assign the keys on the Mac, use the unit LCLtype, and conditionally compile as per the example:

        mnuEditCopy.Shortcut      := ShortCut(VK_C, [ssMeta]);      // Meta-C       [ Command-C on Windows ]
        mnuEditPaste.Shortcut     := ShortCut(VK_V, [ssMeta]);      // Meta-V       [ Command-V on Windows ]
        mnuEditUndo.Shortcut      := ShortCut(VK_Z, [ssMeta]);      // Meta-Z       [ Command-Z on Windows ]
        mnuEditCut.Shortcut       := ShortCut(VK_X, [ssMeta]);      // Meta-X       [ Command-X on Windows ]
        mnuEditSelectAll.Shortcut := ShortCut(VK_A, [ssMeta]);      // Meta-Z       [ Command-A on Windows ]
        mnuGoFirst.Shortcut       := ShortCut(VK_UP, [ssMeta]);     // Meta-Up      [ Command-Up on Windows ]
        mnuGoPrevious.Shortcut    := ShortCut(VK_UP, []);           // Up
        mnuGoNext.Shortcut        := ShortCut(VK_DOWN, []);         // Down
        mnuGoLast.Shortcut        := ShortCut(VK_DOWN, [ssMeta]);   // Meta-Down    [ Command-Down on Windows ]
        mnuFileSave.Shortcut      := ShortCut(VK_S, [ssMeta]);      // Meta-S       [ Command-S on Windows ]
        mnuFilePrint.Shortcut     := ShortCut(VK_P, [ssCtrl]);      // Ctrl-P

Dialog and AboutBoxes are generally not modal

In the Windows environment, make the AboutBox appear modally, while on the Mac environment, do not:

        procedure TfrmMainGUI.mnuAboutClick(Sender: TObject);
          {$IFDEF DARWIN}
            if Assigned(frmAboutBox) then Exit;
            frmAboutBox := TfrmAboutBox.Create(Application);
            frmAboutBox := TfrmAboutBox.Create(Application);

In the About Box Form, conditionally compile for the Mac:

  • make the 'Close' button invisible (in the FormCreate procedure)
  • Unassign the frmAboutBox global variable (in the FormClose procedure)

    procedure TfrmAboutBox.FormClose(Sender: TObject; var CloseAction: TCloseAction
        CloseAction := caFree;
        frmAboutBox := nil;

    procedure TfrmAboutBox.FormCreate(Sender: TObject);
      // According to the Apple guidelines, About Boxes do not have a 'close' button

Location of configuration and other supporting files differ

I have not really got a handle on the location of support files on the Mac. Two websites were helpful:

The final conclusion, although not convincingly decisive, was to store the database in:

  • "C:\Documents and Settings\user\Local Settings\Application Data\vfitness" on Windows (XP)
  • "~/Library/vfitness" on the Mac
    function TfrmMainGUI.GetDBpath():string;
        {$ifdef Darwin}
            temp := '~/Library/vfitness';
            temp := GetAppConfigDir(False);
        Result := ExpandFileName(temp + '/vfitnessDB');

Invisible tabsheets cannot have controls created by code

Controls created by code cannot have as their parent an invisible tabsheet. A workaround is to remove the controls from the tabsheet before making the tabsheet invisible:

procedure TvAddEdit.RemoveParentFromAEcontrols;
  i: integer;
  for i := 0 to MaxFields do
  dteDate.Parent    := nil;
  lblDate.Parent    := nil;
  cmbCourses.Parent := nil;
  lblCourse.Parent  := nil;
  btnNew.Parent     := nil;
  btnGo.Parent      := nil;

procedure TvAddEdit.AddParentToAEcontrols;
  i: integer;
  for i := 0 to MaxFields do
  dteDate.Parent    := TabPage;
  lblDate.Parent    := TabPage;
  cmbCourses.Parent := TabPage;
  lblCourse.Parent  := TabPage;
  btnNew.Parent     := TabPage;
  btnGo.Parent      := TabPage;

TcomboBox onselect events are fired inconsistently

On the Mac, the onselect event in the TcomboBox is fired when setting the itemindex programmatically. It is not, in the Windows environment. The following code was added, after the itemindex is set. Note that 'cmbTableNamesSelect' is the name of my onselect procedure:

  {$ifdef windows}

Source Code

The second edition of the source code is available here, and some Data Files are available here. The Data Files need to be saved to ~/ where ~ maps to your library/vfitness on a Mac, and to your local appdata directory\vfitness v2\ on Windows.

The second edition has the following changes:

  • the header of the sorted column is highlighted in light olive green (sorting is performed by clicking on the header)
  • extensive filtering of the data is possible
  • there is something on the 'options' tab, but is very experimental at this stage
  • also on the 'options' tab is the ability to edit the underlying data tables, including:
    • hide tables and columns
    • reorder the tables and columns
    • change the default field to plot on the X and Y axes
    • change the name of the field as seen in the column header
    • note that there is an edit box to add a new field and table, but this has not been implemented yet
  • another graph type has been added...points (to go with the line and bar graph). Note that the 'mixed' option will mix a bar graph with the latest selected point or line graph. The 'points' graph type was added mainly because changing the field to plot on the X axis caused the line and bar graphs to look quite messy.
  • both grid lines for the left and right axes are possible
  • the colour to plot the graph may be changed by clicking on the coloured box in the legend
  • beware when deleting courses. Currently there is no checking to make sure that the course is not used in another table. The database has not been configured with constraints either.
  • there are some TODO's in mainGUI.pas

You may send me comments by clicking here and making the obvious changes to the address. Please keep the suggestions constructive, and try to avoid trolling. Complements will be gladly accepted.