It is currently Thu May 23, 2013 11:44 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Howto register file extensions and open the files
PostPosted: Wed Sep 17, 2008 4:26 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 5:21 pm
Posts: 5188
Location: Germany
If you want to do one of these things with PB for OSX, then this post is for you:
- associate file extensions to open with your app on doubleclick
- associate an icon with your file extension
- allow files to be opened by draging them to your app icon

Step 1: code

Unlike on other OS, the files to open are not passed on the commandline but through events after the program has launched. This results in more code to catch these events than reading the commanline, but the positive point is that this way you receive a file event even when the user drags/doubleclicks a file after he started your program.

Here is the code to catch the event and extract the filenames:
Code:
;
; Receive the OpenDocument event on OSX
;

; Some required definitions
;
#eventNotHandledErr = -9874

#CoreEventClass = 'aevt'
#AEOpenDocuments = 'odoc'
 
#typeFSS = 'fss '
#typeAEList = 'list'
#typeFSRef = 'fsrf'
#keyDirectObject = '----'

#typeNull = 'null'
#noErr = 0

Structure FSRef
  hidden.b[80]
EndStructure

Structure AEDesc
  desctiptorType.l
  dataHandle.l
EndStructure

; ProcedureCDLL is important, for the right calling convention (on x86) and
; the correct callback behavior (therefore the DLL part)
;
ProcedureCDLL OpenDocument(*appleEvt, *reply, refcon)
 
  ; extract the event parameters
  If AECreateDesc_(#typeNull, 0, 0, @documents.AEDesc) = #noErr
    If AEGetParamDesc_(*appleEvt, #keyDirectObject, #typeAEList, @documents)  = #noErr
      If AECountItems_(@documents, @n) = 0

        *Buffer = AllocateMemory(1000)
        If *Buffer

          ; There can be multiple files sent
          For i = 1 To n
            If AEGetNthPtr_(@documents, i, #typeFSRef, @keyWd, @typeCd, @fileRef.FSRef, SizeOf(FSRef), @actualSize) = #noErr
              If FSRefMakePath_(@fileRef, *Buffer, 1000) = #noErr

                File$ = PeekS(*Buffer, -1, #PB_Ascii)
                ;
                ; If you want to accepte directories too, then change this
                ;
                If FileSize(File$) >= 0
                  ;
                  ; Here you have the filename to open
                  ;
                  AddGadgetItem(0, -1, File$)
                                   
                EndIf
               
              EndIf
            EndIf
          Next i
       
          FreeMemory(*Buffer)
        EndIf
       
      EndIf
    EndIf
    AEDisposeDesc_(@documents)
  EndIf
 
EndProcedure



If OpenWindow(0, 0, 0, 600, 300, "Open Document test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  ListViewGadget(0, 10, 10, 580, 280)
 
  ; Call this before processing the first window events, else you may miss the open event!
  ;
  If AEInstallEventHandler_(#CoreEventClass, #AEOpenDocuments, @OpenDocument(), 0, 0) <> #NoErr
    AddGadgetItem(0, -1, "cannot install event handler!")
  EndIf
 
  Repeat
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

End


If you run this, you will notice that you cannot drag any files to the application. That is because you need to tell finder what types of files you accept. This leads us to the next step...

Step 2: configuration

To tell finder about your file types, edit the "Info.plist" in your bundle directory.
- Compile the above code to a .app
- Select the .app in finder.
- Open the context-menu and select "Show package contents" (this will display the contents of the .app directory)
- Open the Info.plist file in the Contents folder as described below.

Note: The compiler overwrites this file on every compilation, so better save your modifications elsewhere and copy the file back after every new compilation. (You can also automate this by creating a small tool that is run after the executable is created)
Keep in mind that if you make some changes in the compiler options, you have to apply the resulting changes in the generated file also to your saved copy. (mainly the CFBundleExecutable and CFBundleIconFile keys)

Note2: The changes you make to the file may not immediately be seen by the finder. Especially if you previously executed the program with different settings. It sometimes helps to create the .app in a new location or copying the .app to a different folder for finder to notice the changes. In some cases only a restart will make the changes take effect. (happened to me with setting an icon for the files)

An example first:
This is what we add to the Info.plist for the IDE (it goes into the main <dict> tag)
Code:
  <key>CFBundleDocumentTypes</key>
  <array>
    <dict>
      <key>CFBundleTypeExtensions</key>
      <array>
        <string>pb</string>
        <string>pbi</string>
      </array>
      <key>CFBundleTypeIconFile</key>
      <string>FileIcon.icns</string>
      <key>CFBundleTypeName</key>
      <string>PureBasic Sourcecode</string>
      <key>CFBundleTypeRole</key>
      <string>Editor</string>
    </dict>
  </array>


Another example:
Use this if you just want any file to be dragable to your application icon, but no specific filetype to be registered:
Code:
   <key>CFBundleDocumentTypes</key>
   <array>
      <dict>
         <key>CFBundleTypeExtensions</key>
         <array>
            <string>*</string>
         </array>
         <key>CFBundleTypeRole</key>
         <string>Editor</string>
      </dict>
  </array>


- As you can see you can have multiple extensions in the CFBundleTypeExtensions array
- You can also have multiple versions of the entre <dict> part, to associate different extensions with different icons for example
- You need to specify atleast the CFBundleTypeExtensions and CFBundleTypeRole parts, the rest is optional

Here is a short description of the fields:

CFBundleTypeExtensions (required)
Specifies the list of file extensions. The <array> is needed, even if there is only on extension.
To make this setting apply for all types (for example if you want any file to be droppable to your app icon), use a "*".

CFBundleTypeIconFile
Here you can set an icon file for these file extensions. The icon must be copied to the Contents/Resources folder of the .app

CFBundleTypeName
Set a name to describe your file type here.

CFBundleTypeRole (required)
Specify what your application does with the type. Values can be "Editor", "Viewer", "Shell" or "None".

All available keys for the Info.plist are explained in detail here:
http://developer.apple.com/documentatio ... tKeys.html

There are some other keys that may be of intrest to you, like the CFBundleGetInfoString one, which allows to set a string that can be seen when the user selects "Get Info" for your .app.

_________________
Perl – The only language that looks the same before and after RSA encryption.
-- Keith Bostic


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 7:24 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 849
Location: Seattle, USA
I'm trying your example and it works fine but I have a question about icons.

How do I create icons?

[later after going to the Apple site]

This is what Apple says: (explains how icons are made in a drawing program - .png)

http://developer.apple.com/documentatio ... ion_8.html

Then Icon Composer... (how to take your drawing and make it an icon)

http://developer.apple.com/documentatio ... ion_5.html

_________________
MacBook Pro/Retina, OSX 10.8.3 Mountain Lion, PB-5.11x64


Last edited by WilliamL on Fri Jan 09, 2009 9:22 pm, edited 3 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 8:17 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 5:21 pm
Posts: 5188
Location: Germany
Just make differently sized png files with the tool of your choise and then use the icon composer (comes with the development tools, see your link) to put them together into a .icns file.

_________________
Perl – The only language that looks the same before and after RSA encryption.
-- Keith Bostic


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 8:29 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 849
Location: Seattle, USA
Yeah, it works!

The process of the mask and all is explained in the first of my links but the mask doesn't seem to do anything. I did discover that the icons have to be put in a Resources folder in the Contents folder. Also that the Info.plist can be copied at the same location as the original plist and then the copy can be used to replace the new plist when re-compiling (is that clear?).

At first it seems very intimidating but after reading my second link about Icon Composer it was very simple. Certainly easier than using resources!

It does take awhile (by logging-out/re-starting/phases of the moon) for the new icons to appear.

_________________
MacBook Pro/Retina, OSX 10.8.3 Mountain Lion, PB-5.11x64


Last edited by WilliamL on Fri Jan 09, 2009 9:28 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 03, 2009 10:44 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 849
Location: Seattle, USA
ok, question, how do I make the 'hit mask' (or just the 'mask')? All I get is a black box when I view the Masks in Icon Composer.

[later] Oh, I see, the background of the icon has to be transparent.

The app icon can be changed using:

<key>CFBundleIconFile</key>
<string>AppIcon.icns</string>

PLists are a whole topic by themselves.

_________________
MacBook Pro/Retina, OSX 10.8.3 Mountain Lion, PB-5.11x64


Last edited by WilliamL on Fri Jan 09, 2009 9:21 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 09, 2009 9:20 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Aug 04, 2008 10:56 pm
Posts: 849
Location: Seattle, USA
The only reservation I have about using the normal three letter extensions(ie .txt) for identifying files is that I don't know what extensions have already been used. Using only three letters (the norm) really limits how many combinations are available. If I want to use .stx, how will I know if it is already used? I wonder if it would be useful to use four character extensions (ie .aiff) for my programs since 4 letter extensions are seldom used. I suppose if the extension is only used on my computer then I could use any length extension (or is there a limit?).

Any thoughts?

_________________
MacBook Pro/Retina, OSX 10.8.3 Mountain Lion, PB-5.11x64


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye