Detecting which of two apps has the frontmost window

have a JavaScript called “Readability”** that produces a configurable large page of the main event on a web page with surprising accuracy. I like to use it reading newspaper articles in Safari and NetNewsWire feed articles, and it works well with either. Because I’m a keyboard shortcut fan I often run my scripts from Quicksilver triggers and I’d like the script to target either Safari or NetNewswire, whichever has the frontmost window (the one I am about to read). I haven’t found a clean way to do that.


** Readability comes as a link to be dragged to the Bookmarks Bar of a browser, but having done that, you can copy the JavaScript from the bookmark for use in an AppleScript like this (with either Safari or NetNewsWire in the tell): tell application “NetNewsWire” to tell document 1 to do JavaScript “…”


tell application "Safari or NetNewsReader" to tell document 1 to do JavaScript "javascript:(function(){readStyle='style-novel';readSize='size-large';readMargin='margin-wide';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());document.getElementsByTagName('head')[0].appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';_readability_css.type='text/css';_readability_css.media='screen';document.getElementsByTagName('head')[0].appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();"

What’s the cleanest way to determine which is frontmost assuming both have open windows.

Hello Adam,

actually the visible window with the lowest index of the frontmost application is the frontmost window

Adam:

This works (for me - 10.4.11) invoked by keyboard command from FastScripts:


tell application "Finder"
	set last_app to item 1 of (get name of processes whose frontmost is true)
end tell

tell me to activate
display dialog last_app as text

tell application last_app to activate

Peter B.

Works for me too, Peter. Unfortunately, the statement “tell document 1 of application last_app to do JavaScript …” doesn’t (fails to compile) so I have to run this:

(*
The following JavaScript from Arc90 "makes reading on the web more enjoyable by removing the clutter around what you're reading" and the Readability site allows you to set Style, Size and Margin in the material. It is normally used by dragging a link from the Readability page to your Bookmarks Bar, and that puts the JavaScript below as the content of the bookmark. The page thus created in your browser has a link on it to return to the original source.

Visit "http://lab.arc90.com/experiments/readability/" for your own copy.

Because I'm an avid Quicksilver fan (but there are lots of alternatives), I prefer to set up a trigger to run the script below so I can enhance the readability of an article I'm looking at with a simple key combination. Although it cannot render every site I visit, it does remarkably well.
*)

set JS to "javascript:(function(){readStyle='style-novel';readSize='size-large';readMargin='margin-wide';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());document.getElementsByTagName('head')[0].appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';_readability_css.type='text/css';_readability_css.media='screen';document.getElementsByTagName('head')[0].appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();"

tell application "System Events" to set last_app to item 1 of (get name of processes whose frontmost is true)
if last_app is "Safari" then
	tell document 1 of application "Safari" to do JavaScript JS
else if last_app is "NetNewsWire" then
	tell document 1 of application "NetNewsWire" to do JavaScript JS
else
	beep 3
end if

Adam:

I think you might be having problems switching back and forth from Script Editor and QuickSilver ‘contexts’.

I don’t have NetNewsWire, so I’ve commented out the relevant block… but the rest of the following is working for me when triggered from FastScripts…

Peter B.

PS - Readability is of interest… I’ll be following it and think it might be of use.


(*
The following JavaScript from Arc90 "makes reading on the web more enjoyable by removing the clutter around what you're reading" and the Readability site allows you to set Style, Size and Margin in the material. It is normally used by dragging a link from the Readability page to your Bookmarks Bar, and that puts the JavaScript below as the content of the bookmark. The page thus created in your browser has a link on it to return to the original source.

Visit "http://lab.arc90.com/experiments/readability/" for your own copy.

Because I'm an avid Quicksilver fan (but there are lots of alternatives), I prefer to set up a trigger to run the script below so I can enhance the readability of an article I'm looking at with a simple key combination. Although it cannot render every site I visit, it does remarkably well.
*)

set JS to "javascript:(function(){readStyle='style-novel';readSize='size-large';readMargin='margin-wide';_readability_script=document.createElement('SCRIPT');_readability_script.type='text/javascript';_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());document.getElementsByTagName('head')[0].appendChild(_readability_script);_readability_css=document.createElement('LINK');_readability_css.rel='stylesheet';_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';_readability_css.type='text/css';_readability_css.media='screen';document.getElementsByTagName('head')[0].appendChild(_readability_css);_readability_print_css=document.createElement('LINK');_readability_print_css.rel='stylesheet';_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();"

tell application "System Events" to set last_app to item 1 of (get name of processes whose frontmost is true)
if last_app is "Safari" then
	tell application "Safari"
		activate
		do JavaScript JS in document 1
	end tell
	--else if last_app is "NetNewsWire" then
	--tell document 1 of application "NetNewsWire" to do JavaScript JS
	--else
	--beep 3
end if



A much nicer form of the JS (much more readable itself) is this:

set JS to "readStyle='style-novel';
	readSize='size-large';
	readMargin='margin-wide';
	_readability_script=document.createElement('SCRIPT');
	_readability_script.type='text/javascript';
	_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());
	document.getElementsByTagName('head')[0].appendChild(_readability_script);
	_readability_css=document.createElement('LINK');
	_readability_css.rel='stylesheet';
	_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';
	_readability_css.type='text/css';
	_readability_css.media='screen';
	document.getElementsByTagName('head')[0].appendChild(_readability_css);
	_readability_print_css=document.createElement('LINK');
	_readability_print_css.rel='stylesh  eet';
	_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';
	_readability_print_css.media='print';
	_readability_print_css.type='text/css';
	document.getElementsByTagName('head')[0].appendChild(_readability_print_css);"

Hi guys,

I get different behavior depending on how I save my code and where the code is run from. For example if I save my code as a script and run it from the script menu then the script does not become frontmost when run. However, if my code is saved as an applescript application then it does become frontmost when run.

A second variable is whether you save you application as an application bundle or not. An application name matches its process name when using “name” but not “displayed name” from system events. An application bundle name matches its process name when using “displayed name” but not “name”.

Because of these variables I always use the following handler to get the name of the frontmost application. This way I don’t ever have to worry about how/where I save and run my code. It always works.

-- This handler ensures that no matter where your code is run from or
-- how the code is saved that you always get the proper frontmost application

-- We have to check both displayed name and name because...
-- an application name matches its process name when using "name" but not "displayed name"
-- an application bundle name matches its process name when using "displayed name" but not "name"


set frontApp to getFrontAppName()
tell me
	activate
	display dialog frontApp
end tell

on getFrontAppName()
	tell application "System Events"
		-- check name
		set frontApp to name of first process whose frontmost is true
		set scriptName to name of (get path to me)
		if frontApp is scriptName then
			set visible of process scriptName to false
			set frontApp to name of first process whose frontmost is true
		end if
		
		-- check displayed name
		set frontApp to displayed name of first process whose frontmost is true
		set scriptName to displayed name of (get path to me)
		if frontApp is scriptName then
			set visible of process scriptName to false
			set frontApp to displayed name of first process whose frontmost is true
		end if
	end tell
	return frontApp
end getFrontAppName