Determining Whether My Application is the Currently Active Application

I’m writing an Applescript Studio application, and I need to know at a certain point whether my application is in the foreground or the background on the user’s desktop - that is, whether its window is currently the active window.

Note that I don’t need to determine when the window becomes active - for example, via a on became main handler. I need to determine if the window is active at a given moment, during some other handler.

It appears that the non-multitasking nature of Applescript makes it impossible for the “main” property of the window to change while the program is doing something else. It has to be idle and waiting for user input.

What I want to do, specifically, is to perform an action after a given interval, but only if the window is not main at that point. If it becomes main during the wait interval, then I want to abort the action.

I’ve done many Google searches, I’ve read the FAQs here, but so far have had no luck finding a way to do this.

So, is there a way to do what I want to do?

Thank you,

Joe Walsh

Hi,

I’ve had similar problems like yours.

To fix it, I usually ask System Events to check whether a particular application is frontmost or not by adding a few lines of code like this:

tell application “System Events”
if frontmost of application “My Application” is true then
–do something
else
–do another thing
end if
end tell

I hope above helps or gives you some lead that might point the way.

Good luck!

archseed :slight_smile:

Hmm. I tried your code out, but it appears I’m still running into the problem of the app not resigning until it’s out of the current event loop. I even tried telling Finder to set frontmost for my app to false, and that didn’t make any difference. I guess the run loop for Applescript Studio apps is truly single-minded.

Even so, thank you for pointing me in a new direction. I’ll keep thinking about your answer, and hope I figure out a way to make it work.

-Joe

Hi Ransom,

It’s hard to understand what you’re doing, but maybe you could use this. When you send a command to an application, your application ususally (if not always) waits for a reply. When you get the reply, your application continues on. Here’s an example using an AppleScript app.

activate
repeat with i from 1 to 3
display dialog i
end repeat

I saved this with the name “DisplayNumbers”. Now in the Script Editor run this:

–ignoring application responses
tell application “DiaplayNumbers”
launch
run
end tell
–end ignoring
beep 3

When you run that in the Script Editor, it waits for a reply. Now, remove the comments from the ‘ignoring’ and ‘end ignoring’ statements’. This time it doesn’t wait for the reply and beeps 3 times. If this not pertain to your situation, then disregard.

gl,

Hi,

I don’t rightfully know why. May be the environment of your application is already complicated for it to work.

Still, if you wish to check out my suggestion on a very simple situation and see whether it works, please test the simple codes below:


tell application "System Events"
	--set frontmost of application "iTunes" to true
	if frontmost of application "iTunes" is false then
		tell me to display dialog "iTunes is in the back."
	else
		beep
		tell it to display dialog "iTunes is in front."
              -- or tell application "iTunes" to display dialog "iTunes is in front." (alternative code)
	end if
end tell 

Uncomment the second line if you wish to try with iTunes in front and see the response.

Hope this helps.

Good luck.

archseed :slight_smile:

I’ll try to explain better what my situation is, so I can figure out what I’m missing.

I am writing an AppleScript Studio application. The application has a button within its window. I have a “on clicked” handler for that button. When the button is pressed, the “on clicked” handler is called. Within that handler, my application launches another application, then reads the delay value previously set by the user. It then delays for 1 second, checks to see whether it (my application) is frontmost or not, then delays another second, and so on until the total delay value time has elapsed. So, for example, if the delay value was set to 20, it would delay for 1 second then check for foreground 20 times.

When it checks for frontmost status, if it finds that it is indeed frontmost, then it immedialy breaks out of the delay loop and nothing else happens. If it remains not frontmost for the entire delay time, then it takes a screenshot.

The desired effect is that if the user switches back to my application from the launched application, my application should stop the delay loop and go back to business as usual. If the user keeps using the launched application, then my application should take a screenshot.

Thanks to help from Kel and Nigel in the Applescript forum next door, I’m able to make sure that launched application is running. The bit of code I’m seeking help with here will let me make sure that even if it is running, it hasn’t been switched to the background.

Which bring me to where I had this backward. I don’t want to find out if MY application is foreground; I want to find out if the launched app is foreground. I only want a screenshot of /that/ app.

