I could have swore I’ve seen this discussed before, but I’ve searched and searched and I can’t find it mentioned. So I apologize if it does exist somewhere I’ve missed.
I’m creating a stay open app that I will be using as a script library containing handlers I will call from other scripts. However, if I go for a specified period of time (let’s say 5 minutes) without calling it, I’d like for it to quit. This is what I have so far, but I’m not sure if this is the most efficient way to do it. I would greatly appreciate it if someone could take a look at the code and let me know if there is a “standard” or better way to accomplish this.
global idleLoopCount
on run
set idleLoopCount to 0
end run
on idle
set idleLoopCount to idleLoopCount + 1
if idleLoopCount = 2 then tell me to quit
return 300
end idle
on doSomething()
display dialog "foo"
tell me to run
end doSomething
on doSomethingElse()
display dialog "bar"
tell me to run
end doSomethingElse
Thanks!
Brett
Model: MacBook Pro 1.8GHz Core Duo
AppleScript: 1.10.7
Browser: Firefox 1.5.0.7
Operating System: Mac OS X (10.4)
As is, your app won’t “know” if it was used or not. You need to add something to each subroutine that tells that app that it was used. Something like this:
global time_stamp
--
on run
set time_stamp to (current date)
end run
--
on idle
set cur_date to (current date)
if (cur_date - time_stamp) > 1 * minutes then quit
return 2
end idle
--
on DoSomething()
set time_stamp to (current date)
-- do something
activate
display dialog "Hello" default answer "Hello"
return (text returned of result)
end DoSomething
I haven’t tested this, but I think it’s the sort of thing you want. The lastCalled property holds the time the script was last called and it’s the responsibility of each main handler in your library to update the time when it’s called. The system calls the idle handler every minute or so to see how long ago the last call was.
property lastCalled : missing value
on run
set lastCalled to (current date)
end run
on idle
if ((current date) - lastCalled > 5 * minutes) then
quit -- Tell this application to quit when finished.
error number -128 -- Finish now.
end if
return 60 -- Check again in 60 seconds.
end idle
on doSomething()
display dialog "foo"
set lastCalled to (current date)
end doSomething
Another way might be to add a subroutine to update the time last used. Something like this:
global time_stamp
--
on run
set time_stamp to (current date)
end run
--
on idle
set cur_date to (current date)
if (cur_date - time_stamp) > 1 * minutes then quit
return 2
end idle
--
on UpdateTime()
set time_stamp to (current date)
return true
end UpdateTime
--
on DoSomething()
-- do something
activate
display dialog "Hello" default answer "Hello"
return (text returned of result)
end DoSomething
When you call some subroutine you update the time first.
I do have a couple of questions about how a stay open script with idle handler runs. I know the first time it is launched, it process anything in the run block ,then goes through the idle handler once, then proceeds to “idle” for the given time.
Now if I call a some handler it contains, does it run anything besides that handler? Does it re-run the run handler when it finished the initial call? Does it re-run the idle handler after any call?
Thanks!
Model: MacBook Pro 1.8GHz Core Duo
AppleScript: 1.10.7
Browser: Firefox 1.5.0.7
Operating System: Mac OS X (10.4)
I agree with that. In Tiger at least, calling a handler of a stay-open script application only runs that handler and any that the handler calls. But you can call the run and idle handlers individually if required.
The method I used above to quit the application immediately doesn’t seem to work in Tiger. The script still waits out the idle time after receiving the quit command before actually quitting. The only thing I can think of is to shorten the idle time as much as possible in that case:
on idle
if ((current date) - lastCalled > 5 * minutes) then
quit
return 1
else
return 60 -- or your preferred check interval.
end idle
Edit: Actually, there is another way, if you’re feeling clever. Set up an external script to quit the application during its idle period:
on idle
if ((current date) - lastCalled > 5 * minutes) then
do shell script "osascript -e 'delay 0.2' -e 'tell application \"" & (path to me as unicode text) & "\" to quit' > /dev/null 2>&1 & "
end if
return 60 -- or your preferred check interval.
end idle
I got the basic syntax of “osascript” from Dominik in another thread last month. I’ve no idea what the “/dev/null” business at the end does, but “osascript” seems to work better with it there!
You could use the other way where you change the delay time. e.g.
property delay_time : 5
global time_stamp
on run
set time_stamp to (current date)
end run
on idle
set cur_date to (current date)
beep 1
if (cur_date - time_stamp) > 10 then
say “quitting”
set delay_time to 1
quit
end if
return delay_time
end idle
This might look less confusing.
Hi Brett,
Also, found this in AppleScriptLanguageGuide.pdf:
Interrupting a Script Application’s Handlers
A stay-open script application handles incoming commands even if it is
already running a handler in response to a previous command. This means that
execution of a handler can be interrupted while another handler is run. Because
script applications are not multitasking, execution of the ï¬rst handler halts
until the second one ï¬nishes.
This can cause problems if both handlers modify the same script property or
global variable or if both attempt to modify an application’s data.
It might cause a problem here if the script is quitting when you call the subroutine. Not sure what would happen and it is hard to test