starttimer
starttimer
NAME
,
PROPERTY
,
VALUE

The starttimer statement sets up and starts a repeating task that will be performed periodically when Panorama is not otherwise busy.

Parameters

This statement has three parameters:

name – specifies a name for this periodic task. The name must be unique. If the task is specific to a database or a window, we recommend using a heirarchical name in the format task_database_window, for example StopWatch_Races_100m

property – a timer property. Each timer has properties including the task to be run, the interval, etc. See below for detailed descriptions of the different timer properties available. Properties can be specified in either upper or lower case, for example INTERVAL or interval.

value – the new value for the property specified by the previous parameter.

Description

This statement sets up and starts a repeating task that will be performed periodically when Panorama is not otherwise busy. For example, this code will update the elapsedtime variable every second.

    starttimer "stopwatch","code",{elapsedtime=now()-starttime showvariables elapsedtime}

If you later wanted to stop this timer, you would use this code:

    stoptimer "stopwatch"

You can set up multiple timers for different tasks. Each timer works independently, so that timers don’t interfere with each other. Panorama schedules timer tasks very efficiently – for example if there are no timer tasks that need to run for the next 5 minutes, Panorama will not expend any resources on timer tasks until the 5 minutes are up. Whenever a timer task finishes running, Panorama checks to see when the next timer task needs to run, and the timer system will be completely dormant until then. Note: Timers will continue running even if Panorama is not the frontmost application.

### Timer Properties

Each timer has multiple properties – how often the timer runs, what code is used to perform the timer’s task, whether or not the timer runs in the background, etc. Wnen you start a timer, you can specify all the properties you need, like this:

    starttimer name,property1,value1,property2,value2,property3,value3

Most properties have a default value – for example the default interval is one second. The one property you must set up is the `CODE`.

#### Code

Use this property to define the code that will run the repeating task. This property is text, so you’ll need to quote the entire thing with alternate quote characters, for example brackets or pipes.

    starttimer "stopwatch","code",{elapsedtime=now()-starttime showvariables elapsedtime}

You use any kind of code to perform a task, but you should keep the code as minimal as possible. If the code takes too long to run, it could interfere with normal Panorama usage. You normally wouldn’t want the timer code to do anything that affects the user’s use of Panorama. For example, it’s usually not a good idea to have a window suddenly open or close for no apparent reason.

By default, you cannot rely on Panorama being in a certain state when the task begins. For example, you should not rely on a particular window or database being active when the timer runs (there are some exceptions, see the scope and background properties below). It’s even possible to set up a timer that will keep running even if the database that started it has closed.

#### Interval

This property specifies how often the timer task will be performed. For example, this procedure sets up a timer that checks email every 15 minutes.

    starttimer "checkemail","interval",15*60,"code",{farcall myemail,check}

If the interval is not specified, it defaults to once per second.

Note: The interval is the minimum interval, but the timer is not guaranteed to run that often. If Panorama is busy doing something else, the timer will not run. Panorama will run the timer as soon as possible after the interval has passed, but it will not “make up” timer runs. For example, suppose you have a timer with an interval of one second, but Panorama performs some task that keeps it busy for five seconds. After the five second task is complete Panorama will run the timer task as soon as possible, but it will not make up the four times that it was unable to run the timer task.

#### Next