So, now I’m working on trying to turn the return value from “default application of (info for f)” - where ‘f’ is an alias - into something that works with the statement ‘frontmost of application f’.

The script I developed below doesn’t work. At the display dialog phase, if I click on, say, a Script Editor file, it will display “Script Editor”. And, if I replace “the_app” in the “if frontmost of application the_app is false then” statement with literal text “Script Editor”, it works fine. But if I use the variable the_app, it says, “System Events got an error: Can’t make frontmost of application “Script Editor” into type reference.”

So I obviously have the wrong type of data in the end. Although I’ve been programming as a hobbyist and sometimes as a professional since 1983, I’ve only been using Applescript since last Wednesday, so forgive me if the solution to this problem seems blindingly obvious to everyone else here. :wink:

Also, note that in my actual applicaiton, the name of the application being run is initially derived through a " set default_app_path to default application of (info for ((currentFolder & “:” & selectedGame) as alias))" statement. It fails the same way in my app as with my script editor script below.


set f to choose file
set default_app_path to default application of (info for f)
set default_app_path_as_text to "" & default_app_path
set AppleScript's text item delimiters to ":"
set path_as_list to every text item of default_app_path_as_text
set the_app_and_extension to item ((count path_as_list) - 1) of path_as_list
set AppleScript's text item delimiters to "."
set the_app_and_extension_list to every text item of the_app_and_extension
set the_app to first item of the_app_and_extension_list

display dialog "" & the_app

delay 5  -- Take time to move Script Editor to foreground or background.

tell application "System Events"
	if frontmost of application the_app is false then
		display dialog "Not frontmost"
	else
		display dialog "frontmost"
	end if
end tell


Aha! I needed to look for a process in this instance, rather than an application, given my input.

Here’s my code. It’s ugly and only lightly tested, but, hey, that’s why weekends exist!


set f to choose file
set default_app_path to default application of (info for f)
set default_app_path_as_text to default_app_path as text
set len to length of default_app_path_as_text
set default_app_path_final to text 1 thru (len - 5) of default_app_path_as_text
set AppleScript's text item delimiters to ":"
set thelist to every text item of default_app_path_final
set the_app to item (count thelist) of thelist
display dialog "" & the_app

delay 5 -- Take time to move Script Editor to foreground or background

tell application "System Events"
	if frontmost of process the_app is false then
		display dialog "Not frontmost"
	else
		display dialog "frontmost"
	end if
end tell


Browser: Firefox 1.5.0.1
Operating System: Mac OS X (10.4)

Hi Ransom,

I am glad the weekend did not hold you at ransom, huh? :smiley:

No, honestly I am glad you found a solution but be careful with the use of the word “process” as it sometimes does not work. i wish the AppleScript gurus could kindly explain why.

For example, if I substitute the word “process” instead of “application” in the simple test code that I asked you to try earlier, it does not work. Try the modified codes below to find out.

tell application "System Events"
	--set frontmost of application "iTunes" to true
	--test using "process" instead of "application"
	if frontmost of process "iTunes" is false then
		tell me to display dialog "It's in the back."
	else
		beep 2
		--tell application "iTunes" to display dialog "it's in the front."
		tell it to display dialog "It's in the front."
	end if
end tell

In the above case you will get the AppleScript error

unless the application “iTunes” is already up and running and frontmost.

Just a reminder in case you run into such a problem.

archseed :slight_smile:

Good point. I’ll definitely put it in a try block and respond accordingly to an error.

Thank you once again, archseed!

-Joe

Hi,

Here’s an example:

set my_name to name of (info for (path to me))
– remove .app extension if any
if my_name ends with “.app” then
set my_name to (text 1 through -5 of my_name)
end if
set pic_path to quoted form of “/Users/kel/Desktop/Screenshots/Picture.pdf”
set unix_command to ("screencapture " & pic_path)
repeat until (keys pressed) contains “Option” – uses Jon’s Commands ‘keys pressed’
tell application “System Events”
set front_process to (name of first process whose frontmost is true)
end tell
if not (front_process is my_name) then
do shell script unix_command
beep 1
delay 1
end if
end repeat

