I’m attempting to configure a Mac Mini to be a fancy DVD player. I have an ATI Remote Wonder remote control, but the driver for the remote doesn’t have any effect means to switch between applications. (ie. if I map Command-Tab to a button, it just switches between the first two applications in the Finder’s list which isn’t very useful.)
I’m trying to create a script that will:
get a list of all running processes
hide all the windows of the frontmost application
show all the windows of the next process in the list
Here’s what I have so far (some of you may recognize code snippits stolen from other threads here):
on count_windows(a)
with timeout of 1 second
set nw to number of windows of application a
end timeout
return nw
end count_windows
on list_position(this_item, this_list)
repeat with i from 1 to the count of this_list
if item i of this_list is this_item then return i
end repeat
return 0
end list_position
tell application "Finder"
(* Get a list of names of all running processes *)
set allAppNames to the name of every application process
(* Exclude windowless applications *)
global appNames
set appNames to {}
set j to 1
repeat with nam in allAppNames
try
set nw to my count_windows(nam)
on error
set nw to -1
end try
if nw is greater than -1 then
set appNames to appNames & nam
end if
end repeat
(* Get the name of the frontmost application *)
set front_app to (path to frontmost application as Unicode text)
set AppleScript's text item delimiters to ":"
set front_app to front_app's text items
set AppleScript's text item delimiters to {""} --> restore delimiters to default value
set item_num to (count of front_app) - 1
set app_name to item item_num of front_app
set AppleScript's text item delimiters to "."
set app_name to app_name's text items
set AppleScript's text item delimiters to {""} --> restore delimiters to default value
set MyApp to item 1 of app_name
(* Get the next application in the list *)
set p to my list_position(MyApp, appNames)
set c to count of appNames
if p is equal to c then
set cycleNext to 1
else
set cycleNext to p + 1
end if
set NextApp to item cycleNext of appNames
(* Hide every window of the frontmost application *)
(* Show every window of the next application *)
set visible of every process whose visible is true and name is not NextApp to false
set visible of every process whose visible is false and name is NextApp to true
end tell
It seems to work okay when I click “run”. It hides all of the Script Editor windows and shows the Finder. Now when I save this script as an Application and map it to a button, when I press the button, my application gets a “the variable appNames is not defined” error.
I’m not sure if this is the reason for your problems but i found a problematic part in your script:
on count_windows(a)
with timeout of 1 second
set nw to number of windows of application a
end timeout
return nw
end count_windows
Not every application can count it’s windows - for example PhotoShop 7 can’t - so it will be excluded and stay visible.
can’t you simplify this:
set front_app to (path to frontmost application as Unicode text)
set AppleScript's text item delimiters to ":"
set front_app to front_app's text items
set AppleScript's text item delimiters to {""} --> restore delimiters to default value
set item_num to (count of front_app) - 1
set app_name to item item_num of front_app
set AppleScript's text item delimiters to "."
set app_name to app_name's text items
set AppleScript's text item delimiters to {""} --> restore delimiters to default value
set MyApp to item 1 of app_name
by using this?
set MyApp to (name of first application process whose frontmost is true)
Not sure if this gets any closer to what you’re trying to do, ichou - but it might give you one or two ideas.
property currIndex : 0
set appList to {}
tell application "System Events"
repeat with i in (get processes whose background only is false)
if (count i's windows) > 0 then set appList's end to i's contents
end repeat
set appCount to count appList
if appCount < 2 then return
set currIndex to currIndex mod appCount + 1
set currApp to item currIndex of appList
set frontmost of currApp to true
set visible of (processes whose frontmost is false) to false
end tell
Here I go, after a few rounds, I answer my own question. Don’t know why the variable scope is different when running as an application rather than as a script, but using a property lets me get around some “which application is in front” problems.
on count_windows(a)
with timeout of 1 second
set nw to number of windows of application a
end timeout
return nw
end count_windows
on filter_applications(allAppNames)
set localList to {}
set j to 1
repeat with nam in allAppNames
try
set nw to my count_windows(nam)
on error
set nw to -1
end try
-- Exclusions : Note that this script must be saved as "Cycle Applications"
if (nam as string is not equal to "Cycle Applications") and (nam as string is not equal to "System Events") and (nw is greater than -1) then
set localList to localList & nam
end if
end repeat
return localList
end filter_applications
on front_application()
tell application "System Events"
set localName to (the name of first application process whose frontmost is true and background only is false)
end tell
return localName
end front_application
on list_position(this_item, this_list)
repeat with i from 1 to the count of this_list
if item i of this_list is this_item then return i
end repeat
return 0
end list_position
property applist : {}
property frontApp : ""
tell application "Finder"
(* Get the name of the frontmost application *)
if frontApp is "" then
set frontApp to my front_application()
end if
(* Get a list of names of all running processes *)
set allAppNames to the name of every application process
(* Exclude windowless applications *)
set applist to my filter_applications(allAppNames)
(* Get the next application in the list *)
set p to my list_position(frontApp, applist)
set c to count of applist
if (c is equal to 1) or (c is less than 1) then
return
end if
if p is equal to c then
set cycleNext to 1
else
set cycleNext to p + 1
end if
set NextApp to item cycleNext of applist
(* Show every window of the next application *)
set visible of every process whose visible is true and name is not NextApp to false
set visible of every process whose visible is false and name is NextApp to true
(* The following 3 lines is used just to make sure windows are shown/hidden
because for some reason sometimes windows get "missed" *)
display dialog "Switching to " & NextApp buttons {"OK"} default button "OK" giving up after 3
set visible of every process whose visible is true and name is not NextApp to false
set visible of every process whose visible is false and name is NextApp to true
set frontApp to NextApp
end tell
I appreciate the tip about certain applications that don’t count windows. The ones I’m most interested in cycling through should be covered (DVD player, iPhoto, iTunes). Besides, can you imagine trying to manipulate Photoshop with a remote control? This machine doesn’t have a keyboard/mouse. When I need to “type”, I start up a synergy server on my Powerbook and a synergy client on the Mac Mini.