A timer task normally starts running right away, but this property allows you to delay a task until a specified time. The parameter is a superdate that specifies when the task should start running. This example will display a message 5 minutes from now. (The repeat property prevents the message from appearing more than once.

    starttimer "alarm","next",supernow()+5*60,"code",{message "it's time to leave!"},"repeat",1

You can delay the task far into the future (for example next tuesday at 3pm), but of course Panorama must still be running.

#### Repeat

Timers normally keep repeating indefinitely. You can use the stoptimer statement to stop a timer, and you can also set up a timer so that it stops automatically when the database or window is associated with it closes, but you can also set up a timer so that it only repeats a fixed number of times and then stops itself. This code counts down – 3, 2, 1.

    fileglobal countDown
    countDown=3
    showvariables countDown
    starttimer "count","repeat",2,"code",{countdown=countdown-1 showvariables countDown}

This example will always count down to 1. It’s possible that it might take more than 3 seconds to count down, but the count down will always finish before the timer stops itself.

#### Scope

Timers operate in one of three different scopes: global, database, and window.

Database is the default scope. This means that the timer is attached to the database that was current when the timer was started. If the database is closed, the timer stops and is deleted. If the database is not the current database, the timer pauses (unless the background property is enabled, see below).

If a timer is operating using window scope, that means the timer is attached to the window that was current when the timer was started. If the window is closed, the timer stops and is deleted. If the window is not the current window, the timer pauses (unless the background property is enabled, see below).

If a timer is operating using global scope, the timer is not attached to any database or window. The timer will keep running until Panorama quits or until you explicitly stop it. Be careful when writing the code for global timers – you can make absolutely no assumptions about what database or window is open and frontmost (if any) when the timer runs.

This example checks a web page once per minute. It will keep running once per minute as long as Panorama is running.

    global ticklepage
    starttimer "tickle","scope","global","interval",60,"code",
        {ticklepage=loadurl("http://www.someserver/tickle")}

#### Background

When a timer is operating in either database or window scope, the timer normally won’t run when the database or window is not the active database or window. However, if the background property is true, the timer will always run, even when some other database or window is active. Before running the timer task, Panorama will automatically set up a secret window for the database associated with the timer.

In this example, the timer uses database scope because that is the default. Once every 5 minutes, the timer will add a record to the database and log some data collected from a USB device (the technique for doing that is left to the reader!).

    starttimer "datacollection","background","yes","interval",5*60,"code",
        {addrecord call grabDataFromUSBDevice}

This timer will continue collecting data even when some other database is active – the database that is collecting data could even be invisible with all windows closed!

#### Suspend

This property allows you to set up a timer but leave it dormant.

    starttimer "datacollection","background","yes","interval",5*60,"suspend","yes",
        "code",{addrecord call grabDataFromUSBDevice}

Later you can use the changetimer statement to start collecting data.

    changetimer "datacollection","suspend","no"

You can use the changetimer statement over and over again to turn the timer on and off.

#### Error

If an error occurs while a timer is running, the timer is stopped and a notification is displayed in Notification Center. Use this parameter to change the notification option. The available options are notify, alert and console. Notify, the default, displays the error message in Notification Center. The Alert option stops and displays an alert with the error message. The Console option doesn’t display any visible message, but outputs the error to the system log. You can use Apple’s Console application (in the Application/Utilities folder) to view this log. This example shows how to send timer error messages to the console.

    starttimer ...,"error","console"

#### ContinueAfterError

If you don’t want the timer to stop if an error is encountered, set this option to “true” or “yes”. However, a better approach is to handle the error yourself with if error or try/catch (see Error Handling). If you handle the error yourself, the timer will not stop. (Note: You should not use onerror in a timer procedure.)

#### Password

Normally there is nothing to prevent any program from stopping, suspending, or modifying a running timer. If your timer performs a critical function, you may wish to lock it down with a password. If provided, the password option must be the last option (if it is not the last option, any options after it will not work because the timer is already locked). This example shows a timer being created with the password my secret.

    starttimer "My Timer",...,"password","my secret"

A timer that is locked with a password

- Cannot be modified, suspended or stopped without supplying the password.
- Normally won’t be listed by the info(“timers”) function (this can be overriden by a setting in the Advanced panel of the Preferences dialog).
- Won’t have its source code listed by the timerinfo( or info(“timerinfo”) functions.

A locked timer can’t be stopped by another program, but it can still stop normally based on the rules used to set it up. For example, if the timer is configured with a database scope, the timer will stop when the database closes, whether it is locked or not.

A locked timer can be unlocked by using the `"unlock"` option with the changetimer statement. If the unlock password is incorrect, this code will fail with an error (see Error Handling).

    changetimer "My Timer","unlock","my secret"

Once the timer is unlocked, it will remain unlocked. You can lock it again by using the `"unlock"` option again, but with an empty parameter. This example unlocks the timer, suspends it, then locks it again:

    changetimer "My Timer",
        "unlock","my secret",
        "suspend","yes",
        "unlock",""

Note: You don’t have to re-lock the timer, you can leave it unlocked if you like (as long as you know the password).

Here is code to stop a locked timer:

    changetimer "My Timer","unlock","my secret"
    stoptimer "My Timer"

You can use the timerinfo( function to check whether a timer is currently locked or not, like this:

    if getdictionaryvalue(timerinfo("My Timer"),"Locked")
        // timer is locked
        // do something
    endif

Note: You can’t tell the difference between a timer with no password and a timer that has a password that has been unlocked. Both will return the same result.

See Also

- Automatic Field Code -- running a short program when data is entered into a field.
- changetimer -- modifies a repeating task that will be performed periodically when Panorama is not otherwise busy.
- endnoshow -- resumes the output of text and graphics after it has been disabled with the noshow statement.
- executeasap -- executes the specified code at the first possible opportunity, non-atomically.
- Implicitly Triggered Procedures -- Procedures that are triggered automatically when the user performs some normal Panorama action are said to be "implicitly triggered."
- info("computername") -- returns the name of the computer (as set up in the System Preferences Sharing panel).
- info("noshow") -- returns true if noshow is currently turned on, false if it is not.
- info("runningatomic") -- returns true if the current procedure is running as a "atomic" procedure.
- info("timerinfo") -- returns a dictionary that contains all of the properties of the currently running timer.
- info("timers") -- returns a carriage return separated list of all active timers.
- noshow -- temporarily disables the output of text and graphics.
- resumeaftertask -- resumes after a waitfortask statement.
- setwaitinglocal -- assigns a value to a local variable in the parent procedure of an asynchronous task, allowing the asynchronouse code to pass a value back to the code that spawned it.
- stoptimer -- stops and deletes a timer that was set up with the StartTimer statement.
- Timer Workshop -- provides a tool for monitoring timers and testing timer configurations.
- timerexists( -- checks to see whether a timer exists.
- timerinfo( -- returns a dictionary that contains all of the properties of a timer.
- Timers -- executing recurring periodic background code at fixed intervals.
- Understanding the Run Loop -- explanation of how Panorama code interacts with the run loop to respond to mouse clicks, keyboard presses, display updates and other events that require attention.
- wait -- pauses the program for a specified period of time.
- waitfortask -- temporarily pauses a procedure until the specified task is complete.

History

Version | Status | Notes
10.2 | Updated | Timers can now be protected with a password.
10.0 | New | New in this version. Replaces the ExecuteEverySecond, ExecuteEveryMinute, and ExecuteEveryHour features in earlier versions of Panorama.