Stay Open App to Quit If Not Called for Specified Time

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)

Hi Brett,

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

gl,

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

Thanks for the ideas! I’ll give these a shot and see how it works. I’m just glad I was at least on the right track. :slight_smile:

Model: MacBook Pro 1.8GHz Core Duo
AppleScript: 1.10.7
Browser: Firefox 1.5.0.7
Operating System: Mac OS X (10.4)

Hi Brett,

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.

gl,

Thanks for that idea.

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)

Hi Brett,

When you call a subroutine of an app, I think you just interrupt it. After the subroutine is run, then the program just resumes from where it stopped.

gl,

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. :slight_smile: 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!

Hi Nigel,

Replacing your ‘error number -128’ with ‘return 1’ might work in wuitting faster.

Edited: disregard this. I didn’t see that you already did that.

gl,

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 first handler halts
until the second one finishes.

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

gl,