Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



Share:
Notifications
Clear all

[Solved] Lazarus - MacOS X - How to "Open With" for files that open with your Application

1 Posts
1 Users
0 Reactions
2,943 Views
 Hans
(@hans)
Famed Member Admin
Joined: 12 years ago
Posts: 2860
Topic starter  

Sometimes you want to associate a file type with your application, so that a double click opens the given file in your application. This can be either by starting the application, or by opening the file in the application when it's already open.

So how do we do this for MacOS X with Lazarus Pascal?

There are 2 steps to this.

1) Make sure your Mac associates the file type with your application.

The is done in the so called Info.plist file in your application package. Right click your application and select "Show package content" to see what is in the package (a package is actually just a folder name that end with the ".app" extension and is displayed by MacOS X as if it's a single file).

In the "Contents" folder you will find the Info.plist file. You can open the file with a text editor - I recommend using TextWrangler. It's free in the AppStore.

In the Info.plist, you will find something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleDevelopmentRegion</key>
  <string>English</string>
  ... // Some lines removed for readability
  <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeRole</key>
      <string>Viewer</string>
      <key>CFBundleTypeOSTypes</key>
      <array>
        <string>fold</string>
        <string>disk</string>
        <string>*</string>
      </array>
    </dict>
  </array>
  <key>CFBundleIconFile</key>
  <string>icon.icns</string>
  <key>NSHighResolutionCapable</key>
  <true/>
</dict>
</plist>
<array>   

Now we need to add the file extension we'd like to associate with our application. In my example I use the extensions ".myextension".

We need to add a parameter called "CFBundleTypeExtensions", as show below, but make sure to add the file extension without the leading dot. More plist info can be found here.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleDevelopmentRegion</key>
  <string>English</string>
  ... /// Some lines removed for readability
  <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeRole</key>
      <string>Viewer</string>
      <key>CFBundleTypeExtensions</key>
      <array>
        <string>myextension</string>
      </array>
      <key>CFBundleTypeOSTypes</key>
      <array>
        <string>fold</string>
        <string>disk</string>
        <string>*</string>
      </array>
    </dict>
  </array>
  <key>CFBundleIconFile</key>
  <string>icon.icns</string>
  <key>NSHighResolutionCapable</key>
  <true/>
</dict>
</plist>
<array>  

Save the plist - we're done with this step.

2) Make sure you application actually opens the file when you Mac asks it to do so.

Back in the Turbo Pascal (and Delphi) days, we could use "ParamStr", but that simply does not work under MacOS X.

First we set the "AllowDropFiles" property of our mainform to TRUE.

Next we will need to drop a TApplicationProperties on our TForm (the main form), and set a procedure for the "OnDropFiles" event. This event will handle the passed filename(s).

In this procedure the filename(s) will be passed:

procedure TForm1.ApplicationProperties1DropFiles(Sender: TObject; const FileNames: array of String);
begin
  if Length(Filenames)>0 then
    begin
      LoadMyFile(Filenames[0]);
      // and do whatever is needed to handle the file
    end;
end;        

Here we check first if anything arrived, in my example I just assume 1 file, and load that file.
Keep in mind that Filenames can hold multiple files, so a for-loop might be better to handle multiple files.

After all this, the debugging will be a minor challenge. I had to copy the compiled app to the "Applications" folder for testing. Run it once without any extras. And later you'll see that the Finder either by default opens the file, or that you application is listed under the "Open with" option.

It took me a while to figure this out, so I figured, better post it here for future reference.


   
ReplyQuote
Share: