# OPL applications

## Contents

- Defining an application
- Running the application
- How the EPOC device talks to an application
- System screen compliance
- Launching help files
- Example applications
- When an application cannot respond

You can make an OPL program appear as an icon in the system screen, and behave like the other icons there, by converting it into an OPL application.

There are two settings for applications which are set using the FLAGS command:

- `FLAGS 1` is used if your application can create files. It will then be included in the list of applications offered when the user creates a new file from the System screen (like Program, Word etc.).
- `FLAGS 2` prevents the application from appearing in the Extras bar in the System screen. It is very unusual to have this flag set.

Once created, OPL applications may be used in the same way as the built in applications: new document files may be created from the System screen using ‘`New File`’ if the flag 1 is set and/or from the Extras bar if the flag 2 is not set. Existing files may be opened by selecting them on the System screen as usual. You can stop a running app by using the Task list.

## Defining an application

To make an application, your OPL file should begin with the `APP` keyword, followed by a name for the app in the machine’s default language and its UID. The name may be up to 250 characters. (Note that it does not have quote marks.) If the `CAPTION` command is used, however, this default name will be discarded (see below).

The UID specifies the UID of the application. For applications that are to be distributed, UIDs are reserved by contacting Symbian. These official UIDs are guaranteed to be unique to the application and have values of `&10000000` and above. To obtain a reserved UID you should contact Symbian in one of the following ways:

- e-mail to uid_ew@symbian.com
- or use the EPOC World web site, http://developer.epocworld.com/
- or write to UID Allocations, Symbian Ltd, 17 Harcourt St, London W1N 1DT, England

For applications developed for personal use there is no need to reserve official UIDs, and any UID between `&01000000` and `&0fffffff` may be selected. However, if the UIDs of two different applications did clash, then either your application’s documents will have the wrong icon and selecting these will run the other application, or the other application’s documents will seem to belong to your application.

The `APP` line may be followed by any or all of the keywords `CAPTION`, `ICON` and `FLAGS`. Finally, use `ENDA`, and then the first procedure may begin as in a normal OPL file. Here is an example of how an app might start:

        APP Expenses,&20000000    REM !!! Should be a reserved UID !!!
              FLAGS 1
              ICON "icon.mbm"
              CAPTION "Expenses",1        REM English name
              CAPTION "Expenses",10       REM American name
        ENDA

Here is another example:

        APP Picture,&30000000     REM !!! Should be a reserved UID !!!
              FLAGS 2
              ICON "picicon.mbm"
        ENDA

`FLAGS` takes an integer argument of 1 or 2. The meanings of these are outlined above. If you don’t specify the flags, none are set.

`ICON` gives the name of a multi-bitmap file (MBM), also known as an EPOC Picture file, which contains the icons for an OPL application. These icons are used on the Extras bar and for the application’s documents on the System screen. The multi-bitmap file can contain up to three bitmaps of sizes 2424, 3232 and 4848 pixels respectively, but each must be paired with a mask. Each bitmap should be followed by its mask in the multi-bitmap file, so that bitmaps and masks occur alternately. The pixels which are set in the mask specify pixels in the bitmap which are to be used. Pixels which are clear in the mask specify pixels that are not to be used from the bitmap, allowing the background to be displayed in these pixels. Only pixels which are set in the mask are drawn in the final icon.

The different sizes of bitmaps are used for the different zoom levels in the System screen. The sizes are read from the MBM and the most suitable size is zoomed if the exact sizes required are not provided or if some are missing.

You can use `ICON` more than once within the `APP`...`ENDA` construct. The translator only insists that all icons are paired with a mask of the same size in the final `ICON` list. This allows you to use MBMs containing just one bitmap, as produced by the Sketch application. Icons may also be created on a PC (if the appropriate tools are available), or of course by another OPL program or application.

`CAPTION` specifies an application’s public name (or caption) for a particular language, which is the name which will appear below its icon on the Extras bar and in the list of ‘`Programs`’ in the ‘`New File`’ dialog (assuming the setting of `FLAGS` allows these) when that is the language used by the machine. This name is also used as the default document name for documents launched using the Extras bar. The maximum length of the caption is 255 characters. However, note that a caption no longer than around 8 letters will look best on the Extras bar. If any `CAPTION` statement is included in the `APP`…`ENDA` structure, then the default caption provided by the `APP` declaration will be discarded. Therefore as many statements of `CAPTION` as are necessary to cover all the languages required, including the language of the machine on which the application is originally developed, should be used. The constants for the language codes are supplied in `Const.oph`. See Including header files.

Applications can declare themselves capable of handling files of a particular MIME content type. See OPL and MIME for more information on this.

On creation of an application, a folder specifically for the application is also created. For example, if the application has the name `AppXxx` the folder created will be `\System\Apps\AppXxx\`. The `.app` file itself (the translated OPL module) and the application information file (AIF) which contains three icon and mask pairs and the application caption and flags, are created in this folder. For example, the AIF for `AppXxx.app` would be `\System\Apps\AppXxx\AppXxx.aif`. The AIF file will be generated based on all the information contained in the `APP`…`ENDA` construct, but if any information is missing defaults will be used. These are:

- for `ICON`: the default (question mark) icons
- for `CAPTION`: the caption specified in the `APP` declaration
- for `FLAGS`: the default value of 0.

The arguments to any of the keywords between `APP` and `ENDA` must be constants and not expressions.

## Running the application

Once you’ve successfully translated the OPL file, the applications icon will automatically appear on the Extras bar and/or on the ‘`Program’` list in the ‘`New File`’ dialog (as specified by the `FLAGS` setting). The new documents of the application may then be created and existing ones opened as with other EPOC applications.

The first thing a file-based application should do is to get the name of the file to use, and check whether it is meant to create it or open it. `CMD$(2)` returns the full name of the file to use; `CMD$(3)` returns ‘C’ for `Create`, ‘O’ for `Open`, ‘R’ for `Run` or ‘X’ for `Exit`.

All document-based apps should handle all of these cases; for example, if a `Create` fails because the file exists already, or an `Open` fails because it does not, OPL raises the error, and the application should take suitable action. Note however, that in general the System screen will not allow such events to occur and therefore they are unlikely to happen.

‘R’ means that your application has been run from the OPL Program editor or has been selected via the application’s icon on the Extras bar, and not by the selection or creation of one of its documents from the system screen. A default filename, including path, is passed in `CMD$(2)`. When ‘R’ is passed, an application should always try to open the last-used document. This is the document that was in use when the application was last closed, not the document that was most recently opened. The name of this document should be stored in a `.ini` file with the same name and in the same folder as your application but always on drive `C:`. So for example, `AppXxx.app` would have `.ini` file `C:\System\Apps\AppXxx\AppXxx.ini`. If the `.ini` file does not exist or cannot be opened for any reason, or if the document listed there no longer exists, you should create the document named in `CMD$(2)`. `CMD$(2)` is a default name provided by the System based on your application’s caption. If the `.ini` file is corrupt it should be deleted before going on to create `CMD$(2)`. No error message should be displayed in this case.

Constants for the array indices of `CMD$` and the return values of `CMD$(3)` are supplied in `Const.oph` (see Including header files).

## How the EPOC device talks to an application

When the EPOC device wants an app to exit or to switch files, it sends it a System message, in the form of an event. For example, this would happen if the ‘`Close file`’ option in the Task list were used to stop a running app.

`TESTEVENT` and `GETEVENT32` (synchronous) and `GETEVENTA32` (asynchronous) check for certain events, including both keypresses and System messages. All types of application must use these keywords to check for both keypresses and System messages; keyboard commands such as `GET`, `KEY` and `KEYA` cause other events to be discarded.

`GETEVENT32` waits for an event whereas `TESTEVENT` simply checks whether an event has occurred without getting it. If `TESTEVENT` returns non-zero, an event has occurred, and can be read with `GETEVENT32`. However, it is recommended that you use either `GETEVENT32` or `GETEVENTA32` without `TESTEVENT` as the machine will switch off only when waiting on an event. If the program just runs around a loop using `TESTEVENT` to decide when there is something to do, it will simply consume the battery power for no purpose. `GETEVENT32` may be used if you only wish to pick up window server events, but otherwise you should use the asynchronous `GETEVENTA32` together with any other asynchronous requests which you require. `TESTEVENT` should generally only be used when polling while doing something else in background.

`GETEVENT32` and `GETEVENTA32` both take one argument: the name of a long integer array, for example, `GETEVENT32 ev&()`. The array should contain at least 16 long integers.

For example, if the event is a keypress `(ev&(1) AND &400) = 0` and,

- `ev&(1)` = keycode (as for `GET`)
- `ev&(2)` = time stamp (gives the time of the keypress)
- `ev&(3)` = scan code (locates the key on the keyboard)
- `ev&(4)` = modifier code (e.g. Shift, Control)
- `ev&(5)` = repeat. Note that this is strictly the repeat value, i.e. if there is only one keypress, then the value of `ev&(5)` is 0.

For non-key events `(ev&(1) AND &400)` will be non-zero. On the EPOC platforms with a pen, these include pointer events. For an application, it may be suitable to filter out certain pointer events. This may be done using the `POINTERFILTER` command. `POINTERFILTER` takes two arguments: a filter and a mask. Each of the bits in these two arguments represents a certain pointer event, allowing a flag to be set to say whether that event should be filtered out. The bits which are set in the mask specify bits in the filter which are to be used. Bits which are clear in the mask specify bits that are not to be used from the filter. This makes it possible to filter out some pointer events, filter back in some others and leave the settings of some alone all in one call to `POINTERFILTER`. To set or clear flags you would set and clear them in the filter and set all the flags that require changing in the mask. To leave some bits in the filter alone just don’t set the bits in the mask. See the Keyword Reference for more details of `POINTERFILTER` and the values returned to `ev&()` by `GETEVENT32` and `GETEVENTA32`.

If the event is a System message to change files or quit, `ev&(1)=&404`. You should then use `GETCMD$` to find the action required.

`GETCMD$` returns a string, whose first character is "C", "O" or "X".

You can only call `GETCMD$` once for each event. You should do so as soon as possible after reading the event. Assign the value returned by `GETCMD$` to a string variable so that you can extract its components.

If you have `c$=GETCMD$`, the first character, which you can extract with `LEFT$(c$,1)`, has the following meaning:

- "C" - close the current document, and create the specified new file.
- "O" - close the current document, and open the specified existing file.
- "X" - save the name of the current document (if any) to the `.INI` file, close the current document and quit the app.

Again with `c$=GETCMD$`, `MID$(c$,2,255)` is the easiest way to extract the filename.

Note that events are ignored while you are using keywords which pause the execution of the program `GET`, `GET$`, `EDIT`, `INPUT`, `PAUSE`, `MENU` and `DIALOG`. If you need to use these keywords, use `LOCK ON` / `LOCK OFF` (described later) around them to prevent the System screen from sending messages.

## System screen compliance

A well-behaved application should obey the following important guidelines:

- All applications should respond in the standard way to the initial command-line and to any System screen messages to switch files. See How the EPOC device talks to an application, above.
- All applications should support a toolbar. `Toolbar.opo` is supplied in the ROM and provides the set of procedures required for this support. See Toolbars.
- All applications should save non-document files (external files) to their so-called application directory.

You can find out the full file specification of external files by using `PARSE$`. For example, in:

              p$=PARSE$("NEW",LEFT$(CMD$(1),LEN(CMD$(1)-4),x%())

`CMD$(1)` gives the device and the path of the OPL application and the name of the file.

By default the system screen hides the System folder and its subfolders. Use the ‘`Preferences’` option in the ‘`Tools’` menu of the System screen and check the checkboxes for both ‘Show hidden files’ and ‘Show ‘System’ folder’ to show all applications and their files.

- The `FLAGS` keyword in the `APP`...`ENDA` construct should have the value 1 if the application supports documents. Without this flag the application will not be listed when the user chooses to create a new file from the System screen (see sections above).
- You should set `ESCAPE OFF` so that it is impossible for the user to stop the application running by hitting Ctrl+Esc.

## Launching help files

It is possible to write your own Help for your own application, which should be created in the Data application. The file should be similar to the built-in help, using two labels only for each entry to give a title and the explanation itself. The file should be stored in the application’s folder with the filename extension `.hlp`. The procedure `RunApp&:` in `System.opx` (see About OPXs for more details) may then be used to launch Data and open the application help file. For example, if you want to run a help file called `Myapp.hlp`, the help file for your own application called `Myapp`, you should use:

        drv$=LEFT$(CMD$(1),2)
        RunApp&:("Data",drv$+"\System\Apps\Myapp\Myapp.hlp","",0)

You should make it possible for users of your application to launched your help file from the application’s menus. Following the EPOC Style Guide, the ‘`Help’` item should appear on the ‘`Tools’` menu at the bottom of the section above ‘`Infrared’`, so it will be followed by a separating line. The shortcut key should be Ctrl+Shift+H.

Only one copy of the help file should be shown at a time, and the help file should be closed when the application exits. This can be done by creating a global variable called `Help_Thread&` in the program’s main procedure, and by calling the `Help:` procedure below to display the help file:

        PROC Help:
              IF EXIST(MyHelpFile$)
                    IF Help_Thread&<>0   REM Is Data running?
                          ONERR NoLongerOpen::
                          SetForegroundByThread&:(Help_Thread&,0)
                          REM Switch Data to fore
                    ELSE
                          NoLongerOpen::
                          ONERR OFF
                          Help_Thread&=RunApp&:("Data",MyHelpFile$,"",0)
                          REM Start Data and record its thread ID.
                    ENDIF
              ELSE
                    GIPRINT "Help not found", KBusyTopRight%
              ENDIF
        ENDP

This `Exit:` procedure should then be called when your program shuts down (either when the user selects "Close" or Ctrl+E, or when it receives a message from the System to close, as for in example the case of a backup — these different events should be trapped in your main event loop):

        PROC Exit:
              ONERR HelpClosed::
              IF Help_Thread&<>0
                    EndTask&:(Help_Thread&,0)
              ENDIF
              HelpClosed::
              ONERR OFF
              STOP
        ENDP

## Example applications

Here is an application which just prints the keys you press. It is not a document-based application (like `Calc`, but unlike `Word` which is document-based) so it uses `FLAGS 0`. The keyboard procedure `getk&:` returns the key pressed, as with `GET`, but jumps to a procedure `endit:` if a System message to close down is received. (apps with flags set to 0 do not receive "change file" messages.)

        CONST KUidAppMyApp0&=&40000000
                                            REM !!! Should be a reserved UID!!!
        APP myapp0,KUidAppMyApp0&
              CAPTION "Get Key",1
              ICON "myapp0.mbm"
        ENDA

        PROC start:
              GLOBAL a&(10),k&
              FONT 11,16
              PRINT "Q to Quit"
              PRINT " or select ‘Close file’"
              PRINT " from the Task List"
              DO
                    k&=getk&:
                    PRINT CHR$(k&);
              UNTIL (k& AND &ffdf)=%Q            REM Quick way to do uppercase
        ENDP

        PROC getk&:
              DO
                    GETEVENT32 a&()
                    IF a&(1)=&404
                          IF LEFT$(GETCMD$,1)="X"
                                endit:
                          ENDIF
                    ENDIF
              UNTIL a&(1)<256
              RETURN a&(1)
        ENDP

        PROC endit:
              STOP
        ENDP

Here is a similar document-based application It does the same as the previous example, but System messages to change files cause the procedure `fset:` to be called. The relevant files are opened or created. A proper application with a toolbar would call `TBarSetTitle:` to change its title. See Friendlier interaction.

        CONST KUidAppMyApp1&=&50000000
                                      REM !!! Should be a reserved UID!!!
        APP myapp1,KUidAppMyApp1&
              FLAGS 1
              CAPTION "Get Key Doc",1
              ICON "myapp1.mbm"
        ENDA

        PROC start:
              GLOBAL a&(10),k&,w$(255)
              FONT 11,16 :w$=CMD$(2)
              fset:(CMD$(3))
              PRINT "Q to Quit"
              PRINT "use the Task list"
              PRINT "to create/switch files"
              DO
                    k&=getk&:
                    PRINT CHR$(k&);
              UNTIL (k& AND &ffdf)=%Q
        ENDP

        PROC getk&:
              LOCAL t$(1)
              DO
                    GETEVENT32 a&()
                    IF a&(1)=$404
                          w$=GETCMD$
                          t$=LEFT$(w$,1)
                          w$=MID$(w$,2,255)
                          IF t$="X"
                                endit:
                          ELSEIF t$="C" OR t$="O"
                                TRAP CLOSE
                                IF ERR
                                      GIPRINT ERR$(ERR)
                                      CONTINUE
                                ENDIF
                                fset:(t$)
                          ENDIF
                    ENDIF
              UNTIL a&(1)<256
              RETURN a&(1)
        ENDP

        PROC fset:(t$)
              LOCAL p&(6)
              IF t$="C"
                    TRAP DELETE w$
                    SETDOC w$
                    TRAP CREATE w$,A,A$
              ELSEIF t$="O"
                    SETDOC w$
                    TRAP OPEN w$,A,A$
              ENDIF
              IF ERR
                    CLS :PRINT ERR$(ERR)
                    REM should revert to old file if possible
                    GET :STOP
              ENDIF
        ENDP

        PROC endit:
              STOP
        ENDP

You should, as in both these examples, be precise in checking for the System message; if in future the `GETCMD$` function were to use values other than "C", "O" or "X", these procedures would ignore them.

If you need to check the modifier keys for the returned keypress, use `a&(4)` instead of `KMOD`.

`SETDOC` called just before the creation of the file ensures that the created file is a document, i.e. that the file launches its associated application when selected. The strings passed to `SETDOC` and `CREATE` (or `gSAVEBIT`) should be exactly the same, otherwise a non-document file will be created. `SETDOC` should also be called when opening a document to allow the System screen to display the correct document name in its task list. OPL explicitly supports database and multi-bitmap files as documents.

To be strict, whenever creating a file, an application should first use `PARSE$` to find the disk and directory requested. It should then use `TRAP MKDIR` to ensure that the directory exists.

## When an application cannot respond

The `LOCK` command marks an app as locked or unlocked. When an app is locked with `LOCK ON`, the System will not send it events to change files or quit. If, for example, you attempt to close down the app from the Task list, a message will appear, indicating that the app cannot close down at that moment.

You should use `LOCK ON` if your app uses a keyword such as `MENU`, `DIALOG` and `EDIT` which pauses the execution of the program. You might also use it when the app is about to go busy for a considerable length of time, or at any other point where a clean exit is not possible. Do not forget to use `LOCK OFF` as soon as possible afterwards.

An application is initially unlocked.