The FS3 multitasking is a great improvement but, sometimes, a problem for me: I often launch a script (via a keyboard shortcut) when it is already in progress. As a result, I can end up with several occurrences of the same window, waiting for user action.
Some of my scripts are applications and are therefore not affected. But most are compiled scripts or bundles that, for multiple reasons, I can’t convert into applications.
So you will have understood: I am looking for a way to prevent a script from running in FS3 if it is already in progress.
The most immediate solution is to have each script create a temporary file that gets removed upon completion of execution. The creation of the temporary file would be upon condition that such a file did not already exist, and this condition should be life-or-death for the script.
I’ve already thought about this kind of solution.
Save a preference (using NSUserDefault) at first run and then check it on subsequent launches.
But with more than 800 scripts, I hesitate to embark on such an adventure…
I was more thinking of an AppleEvent observer.
I have some scripts for this. I should probably clean it up as some of the below are redundant, but these work:
on pauseUntilAnyScriptIsRunning(isRunning, theTimeout)
tell application "FastScripts"
if class of isRunning is not boolean then set isRunning to isRunning as boolean
if isRunning is true then
set theInverse to false
else
set theInverse to true
end if
set theCount to 0
repeat until theCount > theTimeout
if (my scriptTaskRunningFastscripts(0)) is isRunning then return isRunning
delay 0.1
set theCount to theCount + 0.1
end repeat
end tell
return theInverse
end pauseUntilAnyScriptIsRunning
on pauseUntilNamedScriptIsRunning(isRunning, scriptName, theTimeout)
tell application "FastScripts"
if class of isRunning is not boolean then set isRunning to isRunning as boolean
if isRunning is true then
set theInverse to false
else
set theInverse to true
end if
set theCount to 0
repeat until theCount > theTimeout
if (my namedScriptRunning(scriptName, false)) is isRunning then return isRunning
delay 0.1
set theCount to theCount + 0.1
end repeat
end tell
return theInverse
end pauseUntilNamedScriptIsRunning
on scriptTaskRunningFastscripts(theTimeout) -- any script task
tell application "FastScripts"
set theCount to 0
repeat until theCount > theTimeout
if (count script tasks) > 0 then return true
delay 0.1
set theCount to theCount + 0.1
end repeat
return false
end tell
end scriptTaskRunningFastscripts
on namedScriptRunning(scriptName, returnCount) -- named script task
set theCount to 0
tell application "FastScripts"
set theTasks to (name of (script item of every script task))
repeat with eachName in theTasks
if (eachName as text) is scriptName then
if returnCount is false then
return true
else
set theCount to theCount + 1
end if
end if
end repeat
if returnCount is true then
return theCount
else
return false
end if
end tell
end namedScriptRunning
on scriptActiveTaskCount(scriptPath) -- returns count of host script's active tasks (use `path to me as text`)
tell application "FastScripts"
set scriptTasks to every script task
set myList to {}
repeat with eachScriptTask in scriptTasks
set eachPath to script file of script item of eachScriptTask as text
if eachPath is scriptPath then set end of myList to eachScriptTask
end repeat
end tell
return (count myList)
end scriptActiveTaskCount
on pauseUntilScriptTaskNotRunningByID(scriptTaskID, theTimeout) -- returns true if/when not running
set theCount to 0
tell application "FastScripts"
repeat
if theCount ≥ theTimeout then exit repeat
set theTasks to (id of every script task)
if scriptTaskID is not in theTasks then return true
set theCount to theCount + 0.1
delay 0.1
end repeat
end tell
display alert "Timed out" message scriptTaskID
return false
end pauseUntilScriptTaskNotRunningByID
You probably want pauseUntilNamedScriptIsRunning(false, scriptName, theTimeout).
Sorry I didn’t notice this until now. Interesting conundrum and I can see how it would be useful to be able to designate some scripts as “one at a time”. I’ll think about what I can do to improve this in a future update. And that’s an impressive approach you’ve got @p1r2c1 !
In fact, I forgot one thing: in real conditions (i.e. outside SD), this line will prevent the execution of the subsequent code, because the current script will always be present in the list of tasks.
So,
tell application "FastScripts" to if (count of (script tasks whose script file of script item of it = ((path to me) as «class furl»))) > 1 then return beep