When you use frontmost in a tell application block, it pertains to the application. If the app is not scriptable, then it won’t have the ‘frontmost’ property. To use the ‘frontmost’ property of a process, you need to get a listing.

tell application “System Events”
every process whose frontmost is true
end tell

This gives you one item list of a Finder reference to the frontmost process. This you hardly ever use, so you usually get the name of the process. Note that the name of the process will probably not be the name of the applicaiton which usually ends with .app in OSX. Also, sometimes the name of the process is different from the name of the app even without the .app extension. In this case, you need to find the name of the process by looking in some process viewer when the app is running.

Editted: I forgot to say this. The examples you see here, usually don’t take into account everything. A lot depends on your preference. For instance, ususally it is assumed that the app is running. You determine what to do if an app is running or not. You might run the app or not and just quit the script.

To check for existance:

tell app “System Events”
set is_running to (exists process “SomeProcessName”)
end tell
if is_running then
– do something
end if

fro example.

gl,

Oops, I made a mistake. You can use the boolean value returned by frontmost. I use the name by habit. Rewrote it:

set my_name to name of (info for (path to me))
if my_name ends with “.app” then
set my_name to (text 1 thru -5 of my_name)
end if
repeat until (keys pressed) contains “Option”
tell application “System Events”
set is_frontmost to frontmost of process my_name
end tell
if not is_frontmost then
do shell script “screencapture /Users/kel/Desktop/Picture.pdf”
beep 1
delay 1
else
do shell script “sleep 1”
end if
end repeat

gl,

Hi Kel,

Thanks for the explanation.

I’d say one of the AppleScript gurus has spoken on the issue. I learned a wee bit and will surely remember what “process” is now instead of just blindly relying on faith and hope that it would work (:().

More power to you and MacScripter!

archseed :smiley:

Hi archseed,

You’re welcome, but I have the feeling I was a bit wrong in somethings. Not thinking right right now. Maybe I need a guru. :smiley:

gl,

Hi Kel,

Thank you for the additional explanation! I’ll integrate what you’ve shown me into my application. From what you said, though, I’ll never be able to guarantee that my app will be able to detect whether a given process is frontmost. As you said, if its process name is different than its name on the disk, then this method will fail.

I did test the code with many apps, several of which are relatively obscure, cross-platform projects (and therefore most likely not to adhere to Mac standards). I was pleased that it did work with all of them, so there’s hope the method you and Archseed have explained to me is robust enough for a sufficient number of cases for my app to be useful.

Certainly, it’s an order of magnitude better than what I worked out on my own my first day of Applescripting - using creator codes to figure out which app is likely to launch when a document is double-clicked, then checking the process list for that application. I quickly found out that creator codes are extremely unreliable, at least when it comes to tracking down an application from the code in a data file.

Now, however, my application is always right when it goes to figure out which application will be launching, and it tracks those applications flawlessly so far in alpha testing, right down to knowing whether the application in question is frontmost or not in any given second. That lets my UI remain responsive no matter what the user does.

Again, thank you for your very helpful explanations and examples. I hope I’ll be able to return the favor to you, Archseed, and Nigel some day.

-Joe

Hi Ransom,

It’ rare that a process name will have a different name then the app. I’ve only seen it two times I think. I think it was with some Adobe app and Weatherpop or something like that. In your case, it doesn’t matter though because you’re just using the name of your app (being frontmost or not).

Thanks to archseed for bringing this up. Usually I’m good at reading between the lines.

gl,

Actually, I decided it made more sense to check if the other app is frontmost rather than my app, since some third app could be frontmost instead. So, it might come up, but I’m glad to hear it would be rare.

Thanks again,

-Joe

Hi,

Then you can do this:

tell application “System Events”
set front_process to displayed name of first process whose frontmost is true
end tell

This gives you the name of the file from which the process was launched (the application). I’d still check for the .app extension, because I’m not sure if the extension is always ignored.

BTW, another and more accurate way to get the processes, is to use the unix ‘ps’ command. I used to have a script that gets this, but lost all my new scripts. I don’t know how you could use this here, but you might look into that.

gl,